From ab19431f3b01d8edd0bf5c43d631a0b5925639be Mon Sep 17 00:00:00 2001 From: George Vlahavas Date: Tue, 22 Sep 2015 02:20:34 +0300 Subject: [PATCH] Add Python 3 compatibility Support Python 2 and Python 3 at the same time. * Make sure modules are loaded with the correct names for each version * Use a compatibility layer for GTK * Make sure strings are encoded/decoded properly --- src/xdgmenumaker | 101 +++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/src/xdgmenumaker b/src/xdgmenumaker index eb970ab..22978bd 100755 --- a/src/xdgmenumaker +++ b/src/xdgmenumaker @@ -7,13 +7,28 @@ from __future__ import print_function import os import sys import getopt -import gtk import xdg.DesktopEntry as dentry import xdg.Exceptions as exc import xdg.BaseDirectory as bd -import ConfigParser from operator import attrgetter +# ConfigParser in Python2 has been renamed to configparser (all lower case) +# in Python3. So, it's a good way to find out which Python version is being +# used. +python3 = False +try: + import ConfigParser as cp +except ImportError: + import configparser as cp + python3 = True + +# Under Python3, load the gtk compatibility layer +if python3: + from gi import pygtkcompat + pygtkcompat.enable() + pygtkcompat.enable_gtk(version='3.0') +import gtk + seticon = False iconsize = 16 desktop = False @@ -79,6 +94,7 @@ class MenuCategory: de = dentry.DesktopEntry(filename=desktop_dir + 'xdgmenumaker-applications.directory') applications = de.getName().encode('utf-8') +apps_name = applications.decode() applications_icon = de.getIcon() de = dentry.DesktopEntry(filename=desktop_dir + 'xdgmenumaker-accessories.directory') @@ -131,12 +147,12 @@ other_icon = de.getIcon() terminal_app = os.getenv("XDGMENUMAKERTERM") if not terminal_app: try: - config = ConfigParser.SafeConfigParser() + config = cp.SafeConfigParser() config.read(os.path.expanduser('~/.config/xdgmenumaker.cfg')) terminal_app = config.get('Terminal', 'terminal') # if there isn't, on debian and debian-likes, use the alternatives # system, otherwise default to xterm - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) as e: + except (cp.NoSectionError, cp.NoOptionError) as e: if (os.path.exists('/etc/alternatives/x-terminal-emulator') and os.path.exists('/usr/bin/x-terminal-emulator')): terminal_app = '/usr/bin/x-terminal-emulator' @@ -427,30 +443,32 @@ def fluxbox(): spacing = ' ' if seticon: app_icon = icon_full_path(applications_icon) + if app_icon is None: - print('[submenu] ({})'.format(applications)) + print('[submenu] ({})'.format(apps_name)) else: - print('[submenu] ({}) <{}>'.format(applications, app_icon)) + print('[submenu] ({}) <{}>'.format(apps_name, app_icon)) else: - print('[submenu] ({})'.format(applications)) + print('[submenu] ({})'.format(apps_name)) else: spacing = '' for menu_category in menu(): category = menu_category.category + cat_name = category.decode() if seticon: cat_icon = category_icon(category) cat_icon = icon_full_path(cat_icon) if cat_icon: - print('{s}[submenu] ({c}) <{i}>'.format(s=spacing, c=category, + print('{s}[submenu] ({c}) <{i}>'.format(s=spacing, c=cat_name, i=cat_icon)) else: - print('{s}[submenu] ({c})'.format(s=spacing, c=category)) + print('{s}[submenu] ({c})'.format(s=spacing, c=cat_name)) else: - print('{s}[submenu] ({c})'.format(s=spacing, c=category)) + print('{s}[submenu] ({c})'.format(s=spacing, c=cat_name)) for app in menu_category.applist: # closing parentheses need to be escaped, otherwise they are # cropped out, along with everything that comes after them - name = app.name.replace(')', '\)') + name = app.name.decode().replace(')', '\)') icon = app.icon command = app.command path = app.path @@ -464,22 +482,23 @@ def fluxbox(): n=name, c=command, i=icon)) - print('{s}[end] # ({c})'.format(s=spacing, c=category)) + print('{s}[end] # ({c})'.format(s=spacing, c=cat_name)) if submenu: - print('[end] # ({})'.format(applications)) + print('[end] # ({})'.format(apps_name)) def windowmaker(): - print('"{}" MENU'.format(applications)) + print('"{}" MENU'.format(apps_name)) for menu_category in menu(): category = menu_category.category - print(' "{}" MENU'.format(category)) + cat_name = category.decode() + print(' "{}" MENU'.format(cat_name)) for app in menu_category.applist: - name = app.name + name = app.name.decode() command = app.command print(' "{n}" EXEC {c}'.format(n=name, c=command)) - print(' "{}" END'.format(category)) - print('"{}" END'.format(applications)) + print(' "{}" END'.format(cat_name)) + print('"{}" END'.format(apps_name)) def icewm(): @@ -489,22 +508,23 @@ def icewm(): app_icon = icon_full_path(applications_icon) if app_icon is None: app_icon = "_none_" - print('menu "{a}" {i} {{'.format(a=applications, i=app_icon)) + print('menu "{a}" {i} {{'.format(a=apps_name, i=app_icon)) else: - print('menu "{}" _none_ {{'.format(applications)) + print('menu "{}" _none_ {{'.format(apps_name)) else: spacing = '' for menu_category in menu(): category = menu_category.category + cat_name = category.decode() cat_icon = category_icon(category) cat_icon = icon_full_path(cat_icon) if seticon and cat_icon is not None: - print('{s}menu "{c}" {i} {{'.format(s=spacing, c=category, + print('{s}menu "{c}" {i} {{'.format(s=spacing, c=cat_name, i=cat_icon)) else: - print('{s}menu "{c}" _none_ {{'.format(s=spacing, c=category)) + print('{s}menu "{c}" _none_ {{'.format(s=spacing, c=cat_name)) for app in menu_category.applist: - name = app.name + name = app.name.decode() icon = app.icon command = app.command if seticon and icon is not None: @@ -529,26 +549,27 @@ def pekwmmenu(): if seticon: app_icon = icon_full_path(applications_icon) print('{s}Submenu = "{a}" {{ Icon = "{i}"'.format(s=dspacing, - a=applications, + a=apps_name, i=app_icon)) else: - print('{s}Submenu = "{a}" {{'.format(s=dspacing, a=applications)) + print('{s}Submenu = "{a}" {{'.format(s=dspacing, a=apps_name)) else: spacing = '' for menu_category in menu(): category = menu_category.category + cat_name = category.decode() cat_icon = category_icon(category) cat_icon = icon_full_path(cat_icon) if seticon and cat_icon is not None: print('{d}{s}Submenu = "{c}" {{ Icon = "{i}"'.format(d=dspacing, s=spacing, - c=category, + c=cat_name, i=cat_icon)) else: print('{d}{s}Submenu = "{c}" {{'.format(d=dspacing, s=spacing, - c=category)) + c=cat_name)) for app in menu_category.applist: - name = app.name + name = app.name.decode() icon = app.icon # for some apps (like netbeans) the command is launched with # /bin/sh "command" @@ -583,26 +604,27 @@ def jwm(): if seticon: app_icon = icon_full_path(applications_icon) if app_icon is None: - print(''.format(applications)) + print(''.format(apps_name)) else: print(''.format(i=app_icon, - a=applications)) + a=apps_name)) else: - print(''.format(applications)) + print(''.format(apps_name)) else: spacing = '' for menu_category in menu(): category = menu_category.category + cat_name = category.decode() cat_icon = category_icon(category) cat_icon = icon_full_path(cat_icon) if seticon and cat_icon is not None: print('{s}'.format(s=spacing, i=cat_icon, - c=category)) + c=cat_name)) else: - print('{s}'.format(s=spacing, c=category)) + print('{s}'.format(s=spacing, c=cat_name)) for app in menu_category.applist: - name = app.name + name = app.name.decode() icon = app.icon command = app.command path = app.path @@ -626,21 +648,22 @@ def compizboxmenu(): if seticon: app_icon = icon_strip(applications_icon) print(''.format(i=app_icon, - a=applications)) + a=apps_name)) else: - print(''.format(applications)) + print(''.format(apps_name)) else: spacing = '' for menu_category in menu(ico_paths=False): category = menu_category.category + cat_name = category.decode() cat_icon = category_icon(category) if seticon and cat_icon is not None: print('{s}'.format( - s=spacing, i=cat_icon, c=category)) + s=spacing, i=cat_icon, c=cat_name)) else: - print('{s}'.format(s=spacing, c=category)) + print('{s}'.format(s=spacing, c=cat_name)) for app in menu_category.applist: - name = app.name.replace('&', '&') + name = app.name.decode().replace('&', '&') icon = app.icon command = app.command.replace("'", "'\\''").replace('&', '&') path = app.path