Skip to content

Instantly share code, notes, and snippets.

@xi
Last active November 3, 2023 18:00
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xi/b88af997b485191fa0beb5d6612ead29 to your computer and use it in GitHub Desktop.
Save xi/b88af997b485191fa0beb5d6612ead29 to your computer and use it in GitHub Desktop.
dmenu wrapper around dbus menues
# dmenu wrapper around dbus menues
#
# Example Usage:
# python3 dbusmenu.py org.freedesktop.network-manager-applet /org/ayatana/NotificationItem/nm_applet/Menu
#
# https://github.com/tetzank/qmenu_hud/blob/master/com.canonical.dbusmenu.xml
import subprocess
import sys
import time
import dbus
DMENU_CMD = ['rofi', '-dmenu', '-i', '-no-sort']
def dmenu(_input):
p = subprocess.Popen(
DMENU_CMD,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
encoding='utf-8',
)
out, _ = p.communicate(_input)
return out
def format_toggle_value(props):
toggle_type = props.get('toggle-type', '')
toggle_value = props.get('toggle-state', -1)
if toggle_value == 0:
s = ' '
elif toggle_value == 1:
s = 'X'
else:
s = '~'
if toggle_type == 'checkmark':
return '[%s] ' % s
elif toggle_type == 'radio':
return '(%s) ' % s
else:
return ''
def format_menu_item(item, level=1):
id, props, children = item
if not props.get('visible', True):
return ''
if props.get('type', 'standard') == 'separator':
label = '---'
else:
label = format_toggle_value(props) + props.get('label', '')
if not props.get('enabled', True):
label = '(%s)' % label
ret = '%i%s%s\n' % (id, ' ' * level, label)
for child in children:
ret += format_menu_item(child, level + 1)
return ret
def show_menu(session_bus, bus, path):
obj = session_bus.get_object(bus, path)
iface = dbus.Interface(obj, 'com.canonical.dbusmenu')
_, item = iface.GetLayout(0, -1, [])
menu = format_menu_item(item)
selected = dmenu(menu)
if selected:
id = int(selected.split()[0])
iface.Event(id, 'clicked', '', dbus.UInt32(time.time()))
def show_snis(session_bus):
obj = session_bus.get_object(
'org.freedesktop.StatusNotifierWatcher',
'/StatusNotifierWatcher',
)
iface = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
items = iface.Get(
'org.kde.StatusNotifierWatcher',
'RegisteredStatusNotifierItems',
)
selected = dmenu('\n'.join(items))
if selected:
bus, path = selected.strip().split('/', 1)
show_menu(session_bus, bus, '/%s/Menu' % path)
if __name__ == '__main__':
session_bus = dbus.SessionBus()
if len(sys.argv) == 3:
show_menu(session_bus, sys.argv[1], sys.argv[2])
else:
show_snis(session_bus)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment