On 14/09/2013 15:41, Thomas Funk wrote:
> I found another problem with unicode errors in menu names under
> XUbuntu. I will check this in the next time. So, forget the last
> patch. I will send a new one with the unicode error fix included.
I have now fixed this problem.
The attached patch includes:
- if only one xdg menu exists:
- no output appears with 'fvwm-menu-desktop --get-menus all|desktop'
- No entry "Regenerate XDG menu(s)" appears with
'fvwm-menu-desktop --insert-in-menu MenuRoot'
- if an icon not found but the path was given convert errors occur.
Fixed this with a path check.
- if an converted icon exists the conversion process will be skipped to
reduce progress time.
- if an DecodeEncodeError occurs in menu/menu entry/file path it will be
encoded before printing.
- exchanged all Tabs with spaces to prevent indention errors with the
Python interpreter.
> On sam 14/09/13 19:56 , michel dominique wrote:
> Until a certain extend. I think many experimented fvwm users will
> install a minimum system, and will not get more than 1 or 2 xdg menus.
>
> Also, many distributions don't have their own menu system like debian,
> so the chances are big they will get only 1 xdg menu with a minimum
> install.
>
> It is even worst, on a fresh gentoo install, with only fvwm,
> fvwm-crystal, xorg-server, stalonetray, mc and rxvt-unicode, I get no
> xdg menu file at all.
>
> On Debian, I experimented a little bit with xfce by modifying its menu
> file in /etc/xdg/menus
>
> For now, this is just a prove of concept. This have to be extended to
> all the other main categories. Eventually, files can be provided into
> /usr/share/desktop-directories for automatic translation. I commented
> it because otherwise all the sub-menus are named Multimedia, so
> files must be provided if we want to support the Directory tag.
I looked into different applications.menu files and they look mostly the
same. There're possibilities to implement a skeleton
aplications.menu:
1) this file exists in FVWM and will be copied into /etc/xdg/menus/ e.g.
as 'fvwm-applications.menu'
2) I implement a function in fvwm-menu-desktop which creates a
fvwm-applications.menu in /home/<user>/.config/menus. Also
fvwm-menu-desktop-config.fpl has to be modified to set a creation
flag and shows a fake menu until it is created.
I prefer 1) but this is only because the overhead to write a menu from
scratch will blow up fvwm-menu-desktop much (the complete xml file
structure must pictured in code).
What is the best? 1), 2) or ... 3) no fvwm-applications.menu
Feedback, please ^^
--- fvwm-menu-desktop.in 2013-09-12 13:09:49.000000000 +0200
+++ fvwm-menu-desktop.in.new 2013-09-15 18:05:09.074888400 +0200
@@ -2,6 +2,14 @@
# Modification History
+# Changed on 15/09/13 by Thomas Funk:
+# Some Bugfixes:
+# - DecodeEncodeErrors in menu names
+# - no output appears with 'fvwm-menu-desktop --get-menus all|desktop'
+# - No entry "Regenerate XDG menu(s)" appears with
+# 'fvwm-menu-desktop --insert-in-menu MenuRoot'
+# - exchange all tabs with spaces to prevent indention errors
+
# Changed on 15/06/13 by Thomas Funk:
# support for python-xdg > 0.19.
# add gettext localization.
@@ -114,7 +122,7 @@
sys.exit(2)
global verbose, force, size, theme, icon_dir, top, install_prefix, menu_type, menu_list_length
global with_titles, menu_entry_count, get_menus, timestamp, set_menus, printmode, insert_in_menu
- version = "2.2"
+ version = "2.3"
verbose = False
force = False
desktop=''
@@ -274,9 +282,9 @@
vprint("\n DE weighting search: DE => [user menus, system menus, overall]")
weight_dict = {}
if desktop == '':
- # first the desktops, then debian (shouldn't appear in others) then others holding
- # all other non DE menus e.g. tools and at the end the nones without prefixes
- # If there're other prefixes from other WMs - should be added BEFORE debian
+ # first the desktops, then debian (shouldn't appear in others) then others holding
+ # all other non DE menus e.g. tools and at the end the nones without prefixes
+ # If there're other prefixes from other WMs - should be added BEFORE debian
DEs = ['gnome', 'kde', 'xfce', 'lxde', 'cinnamon', 'mate', 'debian', 'others', 'none']
else:
DEs = [desktop]
@@ -298,9 +306,9 @@
filled = True
for name in menu_names:
menus.add(path+'/'+name)
- # delete each found DE menu from the actual path. So, the menus will be reduced loop by loop.
+ # delete each found DE menu from the actual path. So, the menus will be reduced loop by loop.
menudict[path] = menudict[path]-set(menu_names)
- # count the menus found in the users and systems menu path for later weighting
+ # count the menus found in the users and systems menu path for later weighting
if not path == '/etc/xdg/menus':
user_menus = len(menu_names)
else:
@@ -308,7 +316,7 @@
if filled:
desktop_dict[de] = menus
filled = False
- # fill the weight dictionary with the counts
+ # fill the weight dictionary with the counts
weight_dict[de] = [user_menus, system_menus, user_menus+system_menus]
vprint(" %s => %s" %(de, weight_dict[de]))
@@ -326,18 +334,18 @@
highest_user = weight_dict[de_highest][0]
highest_system = weight_dict[de_highest][1]
highest_total = weight_dict[de_highest][2]
- # first compare the total counts
+ # first compare the total counts
if highest < de_total:
higher = True
elif highest == de_total:
- # if the totals equal compare the users
+ # if the totals equal compare the users
if highest_user < de_user:
higher = True
elif highest_user == de_user:
- # it the users equal compare the system menus
+ # it the users equal compare the system menus
if highest_system < de_system:
higher = True
- # if the systems equal the last wins
+ # if the systems equal the last wins
elif highest_system == de_system:
higher = True # fixme, should be biunique. -but how? With atime?
else:
@@ -352,8 +360,8 @@
if desktop_dict.has_key('none'):
for menu in desktop_dict['none']:
name = menu.replace('.menu', '').split('/')
- # the fnmatch.filter will be used to find NO match because then
- # the menu is not in the list
+ # the fnmatch.filter will be used to find NO match because then
+ # the menu is not in the list
found = fnmatch.filter(desktop_dict[de_highest], '*'+name[-1]+'*')
if found == []:
desktop_dict[de_highest].add(menu)
@@ -372,11 +380,35 @@
if verbose:
sys.stderr.write(text+"\n")
-def printtext(text):
- print text.encode("utf-8")
+def printtext(text, encodetext=True):
+ if encodetext:
+ print text.encode("utf-8")
+ else:
+ print text
+# fix unicode decode problem like
+# UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position xyz: ordinal not in range(128)
+def decodetext(text):
+ old_stdout = sys.stdout
+ fnull = open(os.devnull, 'w')
+ sys.stdout = fnull
+ try:
+ new_text = text.encode("utf-8")
+ printtext('%s' % text)
+ except UnicodeDecodeError:
+ try:
+ unicode_text = text.decode("iso-8859-15")
+ text = "%s" % unicode_text
+ new_text = text.encode("iso-8859-15")
+ print new_text
+ except:
+ new_text = None
+ fnull.close()
+ sys.stdout = old_stdout
+ return new_text
+
def geticonfile(icon):
- iconpath = xdg.IconTheme.getIconPath(icon, size, theme, ["png", "xpm"])
+ iconpath = xdg.IconTheme.getIconPath(icon, None, theme, ["png", "xpm", "svg"])
if not iconpath == None:
extension = os.path.splitext(iconpath)[1]
@@ -400,8 +432,13 @@
if extension == '.svg':
iconfile = iconfile.replace('.svg', '.png')
- os.system("if test \\( ! -f '%s' \\) -o \\( '%s' -nt '%s' \\) ; then convert '%s' -resize %i '%s' ; fi"%
- (iconfile, iconpath, iconfile, iconpath, size, iconfile))
+ if os.path.exists(iconpath):
+ if not os.path.exists(iconfile):
+ os.system("if test \\( ! -f '%s' \\) -o \\( '%s' -nt '%s' \\) ; then convert '%s' -resize %i '%s' ; fi"%
+ (iconfile, iconpath, iconfile, iconpath, size, iconfile))
+ else:
+ sys.stderr.write("%s not found! Use default icon.\n" % iconpath)
+ return None
return iconfile
@@ -417,22 +454,19 @@
iconfile = geticonfile(icon) or getdefaulticonfile(command) or icon
if not iconfile == '':
iconfile = '%'+iconfile+'%'
- # fix unicode decode problem like
- # UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position xyz: ordinal not in range(128)
- try:
- printtext('+ "%s%s" %s' % (name, iconfile, command))
- except UnicodeDecodeError:
- try:
- unicode_name = name.decode("iso-8859-15")
- unicode_command = command.decode("iso-8859-15")
- text = '+ "%s%s" %s' % (unicode_name, iconfile, unicode_command)
- print text.encode("iso-8859-15")
- except:
- sys.stderr.write("A menu entry cannot decode! Skipping it ...\n")
+ name = decodetext(name)
+ command = decodetext(command)
+ iconfile = decodetext(iconfile)
+ if not (name == None or command == None or iconfile == None):
+ printtext('+ "%s%s" %s' % (name, iconfile, command), False)
+ else:
+ sys.stderr.write("A menu entry cannot decode! Skipping ...\n")
+ printtext('# Decode Error! Menu entry skipped.')
def parsemenus(menulist, desktop):
global menu_entry_count
if menu_list_length == 1:
+ new_menulist = menulist
# user defines only one special menu
parsemenu(xdg.Menu.parse(menulist[0]), top)
else:
@@ -475,10 +509,9 @@
printtext('+ "" Nop')
printmenu("$[gt.Regenerate XDG Menu(s)]", "system-software-update", "Module FvwmPerl -l fvwm-menu-desktop-config.fpl" )
- if not get_menus == '':
- printtext('%s' % ' '.join(new_menulist))
-
-
+ if not get_menus == '':
+ printtext('%s' % ' '.join(new_menulist))
+
def parsemenu(menu, name="", title=""):
global menu_entry_count
m = re.compile('%[A-Z]?', re.I) # Pattern for %A-Z (meant for %U)
@@ -487,43 +520,48 @@
if not title:
title = name
if printmode:
- if not insert_in_menu or not (insert_in_menu and name == top and menu_list_length == 1):
- printtext('DestroyMenu "%s"' % name)
- if with_titles:
- # for insert-in-menu AddToMenu doesn't have a title for top menu
- # because this will appear then in the other menu
- if insert_in_menu and name == top and menu_list_length == 1:
- printtext('AddToMenu "%s"' % name)
+ name = decodetext(name)
+ title = decodetext(title)
+ if not (name == None or title == None):
+ if not insert_in_menu or not (insert_in_menu and name == top and menu_list_length == 1):
+ printtext('DestroyMenu "%s"' % name, False)
+ if with_titles:
+ # for insert-in-menu AddToMenu doesn't have a title for top menu
+ # because this will appear then in the other menu
+ if insert_in_menu and name == top and menu_list_length == 1:
+ printtext('AddToMenu "%s"' % name, False)
+ else:
+ printtext('AddToMenu "%s" "%s" Title' % (name, title), False)
else:
- printtext('AddToMenu "%s" "%s" Title' % (name, title))
+ printtext('AddToMenu "%s"' % name, False)
else:
- printtext('AddToMenu "%s"' % name)
+ sys.stderr.write("A menu entry cannot decode! Skipping ...\n")
+ printtext('# Decode Error! Menu entry skipped.')
for entry in menu.getEntries():
- if isinstance(entry, xdg.Menu.Menu):
+ if isinstance(entry, xdg.Menu.Menu):
if printmode:
printmenu(entry.getName(), entry.getIcon(), 'Popup "%s"' % entry.getPath())
- elif isinstance(entry, xdg.Menu.MenuEntry):
+ 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:
+ else:
if printmode:
printtext('# not supported: ' + str(entry))
- # should only appear in a single menu. For more it will insert in parsemenus() when the top menu will built
- if menu_list_length == 1 and not insert_in_menu and name == top:
- printtext('+ "" Nop')
- printmenu("$[gt.Regenerate XDG Menu(s)]", "system-software-update", "Module FvwmPerl -l fvwm-menu-desktop-config.fpl" )
-
if printmode:
+ # should only appear in a single menu. For more it will insert in parsemenus() when the top menu will built
+ if menu_list_length == 1 and name == top:
+ printtext('+ "" Nop')
+ printmenu("$[gt.Regenerate XDG Menu(s)]", "system-software-update", "Module FvwmPerl -l fvwm-menu-desktop-config.fpl" )
printtext('')
for entry in menu.getEntries():
- if isinstance(entry, xdg.Menu.Menu):
- parsemenu(entry)
+ if isinstance(entry, xdg.Menu.Menu):
+ parsemenu(entry)
usage="""
A script which parses xdg menu definitions to build