diff --git a/desktop.conf b/desktop.conf index 88929ea..97ab178 100644 --- a/desktop.conf +++ b/desktop.conf @@ -3,7 +3,7 @@ terminal = "$HOME/.local/bin/st" browser = "prime-run librewolf" modkey = "Mod4" -theme = "unity" +theme = "serenity" shell = "zsh" # Keybindings diff --git a/libs/builder.lua b/libs/builder.lua index 04d8c91..3fb45a4 100644 --- a/libs/builder.lua +++ b/libs/builder.lua @@ -10,6 +10,7 @@ local json = require("dkjson") local gears = require("gears") local wibox = require("wibox") local awful = require("awful") +local menu = require("context_menu") local builtins = { h_spacer = function(o) @@ -126,10 +127,20 @@ return function(description,opts) return builtins[struct.builtin](gears.table.join({ client = (struct.client and c) },struct.options or {})) + elseif struct.multimenu then + local multimenu = menu({items={}}) + if not opts.passthrough then + opts.passthrough = {} + end + opts.passthrough.menu_parent = multimenu + for _,v in pairs(struct.multimenu) do + inner_builder(v,struct.vertical) + end + return multimenu end -- If this gets interpreted it's safe to say none of the constructions -- above got matched. - print("Object where the error occured: ") + print("Object dump: ") gears.debug.dump(struct) error("Builder error: invalid object description") end diff --git a/libs/digger.lua b/libs/digger.lua new file mode 100644 index 0000000..5570d67 --- /dev/null +++ b/libs/digger.lua @@ -0,0 +1,29 @@ +-- Since it would seem that get_widget_by_id is still an open issue (https://github.com/awesomeWM/awesome/issues/2945, https://github.com/awesomeWM/awesome/issues/2181), this abomination is the nuclear solution to finding **ALL** widgets that don't get indexed because they are separated by an already instantiated widget. If you use this, please, use it carefully. Don't call it more than you really need, cache the results if you have to. +-- Hypothetically, if there occurs such a thing as widget cycle, this will get stuck. Also it's very expensive. +return function(widget, id) + local results = {} + local checked = {} + local function walker(widget, id) + if widget.children then + for _,v in pairs(widget:get_children()) do + if (v.id == id) and (not checked[v]) then + table.insert(results, v) + checked[v] = true + end + if (v._private.by_id and v._private.by_id[id]) then + for _,v2 in pairs(v._private.by_id[id]) do + if not checked[v2] then + table.insert(results,v2) + checked[v2] = true + end + end + end + walker(v, id) + end + end + end + walker(widget, id) + return results +end + + diff --git a/themes/reno98/config/root_menu.json b/themes/reno98/config/root_menu.json index 51119cf..db4dabf 100644 --- a/themes/reno98/config/root_menu.json +++ b/themes/reno98/config/root_menu.json @@ -12,14 +12,16 @@ {"widget": "widgets.base.tagswitcher", "screen":true }, - {"widget": "widgets.rootmenu.controls"}, - {"widget": "widgets.xdgmenu", - "options": { - "exclude_category": [ - "Other" - ] + {"multimenu": [ + {"widget": "widgets.rootmenu.controls"}, + {"widget": "widgets.xdgmenu", + "options": { + "exclude_category": [ + "Other" + ] + } } - }, + ]}, {"widget": "widgets.rootmenu.buttons"} ], "vertical": true diff --git a/themes/serenity/config/root_menu.json b/themes/serenity/config/root_menu.json index fb21811..2b761b4 100644 --- a/themes/serenity/config/root_menu.json +++ b/themes/serenity/config/root_menu.json @@ -12,14 +12,16 @@ {"widget": "widgets.base.tagswitcher", "screen":true }, - {"widget": "widgets.rootmenu.controls"}, - {"widget": "widgets.xdgmenu", + {"multimenu":[ + {"widget": "widgets.rootmenu.controls"}, + {"widget": "widgets.xdgmenu", "options": { - "exclude_category": [ - "Other" - ] + "exclude_category": [ + "Other" + ] + } } - }, + ]}, {"widget": "widgets.rootmenu.buttons"} ], "vertical": true diff --git a/themes/unity/config/root_menu.json b/themes/unity/config/root_menu.json index 48247c2..9743a95 100644 --- a/themes/unity/config/root_menu.json +++ b/themes/unity/config/root_menu.json @@ -11,14 +11,16 @@ {"widget": "widgets.base.tagswitcher", "screen":true }, - {"widget": "widgets.rootmenu.controls"}, - {"widget": "widgets.xdgmenu", - "options": { - "exclude_category": [ - "Other" - ] + {"multimenu": [ + {"widget": "widgets.rootmenu.controls"}, + {"widget": "widgets.xdgmenu", + "options": { + "exclude_category": [ + "Other" + ] + } } - }, + ]}, {"widget": "widgets.rootmenu.buttons"} ], "vertical": true diff --git a/themes/unity_mate/config/root_menu.json b/themes/unity_mate/config/root_menu.json index 48247c2..5b126cb 100644 --- a/themes/unity_mate/config/root_menu.json +++ b/themes/unity_mate/config/root_menu.json @@ -11,14 +11,16 @@ {"widget": "widgets.base.tagswitcher", "screen":true }, - {"widget": "widgets.rootmenu.controls"}, - {"widget": "widgets.xdgmenu", - "options": { - "exclude_category": [ - "Other" - ] + {"multimenu":[ + {"widget": "widgets.rootmenu.controls"}, + {"widget": "widgets.xdgmenu", + "options": { + "exclude_category": [ + "Other" + ] + } } - }, + ]}, {"widget": "widgets.rootmenu.buttons"} ], "vertical": true diff --git a/widgets/clientmenu.lua b/widgets/clientmenu.lua index 173baee..b82549a 100644 --- a/widgets/clientmenu.lua +++ b/widgets/clientmenu.lua @@ -11,8 +11,8 @@ local wibox = require("wibox") local awful = require("awful") local gears = require("gears") local builder = require("builder") -local menugen = require("context_menu") local ask = require("asckey") +local digger = require("digger") local style = awmtk2.create_style("client_menu", awmtk2.generic.composite_widget,{}) local templates = awmtk2.create_template_lib("client_menu",awmtk2.templates,{}) @@ -23,22 +23,17 @@ local t = awmtk2.build_templates(templates,style,false) if not context_menu then -- load client menu config local config_file = io.open(root_path.."/themes/"..global.theme..'/config/client_menu.json',"r") - local config + local config if config_file then config = config_file:read("*a") config_file:close() else config = [[{"list":[{"widget":"widgets.clientcontrols"}]}]] end - -- NOTE: Please attach your menus to the prime_menu. It should be available as args.menu_parent via passthrough - local prime_menu = menugen({items={}}) context_menu = awful.popup(t.popup(builder( config, { style = style.base, - passthrough = { - menu_parent = prime_menu - } } ))) -- Close context menu on right click @@ -47,20 +42,46 @@ if not context_menu then context_menu.visible = false end end) + -- Generate a list of all existing menu_root objects + local menus = digger(context_menu.widget,"menu_root") + local context_menu_size = context_menu.width * context_menu.height + context_menu.widget:connect_signal("widget::size_changed",function() + local already_managed = {} + for _,v in pairs(menus) do + already_managed[v] = true + end + menus = digger(context_menu.widget,"menu_root") + for _,v in pairs(menus) do + if not already_managed[v] then + v:connect_signal("cascade::kill",function() + context_menu.visible = false + end) + end + end + end) -- Close all cascading menus if our menu becomes invisible context_menu:connect_signal("property::visible",function() + local current_context_menu_size = context_menu.height * context_menu.width + if current_context_menu_size ~= context_menu_size then + context_menu:emit_signal("widget::size_changed") + context_menu_size = current_context_menu_size + end if not context_menu.visible then - prime_menu:emit_signal("cascade::close") + for _,v in pairs(menus) do + v:emit_signal_recursive("cascade::kill") + end end end) -- If client became unfocused, close menu client.connect_signal("focus",function() context_menu.visible = false end) - -- Close our context menu when any of the attached menus signal cascade::kill - prime_menu:connect_signal("cascade::kill",function() - context_menu.visible = false - end) + -- If any of the menus emits cascade::kill, close the menu + for _,v in pairs(menus) do + v:connect_signal("cascade::kill",function() + context_menu.visible = false + end) + end end root.keys(gears.table.join( root.keys(), diff --git a/widgets/clientmenu/volume.lua b/widgets/clientmenu/volume.lua index 06c2b8e..356d1bf 100644 --- a/widgets/clientmenu/volume.lua +++ b/widgets/clientmenu/volume.lua @@ -20,7 +20,7 @@ if _VERSION:match("5.1") then result = (test_pactl == 0) end if not result then - return function() end + return end local function get_icon(percent) diff --git a/widgets/desktop/battery.lua b/widgets/desktop/battery.lua index 10057fe..efc657d 100644 --- a/widgets/desktop/battery.lua +++ b/widgets/desktop/battery.lua @@ -53,6 +53,11 @@ return function(args) }) -- create popup local popup = awful.popup(t.popup(layout)) + popup:connect_signal("button::press",function(_,_,_,b) + if b == 3 then + popup.visible = false + end + end) local battery_widget do -- create battery widget local style = awmtk2.create_style("battery", diff --git a/widgets/desktop/notifications.lua b/widgets/desktop/notifications.lua index fba29ab..afe967d 100644 --- a/widgets/desktop/notifications.lua +++ b/widgets/desktop/notifications.lua @@ -9,7 +9,6 @@ local awful = require("awful") local pager = require("pager") local beautiful = require("beautiful") -local gears = require("gears") local wibox = require("wibox") local awmtk2 = require("awmtk2") local naughty = require("naughty") @@ -49,6 +48,11 @@ return function(args) },{ visible = false })) + popup:connect_signal("button::press",function(_,_,_,b) + if b == 3 then + popup.visible = false + end + end) naughty.config.notify_callback = function(update_args) count = count + 1 local w = wibox.widget(t.button(t.article({ diff --git a/widgets/desktop/volume.lua b/widgets/desktop/volume.lua index 5e6b6de..9c91522 100644 --- a/widgets/desktop/volume.lua +++ b/widgets/desktop/volume.lua @@ -24,7 +24,7 @@ if _VERSION:match("5.1") then amixer_found = (test_amixer == 0) end if (not (amixer_found or pactl_found)) then - return function() end + return end local try_launch = "pavucontrol" diff --git a/widgets/dismal.lua b/widgets/dismal.lua index 73fd564..e71b4b0 100644 --- a/widgets/dismal.lua +++ b/widgets/dismal.lua @@ -33,8 +33,6 @@ local xdg_search = function(name,rlimit,sorting_method) table.sort(keys,function(a,b) return a > b end) local count = 0 local exit = false - gears.debug.dump(keys) - gears.debug.dump(filter) for k = 1,rlimit do local i = keys[k] if not filter[i] then @@ -52,7 +50,6 @@ local xdg_search = function(name,rlimit,sorting_method) break end end - gears.debug.dump(ranked_results) elseif sorting_method == "recent" then local most_recent = 0 for k,v in pairs(xdg.apps) do diff --git a/widgets/rootmenu.lua b/widgets/rootmenu.lua index 0e28a3e..15bab8b 100644 --- a/widgets/rootmenu.lua +++ b/widgets/rootmenu.lua @@ -10,8 +10,8 @@ local awmtk2 = require("awmtk2") local wibox = require("wibox") local gears = require("gears") local awful = require("awful") -local menugen = require("context_menu") local builder = require("builder") +local digger = require("digger") return function(args) local style = awmtk2.create_style("root_menu", @@ -27,14 +27,9 @@ return function(args) else config = [[{"list": [{"widget": "widgets.rootcontrols"}],"vertical": true}]] end - -- NOTE: **PLEASE** attach your other menus to this thing, ok? IF YOU DON'T, THE MENUS WILL WORK LIKE SHIT - -- NOTE 2: THERE IS NO OTHER "PROPER" FIX FOR THIS, JUST LOOK AT THE PREVIOUS SYSTEM (SPOILER: it was ABSOLUTE GARBAGE) - -- Primary menu to which other menus get attached - local prime_menu = menugen({items = {}}) -- Not yet loaded menu popup (TODO: maybe make it more obvious that it's a global?) root_menu = awful.popup(t.popup({ markup = "brainhurt the game", - prime_menu, widget = wibox.widget.textbox })) -- Close popup on right click @@ -49,22 +44,44 @@ return function(args) { style = style.base, screen = mouse.screen, - passthrough = { - -- This is the menu to which other menus should attach (available as args.menu_parent) - menu_parent = prime_menu, - } } )).widget) - -- Close the menu if prime_menu received a cascade::kill signal - prime_menu:connect_signal("cascade::kill",function() - root_menu.visible = false + -- Generate a list of all existing menu_root objects + local menus = digger(root_menu.widget,"menu_root") + local root_menu_size = root_menu.width * root_menu.height + root_menu:connect_signal("widget::size_changed",function() + local already_managed = {} + for _,v in pairs(menus) do + already_managed[v] = true + end + menus = digger(root_menu.widget,"menu_root") + for _,v in pairs(menus) do + if not already_managed[v] then + v:connect_signal("cascade::kill",function() + root_menu.visible = false + end) + end + end end) -- Close the prime_menu if our menu becomes invisible root_menu:connect_signal("property::visible",function() + local current_root_menu_size = root_menu.width * root_menu.height + if current_root_menu_size ~= root_menu_size then + root_menu:emit_signal("widget::size_changed") + root_menu_size = current_root_menu_size + end if not root_menu.visible then - prime_menu:emit_signal_recursive("cascade::close") + for _,v in pairs(menus) do + v:emit_signal("cascade::kill") + end end end) + -- If any of the menus emits cascade::kill, close the menu + for _,v in pairs(menus) do + v:connect_signal("cascade::kill",function() + root_menu.visible = false + end) + end -- Make the root_menu pop up on the desktop on right click local buttons = root.buttons() root.buttons(gears.table.join(buttons, diff --git a/widgets/xdgmenu.lua b/widgets/xdgmenu.lua index 2ff6fa8..d2c4328 100644 --- a/widgets/xdgmenu.lua +++ b/widgets/xdgmenu.lua @@ -69,10 +69,11 @@ return function(args) -- uhhh there's a lot of things about async, some of which i can't explain local xdg_menu_root = widget:get_children_by_id("xdg_menu_root")[1] xdg_menu_root:reset() - menugen({ + local menu = menugen({ items = items, parent = args.menu_parent }) + xdg_menu_root:add(menu) end) return widget end