chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / scripts / e_gen_menu
1 #!/usr/bin/perl
2 ##############################################################################
3 # generates a file.menu format for Enlightenment out of menu hierarchies
4 #
5 # Copyright (C) 2003-2008 Kim Woelders
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to
9 # deal in the Software without restriction, including without limitation the
10 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11 # sell copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies of the Software, its documentation and marketing & publicity
16 # materials, and acknowledgment shall be given in the documentation, materials
17 # and software packages that this Software was used.
18 #
19 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 # THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23 # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 ##############################################################################
26
27 # Likely  prefixes
28 $Prefixes = "/usr/local:/usr:/opt:/opt/kde:$ENV{'KDEDIR'}";
29 $Prefixes = "$Prefixes:/opt/kde3:/opt/gnome";   # SUSE
30 $Prefixes = RemoveDuplcates($Prefixes);
31
32 # Where to look for GNOME/KDE stuff
33 $AppDirs = MkDirList($Prefixes, "/share/applications:/share/applications/kde:/share/applications/kde4");
34
35 $IconDirs = MkDirList($Prefixes, "/share/pixmaps:/share/icons");
36 $IconDirs2 = MkDirList($Prefixes, "/share/icons");
37 $Themes = "default.kde:gnome:hicolor";
38 $IconCats = "apps:filesystems:actions:devices:categories:places";
39
40 # Where to look for GNOME1 apps
41 $OldGnomeDirs = MkDirList($Prefixes, "/share/gnome/apps");
42 # Where to look for KDE1/2 apps
43 $OldKdeDirs = MkDirList($Prefixes, "/share/applnk");
44
45 # Pick up env vars
46 $EdirUser = "$ENV{'ECONFDIR'}";
47 $EdirRoot = "$ENV{'EROOT'}";
48 $EdirBin  = "$ENV{'EBIN'}";
49
50 # Localization bits. There may be better ways to do this.
51 $Lang = "$ENV{'LANG'}";
52 $loc1 = $loc2 = $loc3 = $Lang;
53 $loc2 =~ s/[\.\@].*//;
54 $loc3 =~ s/_.*//;
55 $loc1 = "" if ($loc1 eq $loc2);
56
57 $EdirUser = "$ENV{'HOME'}/.e16" unless $EdirUser;
58 $EdirRoot = "/usr/share/enlightenment" unless $EdirRoot;
59 $EdirBin  = "/usr/bin" unless $EdirBin;
60
61 $EdirMenus = "$EdirUser/menus";
62
63 $dbg      = "$ENV{'E_MENUGEN_DBG'}";
64
65 # Put EBIN first in path
66 $ENV{'PATH'} = "$EdirBin:$ENV{'PATH'}";
67
68 # Programs
69 $DoIconv = `which iconv`;
70
71 @CatsRemove = (
72         "Qt",
73         "QT",
74         "GTK",
75         "GNOME",
76         "KDE",
77         "UtilityApplication",
78         "Applications",
79         "Application",
80         "X-.*",
81 );
82
83 @MainMenu = (
84         "t:User Menus",
85         "m:User Application List:user_apps.menu",
86         "m:GNOME:menus_GNOME/index.menu",
87         "m:KDE:menus_KDE/index.menu",
88         "m:Other:menus_Other/index.menu",
89         "m:Epplets:epplets.menu",
90         "c:Restart:exit restart",
91         "c:Log Out:exit logout"
92 );
93
94 @UserAppsMenu = (
95         "t:User Application List",
96         "x:Eterm:Eterm",
97         "x:Terminal:Terminal",
98         "x:XTerm:xterm",
99         "x:rxvt:rxvt",
100         "x:urxvt:urxvt",
101         "x:Mozilla:mozilla",
102         "x:Seamonkey:seamonkey",
103         "x:Firefox:firefox",
104         "x:Galeon:galeon",
105         "x:Opera:opera",
106         "x:Gmplayer:gmplayer",
107         "x:Xine:xine",
108         "x:The GIMP:gimp",
109         "x:GQView:gqview",
110         "x:XV:xv",
111         "x:Gaim:gaim",
112         "x:Xchat:xchat",
113         "x:Xchat2:xchat2",
114         "x:Xchat2:xchat-2",
115         "x:XMag:xmag",
116         "x:Grip:grip",
117         "x:XMMS:xmms"
118 );
119
120 # Remove duplicates and nulls in ':' separated dir list
121 sub RemoveDuplcates {
122         local $dl = shift;
123         local @r;
124         local %h;
125         foreach $p (split(':', $dl)) {
126                 next unless $p;
127                 next if $h{$p};
128                 $h{$p} = $p;
129                 push @r, $p;
130         }
131         return join(':', @r);
132 }
133
134 # Make : separated directory list, check that they exist
135 sub MkDirList {
136         local $dl = shift;
137         local $sf = shift;
138         local $d;
139         local @r;
140         foreach $p (split(':', $dl)) {
141                 foreach $q (split(':', $sf)) {
142                         $d = "$p$q";
143                         push(@r, "$d") if -d "$d";
144                 }
145         }
146         return join(':', @r);
147 }
148
149 # Make dir if non-existing
150 sub MkDir {
151         local $d = shift;
152         mkdir("$d") unless (-d "$d");
153 }
154
155 # Make simple menus
156 sub MakeMenu {
157         local $f = shift;
158         local $m = shift;
159
160         $f = "$EdirMenus/$f";
161         return if (-f "$f");
162         open(FD, ">$f");
163         foreach $e (@$m) {
164                 ($t, $n, $p) = split(':', $e);
165                 if ($t eq "t") {
166                         print FD "\"$n\"\n";
167                 } elsif ($t eq "m") {
168                         print FD "\"$n\" NULL menu \"$p\"\n";
169                 } elsif ($t eq "x") {
170                         print FD "\"$n\" NULL exec \"$p\"\n";
171                 } elsif ($t eq "c") {
172                         print FD "\"$n\" NULL \"$p\"\n";
173                 }
174         }
175         close(FD);
176 }
177
178 # Process a .desktop file
179 sub ProcessFile {
180         local $f = shift;
181         local $Name, $Exec, $Icon, $Cats, $Type, $File;
182         local $c;
183
184         if (! -f "$f")  {
185                 print "Not found: $f\n" if $dbg ge 1;
186                 return;
187         }
188
189         # Global ref no
190         $N++;
191
192         $Name = $Exec = $Icon = "";
193         $Nam1 = $Nam2 = $Nam3 = "";
194         $Cats = shift;
195         $Type = shift;
196
197         open(FI,$f) or return;
198         while (<FI>) {
199                 if (/^Name=(.*)$/) {
200                         $Name = $1;
201                 } elsif ($loc1 && /^Name\[$loc1\]=(.*)$/) {
202                         $Nam1 = $1;
203                 } elsif ($loc2 && /^Name\[$loc2\]=(.*)$/) {     
204                         $Nam2 = $1;
205                 } elsif ($loc3 && /^Name\[$loc3\]=(.*)$/) {     
206                         $Nam3 = $1;
207                 } elsif (/^Exec=(.*)$/) {
208                         $Exec = $1;
209                 } elsif (/^Icon=(.*)$/) {
210                         $Icon = $1;
211                 } elsif (/^OnlyShowIn=(.*);$/) {
212                         $Type = $1;
213                 } elsif (/^Categories=(.*)$/) {
214                         next if "$Cats";        # Given
215                         CF: foreach $cf (split(';', $1)) {
216                                 if ($cf eq "KDE") {
217                                         $Type = "KDE";
218                                         next;
219                                 }
220                                 foreach $cr (@CatsRemove) {
221                                         next CF if ($cf =~ /^$cr$/);
222                                 }
223                                 $Cats = "$Cats$cf;";
224                         }
225                 } elsif (/^Type=(.*)$/) {
226                         if ($1 ne "Application") {
227                                 $Name = "";
228                                 last;
229                         }
230                 }
231                 if ($Nam1 || $Nam2 || $Nam3) {
232                         if    ($Nam1) { $Name = $Nam1; }
233                         elsif ($Nam2) { $Name = $Nam2; }
234                         else          { $Name = $Nam3; }
235                         $Name = `echo "$Name" | iconv -f UTF-8` if $DoIconv;
236                         chomp($Name);
237                 }
238         }
239         close FI;
240
241         $Cats =~ s/ +$//;
242         if (!$Name || !$Exec || !$Cats) {
243                 printf("Skipped: %-24s %-24s %-20s %-20s %s\n",
244                         $f, $Name, $Exec, $Icon, $Cats) if $dbg ge 1;
245                 return;
246         }
247
248         # Basename
249         $File = $f; $File =~ s/^.*\///;
250
251         printf("%-24s: %-24s %-20s %-20s %s\n",
252                 $File, $Name, $Exec, $Icon, $Cats) if $dbg ge 3;
253
254         if (!$Type) {
255                 if      ($File =~ /^gnome/) {
256                         $Type = "GNOME";
257                 } elsif ($File =~ /^kde/) {
258                         $Type = "KDE";
259                 } else {
260                         $Type = "Other";
261                 }
262         }
263
264         $Namx = "$Name-$N";     # Make key unique
265         $Namx =~ tr/A-Z/a-z/;   # To lower case (for sorting)
266         $Exec =~ s/\s*%(f|F|i|k|m|n|N|u|U|v)//g;        # Strip unwanted args
267         $Exec =~ s/\s*-\w+\s*"%c"//g;                   # Strip option with caption
268 #       $Exec =~ s/"%c"/'$Name'/g;                      # Alternatively - Substitute caption
269         $File{$Namx} = $File;
270         $Name{$Namx} = $Name;
271         $Exec{$Namx} = $Exec;
272         $Icon{$Namx} = $Icon;
273         $Cats{$Namx} = $Cats;
274         $Type{$Namx} = $Type;
275 }
276
277 # Process all .desktop files in a directory
278 sub ProcessDir {
279         local $d = shift;
280         local $dx = shift;
281         local $t = shift;
282         local @l;
283         local $f;
284
285         @l = grep /\.desktop$/, ReadDir($d);
286         foreach $f (@l) {
287                 $f = "$d/$f";
288                 print "- File $f\n" if $dbg ge 2;
289                 ProcessFile("$f", "$dx", "$t");
290         }
291 }
292
293 # Process old style GNOME/KDE directories
294 sub ProcessOldStyle {
295         local $t = shift;
296         local $dl = shift;
297         local $d, $d2;
298         local @d2l;
299
300         foreach $d (split(':', $dl)) {
301                 print "Processing directory: $d\n" if $dbg ge 1;
302                 if (! -d "$d") {
303                         print "- Not found\n" if $dbg ge 1;
304                         next;
305                 }
306                 @d2l = grep !/^\./, ReadDir($d);
307                 foreach $d2 (@d2l) {
308                         print " Subdir: $d/$d2\n" if $dbg ge 1;
309                         next unless -d "$d/$d2";
310                         ProcessDir("$d/$d2", "$d2", "$t");
311                 }
312         }
313 }
314
315 # Find that $#@! thing
316 sub FindIcon {
317         local $f = shift;
318         local $x = "x";
319
320         return $f if (! $f);
321
322         return $f if (-f $f);
323
324         foreach $d (split(':', $IconDirs)) {
325                 $i = "$d/$f";
326                 unless (-f $i) {
327                         next if ($f =~ /\.png$/);
328                         $i = "$i.png";
329                         next unless -f $i;
330                 }
331                 return $i;
332         }
333
334         foreach $d (split(':', $IconDirs2)) {
335                 next unless (-d "$d");
336                 foreach $t (split(':', $Themes)) {
337                         next unless (-d "$d/$t");
338                         foreach $s (split(':', "48:32:24:16")) {
339                                 $S = "$d/$t/$s$x$s";
340                                 next unless (-d "$S");
341                                 if ($f =~ /^stock/) {
342                                         $i = "$S/stock/*/$f.png";
343                                         $ii = glob("$i");
344                                         print "Testing $i\n" if $dbg >= 2;
345                                         return $ii if (-f $ii);
346                                 } else {
347                                         foreach $u (split(':', $IconCats)) {
348                                                 next unless (-d "$S/$u");
349                                                 $i = "$S/$u/$f";
350                                                 if ($f =~ /\.png|\.xpm$/) {
351                                                         print "Testing $i\n" if $dbg >= 2;
352                                                         return $i if (-f $i);
353                                                 } else {
354                                                         $ii = "$i.png";
355                                                         print "Testing $ii\n" if $dbg >= 2;
356                                                         return $ii if (-f $ii);
357                                                         $ii = "$i.xpm";
358                                                         print "Testing $ii\n" if $dbg >= 2;
359                                                         return $ii if (-f $ii);
360                                                 }
361                                         }
362                                 }
363                         }
364                 }
365         }
366
367         return $f;
368 }
369
370 # Make the Epplets menu
371 sub MakeEppsMenu {
372         local $f = shift;
373         local $d;
374         local %done;
375         open(FD, ">$EdirMenus/$f");
376         print FD "\"Enlightenment Epplets\"\n";
377         foreach $d (split(':', $ENV{'PATH'})) {
378                 next unless -d $d;
379                 next if ($done{$d});
380                 $done{$d} = 1;
381                 print "Looking for epplets in $d\n" if $dbg ge 1;
382                 @el = grep /\.epplet$/, ReadDir($d);
383                 foreach $e (@el) {
384                         $e =~ s/\.epplet$//;
385                         $i = "$EdirRoot/epplet_icons/$e.icon";
386                         print FD "\"$e\" \"$i\" exec \"$d/$e.epplet\"\n";
387                 }
388         }
389         close(FD);
390 }
391
392 # Make the menu for a given app type
393 sub MakeAppsMenu {
394         local $type = shift;
395         local %menus;
396         local $c, $k, $dir;
397
398         $dir = "$EdirMenus/menus_$type";
399         $mdir = "menus_$type";
400         print "Generating Menu: $type in $dir\n" if $dbg ge 1;
401         MkDir($dir);
402
403         # Sort the apps into categories
404         foreach $k (sort(keys(%Name))) {
405                 next if ($Type{$k} ne $type);
406                 $c = $Cats{$k};
407                 $c =~ s/;.*$//;
408 #               $menus{$c} = $k;
409                 push(@{$menus{$c}}, $k);
410         }
411
412         # Make top- and sub-menus
413         open(FTopM, ">$dir/index.menu") or die "*** Couldn't create $dir/index.menu\n";
414         print FTopM "\"$type Menu\"\n";
415         foreach $m (sort(keys(%menus))) {
416                 open(FSubM, ">$dir/$m.menu") or die "*** Couldn't create $dir/$m.menu\n";
417                 print "- Submenu: $m\n" if $dbg ge 2;
418                 print FTopM "\"$m\" \"\" menu \"$mdir/$m.menu\"\n";
419                 print FSubM "\"$m\"\n";
420                 foreach $k (sort(@{$menus{$m}})) {
421                         print " - Item: $k\n" if $dbg ge 2;
422                         $icon = FindIcon($Icon{$k});
423                         printf FSubM "\"%s\" \"%s\" exec \"%s\"\n",
424                                 $Name{$k}, $icon, $Exec{$k};
425                 }
426                 close(FSubM);
427         }
428         close(FTopM);
429 }
430
431 # Return list of files in dir
432 sub ReadDir {
433         local $dir = shift;
434         local @dirs;
435         if (!opendir DH, $dir) { print "*** Could not open: $dir\n"; return 0; }
436         @dirs = readdir DH;
437         closedir DH;
438         return @dirs;
439 }
440
441 # Close all windows named "Message" (we assume they are E dialogs)
442 sub CloseMessageWindows {
443         system("eesh -e 'wop Message* close' >/dev/null");
444 }
445
446
447 ##############################################################################
448 # Here we go
449 ##############################################################################
450 $N = 0;
451
452 CloseMessageWindows();
453 system("eesh -e \"dialog_ok Menus are being generated... Please Wait.\"");
454
455 # Process old style GNOME directories
456 ProcessOldStyle("GNOME", "$OldGnomeDirs");
457
458 # Process old style KDE directories
459 ProcessOldStyle("KDE", "$OldKdeDirs");
460
461 # Process new style (GNOME2, KDE2/3) directories
462 foreach $d (split(':', $AppDirs)) {
463         print "Processing directory: $d\n" if $dbg ge 1;
464         if (! -d $d) {
465                 print "- Not found\n" if $dbg ge 1;
466                 next;
467         }
468         ProcessDir($d);
469 }
470
471 # Make menu dir and scaled icon dir
472 MkDir("$EdirMenus");
473
474 # Make the menus
475 MakeMenu("file.menu", \@MainMenu);
476 MakeMenu("user_apps.menu", \@UserAppsMenu);
477 MakeEppsMenu("epplets.menu");
478 MakeAppsMenu("GNOME");
479 MakeAppsMenu("KDE");
480 MakeAppsMenu("Other");
481
482 CloseMessageWindows();
483 system("eesh -e 'menus reload'");
484 system("eesh -e 'dialog_ok Menu generation complete.'");