diff --git a/.gitignore b/.gitignore index ea05d8b..67ae38c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /links /libs/pam /libs/pam.so +/doc diff --git a/.ldoc.lua b/.ldoc.lua new file mode 100644 index 0000000..3edaddd --- /dev/null +++ b/.ldoc.lua @@ -0,0 +1,4 @@ +file = {"libs","modules","widgets"} +format = "markdown" +title = "Reno Desktop documentation" +description = "Reno Desktop is an AwesomeWM config that harnesses the power of AwesomeWM to bring the essential functionality of a desktop environment." diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..ba2c34a --- /dev/null +++ b/.luarc.json @@ -0,0 +1,31 @@ +{ + "diagnostics": { + "enable": true, + "globals": [ + "awesome", + "button", + "dbus", + "client", + "mouse", + "screen", + "root" + ] + }, + "runtime": { + "version": "Lua 5.3", + "path": [ + "/usr/share/awesome/lib/?/?.lua" + ], + "pathStrict": true + }, + "workspace": { + "library": [ + "runtime/lua", + "/usr/share/awesome/lib" + ], + "checkThirdParty": false, + "maxPreload": 2000, + "preloadFileSize": 1000 + }, + "telemetry.enable": true +} diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..a6cce41 --- /dev/null +++ b/Rakefile @@ -0,0 +1,49 @@ +task default: [:install] +ConfigPath = (ENV["XDG_DATA_HOME"] or ENV["HOME"]+'/.config') + +desc "Copy files to .config" +file "copy-config" => ["rc.lua"] do + sh "mkdir -p #{ConfigPath}/awesome" + ["libs","modules","themes","widgets","rc.lua","desktop.conf"].each { |x| + cp_r "./#{x}" "#{ConfigPath}/awesome" + } +end + +desc "Compile and install luapam" +file "build-luapam" => "#{ConfigPath}/libs/pam.so" do + sh "sh ./extra/install_luapam.sh" +end + +desc "Install config" +task install: ["copy-config","build-luapam"] + +desc "Build documentation" +task :doc do + sh "ldoc ./.ldoc.lua" +end + +desc "Install extras" +task "install-extra" do + if Process.euid != 0 + raise Exception, "You need to be root to install extras" + end + cp "./extra/udev/backlight.rules" "/etc/udev/rules.d" + mkdir "#{ConfigPath}/autostart" + begin + cp "/usr/share/applications/picom.desktop" "#{ConfigPath}/autostart/" + rescue + puts "picom not installed - ignoring" + else + cp "./extra/picom.conf" "#{ConfigPath}" + end + puts "Done! Reload awesome to complete installation" +end + +desc "Uninstall from .config" +task :clean do + rm_rf "#{ConfigPath}/awesome" +end + +desc "Wipe configuration and reinstall from scratch" +task reinstall: [:clean,:install] + diff --git a/desktop.conf b/desktop.conf index 8ad24b8..34de1e5 100644 --- a/desktop.conf +++ b/desktop.conf @@ -17,6 +17,7 @@ modkey+Control+Down = ":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+Shift+c = ":client.kill" @@ -40,6 +41,7 @@ XF86MonBrightnessDown = ":battery.brightness_down" XF86AudioPlay = ":mpc.play" XF86AudioPrev = ":mpc.prev" XF86AudioNext = ":mpc.next" + # Custom keys Print = "flameshot gui" Shift+Print = "flameshot launcher" diff --git a/extra/picom.conf b/extra/picom.conf index 00c1468..208d85e 100644 --- a/extra/picom.conf +++ b/extra/picom.conf @@ -1,6 +1,5 @@ backend = "xrender"; vsync = true; - # Shadow shadow = true; # Enabled client-side shadows on windows. shadow-radius = 12; # The blur radius for shadows. (default 12) @@ -31,7 +30,8 @@ shadow-exclude = [ # This list includes all the affected apps I found in my testing. The "! name~=''" part excludes shadows on any "Unknown" windows, this prevents a visual glitch with the XFWM alt tab switcher. # Fading -fading = true# Fade windows during opacity changes. +fading = true; +# Fade windows during opacity changes. fade-delta = 4; # The time between steps in a fade in milliseconds. (default 10). fade-in-step = 0.03; # Opacity change between steps while fading in. (default 0.028). fade-out-step = 0.03; # Opacity change between steps while fading out. (default 0.03). diff --git a/libs/awmtk2.lua b/libs/awmtk2.lua index 920b729..d524cdf 100644 --- a/libs/awmtk2.lua +++ b/libs/awmtk2.lua @@ -19,7 +19,6 @@ local awmtk = {} awmtk.create_delta = function(name,instance_delta,class_delta,parent_delta) -- to save memory, we create proxies for lower layers called "deltas" -- this function creates that proxy layer using metatables - -- fun story - i used instance_delta instead of {} at first. -- the results were horrifying and confusing. return setmetatable({},{ @@ -28,7 +27,7 @@ awmtk.create_delta = function(name,instance_delta,class_delta,parent_delta) if rawget(instance_delta,k) then return rawget(instance_delta,k) -- class-wide overrides are second in priority - elseif type(class_delta[name]) == "table" + elseif type(class_delta[name]) == "table" and rawget(class_delta[name],k) then return rawget(class_delta[name],k) -- parent is fallback @@ -44,7 +43,7 @@ awmtk.create_style = function(name,parent,overrides) local new_style = {} local odelta = (overrides and overrides[name]) or {} local cdelta = beautiful.widgets[name] or {} - for name,parent_class in pairs(parent) do + for name,parent_class in pairs(parent) do new_style[name] = awmtk.create_delta( name, odelta, @@ -53,7 +52,7 @@ awmtk.create_style = function(name,parent,overrides) ) end return new_style -end +end awmtk.create_template_lib = function(name,parent,overrides) -- same thing but beautiful.templates @@ -85,9 +84,9 @@ awmtk.mask_object_call = function(obj,call) end awmtk.wrap_hooks = function(w,callbacks) - -- attach hooks to function - local mcall = getmetatable(w).__call - return awmtk.mask_object_call(w,function(...) + -- attach hooks to function + local mcall = (getmetatable(w) and getmetatable(w).__call) or w + local call_wrapper = function(...) if callbacks and callbacks.on_create_pre then callbacks.on_create_pre(...) end @@ -96,8 +95,12 @@ awmtk.wrap_hooks = function(w,callbacks) callbacks.on_create(widget,...) end if callbacks and callbacks.on_ready then + callbacks._on_ready_called = false local func = function() - callbacks.on_ready(widget) + if not callbacks._on_ready_called then + callbacks.on_ready(widget) + callbacks._on_ready_called = true + end end widget:connect_signal("widget::layout_changed",func) widget:connect_signal("widget::layout_changed",function() @@ -105,7 +108,9 @@ awmtk.wrap_hooks = function(w,callbacks) end) end return widget - end) + end + return (getmetatable(w) and awmtk.mask_object_call(w,call_wrapper)) or + call_wrapper end awmtk.merge = gears.table.join @@ -245,7 +250,7 @@ awmtk.proto_templates = { shape = style.button.shape, shape_border_color = style.button.shape_border_color, shape_border_width = style.button.shape_border_width, - widget = wibox.container.background + widget = awmtk.wrap_hooks(wibox.container.background,options) },options or {}) end end, @@ -255,7 +260,7 @@ awmtk.proto_templates = { return function(options) return awmtk.merge({ font = style.textbox.font, - widget = wibox.widget.textbox, + widget = awmtk.wrap_hooks(wibox.widget.textbox,options) },options or {}) end end, @@ -264,7 +269,7 @@ awmtk.proto_templates = { -- wow, i guess? return function(options) return awmtk.merge({ - widget = wibox.widget.separator, + widget = awmtk.wrap_hooks(wibox.widget.separator,options), orientation = "horizontal", thickness = style.separator.thickness, color = style.separator.color, @@ -272,12 +277,12 @@ awmtk.proto_templates = { },options or {}) end end, - + vseparator = function(style) -- i'm running out of comments return function(options) return awmtk.merge({ - widget = wibox.widget.separator, + widget = awmtk.wrap_hooks(wibox.widget.separator,options), orientation = "vertical", thickness = style.separator.thickness, color = style.separator.color, @@ -303,9 +308,9 @@ awmtk.proto_templates = { strategy = "exact", height = options.icon_size or style.article.icon_size, - width = options.icon_size or + width = options.icon_size or style.article.icon_size, - widget = wibox.container.constraint + widget = wibox.container.constraint }, widget = wibox.container.place, valign = "center", @@ -332,7 +337,10 @@ awmtk.proto_templates = { layout = wibox.layout.flex.vertical }, spacing = style.article.spacing, - layout = wibox.layout.fixed.horizontal, + layout = awmtk.wrap_hooks( + wibox.layout.fixed.horizontal, + options + ) }, options or {}) end end, @@ -346,11 +354,14 @@ awmtk.proto_templates = { strategy = "exact", height = options.height or style.center.height, - width = options.width or + width = options.width or style.center.width, - widget = wibox.container.constraint + widget = wibox.container.constraint }, - widget = wibox.container.place, + widget = awmtk.wrap_hooks( + wibox.container.place, + options + ), valign = "center", halign = "center" },options or {}) @@ -365,7 +376,7 @@ awmtk.proto_templates = { widget = { widget, margins = style.popup.margins, - layout = wibox.container.margin + layout = awmtk.wrap_hooks(wibox.container.margin,options) }, bgimage = style.popup.bgimage_normal, shape = style.popup.shape, @@ -384,16 +395,16 @@ awmtk.proto_templates = { -- bugs i manage to uncover by some sort of miraculous accident. -- this one fixes a race condition in margins+(left/right/bottom/top) configuration scenario local margins = style.titlebar.margins - if (style.titlebar.left or - style.titlebar.right or - style.titlebar.bottom or + if (style.titlebar.left or + style.titlebar.right or + style.titlebar.bottom or style.titlebar.top) then margins = nil end return awmtk.merge({ layout, margins = margins, - layout = wibox.container.margin, + layout = awmtk.wrap_hooks(wibox.container.margin,options), left = style.titlebar.left, right = style.titlebar.right, bottom = style.titlebar.bottom, @@ -406,16 +417,16 @@ awmtk.proto_templates = { -- just you regular old wibar, but as a style template. return function(layout,options) local margins = style.wibar.margins - if (style.wibar.left or - style.wibar.right or - style.wibar.bottom or + if (style.wibar.left or + style.wibar.right or + style.wibar.bottom or style.wibar.top) then margins = nil end return awmtk.merge({ layout, margins = margins, - layout = wibox.container.margin, + layout = awmtk.wrap_hooks(wibox.container.margin,options), left = style.wibar.left, right = style.wibar.right, bottom = style.wibar.bottom, @@ -442,7 +453,7 @@ awmtk.proto_templates = { bar_border_color = style.slider.bar_border_color, forced_width = style.slider.width, forced_height = style.slider.height, - widget = wibox.widget.slider + widget = awmtk.wrap_hooks(wibox.widget.slider,args) },args or {}) end end, @@ -450,13 +461,16 @@ awmtk.proto_templates = { checkbox = function(style) return function(args) return awmtk.merge({ - color = style.checkbox.bg_focus, - padding = 2, + color = style.checkbox.color or style.checkbox.bg_normal, + paddings = style.checkbox.paddings, shape = style.checkbox.shape, - border_width = style.checkbox.shape_border_width, - bg = style.checkbox.shape_border_color, - widget = wibox.widget.checkbox - },args or {}) + border_width = style.checkbox.border_width, + border_color = style.checkbox.border_color or style.checkbox.bg_normal, + bg = style.checkbox.bg or style.checkbox.bg_focus, + check_color = style.checkbox.check_color or style.checkbox.bg_normal, + check_shape = style.checkbox.check_shape, + widget = awmtk.wrap_hooks(wibox.widget.checkbox,args) + },args) end end } diff --git a/modules/binds.lua b/modules/binds.lua index 3221a35..22b3c46 100644 --- a/modules/binds.lua +++ b/modules/binds.lua @@ -14,6 +14,7 @@ global.modkey = global.modkey or "Mod4" ask.set_keymap(config.keys) local custom_keys = ask.custom_binds() local k = ask.k +local titlebar_states = {} local keys = gears.table.join( k(':root.client_next', @@ -54,6 +55,11 @@ local keys = gears.table.join( awful.spawn(global.browser) end, {description = "open browser", group = "launcher"}), + k(":root.toggle_titlebars", + function (c) + awesome.emit_signal("titlebar::toggle") + end , + {description = "(un)hide all titlebars", group = "client"}), table.unpack(custom_keys)) root.keys(keys) @@ -109,14 +115,9 @@ local clientkeys = gears.table.join( {description = "(un)pin", group = "client"}), k(":client.toggle_titlebars", function (c) - if (not c.titlebar_top.visible) then - c:emit_signal("titlebar::unhide") - else - c:emit_signal("titlebar::hide") - end + c:emit_signal("titlebar::toggle") end , {description = "(un)hide titlebars", group = "client"})) - awful.rules.rules[1].properties.keys = clientkeys local clientbuttons = gears.table.join( diff --git a/modules/desktop.lua b/modules/desktop.lua index b4dc53d..a2816be 100644 --- a/modules/desktop.lua +++ b/modules/desktop.lua @@ -116,15 +116,47 @@ table.insert(awful.rules.rules, } ) +local window_shape_hide = function(cr, width, height) + return gears.shape.partially_rounded_rect(cr,width,height, + false,false,false,false,0) +end + +local window_shape = beautiful.window_shape or function(cr, width, height) + return gears.shape.partially_rounded_rect(cr,width,height, + true,true,false,false,beautiful.window_rounding) +end + client.connect_signal("manage", function(c) - local shape = beautiful.window_shape or function(cr, width, height) - return gears.shape.partially_rounded_rect(cr,width,height, - true,true,false,false,beautiful.window_rounding) - end - c.shape = shape + c.shape = window_shape end) -client.connect_signal("request::titlebars",function(c) +local titlebars_on = true +awesome.connect_signal("titlebar::toggle",function() + titlebars_on = not titlebars_on + for _,c in ipairs(client.get()) do + if titlebars_on then + for _, pos in ipairs({"top","bottom","left","right"}) do + awful.titlebar.show(c,pos) + end + c.shape = window_shape + c:emit_signal("titlebar::perform_action",function(titlebar) + titlebar.widget.visible = true + end) + else + for _, pos in ipairs({"top","bottom","left","right"}) do + awful.titlebar.hide(c,pos) + end + c.shape = window_shape_hide + c:emit_signal("titlebar::perform_action",function(titlebar) + titlebar.widget.visible = false + end) + end + end +end) + +-- Second manage call to create hidden titlebars +client.connect_signal("manage",function(c) + -- Drag and resize buttons local buttons = gears.table.join( awful.button({}, 1, function() c:emit_signal("request::activate","titlebar",{raise=true}) @@ -135,8 +167,10 @@ client.connect_signal("request::titlebars",function(c) awful.mouse.client.resize(c) end) ) + -- Building the titlebars for k,v in pairs({"titlebar_top","titlebar_bottom","titlebar_left","titlebar_right"}) do - local contents = { widget = wibox.container.background } + -- Build content of the titlebar + local contents = { widget = wibox.widget.textbox, text = "" } if titlebar_config[v] then contents = builder(titlebar_config[v],{ client = c, @@ -145,6 +179,7 @@ client.connect_signal("request::titlebars",function(c) buttons = buttons }) end + -- Create the base local titlebar = awful.titlebar(c,{ size = style[v].size or 0, position = v:gsub("titlebar_",""), @@ -156,8 +191,14 @@ client.connect_signal("request::titlebars",function(c) fg_focus = style[v].fg_focus, font = style[v].font }) - c[v] = titlebar:setup(t.titlebar(contents)) + -- Compile and build titlebar + titlebar:setup(t.titlebar({ + contents, + widget = wibox.container.background + })) + -- Since new clients will be placed without titlebars, we need to apply placement rules again awful.rules.rules[1].properties.placement(c) + -- Callbacks for focus/unfocus of titlebars if style[v].onfocus then c:connect_signal("focus",function() style[v].onfocus(titlebar) @@ -168,12 +209,32 @@ client.connect_signal("request::titlebars",function(c) style[v].onunfocus(titlebar) end) end - c:connect_signal("titlebar::hide",function(c) - c[v].visible = false + -- Activate focus callback if our client is focused + if (c == client.focus) and (style[v].onfocus) then + style[v].onfocus(titlebar) + end + -- Add a titlebar toggle signal + c:connect_signal("titlebar::toggle",function(c) + titlebar.widget.visible = not titlebar.widget.visible + if titlebar.widget.visible then + awful.titlebar.show(c,v:gsub("titlebar_","")) + c.shape = window_shape + else + awful.titlebar.hide(c,v:gsub("titlebar_","")) + c.shape = window_shape_hide + end end) - c:connect_signal("titlebar::unhide",function(c) - c[v].visible = true + c:connect_signal("titlebar::perform_action",function(c,f) + f(titlebar) end) + -- Add rules for hiding titlebars on creation + if (not titlebars_on) or + (c.titlebars_enabled == false) or + (c.requests_no_titlebar == true) then + titlebar.widget.visible = false + c.shape = window_shape_hide + awful.titlebar.hide(c,v:gsub("titlebar_","")) + end end end) end --}}} diff --git a/themes/reno98/theme.lua b/themes/reno98/theme.lua index 3b0513d..74e0520 100644 --- a/themes/reno98/theme.lua +++ b/themes/reno98/theme.lua @@ -374,6 +374,7 @@ theme.widgets = { end, }, titlebar = { + hidden_size = 2, bgimage_normal = theme.bgimage_outset, --margins = 5, left = 4, diff --git a/themes/unity/WARNING.txt b/themes/unity/WARNING.txt index 5a79fcf..dd1c576 100644 --- a/themes/unity/WARNING.txt +++ b/themes/unity/WARNING.txt @@ -1,2 +1,3 @@ A compositor (like compton) is ***required*** for this theme to work as intended. -This is in part due to the fact that it makes the top bar look less bland, and in part due to the fact that your titlebar corners will look weird otherwise. +This is in part due to the fact that it makes the top bar look less bland, and in part due to the fact that your titlebar corners will look weird otherwise (the corners won't be properly cut). +You may, of course, dismiss using a compositor, but don't tell me about not exactly round corners being a "bug" in this theme afterwards - it's the best you can get with Awesome. diff --git a/themes/unity/config/root_menu_test.json b/themes/unity/config/root_menu_test.json new file mode 100644 index 0000000..61e9d2f --- /dev/null +++ b/themes/unity/config/root_menu_test.json @@ -0,0 +1,32 @@ +{ + "list": [ + { + "list": [ + {"widget": "widgets.base.popuptitle", + "options":{ + "title":"Reno Unity" + } + }, + {"widget": "widgets.rootcontrols"}, + {"widget": "widgets.xdgmenu", + "options": { + "exclude_category": [ + "Other" + ] + } + } + ], + "vertical": true + }, + { + "list":[ + {"widget": "widgets.base.tagswitcher", + "screen":true + }, + {"widget": "widgets.rootbuttons"} + ], + "vertical":true + } + ], + "vertical":false +} diff --git a/themes/unity/config/wibar_top.json b/themes/unity/config/wibar_top.json index d1c6936..3dbed26 100644 --- a/themes/unity/config/wibar_top.json +++ b/themes/unity/config/wibar_top.json @@ -7,6 +7,7 @@ ], "right": [ + { "widget":"widgets.volume" }, { "widget": "widgets.notifications", "screen": true }, diff --git a/themes/unity/icons/reno.png b/themes/unity/icons/reno.png new file mode 100644 index 0000000..a5a3fe7 Binary files /dev/null and b/themes/unity/icons/reno.png differ diff --git a/themes/unity/icons/volume-high-symbolic.png b/themes/unity/icons/volume-high-symbolic.png new file mode 100644 index 0000000..c4638c2 Binary files /dev/null and b/themes/unity/icons/volume-high-symbolic.png differ diff --git a/themes/unity/icons/volume-low-symbolic.png b/themes/unity/icons/volume-low-symbolic.png new file mode 100644 index 0000000..312a08f Binary files /dev/null and b/themes/unity/icons/volume-low-symbolic.png differ diff --git a/themes/unity/icons/volume-medium-symbolic.png b/themes/unity/icons/volume-medium-symbolic.png new file mode 100644 index 0000000..e3e75b4 Binary files /dev/null and b/themes/unity/icons/volume-medium-symbolic.png differ diff --git a/themes/unity/icons/volume-muted-symbolic.png b/themes/unity/icons/volume-muted-symbolic.png new file mode 100644 index 0000000..727b87c Binary files /dev/null and b/themes/unity/icons/volume-muted-symbolic.png differ diff --git a/themes/unity/icons/volume.png b/themes/unity/icons/volume.png new file mode 100644 index 0000000..31cb3f6 Binary files /dev/null and b/themes/unity/icons/volume.png differ diff --git a/themes/unity/theme.lua b/themes/unity/theme.lua index bcf9cc2..07cc0a6 100644 --- a/themes/unity/theme.lua +++ b/themes/unity/theme.lua @@ -12,8 +12,6 @@ local theme_assets = require("beautiful.theme_assets") local xresources = require("beautiful.xresources") local dpi = xresources.apply_dpi local gears = require("gears") - -local gfs = require("gears.filesystem") local themes_path = root_path.."/themes/" local theme = {} @@ -22,8 +20,8 @@ theme.font = "Ubuntu 8" theme.bg_normal = "#19191D" theme.bg_focus = "#3E3E3E" -theme.bg_urgent = "#2E2E2E" -theme.bg_minimize = "#2E2E2E" +theme.bg_urgent = "#2E2E2E" +theme.bg_minimize = "#2E2E2E" theme.bg_highlight = "#45433D" theme.bg_systray = theme.bg_normal @@ -47,23 +45,23 @@ theme.button_bg_focus = { type = "radial", from = {bsize/2,-0.5*bsize,bsize/10}, to = {bsize/2,-0.5*bsize,bsize*2}, - stops = { + stops = { { 0 , "#FFFFFFBB"}, { 0.45, "#DF744E99"}, { 0.55, "#DF744E99"}, { 1, "#FFFFFF44"} - } + } } theme.button_bg_normal = { type = "radial", from = {bsize/2,-0.5*bsize,bsize/10}, to = {bsize/2,-0.2*bsize,bsize*1.5}, - stops = { + stops = { { 0 , "#FFFFFFFF"}, { 0.5, "#33333333"}, { 1, "#FFFFFF22"} - } + } } theme.button_shape = function(cr,width,height) @@ -103,10 +101,10 @@ theme.bar_border_color = { type = "radial", from = {bsize/2,bsize/(-3),bsize/8}, to = {bsize/2,bsize/(-5),bsize*1}, - stops = { + stops = { { 0 , "#FFFFFF66"}, { 1, "#43434366"}, - } + } } theme.titlebar_bg_focus = theme.bar_bg_focus @@ -214,6 +212,12 @@ theme["mpc-next-symbolic"] = themes_path.."unity/icons/mpc-next-symbolic.png" theme["action-poweroff-symbolic"] = themes_path.."unity/icons/action-poweroff-symbolic.png" theme["action-lock-screen-symbolic"] = themes_path.."unity/icons/action-lock-screen-symbolic.png" theme["action-suspend-symbolic"] = themes_path.."unity/icons/action-suspend-symbolic.png" +theme["volume-high-symbolic"] = themes_path.."unity/icons/volume-high-symbolic.png" +theme["volume-medium-symbolic"] = themes_path.."unity/icons/volume-medium-symbolic.png" +theme["volume-low-symbolic"] = themes_path.."unity/icons/volume-low-symbolic.png" +theme["volume-muted-symbolic"] = themes_path.."unity/icons/volume-muted-symbolic.png" + + theme.wallpaper = themes_path.."unity/background.png" theme.wallpapers_icon = themes_path.."unity/icons/wallpapers.png" -- Default icon for clients @@ -244,7 +248,11 @@ for k,v in pairs({ "action-lock-screen-symbolic", "action-suspend-symbolic", "wallpapers_icon", - "icon_default"}) do + "icon_default", + "volume-high-symbolic", + "volume-medium-symbolic", + "volume-low-symbolic", + "volume-muted-symbolic"}) do if theme[v] and gears.filesystem.file_readable(theme[v]) then theme[v] = gears.color.recolor_image(theme[v],theme.fg_normal) end @@ -281,6 +289,7 @@ theme.widgets = { end, }, titlebar = { + hidden_size = 2, root_shape = function(cr,width,height) return gears.shape.partially_rounded_rect(cr,width,height, true,true,false,false,6) end, @@ -316,9 +325,12 @@ theme.widgets = { bar_border_width = 2 }, checkbox = { + width = 15, + height = 15, shape = gears.shape.circle, - shape_border_width = 3, - shaoe_border_color = theme.bg_focus + border_width = 3, + border_color = theme.bg_normal, + paddings = {2,2,2,2} }, }, -- }}} @@ -528,7 +540,7 @@ theme.widgets = { end, shape_border_color = theme.bg_normal, shape_border_width = dpi(2) - } + } }, lock_clock = { textbox = { @@ -541,15 +553,16 @@ theme.widgets = { local root = titlebar:get_children_by_id("titlebar_root")[1] root:set_bg(theme.titlebar_bg_focus) root:set_shape(function(cr,width,height) - return gears.shape.partially_rounded_rect(cr,width,height, + return gears.shape.partially_rounded_rect( + cr,width,height, true,true,false,false,6) end) - end, onunfocus = function(titlebar) local root = titlebar:get_children_by_id("titlebar_root")[1] root:set_bg(theme.titlebar_bg_normal) root:set_shape(function(cr,width,height) - return gears.shape.partially_rounded_rect(cr,width,height, + return gears.shape.partially_rounded_rect( + cr,width,height, true,true,false,false,6) end) end, bg_focus = "#00000000", diff --git a/widgets/battery.lua b/widgets/battery.lua index aa39521..f0f3384 100644 --- a/widgets/battery.lua +++ b/widgets/battery.lua @@ -19,14 +19,14 @@ local function get_virtual_icon(data) local count = 0 local cumulative = 0 local name = "battery-" - for k,v in pairs(data) do + for _,v in pairs(data) do if type(v) == "number" then cumulative = cumulative + v count = count + 1 end end local percentage = math.floor((cumulative/(count*100))*100) - if percentage < 15 then + if percentage < 15 then name = name.."caution-" elseif percentage < 30 then name = name.."low-" @@ -60,7 +60,7 @@ return function(args) local templates = awmtk2.create_template_lib("battery",awmtk2.templates,args.templates) local t = awmtk2.build_templates(templates,style) battery_widget = wibox.widget(t.button({ - { + { image = beautiful["battery-missing-symbolic"], resize = true, widget = wibox.widget.imagebox, @@ -77,7 +77,7 @@ return function(args) -- make it possible to press the button and make it toggle the popup battery_widget:connect_signal("button::press",style.button.onpress) battery_widget:connect_signal("button::release",style.button.onrelease) - battery_widget:connect_signal("button::press",function(self,x,y,button) + battery_widget:connect_signal("button::press",function(_,_,_,button) if button == 1 then popup.visible = (not popup.visible) if popup.visible then @@ -94,7 +94,7 @@ return function(args) local power_devices = syscontrol.power_supply.enumerate() for _,device in pairs(power_devices) do local data = syscontrol.power_supply.read_attribs(device) - if data.type == "Battery" then + if data.type == "Battery" then widget_map[data.name] = wibox.widget(t.container({ t.article({ icon = get_virtual_icon({ @@ -154,7 +154,7 @@ return function(args) timeout = args.power_polling or 2, autostart = true, callback = function() - for k,v in pairs(power_devices) do + for _,v in pairs(power_devices) do local data,err = syscontrol.power_supply.read_attribs(v) if data and data.type == "Mains" then local w = widget_map[data.name] @@ -184,7 +184,7 @@ return function(args) -- {{{ Backlight local backlight_devices = syscontrol.backlight.enumerate() local default_backlight_device - for k,v in pairs(backlight_devices) do + for _,v in pairs(backlight_devices) do local data = syscontrol.backlight.read_attribs(v) if data then widget_map[data.name] = wibox.widget(t.container({ @@ -193,12 +193,18 @@ return function(args) icon = beautiful["backlight-symbolic"], title = "Backlight", }), - (data.writable and t.checkbox({ - checked = true, - id = "checkbox", - forced_height = style.article.icon_size, - forced_width = style.article.icon_size - })), + (data.writable and t.center( + t.checkbox({ + checked = false, + id = "checkbox", + forced_height = style.article.icon_size, + forced_width = style.article.icon_size + }), + { + width = style.checkbox.width, + height = style.checkbox.height + }) + ), layout = wibox.layout.fixed.horizontal, spacing = style.base.spacing }, @@ -234,7 +240,7 @@ return function(args) if default_backlight_device then local check2 = widget_map[default_backlight_device.name] :get_children_by_id("checkbox")[1] - check2.checked = false + check2.checked = true end default_backlight_device = data end) @@ -247,7 +253,7 @@ return function(args) timeout = args.backlight_polling or 2, autostart = true, callback = function() - for k,v in pairs(backlight_devices) do + for _,v in pairs(backlight_devices) do local data,err = syscontrol.backlight.read_attribs(v) if data then local w = widget_map[data.name] @@ -299,7 +305,7 @@ return function(args) if count(widget_map) == 0 then backlight_update:stop() power_update:stop() - return + return end return battery_widget end diff --git a/widgets/clientbuttons.lua b/widgets/clientbuttons.lua index f311ec2..6eec232 100644 --- a/widgets/clientbuttons.lua +++ b/widgets/clientbuttons.lua @@ -8,8 +8,6 @@ -- Additional client controls, hidden for cleaner UI in the submenu. local awmtk2 = require("awmtk2") local wibox = require("wibox") -local gears = require("gears") -local awful = require("awful") local beautiful = require("beautiful") return function(args) diff --git a/widgets/clientvolume.lua b/widgets/clientvolume.lua index 73d4fc7..19e53b2 100644 --- a/widgets/clientvolume.lua +++ b/widgets/clientvolume.lua @@ -13,12 +13,11 @@ local awmtk2 = require("awmtk2") local fastyaml = require("parsers").fast_split_yaml local beautiful = require("beautiful") local ask = require("asckey") -local pactl_data = {} local test_pactl = os.execute("pactl --version") local result = test_pactl if _VERSION:match("5.1") then - result = (test_pactl == 0) + result = (test_pactl == 0) end if not result then return @@ -45,6 +44,7 @@ return function(args) local widget = wibox.widget(t.container({ t.center({ id = "client_volume_icon", + resize = true, widget = wibox.widget.imagebox }), t.textbox({ @@ -62,16 +62,12 @@ return function(args) 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 slider_touched = false - -- Get initial pactl data - awful.spawn.easy_async("pactl list sink-inputs",function(stdout) - local pactl_data = fastyaml(stdout) - end) + 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 + local cl for k,v in pairs(pactl_data) do if not c then return end if v:match("application.process.id = \""..tostring(c.pid).."\"") then @@ -109,22 +105,21 @@ return function(args) -- Async lock to prevent callback interference local volume_lock = false -- Function to set client volume - local function volume(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) - local cl = {} if not (client.focus and client.focus.pid) then volume_lock = false return end - for k,v in pairs(pactl_data) do + 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, volume) - awful.spawn("pactl set-sink-input-volume "..tostring(sink_id).." "..tostring(volume).."%") + print(sink_id, value) + awful.spawn("pactl set-sink-input-volume "..tostring(sink_id).." "..tostring(value).."%") end end end @@ -132,7 +127,7 @@ return function(args) end) end -- Attach change to slider - slider:connect_signal("widget::redraw_needed",function(widget) + slider:connect_signal("widget::redraw_needed",function() if touched then volume(slider.value) update_timer:again() @@ -150,5 +145,5 @@ return function(args) volume(0) end,{description = "mute client", group = "client"}) )) - return widget + return widget end diff --git a/widgets/volume.lua b/widgets/volume.lua new file mode 100644 index 0000000..6e467f4 --- /dev/null +++ b/widgets/volume.lua @@ -0,0 +1,106 @@ +-- 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 . +-- Pulseaudio per-client volume setting +local awful = require("awful") +local gears = require("gears") +local wibox = require("wibox") +local awmtk2 = require("awmtk2") +local fastyaml = require("parsers").fast_split_yaml +local beautiful = require("beautiful") +local ask = require("asckey") +local pactl_data = {} + +local test_pactl = os.execute("pactl --version") +local pactl_found = test_pactl +if _VERSION:match("5.1") then + pactl_found = (test_pactl == 0) +end +local test_amixer = os.execute("amixer --version") +local amixer_found = test_amixer +if _VERSION:match("5.1") then + amixer_found = (test_amixer == 0) +end +if (not (amixer_found or pactl_found)) then + return +end + +local try_launch = [[which pavucontrol && pavucontrol || which pulsemixer && ]]..global.terminal..[[ -e pulsemixer || which alsamixer && ]]..global.terminal..[[ -e alsamixer ]] + +local function get_icon(percent) + if percent >= 66 then + return beautiful["volume-high-symbolic"] + elseif percent >= 33 then + return beautiful["volume-medium-symbolic"] + elseif percent > 0 then + return beautiful["volume-low-symbolic"] + else + return beautiful["volume-muted-symbolic"] + end +end + +return function(args) + local style = awmtk2.create_style("volume", + awmtk2.generic.oneline_widget, args.style) + local templates = awmtk2.create_template_lib("volume",awmtk2.templates,args.templates) + local t = awmtk2.build_templates(templates,style) + local widget = wibox.widget({ + t.button({ + image = get_icon(0), + id = "volume_icon", + resize = true, + widget = wibox.widget.imagebox + }), + t.container({ + t.slider({ + minimum = 0, + maximum = 100, + id = "volume", + value = -1 + }), + layout = wibox.layout.fixed.horizontal + },{ + visible = false, + id = "slidercontainer" + }), + layout = wibox.layout.fixed.horizontal + }) + local icon = widget:get_children_by_id("volume_icon")[1] + local slider = widget:get_children_by_id("volume")[1] + local container = widget:get_children_by_id("slidercontainer")[1] + -- Alsa master handle + args.device = args.device or "default" + gears.timer { + autostart = true, + timeout = 0.5, + call_now = true, + callback = function() + awful.spawn.easy_async_with_shell("amixer -D "..args.device.." sget Master",function(stdout) + local volume_percent = stdout:match("%[(%d+)%%%]") + volume_percent = tonumber(volume_percent) + if not volume_percent then + return + end + slider.value = volume_percent + icon.image = get_icon(volume_percent) + end) + end + } + slider:connect_signal("widget::redraw_needed",function() + awful.spawn("amixer -D "..args.device.." sset Master "..slider.value.."%") + icon.image = get_icon(slider.value) + end) + icon:connect_signal("button::press",function(self,lx,ly,button) + if button == 1 then + container.visible = not container.visible + end + if button == 2 then + awful.spawn.with_shell(args.mixer or try_launch) + end + end) + return widget +end