Skip to content

Instantly share code, notes, and snippets.



Created Sep 27, 2019
What would you like to do?
#!/usr/bin/env python3
from __future__ import print_function
from xdg import Menu, IconTheme
import sys
import re
TERMINAL_COMMAND = "konsole -e %s"
TERMINAL_PATH_COMMAND = "konsole --workdir %s -e %s"
ICON_THEMES = ('gnome', 'oxygen', 'hicolor')
REMOVE_FROM_EXEC = re.compile(' -caption "?%c"?| -[^ ]+ %[UuFf]| %[UuFfi]')
class FluxboxXDGMenu:
def __init__(self, standalone=False, filename=None):
menu = Menu.parse(filename)
if standalone:
self.contents = "[begin] (Fluxbox)"
self.contents.extend(, depth=1))
self.contents =
def __str__(self):
return "\n".join(self.contents)
# TODO: add a hack to look for more icons in /opt/something and /usr/share/app-install/icons
def _find_icon(self, icon_name):
for theme in ICON_THEMES:
icon = IconTheme.getIconPath(icon_name, theme=theme, extensions=['png', 'xpm'])
if icon:
return icon
if not icon:
return ""
def menu(self, menu, depth=0):
contents = []
indent = " " * 4 * depth
name = menu.getName()
icon = self._find_icon(menu.getIcon()) or ""
contents.append("%s[submenu] (%s) <%s>" % (indent, name, icon))
for entry in menu.getEntries():
if isinstance(entry, Menu.MenuEntry):
contents.append(self.entry(entry, depth + 1))
except ValueError as e:
elif isinstance(entry, Menu.Menu):
contents.extend(, depth + 1))
elif isinstance(entry, Menu.Separator):
contents.append(self.separator(depth + 1))
contents.append("%s[end]" % indent)
return contents
def entry(self, entry, depth):
indent = " " * 4 * depth
name = entry.DesktopEntry.getName()
icon = self._find_icon(entry.DesktopEntry.getIcon()) or ""
d_exec = entry.DesktopEntry.getExec()
if not d_exec:
raise ValueError("No executable information found for entry '%s' (%s)." % (name, entry))
executable = REMOVE_FROM_EXEC.sub('', d_exec)
path = entry.DesktopEntry.getPath()
terminal = entry.DesktopEntry.getTerminal()
if path and terminal:
command = TERMINAL_PATH_COMMAND % (path, executable)
elif terminal: # and not path
command = TERMINAL_COMMAND % executable
elif path: # and not terminal
command = "cd %s; %s" % (path, executable)
else: # if neither
command = executable
return "%s[exec] (%s) {%s} <%s>" % (indent, name, command, icon)
def separator(self, depth):
indent = " " * 4 * depth
return "%s[separator]" % indent
filename = sys.argv[1] if len(sys.argv) > 1 else None
print(FluxboxXDGMenu(standalone=STANDALONE, filename=filename))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.