diff --git a/core.lua b/core.lua index 66cbd70..689d70c 100644 --- a/core.lua +++ b/core.lua @@ -1,50 +1,167 @@ -found_widget_geometry = nil +-- S Y S T R A Y H I N T S +-- rts/oarion7 - ryanthomas.org +-- Module to control the awesomewm systray from the keyboard using +-- vimium-like number hints. Developed and tested on awesome v4.3. + +--TODO: +--Continue testing, clean up + local awful = require("awful") local gears = require("gears") -local b = require("beautiful") +local beautiful = require("beautiful") +local wibox = require("wibox") + + +local was_hidden +local icon_count +local icon_width +local half_icon +local first_icon_x +local icons_y + local s -function hide_systray_hints() - if systray_hints_widget then - systray_hints_widget.visible = false - end +local systray_hints_font = beautiful.systray_hints_font or beautiful.taglist_font or beautiful.font +local systray_hints_bg = beautiful.systray_hints_bg or beautiful.taglist_bg_occupied or "#d6d" +local systray_hints_hi = beautiful.systray_hints_bg_highlight or beautiful.bg_urgent or "#dd6" +local systray_hints_fg = beautiful.systray_hints_fg or beautiful.taglist_fg_occupied or "#000000" + + +awful.screen.connect_for_each_screen(function(screen) if screen.systray then s = screen end end) +if s == nil then return nil end + +-- G L O B A L S +-- Edit here or override to configure options. + +-- Arrows are key names optionally pressed at run-time before entering a number to specify which mouse button is to be clicked. Default is right-click, which is last in the index. The first key will set a left click, and the two middle options (up/down) trigger hover (no click). + +systray_hints = { + arrows = { "Left", "Down", "Up", "Right" }, + --arrows = { "h", "j", "k", "l" }, + default_button = 3, -- right-click by default + --default_button = 1, -- left click by default + wibox = s.mywibox, --where to look for the system tray + systray = s.systray, +} + + + + +local function click(choice, mouse_button) +--local function click(choice, mouse_button, first_icon_x, icons_y, icon_width) + + local target + local factor + local saved_coords + + saved_coords = mouse.coords({x = x, y = y}) --save + if choice == 1 then factor = 0 else factor = choice - 1 end + target = first_icon_x + ( icon_width * factor ) + mouse.coords { x = target , y = icons_y } + + if mouse_button ~= 2 then -- don't click; just hover + root.fake_input("button_press" , tostring(mouse_button)) + root.fake_input("button_release", tostring(mouse_button)) + + gears.timer( { timeout = 0.05, + autostart = true, + single_shot = true, + callback = function() + mouse.coords({x = saved_coords.x, y = saved_coords.y}, true) --restore + end } ) + end + end -function sys_hints_hide_systray() - local s - awful.screen.connect_for_each_screen(function(screen) - if screen.systray then s = screen end - end) - s.systray.visible = false + + + + +local function get_key_input(total) + + local grabber + local mouse_button + local mouse_button = systray_hints.default_button + local function conc(n) return tonumber( 1 .. n ) end + + local function execute(n, mouse_button) + + + + click(n, mouse_button) + + if systray_hints_widget then systray_hints_widget.visible = false end + + + + end + + grabber = awful.keygrabber { + + mask_modkeys = true, + autostart = true, + --start_callback = bcn("Let us begin."), --test + keypressed_callback = function(self, mod, key, cmd) + + if key == '1' and total > 9 then + + if systray_hints_widget then + systray_hints_widget.widget:get_children()[1]:get_all_children()[1].systray_hint_background_item_1.bg = systray_hints_hi + end + grabber.keypressed_callback = function(self, mod, key, cmd) + if key == "Return" then + execute(1, mouse_button) + grabber:stop() + elseif not key:match("%D") then + execute(conc(key), mouse_button) + grabber:stop() + else + grabber:stop() + if was_hidden then s.systray.visible = false end + if systray_hints_widget then systray_hints_widget.visible = false end + end + end + elseif key == systray_hints.arrows[1] then mouse_button = 1 + elseif key == systray_hints.arrows[4] then mouse_button = 3 + elseif key == systray_hints.arrows[2] or key == systray_hints.arrows[3] then mouse_button = 2 + elseif not key:match("%D") then + execute(key, mouse_button) + grabber:stop() + else + grabber:stop() + if was_hidden then s.systray.visible = false end + if systray_hints_widget then systray_hints_widget.visible = false end + end + + end, + + } + end -function systray_show_hints(x, y, w, count) - local sys_hints_geo_x = x or 1390 - local sys_hints_geo_y = y or 0 - local sys_hints_icon_width = w or 28 - local sys_hints_icon_count = count or 8 - local systray_hints_font = b.systray_hints_font or b.font - local systray_hints_bg = b.systray_hints_bg or "#ff00ff" - local systray_hints_fg = b.systray_hints_fg or "#000000" +local function show_systray_hints_widget(sys_hints_geo_x, sys_hints_geo_y, w, sys_hints_icon_count, s) + + local sys_hints_icon_width = w - 2 + + + - sys_hints_icon_width = sys_hints_icon_width - 2 --Subtract 2px from icon width for left/right margins + + if sys_hints_geo_y >= 100 then sys_hints_geo_y = sys_hints_geo_y - sys_hints_icon_width else sys_hints_geo_y = sys_hints_geo_y + sys_hints_icon_width --Decide if hints should display above or below systray icons. end - awful.screen.connect_for_each_screen(function(screen) - if screen.systray.visible == true then s = screen end - end) - - if s == nil then return nil end - - hide_systray_hints() --hide if already displayed + --hide if already displayed + if systray_hints_widget then + systray_hints_widget.visible = false + end local num_rows = sys_hints_icon_count local sys_hints_list = {} @@ -108,25 +225,33 @@ function systray_show_hints(x, y, w, count) end + + local function find_widget_in_wibox(wb, wdg) local function get_geometry(hi) local g = gears.matrix.transform_rectangle local x, y, w, h = g(hi:get_matrix_to_device(), 0, 0, hi:get_size()) - local x = math.floor(x) ; local y = math.floor(y) - local w = math.floor(w) ; local h = math.floor(h) - found_widget_geometry = x .. "," .. y .. "," .. w .. "," .. h + + icon_count = math.floor( ( w - ( w % h) ) / h + 1 ) + icon_width = math.floor(w / icon_count ) + half_icon = math.floor( icon_width / 2) + first_icon_x = math.floor( x + half_icon) + icons_y = math.floor(y + half_icon) + + show_systray_hints_widget( math.floor(x), math.floor(y), icon_width, icon_count, s ) + get_key_input(icon_count) + end local function traverse(hi) if hi:get_widget() == wdg then get_geometry(hi) - return + return end for _, child in ipairs(hi:get_children()) do - -- return traverse(child) traverse(child) - -- Others have the above line instead, but for us it returned + -- Others have return traverse(child) here instead, but for us this returned -- only container widgets. Removing "return" allows for an -- additional round of recursion. end @@ -134,11 +259,20 @@ local function find_widget_in_wibox(wb, wdg) return traverse(wb._drawable._widget_hierarchy) end -awful.screen.connect_for_each_screen(function(screen) - if screen.systray.visible == true then s = screen end -end) +systray_hints.run = function () -if s == nil then return nil end -find_widget_in_wibox(s.mywibox, s.systray) -return found_widget_geometry + if not s.systray.visible then + was_hidden = true + s.systray.visible = true + gears.timer( { timeout = 0.05, + autostart = true, + single_shot = true, + callback = function() + find_widget_in_wibox(systray_hints.wibox, systray_hints.systray) + end } ) + else + find_widget_in_wibox(systray_hints.wibox, systray_hints.systray) + end + +end diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..6cafa7b --- /dev/null +++ b/init.lua @@ -0,0 +1 @@ +require("systray-hints.core") \ No newline at end of file