168 lines
5.7 KiB
Python
Executable file
168 lines
5.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import dbus
|
|
import subprocess
|
|
|
|
"""
|
|
format_label_list
|
|
"""
|
|
def format_label_list(label_list):
|
|
head, *tail = label_list
|
|
result = head
|
|
for label in tail:
|
|
result = result + " > " + label
|
|
return result
|
|
|
|
"""
|
|
try_appmenu_interface
|
|
"""
|
|
def try_appmenu_interface(window_id):
|
|
# --- Get Appmenu Registrar DBus interface
|
|
session_bus = dbus.SessionBus()
|
|
appmenu_registrar_object = session_bus.get_object('com.canonical.AppMenu.Registrar', '/com/canonical/AppMenu/Registrar')
|
|
appmenu_registrar_object_iface = dbus.Interface(appmenu_registrar_object, 'com.canonical.AppMenu.Registrar')
|
|
|
|
# --- Get dbusmenu object path
|
|
try:
|
|
dbusmenu_bus, dbusmenu_object_path = appmenu_registrar_object_iface.GetMenuForWindow(window_id)
|
|
except dbus.exceptions.DBusException:
|
|
return
|
|
|
|
# --- Access dbusmenu items
|
|
dbusmenu_object = session_bus.get_object(dbusmenu_bus, dbusmenu_object_path)
|
|
dbusmenu_object_iface = dbus.Interface(dbusmenu_object, 'com.canonical.dbusmenu')
|
|
dbusmenu_items = dbusmenu_object_iface.GetLayout(0, -1, ["label"])
|
|
|
|
dbusmenu_item_dict = dict()
|
|
|
|
""" explore_dbusmenu_item """
|
|
def explore_dbusmenu_item(item, label_list):
|
|
item_id = item[0]
|
|
item_props = item[1]
|
|
item_children = item[2]
|
|
|
|
if 'label' in item_props:
|
|
new_label_list = label_list + [item_props['label']]
|
|
else:
|
|
new_label_list = label_list
|
|
|
|
# FIXME: This is not excluding all unactivable menuitems.
|
|
if len(item_children) == 0:
|
|
dbusmenu_item_dict[format_label_list(new_label_list)] = item_id
|
|
else:
|
|
for child in item_children:
|
|
explore_dbusmenu_item(child, new_label_list)
|
|
|
|
explore_dbusmenu_item(dbusmenu_items[1], [])
|
|
|
|
# --- Run dmenu
|
|
dmenu_string = ''
|
|
head, *tail = dbusmenu_item_dict.keys()
|
|
dmenu_string = head
|
|
for m in tail:
|
|
dmenu_string += '\n'
|
|
dmenu_string += m
|
|
|
|
dmenu_cmd = subprocess.Popen(['dmenu', '-i', '-l', '10', '-fn', 'xos4 Terminus'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
|
dmenu_cmd.stdin.write(dmenu_string.encode('utf-8'))
|
|
dmenu_result = dmenu_cmd.communicate()[0].decode('utf8')
|
|
dmenu_cmd.stdin.close()
|
|
|
|
# --- Use dmenu result
|
|
if dmenu_result in dbusmenu_item_dict:
|
|
action = dbusmenu_item_dict[dmenu_result]
|
|
print(dbusmenu_object_iface.Event(action, 'clicked', 0, 0))
|
|
|
|
|
|
"""
|
|
try_gtk_interface
|
|
"""
|
|
def try_gtk_interface(gtk_bus_name_cmd, gtk_object_path_cmd):
|
|
gtk_bus_name = gtk_bus_name_cmd.split(' ')[2].split('\n')[0].split('"')[1]
|
|
print(gtk_object_path_cmd)
|
|
gtk_object_path = gtk_object_path_cmd.split(' ')[2].split('\n')[0].split('"')[1]
|
|
print("GTK MenuModel Bus name and object path: ", gtk_bus_name, gtk_object_path)
|
|
|
|
# --- Ask for menus over DBus ---
|
|
session_bus = dbus.SessionBus()
|
|
gtk_menubar_object = session_bus.get_object(gtk_bus_name, gtk_object_path)
|
|
gtk_menubar_object_iface = dbus.Interface(gtk_menubar_object, dbus_interface='org.gtk.Menus')
|
|
gtk_action_object_actions_iface = dbus.Interface(gtk_menubar_object, dbus_interface='org.gtk.Actions')
|
|
gtk_menubar_results = gtk_menubar_object_iface.Start([x for x in range(1024)])
|
|
|
|
# --- Construct menu list ---
|
|
gtk_menubar_menus = dict()
|
|
for gtk_menubar_result in gtk_menubar_results:
|
|
gtk_menubar_menus[(gtk_menubar_result[0], gtk_menubar_result[1])] = gtk_menubar_result[2]
|
|
|
|
gtk_menubar_action_dict = dict()
|
|
gtk_menubar_target_dict = dict()
|
|
|
|
""" explore_menu """
|
|
def explore_menu(menu_id, label_list):
|
|
for menu in gtk_menubar_menus[menu_id]:
|
|
if 'label' in menu:
|
|
menu_label = menu['label'].replace('_', '')
|
|
else:
|
|
menu_label = '?'
|
|
|
|
new_label_list = label_list + [menu_label]
|
|
formatted_label = format_label_list(new_label_list)
|
|
|
|
if 'action' in menu:
|
|
menu_action = menu['action']
|
|
gtk_menubar_action_dict[formatted_label] = menu_action
|
|
if 'target' in menu:
|
|
menu_target = menu['target']
|
|
gtk_menubar_target_dict[formatted_label] = menu_target
|
|
|
|
if ':section' in menu:
|
|
menu_section = menu[':section']
|
|
section_menu_id = (menu_section[0], menu_section[1])
|
|
explore_menu(section_menu_id, label_list)
|
|
|
|
if ':submenu' in menu:
|
|
menu_submenu = menu[':submenu']
|
|
submenu_menu_id = (menu_submenu[0], menu_submenu[1])
|
|
explore_menu(submenu_menu_id, new_label_list)
|
|
|
|
explore_menu((0,0), [])
|
|
|
|
# --- Run dmenu
|
|
dmenu_string = ''
|
|
head, *tail = gtk_menubar_action_dict.keys()
|
|
dmenu_string = head
|
|
for m in tail:
|
|
dmenu_string += '\n'
|
|
dmenu_string += m
|
|
|
|
dmenu_cmd = subprocess.Popen(['dmenu', '-i', '-l', '10', '-fn', 'xos4 Terminus'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
|
dmenu_cmd.stdin.write(dmenu_string.encode('utf-8'))
|
|
dmenu_result = dmenu_cmd.communicate()[0].decode('utf8')
|
|
dmenu_cmd.stdin.close()
|
|
|
|
# --- Use dmenu result
|
|
if dmenu_result in gtk_menubar_action_dict:
|
|
action = gtk_menubar_action_dict[dmenu_result]
|
|
print('GTK Action :', action)
|
|
gtk_action_object_actions_iface.Activate(action.replace('unity.', ''), [], dict())
|
|
|
|
"""
|
|
main
|
|
"""
|
|
|
|
# --- Get X Window ID ---
|
|
window_id_cmd = subprocess.check_output(['xprop', '-root', '-notype', '_NET_ACTIVE_WINDOW']).decode('utf-8')
|
|
window_id = window_id_cmd.split(' ')[4].split('\n')[0]
|
|
|
|
print('Window id is :', window_id)
|
|
|
|
# --- Get GTK MenuModel Bus name ---
|
|
|
|
gtk_bus_name_cmd = subprocess.check_output(['xprop', '-id', window_id, '-notype', '_GTK_UNIQUE_BUS_NAME']).decode('utf-8')
|
|
gtk_object_path_cmd = subprocess.check_output(['xprop', '-id', window_id, '-notype', '_GTK_MENUBAR_OBJECT_PATH']).decode('utf-8')
|
|
|
|
if gtk_bus_name_cmd == '_GTK_UNIQUE_BUS_NAME: not found.\n' or gtk_object_path_cmd == '_GTK_MENUBAR_OBJECT_PATH: not found.\n':
|
|
try_appmenu_interface(int(window_id, 16))
|
|
else:
|
|
try_gtk_interface(gtk_bus_name_cmd, gtk_object_path_cmd)
|