Uploaded scripts.

This commit is contained in:
Ryan Thomas 2022-01-07 16:18:49 -05:00
commit 87769bb02d
14 changed files with 938 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
old/

29
README.md Normal file
View File

@ -0,0 +1,29 @@
~rts/oarion7
Shell script to control the awesome wm systray from the keyboard using vimium-like number hints. Written for awesome v4.3.
When "exec.sh" is executed, the included files are referenced to display an interactive number hint widget next to each icon in the system tray. The number entered on the keyboard sends a right click to the corresponding icon. (To left-click instead, press Ctrl+L before selecting a number. Ctrl+O will do the same for a "hovering" functionality, but it may be less reliable.) The mouse pointer is then restored to its original position.
The script uses "awesome-client" to load and call functions from the included lua file. A consequent limitation is the inability to grab data in the shell from lua return statements directly. My approach therefore requires some use of global variables and functions.
We also make use of rofi to function as a keygrabber to receive number inputs with the "-auto-select" flag so that hitting "return" is never necessary except when there are more than 9 icons to choose from. Finally, mouse.coords, iocane (https://github.com/TrilbyWhite/Iocane), and xdotool are used to simulate mouse actions.
Because the number hints are displayed in the form of a popup widget, visibility of rofi is redundant. An "invisible" theme file has been provided, and assumes a compositor is running. This proved more reliable for us in our tests than enabling rofi's -normal-window mode and attempting to hide the window in rules, and the temporary reassignment of key commands in awesome was one of the relevant matters beyond our immediate grasp. It may also be possible in place of widgets to configure rofi to display options with fixed widths that could be tied to the geometry of the systray icons, but this would become unintuitive in any use case where multi-digit numbers are necessary.
We have been using the following function in global keys to make this as seamless as possible in our environment, where incidentally the systray is hidden by default until needed.
-- Paste New Code Here. Include also the invisible by default line in widgets module.
Here one key combination is used to hide the systray if it is visible, or if not, to display the systray along with the number hints. Sometimes one may wish only to see what is running in the systray rather than actually click on anything in it, immediately pressing the same key combination to hide it. However, "Super+S" will never be received by the window manager when rofi (in its normal, non-windowed state) is in use. The "exit_key" variable, which should be assigned a single letter as its value, is added by the script to the list of valid options, which are themselves all numbers. The default value is "s" to pair with "Super+S". If we hit Super+S while rofi is active, rofi will read it as simply "s", which later triggers the script to clear the value. This allows us to hit the same combination key to cancel/hide the systray and hints as we do to display them. To disable this, exit_key can be set to null or simply commented out. Rofi can always be escaped via the "Escape" key, which should yield exactly the same result.
Additionally, note that obtaining the geometry of the system tray is not directly references in the awesome API for a reason; sometimes it is incorrect and requires a second execution to display correctly. If the same shortcut key is elected to display systray hints as well as to hide them, and one encounters a situation where several icons appear but only one or two hints, a series of two additional taps of the key shortcut is usually sufficient to resolve it right away.
#### #### #### #### ## ### ### ## # # ### ####
# # # # # # # # # # # ## # # #
### #### ### ### #### ### ### #### # # # # ## ###
# # # # # # # # # # # # ## # # #
# # ## #### #### # # #### #### # # # # ### ####

144
core.lua Normal file
View File

@ -0,0 +1,144 @@
found_widget_geometry = nil
local awful = require("awful")
local gears = require("gears")
local b = require("beautiful")
local s
function hide_systray_hints()
if systray_hints_widget then
systray_hints_widget.visible = false
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
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"
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
local num_rows = sys_hints_icon_count
local sys_hints_list = {}
local systray_widget_list = {}
local widget_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 5)
end
local var = {}
for i = 1, num_rows do table.insert(sys_hints_list, tostring(i)) end
for k, v in pairs(sys_hints_list) do
var["text_" .. v] = wibox.widget.textbox(tostring(v))
local text_alias = var["text_" .. v]
text_alias.font = systray_hints_font -- "Sans 14"
text_alias.markup = '<span color="' .. systray_hints_fg ..
'">' .. v .. '</span>'
local item_container_place = {}
table.insert(item_container_place, text_alias)
item_container_place.widget = wibox.container.place
local item_container_background = {}
table.insert(item_container_background, item_container_place)
item_container_background.widget = wibox.container.background
item_container_background.bg = systray_hints_bg -- "#ff00ff"
item_container_background.forced_width = sys_hints_icon_width
item_container_background.shape = widget_shape
item_container_background.shape_border_width = 2
item_container_background.shape_border_color = systray_hints_fg .. 33
item_container_background.id = "systray_hint_background_item_" ..
tostring(v)
local item_container_margin = {}
table.insert(item_container_margin, item_container_background)
item_container_margin.widget = wibox.container.margin
item_container_margin.right = 1
item_container_margin.left = 1
local complete_widget = item_container_margin
table.insert(systray_widget_list, complete_widget)
end
systray_widget_list.layout = wibox.layout.fixed.horizontal
systray_hints_widget = awful.popup {
widget = {
screen = s,
systray_widget_list,
layout = wibox.layout.fixed.horizontal,
},
x = sys_hints_geo_x,
y = sys_hints_geo_y,
visible = true,
ontop = true,
bg = "#00000000",
--hide_on_right_click = true
}
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
end
local function traverse(hi)
if hi:get_widget() == wdg then
get_geometry(hi)
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
-- only container widgets. Removing "return" allows for an
-- additional round of recursion.
end
end
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)
if s == nil then return nil end
find_widget_in_wibox(s.mywibox, s.systray)
return found_widget_geometry

86
exec.sh Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env bash
#rts/oarion7
# See "README" ! Tested with awesome v4.3
script_path="$(dirname $(realpath "$BASH_SOURCE"))"
rofi_theme="${script_path}/invisible.rasi" #key grabber only
exit_key='s' # See "README" !
hover_time='3' #time to hover in seconds if Ctrl+O
deps=( awesome-client iocane rofi xdotool )
for i in "${deps[@]}"; do command -v "$i" >/dev/null ||
errors=$(printf '%s %s\n' "$errors" "$i" | sed -e 's/^ //'); done
[[ "$errors" ]] && { notify-send -u critical \
"Veuillez corriger ces dépendances non satisfaites:" "$errors"; exit 1; }
parse_string() { printf '%s\n' "$1" | awk '{$1=""}1' | sed 's|[ "]||g' ; }
# 'string "X"' --> 'X'
awesome-exec() {
local file
[[ "$(realpath "$1")" == "$1" ]] && file="$1" || file="${script_path}/${1}"
[ -f "$file" ] && awesome-client 'dofile("'"$file"'")' ||
{ echo "Could not find ${1}."; exit 1; }
}
mouse_location() {
[[ "$1" == "save" ]] &&
{ awesome-client 'sys_hints_saved_coords = mouse.coords({x = x, y = y})'; return; }
[[ "$1" == "restore" ]] &&
awesome-client 'mouse.coords({x = sys_hints_saved_coords.x, y = sys_hints_saved_coords.y}, true)'
}
hide_systray_hints() { awesome-client 'hide_systray_hints()' >/dev/null ; }
hide_systray() { awesome-client 'sys_hints_hide_systray()' >/dev/null ; }
seq_with_exit_key() { (printf '%s\n%s\n' "$exit_key" "$(seq $1)") ; }
mouse_to_icon() {
[[ "$1" == "1" ]] && factor='0' || factor=$(("$1" - 1))
target_position_x=$(( $first_icon_x + ( "$icon_width" * "$factor" ) ))
iocane -c "${target_position_x},${icons_y}"
}
get_choice() {
choice=$(seq_with_exit_key "$icon_count" | rofi \
-kb-custom-1 "Ctrl+l" -kb-custom-2 "Ctrl+o" -dmenu -theme "$rofi_theme" \
-no-custom -auto-select 2>/dev/null )
code="$?"
}
awesome-exec "core.lua"
data=$(awesome-client "return found_widget_geometry")
[[ -z "$data" ]] && { echo "Geometery data not found."; exit 1; }
IFS=',' read -r -a array <<< "$(parse_string "$data")"
[[ -n "${array[4]}" ]] || [[ -z "${array[3]}" ]] && { echo "Invalid data: $data"; exit 1; }
x="${array[0]}" ; y="${array[1]}" ; w="${array[2]}" ; h="${array[3]}"
icon_count=$((( $w - ( $w % $h )) / $h + 1 ))
icon_width=$(( $w / $icon_count ))
half_icon=$(( $icon_width / 2 ))
first_icon_x=$(( $x + $half_icon ))
icons_y=$(( $y + $half_icon ))
awesome-client 'systray_show_hints('"${x}, ${y}, ${icon_width}, ${icon_count}"')'
mouse_location save
mouse_button='3' #default to right click
get_choice; [[ "$code" == "10" ]] && { mouse_button='1'; get_choice; }
[[ "$code" == "11" ]] && { unset mouse_button; get_choice; }
hide_systray_hints
[[ "$choice" == "$exit_key" ]] && unset choice
[[ -z "$choice" ]] && { hide_systray; exit 0; }
mouse_to_icon "$choice" &&
[[ -n "$mouse_button" ]] && xdotool click "$mouse_button"
[[ -z "$mouse_button" ]] && sleep "$hover_time" #hover only (not so reliable)
mouse_location restore

42
invisible.rasi Normal file
View File

@ -0,0 +1,42 @@
/**
* ROFI Color theme
* User: Qball
* Copyright: Dave Davenport
*/
* {
background-color: rgba ( 255, 255, 255, 0 % );
border-color: rgba ( 255, 255, 255, 0 % );
text-color: rgba ( 255, 255, 255, 0 % );
font: "Times New Roman 12";
}
#window {
anchor: north;
location: north;
width: 100%;
padding: 4px;
children: [ horibox ];
}
#horibox {
orientation: horizontal;
children: [ prompt, entry, listview ];
}
#listview {
layout: horizontal;
spacing: 5px;
lines: 100;
}
#entry {
expand: false;
width: 10em;
}
#element {
padding: 0px 2px;
}
#element selected {
background-color: rgba ( 255, 255, 255, 0 % );
}

44
old/README Normal file
View File

@ -0,0 +1,44 @@
systraykeys
~rts/oarion7
#### #### #### #### ## ### ### ## # # ### ####
# # # # # # # # # # # ## # # #
### #### ### ### #### ### ### #### # # # # ## ###
# # # # # # # # # # # # ## # # #
# # ## #### #### # # #### #### # # # # ### ####
# Displays a numbered hint widget next to each systray icon to allow use of the systray
# via the keyboard. Uses a hidden rofi instance as the keygrabber to simulate clicking.
# Uses mouse.coords, iocane, and xdotool to simulate mouse actions because the dude who
# wrote this is crazy, and his other personalities don't know anything about computers.
# https://github.com/TrilbyWhite/Iocane
# Defaults to right-click mode. Left-click & hover via Ctrl+L & Ctrl-O, respectively.
# Tested with awesome v4.3
Displays a number hint widget next to each systray icon. The number entered on the keyboard sends a right click to the corresponding icon unless Ctrl+L (i.e. Left) is pressed first. Ctrl+O will do the same for a "hovering" functionality, but it is less reliable. Two lines calling the mouse_location function serve to save and then restore the original pointer coordinates
Uses "awesome-client" to interact with the included lua files which are actually sourceable declarations of bash functions. Some global variables and functions were therefore necessary. Note that awesome-client does not print the results of a return statement to the terminal if that return statement is written inside a function that is called. Also, when editing those files, one must be careful to avoid single quotes when possible, or appropriately "escape" them like '"'"'this'"'"'.
Uses rofi as temporary key grabber by calling it with the -auto-select flag so that hitting "return" is never necessary unless there are more than 9 systray icons. Because the menu options are all displayed in the widget, visibility of rofi is redundant. An "invisible" theme has been provided and enabled in-line, and assumes a compositor is running. This proved more reliable for us in our tests than enabling rofi's -normal-window mode and attempting to hide the window in rules.
Alternative routes for future re-writes: not using 3 separate programs for mouse actions (mouse.coords, iocane, xdotool); just doing the whole damn thing in lua without bash; figure out how to temporarily grab keys in awesome natively instead of using rofi at all (seems perfectly doable, but maybe convoluted), or finally, instead of using widgets for hints and obscuring rofi, one might elect simply to configure rofi to display options with fixed widths, preferably without moving them around while multi-digit numbers are typed.
We have been using the following function in global keys to make this as seamless as possible in our environment, where incidentally the systray is hidden by default until needed.
awful.key({ modkey }, "s", function ()
local s
awful.screen.connect_for_each_screen(
function(screen) if screen.systray then s = screen end
end)
if not s.systray.visible then
s.systray.visible = true
gears.timer.delayed_call(function() awful.util.spawn("/path/to/script/systraykeys/systraykeys.sh") end)
else
s.systray.visible = false
end
end, {description="toggle system tray", group="awesome"}),
Here one key combination is used to hide the systray if it is visible, or if not, to display the systray along with the number hints. Sometimes one may wish only to see what is running in the systray rather than actually click on anything in it, immediately pressing the same key combination to hide it. However, "Super+S" will never be received by the window manager when rofi (in its normal, non-windowed state) is in use. The "exit_key" variable, which should be assigned a single letter as its value, is added by the script to the list of valid options, which are themselves all numbers. The default value is "s" to pair with "Super+S". If we hit Super+S while rofi is active, rofi will read it as simply "s", which later triggers the script to clear the value. This allows us to hit the same combination key to cancel/hide the systray and hints as we do to display them. To disable this, exit_key can be set to null or simply commented out.

38
old/find_systray_lua Normal file
View File

@ -0,0 +1,38 @@
get_systray_geometry() {
awesome-client '
local awful = require("awful")
local s
local found_widget_geometry
awful.screen.connect_for_each_screen(function(screen)
if screen.systray.visible == true then s = screen end
end)
local function find_widget_in_wibox(wb, wdg)
local function get_geometry(hi)
local x, y, w, h = gears.matrix.transform_rectangle(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
end
local function traverse(hi)
if hi:get_widget() == wdg then
get_geometry(hi)
return
end
for _, child in ipairs(hi:get_children()) do
-- return traverse(child) -- Others have this line, but for us it returned only container widgets.
traverse(child) -- Removing "return" allows for an additional round of recursion, tested on v4.3
end
end
return traverse(wb._drawable._widget_hierarchy)
end
if s == nil then return nil end
find_widget_in_wibox(s.mywibox, s.systray)
return found_widget_geometry
'
}

42
old/invisible.rasi Normal file
View File

@ -0,0 +1,42 @@
/**
* ROFI Color theme
* User: Qball
* Copyright: Dave Davenport
*/
* {
background-color: rgba ( 255, 255, 255, 0 % );
border-color: rgba ( 255, 255, 255, 0 % );
text-color: rgba ( 255, 255, 255, 0 % );
font: "Times New Roman 12";
}
#window {
anchor: north;
location: north;
width: 100%;
padding: 4px;
children: [ horibox ];
}
#horibox {
orientation: horizontal;
children: [ prompt, entry, listview ];
}
#listview {
layout: horizontal;
spacing: 5px;
lines: 100;
}
#entry {
expand: false;
width: 10em;
}
#element {
padding: 0px 2px;
}
#element selected {
background-color: rgba ( 255, 255, 255, 0 % );
}

View File

@ -0,0 +1,37 @@
get_systray_geometry() {
awesome-client '
local awful = require("awful")
local s
local found_widget_geometry
awful.screen.connect_for_each_screen(function(screen)
if screen.systray.visible == true then s = screen end
end)
local function find_widget_in_wibox(wb, wdg)
local function get_geometry(hi)
local x, y, w, h = gears.matrix.transform_rectangle(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
end
local function traverse(hi)
if hi:get_widget() == wdg then
get_geometry(hi)
return
end
for _, child in ipairs(hi:get_children()) do
traverse(child)
end
end
return traverse(wb._drawable._widget_hierarchy)
end
if s == nil then return nil end
find_widget_in_wibox(s.mywibox, s.systray)
return found_widget_geometry
'
}

View File

@ -0,0 +1,42 @@
/**
* ROFI Color theme
* User: Qball
* Copyright: Dave Davenport
*/
* {
background-color: rgba ( 255, 255, 255, 0 % );
border-color: rgba ( 255, 255, 255, 0 % );
text-color: rgba ( 255, 255, 255, 0 % );
font: "Times New Roman 12";
}
#window {
anchor: north;
location: north;
width: 100%;
padding: 4px;
children: [ horibox ];
}
#horibox {
orientation: horizontal;
children: [ prompt, entry, listview ];
}
#listview {
layout: horizontal;
spacing: 5px;
lines: 100;
}
#entry {
expand: false;
width: 10em;
}
#element {
padding: 0px 2px;
}
#element selected {
background-color: rgba ( 255, 255, 255, 0 % );
}

View File

@ -0,0 +1,115 @@
show_hints() {
#--called as show_hints "$x" "$y" "$icon_width" "$icon_count"
[[ "$1" ]] && arg1="$1" || arg1='1390'
[[ "$2" ]] && arg2="$2" || arg2='0'
[[ "$3" ]] && arg3="$3" || arg3='28'
[[ "$4" ]] && arg4="$4" || arg4='8'
#--For now, allow failure to declare parameters for testing purposes
awesome-client '
local awful = require("awful")
local beautiful = require("beautiful")
local gears = require("gears")
local s
local sys_hints_geo_x = '"$arg1"'
local sys_hints_geo_y = '"$arg2"'
local sys_hints_icon_width = '"$arg3"'
local sys_hints_icon_count = '"$arg4"'
local systray_hints_font = beautiful.systray_hints_font or beautiful.font
local systray_hints_bg = beautiful.systray_hints_bg or "#ff00ff"
local systray_hints_fg = beautiful.systray_hints_fg or "#000000"
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 --Put hints above/below systray
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
function hide_systray_hints()
if systray_hints_widget then systray_hints_widget.visible = false end
end
function sys_hints_kill_rofi(c)
if c.instance == "rofi" and systray_hints_widget and systray_hints_widget.visible then
c:kill()
client.disconnect_signal("unfocus", sys_hints_kill_rofi)
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
end
hide_systray_hints()
client.connect_signal("unfocus", sys_hints_kill_rofi)
local num_rows = sys_hints_icon_count
local sys_hints_list = {}
local systray_widget_list = {}
local widget_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 5)
end
local var = {}
for i = 1, num_rows do table.insert(sys_hints_list, tostring(i)) end
for k, v in pairs(sys_hints_list) do
var["ryan_text_" .. v] = wibox.widget.textbox(tostring(v))
local text_alias = var["ryan_text_" .. v]
text_alias.font = systray_hints_font -- "Sans 14"
text_alias.markup = "<span color='"'"'" .. systray_hints_fg .. "'"'"'>" .. v .. "</span>"
local item_container_place = {}
table.insert(item_container_place, text_alias)
item_container_place.widget = wibox.container.place
local item_container_background = {}
table.insert(item_container_background, item_container_place)
item_container_background.widget = wibox.container.background
item_container_background.bg = systray_hints_bg -- "#ff00ff"
item_container_background.forced_width = sys_hints_icon_width
item_container_background.shape = widget_shape
--item_container_background.shape_border_width = 1
--item_container_background.shape_border_color = systray_hints_fg
item_container_background.id = "systray_hint_background_item_" .. tostring(v)
local item_container_margin = {}
table.insert(item_container_margin, item_container_background)
item_container_margin.widget = wibox.container.margin
item_container_margin.right = 1
item_container_margin.left = 1
local complete_widget = item_container_margin
table.insert(systray_widget_list, complete_widget)
end
systray_widget_list.layout = wibox.layout.fixed.horizontal
systray_hints_widget = awful.popup {
widget = {
screen = s,
systray_widget_list,
layout = wibox.layout.fixed.horizontal,
},
x = sys_hints_geo_x,
y = sys_hints_geo_y,
visible = true,
ontop = true,
bg = "#00000000",
--hide_on_right_click = true
}
'
}

View File

@ -0,0 +1,116 @@
#!/usr/bin/env bash
#rts/oarion7
# * Displays number hints next to systray icons. The number entered on the keyboard sends
# right click to the corresponding icon unless Ctrl+L (i.e. Left) is pressed first.
#
# * Uses rofi as temporary key grabber by invoking it with auto-select.
#
# * Because the menu options are displays in the widget, visibility of rofi is
# unnecessary. Running rofi in normal window mode, we can put the following in
# our rules to keep it hidden:
#
# * * * Currently, trying an "invisible" theme instead of -normal-window, so these rules are *NOT* read or needed!
#
# { rule = { instance = "rofi" }, callback = function(c)
# if systray_hints_widget and systray_hints_widget.visible then
# c.name = "Select item by number key" ; c.border_width = 0; c.floating = true ;
# c.x = 1 ; c.y = 1; c.width = 1; c.height = 1
# end end }, --c.opacity = 0 doesn't work here, so resize window & hide borders for now
#
# * I am using the following function in global keys to make this as seamless as possible in my environment
#
# awful.key({ modkey }, "s", function ()
# local s
# awful.screen.connect_for_each_screen(
# function(screen) if screen.systray then s = screen end
# end)
# if not s.systray.visible then
# s.systray.visible = true
# gears.timer.delayed_call(function() awful.util.spawn("/home/ryan/scripts/systraykeys/systraykeys.sh") end)
# --awful.util.spawn_with_shell("/home/ryan/scripts/systraykeys/systraykeys.sh")
# else
# s.systray.visible = false
# if client.focus and client.focus.instance == "rofi" then
# client.focus:kill()
# end
# end
# end, {description="toggle system tray", group="awesome"}),
#
# * The if statement relating to rofi (contained in the last else section of the above) is only relevant if rofi is launched in normal window mode, as the window could be accidentally unfocused and thus needed to be killed. Super+S will never be received by the window manager if using the invisible normal (non-window state) rofi. Because of that, I have modifed the line include the seq command below to include a single letter string (the value of exit key), "s", which will be selected and sent if I hit Super+S (which rofi will read as "S", allow me to hit the same combination key to cancel as I do to start). To disable this, set exit_key value to null or comment it out
exit_key='s'
rofi_theme='/home/ryan/scripts/systraykeys/invisible.rasi'
lua1='/home/ryan/scripts/systraykeys/find_systray_lua' # function: get_systray_geometry()
lua2='/home/ryan/scripts/systraykeys/show_hints_lua' # functions: show_hints() and hide_systray_hints()
[ -f "$lua1" ] && source "$lua1" || { echo "Could not read $lua1"; exit 1; }
[ -f "$lua2" ] && source "$lua2" || { echo "Could not read $lua2"; exit 1; }
deps=( awesome-client iocane rofi xdotool ) #https://github.com/TrilbyWhite/Iocane
for i in "${deps[@]}"; do command -v "$i" >/dev/null || errors=$(printf '%s %s\n' "$errors" "$i" | sed -e 's/^ //'); done
[[ "$errors" ]] && { notify-send -u critical "Veuillez corriger ces dépendances non satisfaites:" "$errors"; exit 1; }
data=$(get_systray_geometry) ; [[ -z "$data" ]] && { echo "Geometery data not found."; exit 0; }
parse_string() { printf '%s\n' "$1" | awk '{$1=""}1' | sed 's|[ "]||g' ; } # 'string "X"' --> 'X'
mouse_location() {
[[ "$1" == "save" ]] &&
{ awesome-client 'sys_hints_saved_coords = mouse.coords({x = x, y = y})'; return; }
[[ "$1" == "restore" ]] &&
awesome-client 'mouse.coords({x = sys_hints_saved_coords.x, y = sys_hints_saved_coords.y}, true)'
}
#hide_systray() { awesome-client 'require("awful.screen").focused().systray.visible = false' >/dev/null ; }
hide_systray() { awesome-client 'sys_hints_hide_systray()' >/dev/null ; }
seq_with_exit_key() { (printf '%s\n%s\n' "$exit_key" "$(seq $1)") ; }
mouse_to_icon() {
[[ "$1" == "1" ]] && factor='0' || factor=$(("$1" - 1))
target_position_x=$(( $first_icon_x + ( "$icon_width" * "$factor" ) ))
iocane -c "${target_position_x},${icons_y}"
}
get_choice() {
choice=$(seq_with_exit_key "$icon_count" | rofi \
-kb-custom-1 "Ctrl+l" -kb-custom-2 "Ctrl+o" -dmenu -theme "$rofi_theme" -no-custom -auto-select 2>/dev/null )
# Change -theme "$rofi_theme" and add -normal-window if desired.
code="$?"
}
IFS=',' read -r -a array <<< "$(parse_string "$data")"
[[ -n "${array[4]}" ]] || [[ -z "${array[3]}" ]] && { echo "Invalid data: $data"; exit 1; }
x="${array[0]}" ; y="${array[1]}" ; w="${array[2]}" ; h="${array[3]}"
#echo "${x}x$y ${w}x$h"
icon_count=$((( $w - ( $w % $h )) / $h + 1 ))
icon_width=$(( $w / $icon_count ))
half_icon=$(( $icon_width / 2 ))
first_icon_x=$(( $x + $half_icon ))
icons_y=$(( $y + $half_icon ))
#echo "Counted $icon_count icons."
show_hints "$x" "$y" "$icon_width" "$icon_count"
mouse_location save
mouse_button='3' #default to right click
get_choice; [[ "$code" == "10" ]] && { mouse_button='1'; get_choice; }
[[ "$code" == "11" ]] && { unset mouse_button; get_choice; }
awesome-client 'hide_systray_hints()' >/dev/null
[[ "$choice" == "$exit_key" ]] && unset choice
[[ -z "$choice" ]] && { hide_systray; exit 0; }
awesome-client 'client.disconnect_signal("unfocus", sys_hints_kill_rofi)'
#needed only for "-normal-window" mode, if you comment out, then also remove the connect command from $lua2 file
mouse_to_icon "$choice" &&
[[ -n "$mouse_button" ]] && xdotool click "$mouse_button"
[[ -z "$mouse_button" ]] && sleep 3 #hover only (this is not that reliable)
mouse_location restore

108
old/show_hints_lua Normal file
View File

@ -0,0 +1,108 @@
show_hints() {
#--called as show_hints "$x" "$y" "$icon_width" "$icon_count"
[[ "$1" ]] && arg1="$1" || arg1='1390'
[[ "$2" ]] && arg2="$2" || arg2='0'
[[ "$3" ]] && arg3="$3" || arg3='28'
[[ "$4" ]] && arg4="$4" || arg4='8'
#--For now, allow failure to declare parameters for testing purposes
awesome-client '
local awful = require("awful")
local beautiful = require("beautiful")
local gears = require("gears")
local s
local sys_hints_geo_x = '"$arg1"'
local sys_hints_geo_y = '"$arg2"'
local sys_hints_icon_width = '"$arg3"'
local sys_hints_icon_count = '"$arg4"'
local systray_hints_font = beautiful.systray_hints_font or beautiful.font
local systray_hints_bg = beautiful.systray_hints_bg or "#ff00ff"
local systray_hints_fg = beautiful.systray_hints_fg or "#000000"
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 --Put hints above/below systray
end
local s
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
function hide_systray_hints()
if systray_hints_widget then systray_hints_widget.visible = false 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
end
hide_systray_hints() --hide if already displayed
local num_rows = sys_hints_icon_count
local sys_hints_list = {}
local systray_widget_list = {}
local widget_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 5)
end
local var = {}
for i = 1, num_rows do table.insert(sys_hints_list, tostring(i)) end
for k, v in pairs(sys_hints_list) do
var["text_" .. v] = wibox.widget.textbox(tostring(v))
local text_alias = var["text_" .. v]
text_alias.font = systray_hints_font -- "Sans 14"
text_alias.markup = "<span color='"'"'" .. systray_hints_fg .. "'"'"'>" .. v .. "</span>"
local item_container_place = {}
table.insert(item_container_place, text_alias)
item_container_place.widget = wibox.container.place
local item_container_background = {}
table.insert(item_container_background, item_container_place)
item_container_background.widget = wibox.container.background
item_container_background.bg = systray_hints_bg -- "#ff00ff"
item_container_background.forced_width = sys_hints_icon_width
item_container_background.shape = widget_shape
--item_container_background.shape_border_width = 1
--item_container_background.shape_border_color = systray_hints_fg
item_container_background.id = "systray_hint_background_item_" .. tostring(v)
local item_container_margin = {}
table.insert(item_container_margin, item_container_background)
item_container_margin.widget = wibox.container.margin
item_container_margin.right = 1
item_container_margin.left = 1
local complete_widget = item_container_margin
table.insert(systray_widget_list, complete_widget)
end
systray_widget_list.layout = wibox.layout.fixed.horizontal
systray_hints_widget = awful.popup {
widget = {
screen = s,
systray_widget_list,
layout = wibox.layout.fixed.horizontal,
},
x = sys_hints_geo_x,
y = sys_hints_geo_y,
visible = true,
ontop = true,
bg = "#00000000",
--hide_on_right_click = true
}
'
}

94
old/systraykeys.sh Executable file
View File

@ -0,0 +1,94 @@
#!/usr/bin/env bash
#rts/oarion7
# Displays a numbered hint widget next to each systray icon to allow use of the systray
# via the keyboard. Uses a hidden rofi instance as keygrabber to receive number inputs.
# Uses mouse.coords, iocane, and xdotool to simulate mouse actions because the dude who
# wrote this is crazy, and his other personalities don't know anything about computers.
# https://github.com/TrilbyWhite/Iocane
# Defaults to right-click mode. Left-click & hover via Ctrl+L & Ctrl-O, respectively.
# Tested with awesome v4.3
# See "README" !
script_path="$HOME/scripts/systraykeys/old"
rofi_theme="${script_path}/invisible.rasi"
lua1="${script_path}/find_systray_lua" #bash function get_systray_geometry
lua2="${script_path}/show_hints_lua" #bash function show_hints() + global lua functions
exit_key='s' #you can always hit Esc to exit rofi, but this can be useful! See README.
hover_time='3' #time to hover in seconds if Ctrl+O
[ -f "$lua1" ] && source "$lua1" || { echo "Could not read $lua1"; exit 1; }
[ -f "$lua2" ] && source "$lua2" || { echo "Could not read $lua2"; exit 1; }
deps=( awesome-client iocane rofi xdotool )
for i in "${deps[@]}"; do command -v "$i" >/dev/null ||
errors=$(printf '%s %s\n' "$errors" "$i" | sed -e 's/^ //'); done
[[ "$errors" ]] && { notify-send -u critical \
"Veuillez corriger ces dépendances non satisfaites:" "$errors"; exit 1; }
data=$(get_systray_geometry)
[[ -z "$data" ]] && { echo "Geometery data not found."; exit 0; }
parse_string() { printf '%s\n' "$1" | awk '{$1=""}1' | sed 's|[ "]||g' ; }
# 'string "X"' --> 'X'
mouse_location() {
[[ "$1" == "save" ]] &&
{ awesome-client 'sys_hints_saved_coords = mouse.coords({x = x, y = y})'; return; }
[[ "$1" == "restore" ]] &&
awesome-client 'mouse.coords({x = sys_hints_saved_coords.x, y = sys_hints_saved_coords.y}, true)'
}
hide_systray_hints() { awesome-client 'hide_systray_hints()' >/dev/null ; }
hide_systray() { awesome-client 'sys_hints_hide_systray()' >/dev/null ; }
seq_with_exit_key() { (printf '%s\n%s\n' "$exit_key" "$(seq $1)") ; }
mouse_to_icon() {
[[ "$1" == "1" ]] && factor='0' || factor=$(("$1" - 1))
target_position_x=$(( $first_icon_x + ( "$icon_width" * "$factor" ) ))
iocane -c "${target_position_x},${icons_y}"
}
get_choice() {
choice=$(seq_with_exit_key "$icon_count" | rofi \
-kb-custom-1 "Ctrl+l" -kb-custom-2 "Ctrl+o" -dmenu -theme "$rofi_theme" \
-no-custom -auto-select 2>/dev/null )
code="$?"
}
IFS=',' read -r -a array <<< "$(parse_string "$data")"
[[ -n "${array[4]}" ]] || [[ -z "${array[3]}" ]] && { echo "Invalid data: $data"; exit 1; }
x="${array[0]}" ; y="${array[1]}" ; w="${array[2]}" ; h="${array[3]}"
#echo "${x}x$y ${w}x$h"
icon_count=$((( $w - ( $w % $h )) / $h + 1 ))
icon_width=$(( $w / $icon_count ))
half_icon=$(( $icon_width / 2 ))
first_icon_x=$(( $x + $half_icon ))
icons_y=$(( $y + $half_icon ))
#echo "Counted $icon_count icons."
show_hints "$x" "$y" "$icon_width" "$icon_count"
mouse_location save
mouse_button='3' #default to right click
get_choice; [[ "$code" == "10" ]] && { mouse_button='1'; get_choice; }
[[ "$code" == "11" ]] && { unset mouse_button; get_choice; }
hide_systray_hints
[[ "$choice" == "$exit_key" ]] && unset choice
[[ -z "$choice" ]] && { hide_systray; exit 0; }
mouse_to_icon "$choice" &&
[[ -n "$mouse_button" ]] && xdotool click "$mouse_button"
[[ -z "$mouse_button" ]] && sleep "$hover_time" #hover only (this is not that reliable)
mouse_location restore