diff --git a/README.md b/README.md index 3a6f765..ced8dbb 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Because \*box-style compositors are minimalist, most functionality is left to ex * [wl-clipboard](https://wayland.emersion.fr/mako/): Access the clipboard in scripts (also used by [neovim](https://neovim.io/)) * Screenshots: [grim](https://git.sr.ht/~emersion/grim) and [slurp](https://github.com/emersion/slurp) * Screen recording: [wf-recorder](https://github.com/ammen99/wf-recorder) +* Menu support: [rofi-wayland](https://github.com/lbonn/rofi) ### Contact I can be found as wiz on Rizon and wizbright on Libera. diff --git a/data/menu b/data/menu new file mode 100644 index 0000000..4c74c10 --- /dev/null +++ b/data/menu @@ -0,0 +1,44 @@ +#!/bin/env python + +import os, subprocess, sys +import xml.dom.minidom as dom + +def get_waybox_pid(name='waybox'): + lines = subprocess.Popen(['pgrep', '-x', name], stdout=subprocess.PIPE).stdout.read().splitlines() + if lines: + return int(lines[0]) + else: + return 0 + +def get_menu_items(menu, indent): + print("%s⇢ %s\0nonselectable\x1ftrue\x1ficon\x1fgo-next-symbolic" % (indent, menu.getAttribute('label').replace('_', '') or menu.getAttribute('id'))) + indent = indent + " " + children = menu.childNodes + for i in range(0, children.length): + if children[i].nodeType == dom.Node.ELEMENT_NODE and children[i].tagName == 'item': + action = children[i].getElementsByTagName('action')[0].getAttribute('name') + cmd = "" + icon = children[i].getAttribute('icon') + label = children[i].getAttribute('label').replace('_', '') + if action == 'Execute': + cmd = children[i].getElementsByTagName('execute')[0].firstChild.nodeValue + elif action == 'Exit': + cmd = "kill -s SIGTERM %d" % get_waybox_pid() + elif action == 'Reconfigure': + cmd = "kill -s SIGUSR2 %d" % get_waybox_pid() + print("%s %s\0info\x1f%s\x1ficon\x1f%s" % (indent, label, cmd, icon)) + elif children[i].nodeType == dom.Node.ELEMENT_NODE and children[i].tagName == 'menu': + get_menu_items(children[i], indent) + +menu_xml = os.getenv("WB_MENU_XML") or "menu.xml" +# If ran as a rofi script (not possible with wofi) +if not os.getenv('ROFI_RETV') is None: + import shlex + print("\0message\x1f%s" % os.path.abspath(menu_xml)) + if not (info := os.getenv('ROFI_INFO')) is None: + subprocess.Popen(shlex.split(info), stdout=subprocess.PIPE) + sys.exit(0) + +document = dom.parse(menu_xml) +root_menu = document.getElementsByTagName('menu')[0] +get_menu_items(root_menu, "") diff --git a/data/meson.build b/data/meson.build index a5a233b..c092cba 100644 --- a/data/meson.build +++ b/data/meson.build @@ -16,6 +16,7 @@ configure_file( scripts = files( 'autostart', 'environment', + 'menu', 'xdg-autostart', ) diff --git a/data/rc.xml b/data/rc.xml index ea2b38a..5bff008 100644 --- a/data/rc.xml +++ b/data/rc.xml @@ -69,6 +69,11 @@ grim -g "$(slurp -d)" "$(xdg-user-dir PICTURES)/$(date +'%Y-%m-%d-%H%M%S_grim_sel.png')" + + + rofi -show menu:$WB_CONF_DIR/menu + + obrun l diff --git a/data/waybox.sh b/data/waybox.sh index 23c2391..01448ce 100644 --- a/data/waybox.sh +++ b/data/waybox.sh @@ -72,6 +72,26 @@ then WB_XDG_AUTOSTART="@libexecdir@/openbox-autostart OPENBOX"; fi +if test -f $WB_USER_CONF_DIR/menu.xml; +then + WB_MENU_XML=$WB_USER_CONF_DIR/menu.xml +elif test -f $WB_SYS_CONF_DIR/menu.xml; +then + WB_MENU_XML=$WB_SYS_CONF_DIR/menu.xml +elif test -f $OB_USER_CONF_DIR/menu.xml; +then + _ "WARNING: Using files from Openbox. These may not work correctly." + WB_MENU_XML=$OB_USER_CONF_DIR/menu.xml +elif test -f $OB_SYS_CONF_DIR/menu.xml; +then + _ "WARNING: Using files from Openbox. These may not work correctly." + WB_MENU_XML=$OB_SYS_CONF_DIR/menu.xml; +else + _ "ERROR: No menu file found." >&2 + exit 1 +fi +export WB_MENU_XML + if test -f $WB_USER_CONF_DIR/rc.xml; then WB_RC_XML=$WB_USER_CONF_DIR/rc.xml diff --git a/waybox/layer_shell.c b/waybox/layer_shell.c index 78ec531..c204099 100644 --- a/waybox/layer_shell.c +++ b/waybox/layer_shell.c @@ -310,6 +310,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { if (layer_surface->output == NULL) { struct wb_server *server = wl_container_of(listener, server, new_layer_surface); + if (wl_list_length(&server->toplevels) == 0) return; struct wb_toplevel *toplevel = wl_container_of(server->toplevels.next, toplevel, link); layer_surface->output = get_active_output(toplevel);