11 Commits
1.1 ... master

  1. 23
      README.md
  2. 128
      desktop.conf
  3. 4
      extra/README.md
  4. 12
      libs/awmtk2.lua
  5. 8
      libs/digger.lua
  6. 7
      libs/imagemagick_blur.lua
  7. 29
      libs/parser_test.lua
  8. 98
      libs/parsers.lua
  9. 137
      libs/xdg_data.lua
  10. 85
      modules/autostart.lua
  11. 7
      modules/macros.lua
  12. 2
      modules/powermanX.lua
  13. 25
      modules/rules_stub.lua
  14. 7
      modules/tiling.lua
  15. 99
      modules/xdg_data.lua
  16. 2
      rc.lua
  17. 2
      themes/reno98/theme.lua
  18. 3
      themes/unity_mate/theme.lua
  19. 7
      widgets/base/layout.lua
  20. 2
      widgets/base/systray.lua
  21. 280
      widgets/clientmenu/volume.lua
  22. 4
      widgets/desktop/battery.lua
  23. 17
      widgets/desktop/tasklist.lua
  24. 4
      widgets/lock/clock.lua
  25. 2
      widgets/rootmenu.lua
  26. 51
      widgets/rootmenu/controls.lua
  27. 59
      widgets/supermenu/applications-tab.lua

23
README.md

@ -1,6 +1,6 @@
# Reno desktop - awesomewm || ( openbox && xfce )
Reno is an evolution of my previous configuration, https://512mb.org/git/Yessiest/awesome. This time, this bad boy can fit 90% more configuration options, through the use of AWMTK2 (or RenoTK, never really decided on the name).
Reno is an evolution of my previous configuration, https://512mb.org/git/Yessiest/awesome. This time, this bad boy can fit 90% more configuration options, through the use of AWMTK2 (or RenoTK, haven't really decided on the name).
Through advancements in the ~~science~~ dark magic art of lua metatablery, AWMTK2 makes it possible to create complex and visually rich themes, while mainting relatively low memory footprint.
@ -11,23 +11,36 @@ Thanks to the ethically questionable decision of employing JSON to Widget Layout
#### Current default theme, Reno98
![Totally not windows 98 trust me it's legally distinct](https://adastra7.net/git/Yessiest/reno/raw/branch/master/extra/screenshots/reno98.png)
#### An iteration on the look of Ubuntu with Ambiance theme
![Totally not ubuntu guys this how can't you see that](https://adastra7.net/git/Yessiest/reno/raw/branch/master/extra/screenshots/unity.png)
- Works best with [Chicago95](https://github.com/grassmunk/Chicago95) for GTK and [QTStep (QTStepWMakerDefault in particular)](https://github.com/andbgr/QTStep) on [Kvantum](https://github.com/tsujan/Kvantum).
- For Wine apps, use `winecfg`, go to Desktop Integration and set "(No Theme)" under "Theme". A matching QTStep theme is "QTStepBeige", but it doesn't quite match Chicago95, so you may want to configure the window colors using the Item editor, or by installing a custom theme.
#### Unity: a theme that mimics the look of Ubuntu with Ambiance theme
![Totally not ubuntu guys how can't you see that](https://adastra7.net/git/Yessiest/reno/raw/branch/master/extra/screenshots/unity.png)
- Works best with official [Ubuntu Themes](https://launchpad.net/ubuntu-themes) ([AUR package](https://aur.archlinux.org/packages/ubuntu-themes)) for GTK and [Kvantum's](https://github.com/tsujan/Kvantum) default themes KvAmbiance or KvAmbience.
- For Wine apps, [Ubuntu Light for Windows XP](http://freddi67.deviantart.com/art/Ubuntu-Light-for-Windows-XP-177514325) theme exists on DeviantArt, which you can install using `winecfg`.
## Installation
The installation process is not much different from the previous iteration, except this time the window manager does not crash if you don't install luapam. Instead, the lock widget will simply refuse to operate.
Reno internally requires [ImageMagick](https://imagemagick.org/) to generate thumbnails for images. Please consider installing ImageMagick for things to function correctly.
1. `git clone` the repository to your .config folder
2. Rename `reno` folder to `awesome`
3. Install AwesomeWM (version 4.3 as of right now)
4. (Optional) Read additional installation steps in `extra/README.md`
4. Change your shell, terminal emulator, browser, keybindings and other settings in `desktop.conf`
5. (Optional) Read additional installation steps in `extra/README.md`
6. Reload your awesomewm if you have already loaded it.
## Keybindings and user guide
- press win+s
- read extra/README.md
- enjoy
## Feedback
Your feedback would be highly appreciated. However, please understand that I may not be able to answer all of your issues in a timely manner.
## Roadmap
- [x] Port widgets from original config to AWMTK2

128
desktop.conf

@ -1,87 +1,90 @@
# Global variables
[global]
terminal = "st"
browser = "librewolf"
# Your preferred terminal emulator
terminal = "xterm"
# Your preferred browser (opens the first one available by default)
browser = "xdg-open about:blank"
# Your modkey (Mod4 = Super key (Win key))
modkey = "Mod4"
# Your theme (one of the themes available in ./themes/)
theme = "unity"
shell = "zsh"
# Your shell (currently doesn't do much, preferrably should remain the same)
shell = "bash"
# Keybindings
# Format: <modifier>(+<modifier>+...)+<key> = "<command or :internal.function>"
# "modkey" as modifier will be substituted for modkey variable in [global]
[keys]
modkey+Left = ":root.tag_next"
modkey+Right = ":root.tag_prev"
modkey+j = ":root.client_next"
modkey+k = ":root.client_previous"
modkey+Control+j = ":root.screen_next"
modkey+Control+k = ":root.screen_previous"
modkey+Tab = ":root.client_swap"
modkey+Return = ":root.spawn_terminal"
modkey+Shift+Return = ":root.spawn_browser"
modkey+Shift+y = ":root.toggle_titlebars"
"modkey+Left" = ":root.tag_next"
"modkey+Right" = ":root.tag_prev"
"modkey+j" = ":root.client_next"
"modkey+k" = ":root.client_previous"
"modkey+Control+j" = ":root.screen_next"
"modkey+Control+k" = ":root.screen_previous"
"modkey+Tab" = ":root.client_swap"
"modkey+Return" = ":root.spawn_terminal"
"modkey+Shift+Return" = ":root.spawn_browser"
"modkey+Shift+y" = ":root.toggle_titlebars"
# Client keys only work if a focused client exists
modkey+Control+o = ":client.move_to_screen"
modkey+Shift+c = ":client.kill"
modkey+t = ":client.cycle_screen"
modkey+o = ":client.ontop"
modkey+b = ":client.below"
modkey+f = ":client.fullscreen"
modkey+n = ":client.minimize"
modkey+m = ":client.maximize"
modkey+p = ":client.pin"
modkey+y = ":client.toggle_titlebars"
"modkey+Control+o" = ":client.move_to_screen"
"modkey+Shift+c" = ":client.kill"
"modkey+t" = ":client.cycle_screen"
"modkey+o" = ":client.ontop"
"modkey+b" = ":client.below"
"modkey+f" = ":client.fullscreen"
"modkey+n" = ":client.minimize"
"modkey+m" = ":client.maximize"
"modkey+p" = ":client.pin"
"modkey+y" = ":client.toggle_titlebars"
# Widget keys
modkey+r = ":dismal.run"
modkey+s = ":help.show"
modkey+q = ":client.menu"
modkey+x = ":supermenu.open"
"modkey+r" = ":dismal.run"
"modkey+s" = ":help.show"
"modkey+q" = ":client.menu"
"modkey+x" = ":supermenu.open"
Control+XF86AudioRaiseVolume = ":client.volume_up"
Control+XF86AudioLowerVolume = ":client.volume_down"
Control+XF86AudioMute = ":client.volume_mute"
XF86AudioRaiseVolume = ":root.volume_up"
XF86AudioLowerVolume = ":root.volume_down"
XF86AudioMute = ":root.volume_mute"
XF86MonBrightnessUp = ":battery.brightness_up"
XF86MonBrightnessDown = ":battery.brightness_down"
XF86AudioPlay = ":mpc.play"
XF86AudioPrev = ":mpc.prev"
XF86AudioNext = ":mpc.next"
"Control+XF86AudioRaiseVolume" = ":client.volume_up"
"Control+XF86AudioLowerVolume" = ":client.volume_down"
"Control+XF86AudioMute" = ":client.volume_mute"
"XF86AudioRaiseVolume" = ":root.volume_up"
"XF86AudioLowerVolume" = ":root.volume_down"
"XF86AudioMute" = ":root.volume_mute"
"XF86MonBrightnessUp" = ":battery.brightness_up"
"XF86MonBrightnessDown" = ":battery.brightness_down"
"XF86AudioPlay" = ":mpc.play"
"XF86AudioPrev" = ":mpc.prev"
"XF86AudioNext" = ":mpc.next"
# Custom keys
Print = "flameshot gui"
Shift+Print = "flameshot launcher"
"Print" = "flameshot gui"
"Shift+Print" = "flameshot launcher"
# Macro recording/playback keys
KP_Home = ":macro.play_1"
KP_Up = ":macro.play_2"
KP_PageUp = ":macro.play_3"
KP_Left = ":macro.record_1"
KP_Begin = ":macro.record_2"
KP_Right = ":macro.record_3"
KP_Divide = ":macro.play_1"
KP_Multiply = ":macro.play_2"
KP_Add = ":macro.record_1"
KP_Subtract = ":macro.record_2"
KP_Delete = ":macro.loop"
# Tiling
modkey+Shift+j = ":layout.swap_next_client"
modkey+Shift+k = ":layout.swap_prev_client"
modkey+Control+Return = ":client.swap_to_master"
modkey+l = ":layout.increase_master"
modkey+h = ":layout.decrease_master"
modkey+Shift+l = ":layout.increase_master_count"
modkey+Shift+h = ":layout.decrease_master_count"
modkey+Control+l = ":layout.increase_column_count"
modkey+Control+h = ":layout.decrease_column_count"
modkey+[ = ":layout.next_layout"
modkey+] = ":layout.prev_layout"
"modkey+Shift+j" = ":layout.swap_next_client"
"modkey+Shift+k" = ":layout.swap_prev_client"
"modkey+Control+Return" = ":client.swap_to_master"
"modkey+l" = ":layout.increase_master"
"modkey+h" = ":layout.decrease_master"
"modkey+Shift+l" = ":layout.increase_master_count"
"modkey+Shift+h" = ":layout.decrease_master_count"
"modkey+Control+l" = ":layout.increase_column_count"
"modkey+Control+h" = ":layout.decrease_column_count"
"modkey+[" = ":layout.next_layout"
"modkey+]" = ":layout.prev_layout"
# Power manager module
[powerman]
# Bad battery condition warning threshold
# Bad battery condition warning threshold (in %)
battery_quality_min = 33
# Low battery warning threshold
# Low battery warning threshold (in %)
battery_capacity_min = 15
# Process to execute on low battery
on_low_battery = ""
@ -99,3 +102,10 @@ exec = "picom"
[macros]
step = 10
# Autostart system
[autostart]
# Enable minimization of apps with "Hidden" in their .desktop file
minimize_enable = true
# How long to target apps that should be minimized
minimize_timeout = 120

4
extra/README.md

@ -11,11 +11,11 @@
- install mpc
- quick links
- create `links` directory in the config directory
- add .desktop files with of apps you want to show on the quick launcher
- add .desktop files of apps you want to have on the quick launcher
- anti-aliased window corners (unity theme only)
- install picom
- drop the picom.conf file into your .config folder
- enable picom to run on wm boot (read autostart)
- autostart
- create "autostart" directory in .config folder
- drop .desktop files (files in /usr/share/applications) of apps you want torun on wm boot
- drop .desktop files (files in /usr/share/applications) of apps you want to run on wm boot

12
libs/awmtk2.lua

@ -1,10 +1,10 @@
-- this file is part of reno desktop.
-- This file is part of Reno desktop.
--
-- reno desktop is free software: you can redistribute it and/or modify it under the terms of the gnu general public license as published by the free software foundation, either version 3 of the license, or (at your option) any later version.
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- reno desktop is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. see the gnu general public license for more details.
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- you should have received a copy of the gnu general public license along with reno desktop. if not, see <https://www.gnu.org/licenses/>.
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- renotk (formerly awmtk2) - template/granular styling library for reno
local wibox = require("wibox")
local gears = require("gears")
@ -143,7 +143,7 @@ awmtk.proto_style = {
-- }
-- { callbacks
-- a tiny bit more complex thing to account for more extensibility
-- the stub functions do nothing - you should implement functionality inside theme
-- the stub functions do nothing - you should implement functionality inside the theme
onpress = function() end,
onrelease = function() end,
-- }
@ -463,7 +463,7 @@ awmtk.proto_templates = {
end,
wibar = function(style)
-- just you regular old wibar, but as a style template.
-- just your regular old wibar, but as a style template.
return function(layout,options)
local margins = style.wibar.margins
if (style.wibar.left or

8
libs/digger.lua

@ -1,3 +1,11 @@
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- 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)

7
libs/imagemagick_blur.lua

@ -1,3 +1,10 @@
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- If possible, try to blur the image and return its path via callback. Relies on ImageMagick
local awful = require("awful")
return function(image_path,callback)

29
libs/parser_test.lua

@ -30,23 +30,22 @@ shell = "zsh"
# Format: <modifier>(+<modifier>+...)+<key> = "<command or :internal.function>"
# "modkey" as modifier will be substituted for modkey variable in [global]
[keys]
modkey+Up = ":root.client_next"
modkey+Down = ":root.client_previous"
modkey+Control+Up = ":root.screen_next"
modkey+Control+Down = ":root.screen_previous"
modkey+Tab = ":root.client_swap"
modkey+Return = ":root.spawn_terminal"
modkey+Shift+Return = ":root.spawn_browser"
"modkey+Up" = ":root.client_next"
"modkey+Down" = ":root.client_previous"
"modkey+Control+Up" = ":root.screen_next"
"modkey+Control+Down" = ":root.screen_previous"
"modkey+Tab" = ":root.client_swap"
"modkey+Return" = ":root.spawn_terminal"
"modkey+Shift+Return" = ":root.spawn_browser"
# Client keys only work if a focused client exists
modkey+Shift+c = ":client.kill"
modkey+t = ":client.cycle_screen"
modkey+o = ":client.ontop"
modkey+b = ":client.below"
modkey+f = ":client.fullscreen"
modkey+n = ":client.minimize"
modkey+m = ":client.maximize"
"modkey+Shift+c" = ":client.kill"
"modkey+t" = ":client.cycle_screen"
"modkey+o" = ":client.ontop"
"modkey+b" = ":client.below"
"modkey+f" = ":client.fullscreen"
"modkey+n" = ":client.minimize"
"modkey+m" = ":client.maximize"
]]
for k,v in pairs(parsers.conf(data)) do
print("Block: ["..k.."]")

98
libs/parsers.lua

@ -10,7 +10,7 @@
local parsers = {}
local function split_strings(text)
-- probably the cleanest function to split by strings i've written
-- probably the cleanest function to split by strings i've written to date
local split = {}
while text:find("\"") do
local strstart = text:find("\"")
@ -86,48 +86,74 @@ parsers.yaml_pseudo = function(cfgtext)
return struct
end
local function quotestrip(txt)
if (txt:sub(1,1):match("['\"]"))
and (txt:sub(-1,-1) == txt:sub(1,1)) then
return txt:sub(2,-2)
else
return txt
end
end
parsers.conf = function(cfgtext)
-- Conf style parser (not exactly TOML)
cfgtext = cfgtext:gsub("#[^\n]*","")
local split_by_strings,err = split_strings(cfgtext)
if not split_by_strings then
error(err)
if not split_by_strings then error(err) end
local full_split = {{}}
local current_line = full_split[1]
-- tokenizer
for _,v in pairs(split_by_strings) do
v = v:match("^[ \t]*(.*)[ \t]*$")
if (not (v == "")) then
if not v:match("^\".*\"$") then
v:gsub("[^ \t]+",function(text)
while text:match("\n") do
local before,after = text:match("([^\n]*)\n(.*)")
if before ~= "" then
table.insert(current_line,before)
end
if #current_line > 0 then
table.insert(full_split,{})
current_line = full_split[#full_split]
end
text = after
end
if text ~= "" then
table.insert(current_line,text)
end
end)
else
table.insert(current_line,v)
end
end
end
table.remove(full_split,#full_split)
local struct = {global = {}}
local block = "global"
local last_string_key = nil
local err
for k,v in pairs(split_by_strings) do
if not v:match("^\".*\"$") then
v:gsub("[^\n]*",function(line)
-- Nothing
if line:match("^%s*$") then
return
end
-- Namespace block
if line:match("^%s*%[[^%]]-%]%s*$") then
block = line:match("%[([^%]]-)%]")
struct[block] = {}
return
end
-- String/Multiline string assignment
if line:match("^%s*[^=]-%s*=%s*$") then
last_string_key = line:match("^%s*([^=]-)%s*=%s*$")
return
end
-- Number/boolean assignment
local key,value = line:match("^%s*([^=]-)%s*=%s*(.-)%s*$")
-- number
if value:match("^[%d%.]*$") then
value = tonumber(value)
-- bool
elseif (value:lower() == "yes") or (value:lower() == "no") then
value = (value:lower() == "yes")
end
struct[block][key] = value
end)
else
struct[block][last_string_key] = v:sub(2,-2)
-- parser
for _,line in pairs(full_split) do
if line[1] and line[1]:match("^%[[^%]]+%]$") then -- block
block = line[1]:match("^%[([^%]]+)%]$")
struct[block] = {}
elseif #line == 3 then -- assignment
if (line[3]:sub(1,1):match("['\"]")) -- string
and (line[3]:sub(-1,-1) == line[3]:sub(1,1)) then
struct[block][quotestrip(line[1])] = quotestrip(line[3])
elseif line[3]:match("^%d+$") then -- number
struct[block][quotestrip(line[1])] = tonumber(line[3])
elseif (line[3] == "true") or (line[3] == "false") then -- boolean
struct[block][quotestrip(line[1])] = (line[3] == "true")
else
error("Invalid assignment expression: "..line[3])
end
else -- invalid
local textline = ""
for _,v in pairs(line) do
textline = textline..v.." "
end
error("Invalid config expression: "..textline:sub(1,-2))
end
end
return struct

137
libs/xdg_data.lua

@ -0,0 +1,137 @@
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- Asynchronous XDG data aggregator (library)
local menu_utils = require("menubar.utils")
local awful = require("awful")
local gears = require("gears")
local json = require("dkjson")
local lib = {}
function lib.init_xdg_struct()
-- Global xdg data struct
local xdg = {
directory_integrity = {},
directory_listings = {},
apps = {},
categories = {
Other = {
icon = "applications-other",
apps = {}
},
Wine = {
icon = "wine",
apps = {}
}
}
}
return xdg
end
function lib.load_xdg_cache()
-- Load cached applications
local cache_file = io.open(gears.filesystem.get_xdg_cache_home()..".reno_xdg_cache.json","r")
local cache
if cache_file then
cache = json.decode(cache_file:read("*a"))
cache_file:close()
end
return cache
end
function lib.add_categories(xdg, categories)
-- Add missing category entries as defined by awesome
for _,v in pairs(categories) do
xdg.categories[v.app_type] = {
name = v.name,
icon = v.icon_name,
apps = {}
}
end
end
function lib.async_process_dirs(xdg, dirs, cache, on_dir_done)
-- Asynchronous scanning process
for _,v in pairs(dirs) do
xdg.directory_listings[v] = {}
awful.spawn.with_line_callback("find "..tostring(v).." -maxdepth 1 -name *.desktop",{
stdout = function(line)
-- Assume the cache is valid for a listed file
if cache and cache.directory_listings[v][line] then
xdg.directory_listings[v][line] = true
xdg.apps[line] = cache.apps[line]
xdg.categories[cache.apps[line].category].apps[line] = cache.apps[line]
return
end
local data = menu_utils.parse_desktop_file(line)
if data.NoDisplay then
return
end
local appdata = {
name = data.Name,
category = "Other",
exec = data.Exec,
icon = (data.Icon and menu_utils.lookup_icon(data.Icon)),
description = data.Comment
}
-- Match first available cateogry for sorting
for _,vv in pairs(data.Categories or {"Other"}) do
if xdg.categories[vv] then
appdata.category = vv
break
end
-- Oh how do I love those Wine applications and their categories
if vv:match("^Wine") then
appdata.category = "Wine"
break
end
end
-- Open terminal apps in the terminal (duh)
if data.Terminal then
appdata.exec = global.terminal.." -e "..appdata.exec
end
-- Just for you, Wine - special case because you're being a shit
if (appdata.exec and appdata.exec:find("%W?wine ")) then
appdata.category = "Wine"
end
xdg.apps[line] = appdata
xdg.categories[appdata.category].apps[line] = appdata
-- Add the file to the listing of cached ones
xdg.directory_listings[v][line] = true
end,
output_done = function(...) on_dir_done(v,...) end
})
end
end
function lib.generate_meta_patch(xdg)
local patch = {apps = {}}
for k,v in pairs(xdg.apps) do
patch.apps[k] = {}
for kk,vv in pairs(v) do
patch.apps[k][kk] = vv
end
patch.apps[k].name = nil
patch.apps[k].category = nil
patch.apps[k].exec = nil
patch.apps[k].icon = nil
patch.apps[k].description = nil
end
return patch
end
function lib.apply_meta_patch(xdg,patch)
for k,v in pairs(patch.apps) do
if xdg.apps[k] then
for kk,vv in pairs(v) do
xdg.apps[k][kk] = vv
end
end
end
end
return lib

85
modules/autostart.lua

@ -5,11 +5,82 @@
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- XFCE style autostart system
-- XFCE style autostart system with a system to automatically kill children just to fuck over Steam. (now with SMЯT targeting software package!)
local awful = require("awful")
local gears = require("gears")
local gfs = gears.filesystem
local menu_utils = require("menubar.utils")
local hide_ids = {}
local related_ids = {}
local settings = config.autostart
local stop_checking = false
-- I know this is linux specific, blame Steam for creating a triple-forking launcher with no startup id.
-- I love the fact that valve is supportive of linux and thinks it's the future of gaming and all that
-- but you could've just done the due diligence and, yk, maybe research how things work with XDG?
-- P.S. if you know how to make this function work in similar vein on BSD, feel free to contribute
local function is_child_of(pid,related)
related = related or pid
local ppidfile = io.open("/proc/"..tostring(pid).."/status","rb")
if not ppidfile then return false end
local ppid = ppidfile:read("*a"):match("PPid:%s*(%d+)")
ppidfile:close()
if (not ppid) or (ppid == "1") then return false end
if hide_ids[tonumber(ppid)] then
related_ids[related] = tonumber(ppid)
return true
else
return is_child_of(ppid,related)
end
end
-- Play whack-a-mole with the clients that match ids to hide
-- NO MORE MR NICE GUY, until the user EXPLICITLY activates the client,
-- it's being hidden.
local callback = function(c)
if not settings.minimize_enable then return end
if stop_checking then return end
gears.timer.delayed_call(function()
local kill_later = false
if c.pid and hide_ids[c.pid] then
kill_later = true
end
if c.startup_id and hide_ids[c.startup_id] then
kill_later = true
end
if c.pid and is_child_of(c.pid) then
kill_later = true
end
if kill_later then
c.minimized = true
end
end)
end
client.connect_signal("focus",callback)
client.connect_signal("manage",callback)
-- if the client has been mouse pressed we no longer hide it or any of its siblings - user needs the client to be active.
client.connect_signal("request::activate",function(c,reason)
if (reason ~= "mouse_click") and (reason ~= "tasklist") then
return
end
if c.pid then
hide_ids[c.pid] = nil
if related_ids[c.pid] then
hide_ids[related_ids[c.pid]] = nil
end
end
if c.startup_id then
hide_ids[c.startup_id] = nil
end
end)
-- this ain't happy hour - stop hitting everything in sight.
gears.timer {
timeout = settings.minimize_timeout or 30,
autostart = true,
single_shot = true,
callback = function()
stop_checking = true
hide_ids = {}
end
}
local stdir = os.getenv("XDG_RUNTIME_DIR").."/.awesome_startup/"
gfs.make_directories(stdir)
awful.spawn.with_line_callback("find "..gfs.get_xdg_config_home().."autostart/ -name *.desktop",{
@ -17,8 +88,16 @@ awful.spawn.with_line_callback("find "..gfs.get_xdg_config_home().."autostart/ -
local data = menu_utils.parse_desktop_file(line)
if (data.RunHook == "0") or (data.RunHook == nil) then
if not gfs.file_readable(stdir..line:match("[^/]*$")) then
io.open(stdir..line:match("[^/]*$"),"w"):close()
awful.spawn(data.Exec:gsub("%%%w",""))
local npid,nsnid = awful.spawn(data.Exec:gsub("%%%w",""))
io.open(stdir..line:match("[^/]*$"),"w"):write(npid):close()
if data.Hidden then
if npid then
hide_ids[npid] = true
end
if nsnid then
hide_ids[nsnid] = true
end
end
end
end
end

7
modules/macros.lua

@ -1,3 +1,10 @@
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
local awful = require("awful")
local gears = require("gears")
local ask = require("asckey")

2
modules/powermanX.lua

@ -5,7 +5,7 @@
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- Powerman X - second generation of the power management daemon
-- Powerman X - second generation of the power management module
local awful = require("awful")
local sysctl = require("syscontrol")
local naughty = require("naughty")

25
modules/rules_stub.lua

@ -9,13 +9,26 @@ awful.rules.rules = gears.table.join(awful.rules.rules, {
}},
properties = {inhibit_compositor = true},
},
{ rule_any = { class = {
"thunderbird"
}},
properties = {callback = function(c)
{ rule = { name = "notificationtoasts.*" },
properties = {
focusable = false
}
},
{ rule = { fullscreen = true },
properties = {
titlebars_enabled = false,
floating = true,
border_width = 0,
border_color = 0,
size_hints_honor = false,
placement=awful.placement.no_offscreen
},
callback = function(c)
gears.timer.delayed_call(function()
c.minimized = true
if c.valid then
c:geometry(c.screen.geometry)
end
end)
end}
end
}
})

7
modules/tiling.lua

@ -1,3 +1,10 @@
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
local awful = require("awful")
awful.layout.layouts = {

99
modules/xdg_data.lua

@ -6,13 +6,11 @@
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- Asynchronous XDG data aggregator
local start_human = os.time()
local start_computer = os.clock()
local menu_utils = require("menubar.utils")
local menu_gen = require("menubar.menu_gen")
local awful = require("awful")
local gears = require("gears")
local json = require("dkjson")
local lib = require("xdg_data")
menu_utils.wm_name = ""
-- Directories to scan for .desktop files
@ -27,95 +25,18 @@ end)
-- Global xdg data struct
_G.xdg = {
directory_integrity = {},
directory_listings = {},
apps = {},
categories = {
Other = {
icon = "applications-other",
apps = {}
},
Wine = {
icon = "wine",
apps = {}
}
}
}
_G.xdg = lib.init_xdg_struct()
-- Load cached applications
local cache_file = io.open(gears.filesystem.get_xdg_cache_home()..".reno_xdg_cache.json","r")
local cache
if cache_file then
cache = json.decode(cache_file:read("*a"))
cache_file:close()
end
local cache = lib.load_xdg_cache()
-- Add missing category entries as defined by awesome
for _,v in pairs(menu_gen.all_categories) do
xdg.categories[v.app_type] = {
name = v.name,
icon = v.icon_name,
apps = {}
}
end
lib.add_categories(xdg,menu_gen.all_categories)
-- Asynchronous scanning process
for _,v in pairs(desktop_dirs) do
xdg.directory_listings[v] = {}
awful.spawn.with_line_callback("find "..tostring(v).." -maxdepth 1 -name *.desktop",{
stdout = function(line)
-- Assume the cache is valid for a listed file
if cache and cache.directory_listings[v][line] then
xdg.directory_listings[v][line] = true
xdg.apps[line] = cache.apps[line]
xdg.categories[cache.apps[line].category].apps[line] = cache.apps[line]
return
end
local data = menu_utils.parse_desktop_file(line)
if data.NoDisplay then
return
end
local appdata = {
name = data.Name,
category = "Other",
exec = data.Exec,
icon = (data.Icon and menu_utils.lookup_icon(data.Icon)),
description = data.Comment
}
-- Match first available cateogry for sorting
for _,vv in pairs(data.Categories or {"Other"}) do
if xdg.categories[vv] then
appdata.category = vv
break
end
-- Oh how do I love those Wine applications and their categories
if vv:match("^Wine") then
appdata.category = "Wine"
break
end
end
-- Open terminal apps in the terminal (duh)
if data.Terminal then
appdata.exec = global.terminal.." -e "..appdata.exec
end
-- Just for you, Wine - special case because you're being a shit
if (appdata.exec and appdata.exec:find("%W?wine ")) then
appdata.category = "Wine"
end
xdg.apps[line] = appdata
xdg.categories[appdata.category].apps[line] = appdata
-- Add the file to the listing of cached ones
xdg.directory_listings[v][line] = true
end,
output_done = function()
-- Save directory listing hash
desktop_dirs_complete = desktop_dirs_complete + 1
-- Call a global signal
awesome.emit_signal("xdg::dir_finished",v)
end
})
end
lib.async_process_dirs(xdg,desktop_dirs,cache,function(v)
-- Count completed directory
desktop_dirs_complete = desktop_dirs_complete + 1
-- Call a global signal
awesome.emit_signal("xdg::dir_finished",v)
end)
local count = function(t)
local n = 0

2
rc.lua

@ -18,11 +18,11 @@ require("modules.collect_garbage")
require("modules.global")
require("modules.powermanX")
require("modules.base")
require("modules.autostart")
require("modules.rules_stub")
require("modules.compositor")
require("modules.binds")
require("modules.xdg_data")
require("modules.autostart")
require("modules.static_tags")
require("modules.tiling")
require("modules.desktop")

2
themes/reno98/theme.lua

@ -494,7 +494,7 @@ theme.widgets = {
},
-- awesomewm: yo pass me that pango markup
-- pango: you better not make unintuitive cryptic shit
-- awesomewm: *attach foreground setting to drawable container*
-- awesomewm: *attaches foreground text color setting to container*
fg_normal = "#FAFAFA"
}
},

3
themes/unity_mate/theme.lua

@ -636,9 +636,6 @@ theme.widgets = {
return gears.shape.rounded_rect(cr,width,height,0)
end,
margins = 0,
-- WARNING: Change this to true only if you're wiliing to take
-- the visual performance impact from cairo re-rendering the
-- canvas a lot!
transparent = true
},
icon = {

7
widgets/base/layout.lua

@ -1,2 +1,9 @@
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
local awful = require("awful")
return function(args) return awful.widget.layoutbox(args.screen) end

2
widgets/base/systray.lua

@ -21,7 +21,7 @@ return function(args)
if args.vertical then
widget:get_children_by_id("systray")[1]:set_horizontal(false)
end
-- Part of a private API
-- Stolen from the API. Apparently this function is entirely undocumented.
if awesome.systray() == 0 then
widget.visible = false
end

280
widgets/clientmenu/volume.lua

@ -15,6 +15,53 @@ local beautiful = require("beautiful")
local ask = require("asckey")
local test_pactl = os.execute("pactl --version")
G_ClientSinksByPID = G_ClientSinksByPID or {}
G_ClientSinksByName = G_ClientSinksByName or {}
G_SinkVolumeLevels = G_SinkVolumeLevels or {}
G_SinkMediaTypes = G_SinkMediaTypes or {}
local update_client_volumes = function()
awful.spawn.easy_async("pactl -n \"awesome\" list sink-inputs",function(stdout)
local pactl_data = fastyaml(stdout)
local indexed_sinks = {}
local sinks_by_pid = {}
local sinks_by_name = {}
local sink_volume_levels = {}
local sink_media_types = {}
for _,v in pairs(pactl_data) do
local sink_id = tonumber(v:match("Sink Input #(%d+)"))
if sink_id then
if v:match("application.process.id = \"(%d+)\"") then
local pid = tonumber(v:match("application.process.id = \"(%d+)\""))
sinks_by_pid[pid] = sinks_by_pid[pid] or {}
table.insert(sinks_by_pid[pid], sink_id)
indexed_sinks[sink_id] = true
end
if v:match("application.name = \"([^\n]+)\"") then
local name = v:match("application.name = \"([^\n]+)\"")
sinks_by_name[name] = sinks_by_name[name] or {}
if not indexed_sinks[sink_id] then
indexed_sinks[sink_id] = true
table.insert(sinks_by_name[name], sink_id)
end
end
if indexed_sinks[sink_id] then
sink_volume_levels[sink_id] = tonumber(v:match("Volume: .-(%d+)%%"))
sink_media_types[sink_id] = v:match("media.name = \"([^\"]+)\"") or
v:match("media.class = \"([^\"]+)\"")
end
end
end
G_ClientSinksByName = sinks_by_name
G_ClientSinksByPID = sinks_by_pid
G_SinkVolumeLevels = sink_volume_levels
G_SinkMediaTypes = sink_media_types
end)
end
G_ClientSinksUpdateTimer = G_ClientSinksUpdateTimer or gears.timer({
timeout = 0.5,
autostart = true,
callback = update_client_volumes
})
local result = test_pactl
if _VERSION:match("5.1") then
result = (test_pactl == 0)
@ -38,117 +85,180 @@ end
return function(args)
local style = awmtk2.create_style("client_volume",
awmtk2.generic.oneline_widget, args.style,args.vertical)
awmtk2.generic.oneline_widget, args.style)
local templates = awmtk2.create_template_lib("client_volume",awmtk2.templates,args.templates)
local t = awmtk2.build_templates(templates,style,args.vertical)
local t = awmtk2.build_templates(templates,style)
local widget = wibox.widget(t.container({
t.icon({
id = "client_volume_icon",
resize = true,
}),
(args.vertical and {
{
t.icon({
image = get_icon(0);
resize = true
}),
t.textbox({
id = "error"
markup = "No sound/Not available"
}),
widget = wibox.container.rotate,
direction = "east"
}) or t.textbox({
id = "error"
}),
t.slider({
minimum = 0,
maximum = 100,
id = "client_volume",
value = -1
}),
layout = (args.vertical and wibox.layout.fixed.vertical) or
wibox.layout.fixed.horizontal
visible = true,
id = "error",
spacing = style.base.spacing,
layout = wibox.layout.fixed.horizontal
},
{
id = "client_volume_container",
spacing = style.base.spacing,
layout = wibox.layout.fixed.vertical
},
spacing = style.base.spacing,
layout = wibox.layout.fixed.vertical
}))
local client_volume_container = widget:get_children_by_id("client_volume_container")[1]
local errorbox = widget:get_children_by_id("error")[1]
local icon = widget:get_children_by_id("client_volume_icon")[1]
local slider = widget:get_children_by_id("client_volume")[1]
-- Local tracking value to prevent zero volume on start
local touched = false
-- Attach to focus change
client.connect_signal("update_volume",function(c)
awful.spawn.easy_async("pactl list sink-inputs",function(stdout)
local pactl_data = fastyaml(stdout)
local cl
for _,v in pairs(pactl_data) do
if not c then return end
if v:match("application.process.id = \""..tostring(c.pid).."\"") then
cl = v
local id_by_slider_container = {}
local active_sliders = {}
-- Asynchronous promise for a "create_slider" function
local create_slider = function(sink_input_id) end
local remove_slider = function(sink_input_id)
local index_to_remove = nil
for k,v in pairs(client_volume_container.children) do
if id_by_slider_container[v] == sink_input_id then
index_to_remove = k
end
end
if index_to_remove then
active_sliders[sink_input_id] = nil
client_volume_container:remove(index_to_remove)
end
end
-- Callback to update all slider values
local function update_active_sliders()
local checked_sliders = {}
if client.focus and client.focus.name then
for _,v in pairs(G_ClientSinksByName[client.focus.name] or {}) do
checked_sliders[v] = true
if not active_sliders[v] then
create_slider(v)
end
end
if not cl then
slider.visible = false
errorbox.visible = true
errorbox:set_markup("No sound/Not available")
icon:set_image(beautiful["volume-muted-symbolic"])
return
end
if client.focus and client.focus.pid then
for _,v in pairs(G_ClientSinksByPID[client.focus.pid] or {}) do
checked_sliders[v] = true
if not active_sliders[v] then
create_slider(v)
end
end
local volume = tonumber(cl:match("Volume:[^\n]-(%d*)%%"))
slider.visible = true
errorbox.visible = false
icon:set_image(get_icon(volume))
slider.value = volume
touched = true
end)
end)
client.connect_signal("focus",function(c)
touched = false
c:emit_signal("update_volume")
end)
local update_timer = gears.timer({
timeout = 0.5,
autostart = true,
callback = function()
if client.focus then
client.focus:emit_signal("update_volume")
end
for k,_ in pairs(active_sliders) do
if not checked_sliders[k] then
remove_slider(k)
end
end
for sink_input_id,slider in pairs(active_sliders) do
slider.value = G_SinkVolumeLevels[sink_input_id] or -1
end
end
-- Update sliders every 0.5 seconds
local update_sliders = gears.timer({
timeout = 0.5,
autostart = true,
callback = update_active_sliders
})
-- Async lock to prevent callback interference
local volume_lock = false
-- Function to set client volume
local function volume(value)
if volume_lock then return end
volume_lock = true
awful.spawn.easy_async("pactl list sink-inputs",function(stdout)
local pactl_data = fastyaml(stdout)
if not (client.focus and client.focus.pid) then
volume_lock = false
return
local function volume(filter,value)
update_sliders:again()
if type(filter) == "number" then
awful.spawn("pactl set-sink-input-volume "..tostring(filter).." "..tostring(value).."%")
elseif filter then
if filter.name then
for _,v in pairs(G_ClientSinksByName[filter.name] or {}) do
awful.spawn("pactl set-sink-input-volume "..tostring(v).." "..tostring(value).."%")
end
end
for _,v in pairs(pactl_data) do
if v:match("application.process.id = \""..tostring(client.focus.pid).."\"") then
local sink_id = v:match("^%s*Sink Input #(%d+)")
if sink_id then
print(sink_id, value)
awful.spawn("pactl set-sink-input-volume "..tostring(sink_id).." "..tostring(value).."%")
end
if filter.pid then
for _,v in pairs(G_ClientSinksByPID[filter.pid] or {}) do
awful.spawn("pactl set-sink-input-volume "..tostring(v).." "..tostring(value).."%")
end
end
volume_lock = false
end
end
create_slider = function(sink_input_id)
local slider_icon_container = wibox.widget(t.icon({
id = "client_volume_icon",
resize = true,
}))
local slider_icon = slider_icon_container:get_children_by_id("client_volume_icon")[1]
local slider_container = wibox.widget(t.slider({
minimum = 0,
maximum = 100,
id = "client_volume",
value = -1,
}))
local slider = slider_container:get_children_by_id("client_volume")[1]
local slider_touching = false
slider:connect_signal("widget::redraw_needed",function()
if slider_touching then
volume(sink_input_id,slider.value)
end
slider_icon.image = get_icon(slider.value)
end)
active_sliders[sink_input_id] = slider
slider:connect_signal("mouse::enter", function()
slider_touching = true
end)
slider:connect_signal("mouse::leave", function()
slider_touching = false
end)
local new_widget = wibox.widget({
t.textbox({
markup = G_SinkMediaTypes[sink_input_id],
ellipsize = "end",
forced_width = style.slider.width,
forced_height = style.slider.height*(2/3)
}),
{
slider_icon_container,
slider_container,
layout = wibox.layout.fixed.horizontal
},
spacing = style.base.spacing,
layout = wibox.layout.fixed.vertical,
id = tostring(sink_input_id)
})
client_volume_container:add(new_widget)
id_by_slider_container[new_widget] = sink_input_id
end
-- Attach change to slider
slider:connect_signal("widget::redraw_needed",function()
if touched then
volume(slider.value)
update_timer:again()
local function update_slider_list(c)
active_sliders = {}
client_volume_container:reset()
update_sliders:again()
local count = false
if c.name then
for _,v in pairs(G_ClientSinksByName[c.name] or {}) do
create_slider(v)
count = true
end
end
end)
if c.pid then
for _,v in pairs(G_ClientSinksByPID[c.pid] or {}) do
create_slider(v)
count = true
end
end
update_active_sliders()
errorbox.visible = not count
end
-- Attach to focus change
client.connect_signal("focus",update_slider_list)
-- Update
root.keys(gears.table.join(
root.keys(),
ask.k(":client.volume_up", function()
volume("+5")
volume(client.focus,"+5")
end,{description = "increase client volume", group = "client"}),
ask.k(":client.volume_down", function()
volume("-5")
volume(client.focus,"-5")
end,{description = "decrease client volume", group = "client"}),
ask.k(":client.volume_mute", function()
volume(0)
volume(client.focus,0)
end,{description = "mute client", group = "client"})
))
return widget

4
widgets/desktop/battery.lua

@ -15,7 +15,7 @@ local syscontrol = require("syscontrol")
local ask = require("asckey")
local function get_virtual_icon(data)
-- Get an icon from a cumulative total of battery percentages and current charging state
-- Get an icon from average of total battery percentage and current charging state
local count = 0
local cumulative = 0
local name = "battery-"
@ -142,7 +142,7 @@ return function(args)
percentage_map["charge"] = data.online
end
end
-- "Virtual" here means a battery that displays the state of a cumulative total of all attached batteries (as if there are any devices that even have more than 1 battery)
-- "Virtual" here means an abstract icon that represents the average state of all batteries.
local function update_virtual_battery()
local icon = battery_widget:get_children_by_id("virtual_id")[1]
local percentage = battery_widget:get_children_by_id("percentage_id")[1]

17
widgets/desktop/tasklist.lua

@ -60,13 +60,17 @@ return function(args)
return
end
local textbox = self:get_children_by_id("text_role")[1] or {}
-- Apparently the original system for changing bgimage is
-- Apparently the original system for changing
-- the bgimage of a tasklist is
-- 1) broken
-- 2) uses deprecated functions (nice code practices awesomewm)
-- Solution: write my own. I blame material design for all this.
-- (P.S: Not to bullshit you, check it yourself - replicatable
-- by adding theme.tasklist_bg_image_normal or
-- theme.tasklist_bg_image_focus in current beautiful theme.)
-- (P.S: Not to bullshit you, check it yourself:
-- you can replicate this by adding
-- ``theme.tasklist_bg_image_normal``
-- or
-- ``theme.tasklist_bg_image_focus``
-- in the default awesomewm config.)
local onfocus = function()
self.bgimage = style.button.bgimage_focus
self.bg = style.button.bg_focus
@ -105,13 +109,14 @@ return function(args)
c:connect_signal("unfocus",onunfocus)
c:connect_signal("property::urgent",onurgent)
c:connect_signal("property::minimized",onminimize)
if client.focus == c then
if client.focus == c then
onfocus()
else
onunfocus()
end
end,
-- Uncomment this only, and **ONLY** if you actually need it.
-- Uncomment this only, and **ONLY** if you actually need it.
-- (P.S: you don't need it.)
--id = "background_role"
})
return awful.widget.tasklist {

4
widgets/lock/clock.lua

@ -20,14 +20,14 @@ return function(args)
awmtk2.generic.status_widget,args.style,args.vertical)
local templates = awmtk2.create_template_lib("lock_clock",awmtk2.templates,args.templates)
local t = awmtk2.build_templates(templates,style,args.vertical)
-- Don't mind me just stealing default library code
-- Don't mind me just stealing standard library code
local format = args.format or "%a %b %d, %H:%M"
local refresh = args.refresh or 60
local tzid = args.tzid
local timezone = (tzid and TimeZone.new(tzid)) or TimeZone.new_local()
-- Seriously, was it so hard to add a font parameter for textclock?
-- Do you actually expect of nobody to change the font to something like
-- Do you actually expect nobody to change the font to something like
-- idk, 7-segment display? Goddamnit awesome. I trusted you.
local widget = wibox.widget(t.container(t.textbox({
id = "clocktext"

2
widgets/rootmenu.lua

@ -77,7 +77,7 @@ return function(args)
end
end
end)
-- If any of the menus emits cascade::kill, close the menu
-- If any of the menus emit cascade::kill, close the menu
for _,v in pairs(menus) do
v:connect_signal("cascade::kill",function()
root_menu.visible = false

51
widgets/rootmenu/controls.lua

@ -8,11 +8,62 @@
-- Simple global context menu controls
local beautiful = require("beautiful")
local menugen = require("context_menu")
local xdglib = require("xdg_data")
local menu_gen = require("menubar.menu_gen")
local gears = require("gears")
local json = require("dkjson")
local function regenerate_xdg()
local desktop_dirs = {os.getenv("HOME").."/Desktop"}
local desktop_dirs_complete = 0
local _ = ((table.concat(gears.filesystem.get_xdg_data_dirs(),":") or
"/usr/share:/usr/local/share")..":"..os.getenv("HOME").."/.local/share")
:gsub("[^:]*",function(path)
if gears.filesystem.dir_readable(path.."/applications") then
table.insert(desktop_dirs,path.."/applications")
end
end)
local function count(t)
local c = 0
for _,_ in pairs(t) do
c = c +1
end
return c
end
require("naughty").notify({title="Regenerating XDG cache..."})
-- Generate a patch containing metadata
local meta = xdglib.generate_meta_patch(_G.xdg)
-- Initialize structure
_G.xdg = xdglib.init_xdg_struct()
-- Add missing category entries
xdglib.add_categories(xdg,menu_gen.all_categories)
-- Asynchronous process scanning
xdglib.async_process_dirs(xdg,desktop_dirs,nil,function()
desktop_dirs_complete = desktop_dirs_complete + 1
if desktop_dirs_complete == #desktop_dirs then
for k,v in pairs(xdg.categories) do
if count(v.apps) == 0 then
xdg.categories[k] = nil
end
end
xdglib.apply_meta_patch(xdg,meta)
require("naughty").notify({
text="Done! Restart WM to reload menus."
})
io.open(gears.filesystem.get_xdg_cache_home()..
".reno_xdg_cache.json","w"
):write(json.encode(xdg)):close()
end
end)
end
return function(args)
local widget = menugen({
items = {
{"Awesome", {
{"reload cache",regenerate_xdg},
{"open config dir", "xdg-open "..root_path},
{"open docs", "xdg-open https://awesomewm.org/doc/api/"},
{"restart", function() awesome.restart() end},

59
widgets/supermenu/applications-tab.lua

@ -1,8 +1,17 @@
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
local awful = require("awful")
local gears = require("gears")
local awmtk2 = require("awmtk2")
local wibox = require("wibox")
local beautiful = require("beautiful")
local pager_gen = require("pager")
local asckey_context = require("asckey").context
local icon = beautiful["applications-tab-symbolic"]
@ -161,6 +170,37 @@ return function(args)
sorting_method = "recent"
end)
local appgrid = widget:get_children_by_id("appgrid")[1]
local pager = pager_gen(appgrid,{},args.rows*args.columns)
local pager_context = asckey_context(gears.table.join(
awful.key({},"Next",function()
pager:next()
end),
awful.key({},"Prior",function()
pager:prev()
end),
awful.key({},"Return",function()
searchbox:emit_signal("button::press")
end),
awful.key({}," ",function()
searchbox:emit_signal("button::press")
end)
))
supermenu:connect_signal("property::visible",function()
if (not pager_context.active) and (supermenu.visible) then
pager_context:activate()
end
if (pager_context.active) and (not supermenu.visible) then
pager_context:deactivate()
end
end)
local root = widget:get_children_by_id("root_ratio")[1]
root:connect_signal("button::press",function(_,_,_,button)
if button == 4 then
pager:prev()
elseif button == 5 then
pager:next()
end
end)
local icon_cache = gears.cache(function(icon,title,exec)
local appicon = wibox.widget({
t.icon({
@ -177,7 +217,7 @@ return function(args)
appicon:connect_signal("button::press",function(_,_,_,button)
if button == 1 then
supermenu.visible = false
awful.spawn(exec)
awful.spawn(exec:gsub("%%%w",""))
end
end)
return appicon
@ -190,19 +230,22 @@ return function(args)
end
end)
searchbox:connect_signal("button::press",function()
if prompt_open then return end
prompt_open = true
awful.prompt.run {
textbox = searchtext,
exe_callback = function(command)
local results = xdg_search(command, args.rows*args.columns, sorting_method)
appgrid:reset()
local results = xdg_search(command, math.huge, sorting_method)
pager.list = {}
pager.index = 0
for _,v in pairs(results) do
appgrid:add(icon_cache:get(
table.insert(pager.list,icon_cache:get(
v[2].icon or beautiful.icon_default,
v[2].name,
v[2].exec
))
end
pager:update()
end,
done_callback = function()
prompt_open = false
@ -211,14 +254,10 @@ return function(args)
}
end)
awesome.connect_signal("xdg::all_finished",function()
local count = 0
for _,v in pairs(xdg.apps) do
count = count + 1
appgrid:add(icon_cache:get(v.icon or beautiful.icon_default,v.name,v.exec))
if count >= args.columns*args.rows then
break
end
table.insert(pager.list,icon_cache:get(v.icon or beautiful.icon_default,v.name,v.exec))
end
pager:update()
end)
return widget,icon
end
Loading…
Cancel
Save