FINALLY, ASYNCHRONOUS MULTIMENUS
This commit is contained in:
parent
39ca509391
commit
c6ca21f73a
|
@ -3,7 +3,7 @@
|
|||
terminal = "$HOME/.local/bin/st"
|
||||
browser = "prime-run librewolf"
|
||||
modkey = "Mod4"
|
||||
theme = "unity"
|
||||
theme = "serenity"
|
||||
shell = "zsh"
|
||||
|
||||
# Keybindings
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,{})
|
||||
|
@ -30,15 +30,10 @@ if not context_menu then
|
|||
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(),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue