FINALLY, ASYNCHRONOUS MULTIMENUS
This commit is contained in:
parent
39ca509391
commit
c6ca21f73a
|
@ -3,7 +3,7 @@
|
||||||
terminal = "$HOME/.local/bin/st"
|
terminal = "$HOME/.local/bin/st"
|
||||||
browser = "prime-run librewolf"
|
browser = "prime-run librewolf"
|
||||||
modkey = "Mod4"
|
modkey = "Mod4"
|
||||||
theme = "unity"
|
theme = "serenity"
|
||||||
shell = "zsh"
|
shell = "zsh"
|
||||||
|
|
||||||
# Keybindings
|
# Keybindings
|
||||||
|
|
|
@ -10,6 +10,7 @@ local json = require("dkjson")
|
||||||
local gears = require("gears")
|
local gears = require("gears")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
|
local menu = require("context_menu")
|
||||||
|
|
||||||
local builtins = {
|
local builtins = {
|
||||||
h_spacer = function(o)
|
h_spacer = function(o)
|
||||||
|
@ -126,10 +127,20 @@ return function(description,opts)
|
||||||
return builtins[struct.builtin](gears.table.join({
|
return builtins[struct.builtin](gears.table.join({
|
||||||
client = (struct.client and c)
|
client = (struct.client and c)
|
||||||
},struct.options or {}))
|
},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
|
end
|
||||||
-- If this gets interpreted it's safe to say none of the constructions
|
-- If this gets interpreted it's safe to say none of the constructions
|
||||||
-- above got matched.
|
-- above got matched.
|
||||||
print("Object where the error occured: ")
|
print("Object dump: ")
|
||||||
gears.debug.dump(struct)
|
gears.debug.dump(struct)
|
||||||
error("Builder error: invalid object description")
|
error("Builder error: invalid object description")
|
||||||
end
|
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",
|
{"widget": "widgets.base.tagswitcher",
|
||||||
"screen":true
|
"screen":true
|
||||||
},
|
},
|
||||||
{"widget": "widgets.rootmenu.controls"},
|
{"multimenu": [
|
||||||
{"widget": "widgets.xdgmenu",
|
{"widget": "widgets.rootmenu.controls"},
|
||||||
"options": {
|
{"widget": "widgets.xdgmenu",
|
||||||
"exclude_category": [
|
"options": {
|
||||||
"Other"
|
"exclude_category": [
|
||||||
]
|
"Other"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]},
|
||||||
{"widget": "widgets.rootmenu.buttons"}
|
{"widget": "widgets.rootmenu.buttons"}
|
||||||
],
|
],
|
||||||
"vertical": true
|
"vertical": true
|
||||||
|
|
|
@ -12,14 +12,16 @@
|
||||||
{"widget": "widgets.base.tagswitcher",
|
{"widget": "widgets.base.tagswitcher",
|
||||||
"screen":true
|
"screen":true
|
||||||
},
|
},
|
||||||
{"widget": "widgets.rootmenu.controls"},
|
{"multimenu":[
|
||||||
{"widget": "widgets.xdgmenu",
|
{"widget": "widgets.rootmenu.controls"},
|
||||||
|
{"widget": "widgets.xdgmenu",
|
||||||
"options": {
|
"options": {
|
||||||
"exclude_category": [
|
"exclude_category": [
|
||||||
"Other"
|
"Other"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]},
|
||||||
{"widget": "widgets.rootmenu.buttons"}
|
{"widget": "widgets.rootmenu.buttons"}
|
||||||
],
|
],
|
||||||
"vertical": true
|
"vertical": true
|
||||||
|
|
|
@ -11,14 +11,16 @@
|
||||||
{"widget": "widgets.base.tagswitcher",
|
{"widget": "widgets.base.tagswitcher",
|
||||||
"screen":true
|
"screen":true
|
||||||
},
|
},
|
||||||
{"widget": "widgets.rootmenu.controls"},
|
{"multimenu": [
|
||||||
{"widget": "widgets.xdgmenu",
|
{"widget": "widgets.rootmenu.controls"},
|
||||||
"options": {
|
{"widget": "widgets.xdgmenu",
|
||||||
"exclude_category": [
|
"options": {
|
||||||
"Other"
|
"exclude_category": [
|
||||||
]
|
"Other"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]},
|
||||||
{"widget": "widgets.rootmenu.buttons"}
|
{"widget": "widgets.rootmenu.buttons"}
|
||||||
],
|
],
|
||||||
"vertical": true
|
"vertical": true
|
||||||
|
|
|
@ -11,14 +11,16 @@
|
||||||
{"widget": "widgets.base.tagswitcher",
|
{"widget": "widgets.base.tagswitcher",
|
||||||
"screen":true
|
"screen":true
|
||||||
},
|
},
|
||||||
{"widget": "widgets.rootmenu.controls"},
|
{"multimenu":[
|
||||||
{"widget": "widgets.xdgmenu",
|
{"widget": "widgets.rootmenu.controls"},
|
||||||
"options": {
|
{"widget": "widgets.xdgmenu",
|
||||||
"exclude_category": [
|
"options": {
|
||||||
"Other"
|
"exclude_category": [
|
||||||
]
|
"Other"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]},
|
||||||
{"widget": "widgets.rootmenu.buttons"}
|
{"widget": "widgets.rootmenu.buttons"}
|
||||||
],
|
],
|
||||||
"vertical": true
|
"vertical": true
|
||||||
|
|
|
@ -11,8 +11,8 @@ local wibox = require("wibox")
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local gears = require("gears")
|
local gears = require("gears")
|
||||||
local builder = require("builder")
|
local builder = require("builder")
|
||||||
local menugen = require("context_menu")
|
|
||||||
local ask = require("asckey")
|
local ask = require("asckey")
|
||||||
|
local digger = require("digger")
|
||||||
local style = awmtk2.create_style("client_menu",
|
local style = awmtk2.create_style("client_menu",
|
||||||
awmtk2.generic.composite_widget,{})
|
awmtk2.generic.composite_widget,{})
|
||||||
local templates = awmtk2.create_template_lib("client_menu",awmtk2.templates,{})
|
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
|
if not context_menu then
|
||||||
-- load client menu config
|
-- load client menu config
|
||||||
local config_file = io.open(root_path.."/themes/"..global.theme..'/config/client_menu.json',"r")
|
local config_file = io.open(root_path.."/themes/"..global.theme..'/config/client_menu.json',"r")
|
||||||
local config
|
local config
|
||||||
if config_file then
|
if config_file then
|
||||||
config = config_file:read("*a")
|
config = config_file:read("*a")
|
||||||
config_file:close()
|
config_file:close()
|
||||||
else
|
else
|
||||||
config = [[{"list":[{"widget":"widgets.clientcontrols"}]}]]
|
config = [[{"list":[{"widget":"widgets.clientcontrols"}]}]]
|
||||||
end
|
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(
|
context_menu = awful.popup(t.popup(builder(
|
||||||
config,
|
config,
|
||||||
{
|
{
|
||||||
style = style.base,
|
style = style.base,
|
||||||
passthrough = {
|
|
||||||
menu_parent = prime_menu
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)))
|
)))
|
||||||
-- Close context menu on right click
|
-- Close context menu on right click
|
||||||
|
@ -47,20 +42,46 @@ if not context_menu then
|
||||||
context_menu.visible = false
|
context_menu.visible = false
|
||||||
end
|
end
|
||||||
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
|
-- Close all cascading menus if our menu becomes invisible
|
||||||
context_menu:connect_signal("property::visible",function()
|
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
|
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
|
||||||
end)
|
end)
|
||||||
-- If client became unfocused, close menu
|
-- If client became unfocused, close menu
|
||||||
client.connect_signal("focus",function()
|
client.connect_signal("focus",function()
|
||||||
context_menu.visible = false
|
context_menu.visible = false
|
||||||
end)
|
end)
|
||||||
-- Close our context menu when any of the attached menus signal cascade::kill
|
-- If any of the menus emits cascade::kill, close the menu
|
||||||
prime_menu:connect_signal("cascade::kill",function()
|
for _,v in pairs(menus) do
|
||||||
context_menu.visible = false
|
v:connect_signal("cascade::kill",function()
|
||||||
end)
|
context_menu.visible = false
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
root.keys(gears.table.join(
|
root.keys(gears.table.join(
|
||||||
root.keys(),
|
root.keys(),
|
||||||
|
|
|
@ -20,7 +20,7 @@ if _VERSION:match("5.1") then
|
||||||
result = (test_pactl == 0)
|
result = (test_pactl == 0)
|
||||||
end
|
end
|
||||||
if not result then
|
if not result then
|
||||||
return function() end
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_icon(percent)
|
local function get_icon(percent)
|
||||||
|
|
|
@ -53,6 +53,11 @@ return function(args)
|
||||||
})
|
})
|
||||||
-- create popup
|
-- create popup
|
||||||
local popup = awful.popup(t.popup(layout))
|
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
|
local battery_widget
|
||||||
do -- create battery widget
|
do -- create battery widget
|
||||||
local style = awmtk2.create_style("battery",
|
local style = awmtk2.create_style("battery",
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local pager = require("pager")
|
local pager = require("pager")
|
||||||
local beautiful = require("beautiful")
|
local beautiful = require("beautiful")
|
||||||
local gears = require("gears")
|
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
local awmtk2 = require("awmtk2")
|
local awmtk2 = require("awmtk2")
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
|
@ -49,6 +48,11 @@ return function(args)
|
||||||
},{
|
},{
|
||||||
visible = false
|
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)
|
naughty.config.notify_callback = function(update_args)
|
||||||
count = count + 1
|
count = count + 1
|
||||||
local w = wibox.widget(t.button(t.article({
|
local w = wibox.widget(t.button(t.article({
|
||||||
|
|
|
@ -24,7 +24,7 @@ if _VERSION:match("5.1") then
|
||||||
amixer_found = (test_amixer == 0)
|
amixer_found = (test_amixer == 0)
|
||||||
end
|
end
|
||||||
if (not (amixer_found or pactl_found)) then
|
if (not (amixer_found or pactl_found)) then
|
||||||
return function() end
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local try_launch = "pavucontrol"
|
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)
|
table.sort(keys,function(a,b) return a > b end)
|
||||||
local count = 0
|
local count = 0
|
||||||
local exit = false
|
local exit = false
|
||||||
gears.debug.dump(keys)
|
|
||||||
gears.debug.dump(filter)
|
|
||||||
for k = 1,rlimit do
|
for k = 1,rlimit do
|
||||||
local i = keys[k]
|
local i = keys[k]
|
||||||
if not filter[i] then
|
if not filter[i] then
|
||||||
|
@ -52,7 +50,6 @@ local xdg_search = function(name,rlimit,sorting_method)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
gears.debug.dump(ranked_results)
|
|
||||||
elseif sorting_method == "recent" then
|
elseif sorting_method == "recent" then
|
||||||
local most_recent = 0
|
local most_recent = 0
|
||||||
for k,v in pairs(xdg.apps) do
|
for k,v in pairs(xdg.apps) do
|
||||||
|
|
|
@ -10,8 +10,8 @@ local awmtk2 = require("awmtk2")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
local gears = require("gears")
|
local gears = require("gears")
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local menugen = require("context_menu")
|
|
||||||
local builder = require("builder")
|
local builder = require("builder")
|
||||||
|
local digger = require("digger")
|
||||||
|
|
||||||
return function(args)
|
return function(args)
|
||||||
local style = awmtk2.create_style("root_menu",
|
local style = awmtk2.create_style("root_menu",
|
||||||
|
@ -27,14 +27,9 @@ return function(args)
|
||||||
else
|
else
|
||||||
config = [[{"list": [{"widget": "widgets.rootcontrols"}],"vertical": true}]]
|
config = [[{"list": [{"widget": "widgets.rootcontrols"}],"vertical": true}]]
|
||||||
end
|
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?)
|
-- Not yet loaded menu popup (TODO: maybe make it more obvious that it's a global?)
|
||||||
root_menu = awful.popup(t.popup({
|
root_menu = awful.popup(t.popup({
|
||||||
markup = "brainhurt the game",
|
markup = "brainhurt the game",
|
||||||
prime_menu,
|
|
||||||
widget = wibox.widget.textbox
|
widget = wibox.widget.textbox
|
||||||
}))
|
}))
|
||||||
-- Close popup on right click
|
-- Close popup on right click
|
||||||
|
@ -49,22 +44,44 @@ return function(args)
|
||||||
{
|
{
|
||||||
style = style.base,
|
style = style.base,
|
||||||
screen = mouse.screen,
|
screen = mouse.screen,
|
||||||
passthrough = {
|
|
||||||
-- This is the menu to which other menus should attach (available as args.menu_parent)
|
|
||||||
menu_parent = prime_menu,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)).widget)
|
)).widget)
|
||||||
-- Close the menu if prime_menu received a cascade::kill signal
|
-- Generate a list of all existing menu_root objects
|
||||||
prime_menu:connect_signal("cascade::kill",function()
|
local menus = digger(root_menu.widget,"menu_root")
|
||||||
root_menu.visible = false
|
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)
|
end)
|
||||||
-- Close the prime_menu if our menu becomes invisible
|
-- Close the prime_menu if our menu becomes invisible
|
||||||
root_menu:connect_signal("property::visible",function()
|
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
|
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
|
||||||
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
|
-- Make the root_menu pop up on the desktop on right click
|
||||||
local buttons = root.buttons()
|
local buttons = root.buttons()
|
||||||
root.buttons(gears.table.join(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
|
-- 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]
|
local xdg_menu_root = widget:get_children_by_id("xdg_menu_root")[1]
|
||||||
xdg_menu_root:reset()
|
xdg_menu_root:reset()
|
||||||
menugen({
|
local menu = menugen({
|
||||||
items = items,
|
items = items,
|
||||||
parent = args.menu_parent
|
parent = args.menu_parent
|
||||||
})
|
})
|
||||||
|
xdg_menu_root:add(menu)
|
||||||
end)
|
end)
|
||||||
return widget
|
return widget
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue