Hi,

attached is a patch (fvwm-menu-desktop.in.p5.patch) related to the newest CVS version of fvwm-menu-desktop.in with:
- some bug fixes:
  - corrects error output
  - keyerror 'debian'
  - not working regex with trailing slash in install-prefix interpretation
  - eliminate % behind menu entries if no icon will be found
- two new parameters:
  --get-menus
prints a comma separated list with full menu paths. 'selected' prints the desktop related menus. 'all' prints all founded menus on the system. Both without empty ones. No menu generation will be done. Useful to create a FvwmForm with the available menus - 'all' to get a complete list and
    'selected' to set the suggested ones ^^ .
  --set-menuswithout empty ones
expects a comma separated list of menu paths to generate user specified menus. User select some
    and fvwm-menu-desktop creates them.
- refreshed help
- fix fixme for 'Regenerate Menu'. Put it into the root menu because the user won't find it. I see this under SuSE. Too much menus. In the root she/he will find it at once. But Dan, if you would like the old version patch fvwm-menu-desktop.in.p6.patch over p5. Then it will appear in the System-Tools folder again. - extend --verbose: prints a time output at the end how long the process took.

btw. In the CVS version is #!/usr/bin/python set. Should this not be #!@PYTHON@ ?

Thomas
--- fvwm-menu-desktop.orig	2012-07-03 22:56:01.316247721 +0200
+++ fvwm-menu-desktop.in.py	2012-07-04 22:31:36.740854523 +0200
@@ -42,6 +42,8 @@
 import os.path
 import os
 from xdg.DesktopEntry import *
+import fnmatch
+import time
 
 
 def main ():
@@ -81,7 +83,6 @@
                'png-icons-path',
                'submenu-name-prefix',
                'time-limit',
-               'title',
                'tran-icons-path',
                'tran-mini-icons-path',
                'type',
@@ -97,14 +98,16 @@
 
     try:
         opts, args = getopt.getopt(sys.argv[1:], "hs:t:vw",
-                                   ["help", "verbose", "enable-mini-icons", "with-titles",
-                                    "desktop=", "size=", "theme=", "install-prefix=", "menu-type="]+obs_args+equaled_obs_parms)
+                                   ["help", "verbose", "enable-mini-icons", "with-titles", "verbose",
+                                    "desktop=", "size=", "theme=", "install-prefix=", "menu-type=",
+                                    "title=", "get-menus=", "set-menus="]+obs_args+equaled_obs_parms)
     except getopt.GetoptError, err:
         # print help information and exit:
         print str(err) # will print something like "option -a not recognized"
         print usage
         sys.exit(2)
-    global verbose, force, size, theme, icon_dir, top, install_prefix, menu_type, with_titles
+    global verbose, force, size, theme, icon_dir, top, install_prefix, menu_type 
+    global with_titles, menu_entry_count, get_menus, timestamp, set_menus, printmode
     verbose = False
     force = False
     desktop=''
@@ -112,9 +115,13 @@
     theme='gnome'
     icon_dir="~/.fvwm/icons"
     top='FvwmMenu'
-    install_prefix = '/etc/xdg/menus/'
-    menu_type = 'applications'
+    install_prefix = ''
+    menu_type = ''
     with_titles = False
+    menu_entry_count = 0
+    get_menus = ''
+    printmode = True
+    set_menus = []
 
     for o, a in opts:
         if o == "-v":
@@ -125,14 +132,20 @@
         elif o in ("--enable-mini-icons") :
             force=True
         elif o in ("--desktop") :
-            #?desktop=a + '-'
             desktop=a
+        elif o in ("--title") :
+            top=a
+        elif o in ("--get-menus") :
+            get_menus=a
+            printmode = False
+        elif o in ("--set-menus") :
+            set_menus=a.split(',')
         elif o in ("--install-prefix") :
             if a and not os.path.isabs(a):
                 assert False, "install-prefix must be an absolute path"
             # add trailing slash if not there already
-            if (not re.search('.*[.]/$',a)) : # no trailing slash
-                a=a+'/'
+            if not a[-1] == '/' : # trailing slash
+                a=a + '/'
             install_prefix = a
 
         elif o in ("-s","--size") :
@@ -143,33 +156,177 @@
             menu_type = a
         elif o in ("-w","--with-titles") :
             with_titles = True
+        elif o in ("--verbose") :
+            verbose = True
         elif o in (str(dashed_obs_args+dashed_obs_parms)) :
             # Ignore
             sys.stderr.write( "Warning: Arg "+o+" is obsolete and ignored\n" )
         else:
             assert False, "unhandled option"
 
-    check=install_prefix+desktop+menu_type+'.menu'
-    menu = checkmenu(check)
-
-    if menu == None and menu_type == 'applications':
-        # it could be a Debian system
-        check = install_prefix + 'debian-menu.menu'
-        menu = checkmenu(check)
-        
-    if menu == None:
-        # fixme, no point in trying to print "None".
-        sys.stderr.write(check+" not available on this system. Exiting...\n")
-        sys.exit()
+    timestamp = time.time()
+    
+    if len(set_menus) == 0:
+        xdg_menu_prefix = ((os.environ['XDG_MENU_PREFIX'] if os.environ.has_key('XDG_MENU_PREFIX') else ''))
+    
+        # First check if no user presettings made
+        if desktop == '':
+            # check if $XDG_MENU_PREFIX is set
+            if not xdg_menu_prefix == '':
+                desktop = xdg_menu_prefix.replace('-', '').lower()
+        
+        vprint("Parameters for creating menu list:")
+        vprint(" XDG_MENU_PREFIX:  \'%s\'" %xdg_menu_prefix)
+        vprint(" --install-prefix: \'%s\'" %install_prefix)
+        vprint(" --desktop:        \'%s\'" %desktop)
+        vprint(" --menu-type:      \'%s\'" %menu_type)
+        
+        vprint("\nStart search ...")
+        menulist, desktop_temp = getmenulist(desktop, menu_type)
+        if not desktop_temp == '':
+            desktop = desktop_temp
+    else:
+        menulist = set_menus
+    
+    vprint(" Menu list: %s\n" %menulist)        
+        
+    if len(menulist) == 0:
+        if not desktop == '':
+            desktop = desktop + '-'
+        sys.stderr.write(install_prefix+desktop+menu_type+".menu not available on this system. Exiting...\n")
+        sys.exit(1)
     else:
-        parsemenu(xdg.Menu.parse(menu), top)
+        parsemenus(menulist, desktop)
              
-def checkmenu(menu):
-    if not os.path.exists(menu):
-        menu = None
-    return menu
+def getmenulist(desktop, menu_type):
+    menudict = {} 
+    config_dirs = []
+    if not install_prefix == '':
+        config_dirs = [install_prefix[:-1]]
+    else:
+        config_dirs = xdg_config_dirs
 
+    founded_menus = 0
+    for dir in config_dirs:
+        if install_prefix == '':
+            dir = dir + '/menus'
+        if os.path.exists(dir):
+            filelist = set([])
+            dir_list = os.listdir(dir)
+            pattern = '*'+desktop+'*'+menu_type+'*.menu'
+            for filename in fnmatch.filter(dir_list, pattern):
+                filelist.add(filename)
+            
+            menudict[dir] = filelist
+            founded_menus += len(filelist)
+            vprint(" found in %s: %s" %(dir, list(filelist)))
+    
+    desktop_dict = {}
+    if not founded_menus == 0:
+        all_menus = []
+        # remove all menus in /etc/xdg/menus imenudict['/etc/xdg/menus']menudict['/etc/xdg/menus']f exist in user dir
+        for path in menudict.keys():
+            if not path == '/etc/xdg/menus':
+                menudict['/etc/xdg/menus'] = menudict['/etc/xdg/menus'] - menudict[path]
+                for menu in list(menudict[path]):
+                    all_menus.append(path + '/' + menu)
+        
+        if not menudict['/etc/xdg/menus'] == 0:
+            for menu in list(menudict['/etc/xdg/menus']):
+                all_menus.append('/etc/xdg/menus/' + menu) 
+         
+        if get_menus == 'all':
+            return all_menus, ''
+        
+        # sort menus related to desktops and create a weighting
+        vprint("\n DE weighting search: DE => [user menus, system menus, overall]")
+        weight_dict = {}
+        if desktop == '':
+            DEs = ['gnome', 'kde', 'xfce', 'lxde', 'debian', 'others', 'none']
+        else:
+            DEs = [desktop]
+        for de in DEs:
+            menus = set([])
+            user_menus = 0
+            system_menus = 0
+            filled = False
+            for path in menudict.keys():
+                if de == 'none':
+                    pattern = '*'
+                elif de == 'others':
+                    pattern = '*-*'
+                else:
+                    pattern = '*'+de+'*'
+                menu_names = fnmatch.filter(menudict[path], pattern)
+                if not len(menu_names) == 0:
+                    filled = True
+                for name in menu_names:
+                    menus.add(path+'/'+name)
+                menudict[path] = menudict[path]-set(menu_names)
+                if not path == '/etc/xdg/menus':
+                    user_menus = len(menu_names)
+                else:
+                    system_menus = len(menu_names)
+            if filled:
+                desktop_dict[de] = menus
+                filled = False
+            weight_dict[de] = [user_menus, system_menus, user_menus+system_menus]
+            vprint(" %s => %s" %(de, weight_dict[de]))
+    
+        # get the highest rated desktop
+        highest = 0
+        de_highest = ''
+        for de in sorted(weight_dict.keys()):
+            de_user = weight_dict[de][0]
+            de_system = weight_dict[de][1]
+            de_total = weight_dict[de][2]
+            higher = False
+            if not de_highest == '':
+                # don't weight 'none' and 'others cause both not DEs
+                if not de == 'none' and not de == 'others':
+                    highest_user = weight_dict[de_highest][0]
+                    highest_system = weight_dict[de_highest][1]
+                    highest_total = weight_dict[de_highest][2]
+                    if highest < de_total:
+                        higher = True
+                    elif highest == de_total:
+                        if highest_user < de_user:
+                            higher = True
+                        elif highest_user == de_user:
+                            if highest_system < de_system:
+                                higher = True
+                            elif highest_system == de_system:
+                                higher = True # fixme, should be biunique. -but how? With atime?
+            else:
+                higher = True
+                
+            if higher:
+                highest = de_total
+                de_highest = de
+        vprint( "\n Winner: %s" %de_highest)
+        
+        # Perhaps there're a global menus available which are not in the highest rated list
+        if desktop_dict.has_key('none'):
+            for menu in desktop_dict['none']:
+                name = menu.replace('.menu', '').split('/')
+                found = fnmatch.filter(desktop_dict[de_highest], '*'+name[-1]+'*')
+                if found == []:
+                    desktop_dict[de_highest].add(menu)
+        
+        # Add 'others' menus to list, because these could be tool menus like yast, etc
+        if desktop_dict.has_key('others'):
+            for menu in desktop_dict['others']:
+                desktop_dict[de_highest].add(menu)
+                
+    if len(desktop_dict) == 0:
+        return [], ''
+    else:
+        return list(desktop_dict[de_highest]), de_highest
 
+def vprint(text):
+    if verbose:
+        sys.stderr.write(text+"\n")
+    
 def printtext(text):
     print text.encode("utf-8")
 
@@ -213,38 +370,89 @@
     iconfile = ''
     if force :
         iconfile = geticonfile(icon) or getdefaulticonfile(command) or icon
-        iconfile = '%'+iconfile+'%'
+        if not iconfile == '':
+            iconfile = '%'+iconfile+'%'
     printtext('+ "%s%s" %s' % (name, iconfile, command))
 
-def parsemenu(menu, name=""):
+def parsemenus(menulist, desktop):
+    if len(menulist) == 1:
+        # user defines only one special menu
+        parsemenu(xdg.Menu.parse(menulist[0]), top)
+    else:
+        # create a top title list
+        top_titles = []
+        for file in menulist:
+            name = file.replace('.menu', '').split('/')
+            top_titles.append(name[-1][0].upper()+name[-1][1:])
+        
+        # create the submenus
+        new_toptitles = []
+        new_menulist = []
+        for title, menu in zip(top_titles, menulist):
+            name = 'Fvwm'+title
+            vprint("Create submenu \'%s\' from \'%s\'" %(name, menu))
+            parsemenu(xdg.Menu.parse(menu), name, title)
+            # remove a menu if no menu entry was created in its sub menus
+            if not menu_entry_count == 0:
+                new_toptitles.append(title)
+                new_menulist.append(menu)
+            else:
+                vprint(" Menu is empty - won't be used!")
+        
+        # create the root menu
+        if printmode:
+            printtext('DestroyMenu "%s"' % top)
+            if with_titles:
+                printtext('AddToMenu "%s" "%s" Title' % (top, top))
+            else:
+                printtext('AddToMenu "%s"' % top)
+    
+            for title in sorted(new_toptitles):
+                name = 'Fvwm'+title
+                printmenu(title, '', 'Popup "%s"' % name)
+        
+            printtext('+ "" Nop')
+            printmenu("Regenerate "+top, "system-software-update", "FvwmForm FvwmForm-Desktop" )
+
+        if not get_menus == '':
+            printtext('%s' % ','.join(new_menulist))
+        
+        vprint("\nProcess took " + str(time.time()-timestamp) + " seconds")
+    
+def parsemenu(menu, name="", title=""):
+    global menu_entry_count
     m = re.compile('%[A-Z]?', re.I) # Pattern for %A-Z (meant for %U)
     if not name :
         name = menu.getPath()
-    printtext('DestroyMenu "%s"' % name)
-    if with_titles:
-        printtext('AddToMenu "%s" "%s" Title' % (name, name))
-    else:
-        printtext('AddToMenu "%s"' % name)
-    for entry in menu.getEntries():
-	if isinstance(entry, xdg.Menu.Menu):
-	    printmenu(entry.getName(), entry.getIcon(),
-		      'Popup "%s"' % entry.getPath())
-	elif isinstance(entry, xdg.Menu.MenuEntry):
-	    desktop = DesktopEntry(entry.DesktopEntry.getFileName())
-            # eliminate '%U' etc behind execute string
-            execProgram = m.sub('', desktop.getExec())
-	    printmenu(desktop.getName(), desktop.getIcon(),
-                      "Exec exec " + desktop.getExec() )
-	else:
-	    printtext('# not supported: ' + str(entry))
-
+    if not title:
+        title = name
+    if printmode:
+        printtext('DestroyMenu "%s"' % name)
+        if with_titles:
+            printtext('AddToMenu "%s" "%s" Title' % (name, title))
+        else:
+            printtext('AddToMenu "%s"' % name)
     for entry in menu.getEntries():
-	if isinstance(entry, xdg.Menu.Menu):
-	    parsemenu(entry)
+    	if isinstance(entry, xdg.Menu.Menu):
+            if printmode:
+                printmenu(entry.getName(), entry.getIcon(), 'Popup "%s"' % entry.getPath())
+    	elif isinstance(entry, xdg.Menu.MenuEntry):
+            if printmode:
+                desktop = DesktopEntry(entry.DesktopEntry.getFileName())
+                # eliminate '%U' etc behind execute string
+                execProgram = m.sub('', desktop.getExec())
+                printmenu(desktop.getName(), desktop.getIcon(), "Exec exec " + " " + execProgram)
+            menu_entry_count += 1
+    	else:
+            if printmode:
+                printtext('# not supported: ' + str(entry))
 
-    if (re.search('.*System Tools$',name)) : # fixme, find a better way to do this?
-        printmenu("Regenerate Applications Menu", "", "FvwmForm " "FvwmForm-Desktop" )
+    if printmode:
+        printtext('')
 
+    for entry in menu.getEntries():
+    	if isinstance(entry, xdg.Menu.Menu):
+    	    parsemenu(entry)
 
 usage="""
 A script which parses xdg menu definitions to build
@@ -252,19 +460,27 @@
 
 Usage: $0 [OPTIONS]
 Options:
-	-h, --help                show this help and exit
-	--version                 show version and exit
-	--install-prefix DIR      install prefix of the desktop menu files.
-                                  Default is /etc/xdg/menus
-	--desktop NAME            desktop to build the menu for:
-		gnome-sys, gnome-user, gnome-redhat, gnome-mandriva,
-		kde-sys, kde-user.
-	--title NAME              menu title, default depends on --desktop
-	--enable-mini-icons       enable mini-icons in menus
-        -s, --size                Icon size in pixels.  Default is 24.
-        --theme                   theme name for icon selection.
-	-v, --verbose             run and display debug info on STDERR
-	-w, --with-titles         Generate menus with titles."""
+    -h, --help                show this help and exit
+    --version                 show version and exit
+    --install-prefix DIR      install prefix of the desktop menu files. Per default not set.
+                              For the system wide menus use /etc/xdg/menus/
+    --desktop NAME            desktop name to build menus for:
+                              gnome, kde, xfce, lxde, debian, etc.
+    --menu-type NAME          applications (default), settings, preferences, etc.
+    --theme NAME              gnome (default), oxygen, etc. Don't use hicolor. 
+                              It's the default fallback theme if no icon will be found.
+    --with-titles             generate menus with titles.
+    --enable-mini-icons       enable mini-icons in menu
+    -s, --size                set size of mini-icons in menu. Default is 24.
+    --title NAME              menu title of the top menu used by Popup command.
+                              Default is FvwmMenu
+    --get-menus               prints a comma separated list with full menu paths.
+                              'selected' prints the desktop related menus. 'all' prints 
+                              all founded menus on the system except empty ones. No
+                              menu generation will be done.
+    --set-menus               expects a comma separated list of full menu paths to generate
+                              user specified menus
+    -v, --verbose             run and display debug info on STDERR"""
 
 if __name__ == "__main__":
     main()
--- Old/fvwm-menu-desktop.in.p5.py	2012-07-04 22:31:36.000000000 +0200
+++ fvwm-menu-desktop.in.py	2012-07-04 22:40:32.560885439 +0200
@@ -411,9 +411,6 @@
                 name = 'Fvwm'+title
                 printmenu(title, '', 'Popup "%s"' % name)
         
-            printtext('+ "" Nop')
-            printmenu("Regenerate "+top, "system-software-update", "FvwmForm FvwmForm-Desktop" )
-
         if not get_menus == '':
             printtext('%s' % ','.join(new_menulist))
         
@@ -421,9 +418,11 @@
     
 def parsemenu(menu, name="", title=""):
     global menu_entry_count
+    gen_name = ''
     m = re.compile('%[A-Z]?', re.I) # Pattern for %A-Z (meant for %U)
     if not name :
         name = menu.getPath()
+        gen_name = menu.getPath(True)
     if not title:
         title = name
     if printmode:
@@ -447,6 +446,10 @@
             if printmode:
                 printtext('# not supported: ' + str(entry))
 
+    if (gen_name == 'System'):
+        if printmode:
+            printmenu("Regenerate "+top, "system-software-update", "FvwmForm FvwmForm-Desktop" )
+
     if printmode:
         printtext('')
 

Reply via email to