commit 5a99cb9e8202d415f8b14f12ee4f94755e703264 Author: Adriel Sand Date: Mon Apr 26 11:20:41 2021 +0300 Initial Commit diff --git a/battery-widget b/battery-widget new file mode 160000 index 0000000..25b7e94 --- /dev/null +++ b/battery-widget @@ -0,0 +1 @@ +Subproject commit 25b7e94a34ed854697d61e3cbb0a3ebd9745dbd4 diff --git a/configuration/apps.lua b/configuration/apps.lua new file mode 100644 index 0000000..85c71de --- /dev/null +++ b/configuration/apps.lua @@ -0,0 +1,62 @@ +local filesystem = require('gears.filesystem') +local beautiful = require('beautiful') + +-- Thanks to jo148 on github for making rofi dpi aware! +local with_dpi = require('beautiful').xresources.apply_dpi +local get_dpi = require('beautiful').xresources.get_dpi +local rofi_command = 'env /usr/bin/rofi -show drun -display-drun -run-command "/bin/bash -c -i \'shopt -s expand_aliases; {cmd}\'"' + +return { + -- List of apps to start by default on some actions + default = { + terminal = 'env alacritty', + rofi = rofi_command, + lock = 'i3lock -c 000000', + quake = 'alacritty', + screenshot = 'flameshot full -p ~/Pictures', + region_screenshot = 'flameshot gui -p ~/Pictures', + delayed_screenshot = 'flameshot gui -p ~/Pictures', + + -- Editing these also edits the default program + -- associated with each tag/workspace + browser = 'env brave', + editor = 'code', -- gui text editor + social = 'telegram-desktop', + game = rofi_command, + files = 'nautilus', + music = 'clementine', + video = 'vlc', + appmng = 'alacritty -e htop', + vmapp = 'virtualbox', + power_command = 'i3lock-fancy', + audiomng = 'pavucontrol', + obs = 'obs', + }, + -- List of apps to start once on start-up + run_on_start_up = { + -- Add applications that need to be killed between reloads + -- to avoid multipled instances, inside the autostart script + '~/.config/awesome/configuration/autostart', -- Spawn "dirty" apps that can linger between sessions + --'compton', + 'picom --config ' .. filesystem.get_configuration_dir() .. '/configuration/picom.conf', + 'nitrogen --restore', + 'nm-applet --indicator', -- wifi + 'xfce4-power-manager', -- Power manager + 'pamac-tray', + -- 'ibus-daemon --xim --daemonize', -- Ibus daemon for keyboard + 'scream-start', -- scream audio sink + -- 'flameshot', -- screenshots + -- 'numlockx on', -- enable numlock + '/usr/lib/xfce-polkit/xfce-polkit & eval $(gnome-keyring-daemon -s --components=pkcs11,secrets,ssh,gpg)', -- credential manager + 'blueman-tray', -- bluetooth tray + --'copyq', + 'dropbox', + 'megasync', + '~/.config/awesome/configuration/awspawn', -- Spawn "dirty" apps that can linger between sessions + -- '/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 &")', + 'keepassxc', + 'kdeconnect-indicator', + 'planner', + } +} + diff --git a/configuration/autostart b/configuration/autostart new file mode 100755 index 0000000..be2130f --- /dev/null +++ b/configuration/autostart @@ -0,0 +1,53 @@ +#!/bin/bash +## This configuration file is meant for applications that +# still run in the background when a reload is triggered +# for awesome, this script just kills the running instance +# and starts a new one. +# Only add applications/scripts without parameters here +# (if you want to apply parameters then use a script file!) + +# List of applications to run +# the script $HOME/.config/awesomestart +# is intended to be a copy of this file +# to allow out of tree autostart programs +APPS=( + # keepassxc + # kdeconnect-indicator + radeon-profile + $HOME/.config/awesomestart + ) +# Some applications start child applications that need to be killed on reload +KILL=( + synergyc + nextcloud + ) +# Some applications need to be started without GUI +SILENT=( + gnome-clocks + ) + +#Kill the polkit +killall xfce-polkit + +# First kill lingering apps +for app in "${APPS[@]}" +do + kill -9 $(pidof $app) +done +for app in "${KILL[@]}" +do + kill -9 $(pidof $app) +done + +# Start new instances +for app in "${APPS[@]}" +do + env $app ${@:2} & +done + +# Run silent apps +Xvfb :99 & +for silentapp in "${SILENT[@]}" +do + DISPLAY=:99 $silentapp & +done diff --git a/configuration/client/buttons.lua b/configuration/client/buttons.lua new file mode 100644 index 0000000..d3340c0 --- /dev/null +++ b/configuration/client/buttons.lua @@ -0,0 +1,13 @@ +local awful = require('awful') + +local modkey = require('configuration.keys.mod').modKey + +return awful.util.table.join(awful.button({}, 1, function(c) + _G.client.focus = c + c:raise() +end), awful.button({modkey}, 1, awful.mouse.client.move), awful.button({modkey, 'Shift'}, 1, awful.mouse.client.resize), + awful.button({modkey}, 4, function() + awful.layout.inc(1) + end), awful.button({modkey}, 5, function() + awful.layout.inc(-1) + end)) diff --git a/configuration/client/init.lua b/configuration/client/init.lua new file mode 100644 index 0000000..bbd5480 --- /dev/null +++ b/configuration/client/init.lua @@ -0,0 +1 @@ +require('configuration.client.rules') diff --git a/configuration/client/keys.lua b/configuration/client/keys.lua new file mode 100644 index 0000000..69d852a --- /dev/null +++ b/configuration/client/keys.lua @@ -0,0 +1,27 @@ +local awful = require('awful') +require('awful.autofocus') +local modkey = require('configuration.keys.mod').modKey +local altkey = require('configuration.keys.mod').altKey + +local clientKeys = + awful.util.table.join( + awful.key( + {modkey}, + 'f', + function(c) + c.fullscreen = not c.fullscreen + c:raise() + end, + {description = 'toggle fullscreen', group = 'client'} + ), + awful.key( + {modkey}, + 'q', + function(c) + c:kill() + end, + {description = 'close', group = 'client'} + ) +) + +return clientKeys diff --git a/configuration/client/rules.lua b/configuration/client/rules.lua new file mode 100644 index 0000000..fa85474 --- /dev/null +++ b/configuration/client/rules.lua @@ -0,0 +1,74 @@ +local awful = require('awful') +local gears = require('gears') +local client_keys = require('configuration.client.keys') +local client_buttons = require('configuration.client.buttons') + +-- Rules +awful.rules.rules = {{ + rule = {}, + properties = { + focus = awful.client.focus.filter, + raise = true, + keys = client_keys, + buttons = client_buttons, + screen = awful.screen.preferred, + placement = awful.placement.no_offscreen, + floating = false, + maximized = false, + above = false, + below = false, + ontop = false, + sticky = false, + maximized_horizontal = false, + maximized_vertical = false + } +}, { + rule_any = { + type = {'dialog'}, + class = {'Wicd-client.py', 'calendar.google.com'} + }, + properties = { + placement = awful.placement.centered, + ontop = true, + floating = true, + drawBackdrop = true, + shape = function() + return function(cr, w, h) + gears.shape.rounded_rect(cr, w, h, 8) + end + end, + skip_decoration = true + } +}, { + rule_any = { + type = {'modal'} + }, + properties = { + titlebars_enabled = true, + floating = true, + above = true, + skip_decoration = true, + placement = awful.placement.centered + } +}, { + rule_any = { + type = {'utility'} + }, + properties = { + titlebars_enabled = false, + floating = true, + skip_decoration = true, + placement = awful.placement.centered + } +}, { + rule_any = { + type = {'splash'}, + name = {'Discord Updater'} + }, + properties = { + floating = true, + above = true, + skip_decoration = true, + placement = awful.placement.centered + } +}} diff --git a/configuration/init.lua b/configuration/init.lua new file mode 100644 index 0000000..8ea676f --- /dev/null +++ b/configuration/init.lua @@ -0,0 +1,4 @@ +return { + keys = require('configuration.keys'), + apps = require('configuration.apps') +} diff --git a/configuration/keys/global.lua b/configuration/keys/global.lua new file mode 100644 index 0000000..99d7b7f --- /dev/null +++ b/configuration/keys/global.lua @@ -0,0 +1,274 @@ +local awful = require('awful') +require('awful.autofocus') +local beautiful = require('beautiful') +local hotkeys_popup = require('awful.hotkeys_popup').widget + +local modkey = require('configuration.keys.mod').modKey +local altkey = require('configuration.keys.mod').altKey +local apps = require('configuration.apps') + +function poweroff_command() + awful.spawn.with_shell('poweroff') + awful.keygrabber.stop(_G.exit_screen_grabber) +end + +-- Key bindings +local globalKeys = awful.util.table.join( -- Hotkeys +awful.key({modkey}, 'F1', hotkeys_popup.show_help, + {description = 'show help', group = 'awesome'}), -- Tag browsing +awful.key({modkey}, 'w', awful.tag.viewprev, + {description = 'view previous', group = 'tag'}), +awful.key({modkey}, 's', awful.tag.viewnext, + {description = 'view next', group = 'tag'}), +awful.key({altkey, 'Control'}, 'Left', awful.tag.viewprev, + {description = 'view previous', group = 'tag'}), +awful.key({altkey, 'Control'}, 'Right', awful.tag.viewnext, + {description = 'view next', group = 'tag'}), +awful.key({modkey}, 'Escape', awful.tag.history.restore, + {description = 'go back', group = 'tag'}), -- Default client focus +awful.key({modkey}, 'r', function() _G.awesome.spawn(apps.default.rofi) end, + {description = 'show rofi menu', group = 'awesome'}), +awful.key({modkey}, 'd', function() + local flag = false + for _, c in ipairs(mouse.screen.selected_tag:clients()) do + if c.minimized == true then flag = true end + c.minimized = true + end + for _, c in ipairs(mouse.screen.selected_tag:clients()) do + if flag == true then c.minimized = false end + end +end, {description = 'minimize all clients', group = 'awesome'}), +awful.key({modkey}, 'u', awful.client.urgent.jumpto, + {description = 'jump to urgent client', group = 'client'}), +awful.key({modkey}, 'Tab', function() + -- awful.client.focus.history.previous() + awful.client.focus.byidx(1) + if _G.client.focus then _G.client.focus:raise() end +end, {description = 'Switch to next window', group = 'client'}), +awful.key({modkey, 'Shift'}, 'Tab', function() + -- awful.client.focus.history.previous() + awful.client.focus.byidx(-1) + if _G.client.focus then _G.client.focus:raise() end +end, {description = 'Switch to previous window', group = 'client'}), +-- Programms +awful.key({modkey}, 'l', function() awful.spawn(apps.default.lock) end, + {description = 'Lock the screen', group = 'awesome'}), +awful.key({modkey, 'Shift'}, 'z', function() + awful.util.spawn_with_shell(apps.default.delayed_screenshot) +end, { + description = 'Mark an area and screenshot it (clipboard)', + group = 'screenshots (clipboard)' +}), +--[[ awful.key({modkey}, 'z', function() + awful.util.spawn_with_shell(apps.default.screenshot) +end, { + description = 'Take a screenshot of your active monitor and copy it to clipboard', + group = 'screenshots (clipboard)' +}), awful.key({'Control'}, 'Print', function() + awful.util.spawn_with_shell(apps.default.region_screenshot) +end, { + description = 'Mark an area and screenshot it to your clipboard', + group = 'screenshots (clipboard)' +}),]] +awful.key({modkey}, 'c', function() awful.util.spawn(apps.default.editor) end, + {description = 'open a text/code editor', group = 'launcher'}), +awful.key({modkey}, 'b', function() awful.util.spawn(apps.default.browser) end, + {description = 'open a browser', group = 'launcher'}), +-- Open private browser/brave +--[[awful.key({modkey}, 'b', + function() awful.util.spawn_with_shell('firefox') end, + {description = 'Open Firefox', group = 'launcher'}), +--]] + awful.key({modkey, 'Shift'}, 'e', function() + awful.util.spawn(apps.default.files) + end, { + description = 'open a file explorer', + group = 'launcher' + }), + awful.key({modkey, 'Shift'}, 'a', function() + awful.util.spawn(apps.default.audiomng) + end, { + description = 'open a pavucontrol window', + group = 'launcher' + }), + awful.key({modkey, 'Shift'}, 'h', function() + awful.util.spawn(apps.default.appmng) + end, { + description = 'open a process manager', + group = 'launcher' + }), + awful.key({modkey, 'Shift'}, 's', function() + awful.util.spawn(apps.default.obs) + end, { + description = 'open obs', + group = 'launcher' + }), +-- Standard program +awful.key({modkey}, 'x', + function() awful.util.spawn_with_shell(apps.default.terminal) end, + {description = 'open a terminal', group = 'launcher'}), +awful.key({modkey, 'Control'}, 'r', _G.awesome.restart, + {description = 'reload awesome', group = 'awesome'}), +awful.key({modkey, 'Control'}, 'q', _G.awesome.quit, + {description = 'quit awesome', group = 'awesome'}), +awful.key({modkey}, 'm', function() _G.dashboard_show() end, + {description = 'toggle main menu', group = 'awesome'}), +awful.key({modkey, 'Shift'}, 'p', function() _G.exit_screen_show() end, + {description = 'end session menu', group = 'awesome'}), +awful.key({altkey, 'Shift'}, 'Right', function() awful.tag.incmwfact(0.05) end, + {description = 'increase master width factor', group = 'layout'}), +awful.key({altkey, 'Shift'}, 'Left', function() awful.tag.incmwfact(-0.05) end, + {description = 'decrease master width factor', group = 'layout'}), +awful.key({altkey, 'Shift'}, 'Down', function() awful.client.incwfact(0.05) end, + {description = 'decrease master height factor', group = 'layout'}), +awful.key({altkey, 'Shift'}, 'Up', function() awful.client.incwfact(-0.05) end, + {description = 'increase master height factor', group = 'layout'}), +awful.key({modkey, 'Shift'}, 'Left', + function() awful.tag.incnmaster(1, nil, true) end, { + description = 'increase the number of master clients', + group = 'layout' +}), awful.key({modkey, 'Shift'}, 'Right', + function() awful.tag.incnmaster(-1, nil, true) end, { + description = 'decrease the number of master clients', + group = 'layout' +}), awful.key({modkey, 'Control'}, 'Left', + function() awful.tag.incncol(1, nil, true) end, { + description = 'increase the number of columns', + group = 'layout' +}), awful.key({modkey, 'Control'}, 'Right', + function() awful.tag.incncol(-1, nil, true) end, { + description = 'decrease the number of columns', + group = 'layout' +}), awful.key({modkey}, 'space', function() awful.layout.inc(1) end, + {description = 'select next', group = 'layout'}), +awful.key({modkey, 'Shift'}, 'space', function() awful.layout.inc(-1) end, + {description = 'select previous', group = 'layout'}), +awful.key({modkey, 'Control'}, 'n', function() + local c = awful.client.restore() + -- Focus restored client + if c then + _G.client.focus = c + c:raise() + end +end, {description = 'restore minimized', group = 'client'}), +-- Dropdown application +awful.key({modkey}, 'z', function() _G.toggle_quake() end, + {description = 'dropdown application', group = 'launcher'}), +-- Widgets popups +--[[awful.key( + {altkey}, + 'h', + function() + if beautiful.fs then + beautiful.fs.show(7) + end + end, + {description = 'show filesystem', group = 'widgets'} + ), + awful.key( + {altkey}, + 'w', + function() + if beautiful.weather then + beautiful.weather.show(7) + end + end, + {description = 'show weather', group = 'widgets'} + ),--]] +-- Brightness +awful.key({}, 'XF86MonBrightnessUp', + function() awful.spawn('xbacklight -inc 10') end, + {description = '+10%', group = 'hotkeys'}), +awful.key({}, 'XF86MonBrightnessDown', + function() awful.spawn('xbacklight -dec 10') end, + {description = '-10%', group = 'hotkeys'}), -- ALSA volume control +awful.key({}, 'XF86AudioRaiseVolume', function() + awful.spawn.easy_async('amixer -D pulse set Master 5%+', function() + _G.update_volume() + end) +end, {description = 'volume up', group = 'hotkeys'}), +awful.key({}, 'XF86AudioLowerVolume', function() + awful.spawn.easy_async('amixer -D pulse set Master 5%-', function() + _G.update_volume() + end) +end, {description = 'volume down', group = 'hotkeys'}), +awful.key({}, 'XF86AudioMute', function() + awful.spawn('amixer -D pulse set Master 1+ toggle') + _G.update_volume() +end, {description = 'toggle mute', group = 'hotkeys'}), +awful.key({}, 'XF86AudioNext', function() + -- +end, {description = 'toggle mute', group = 'hotkeys'}), +awful.key({}, 'XF86PowerDown', function() + -- +end, {description = 'toggle mute', group = 'hotkeys'}), +awful.key({}, 'XF86PowerOff', function() _G.exit_screen_show() end, + {description = 'toggle mute', group = 'hotkeys'}), +-- Screen management +awful.key({modkey}, 'o', awful.client.movetoscreen, + {description = 'move window to next screen', group = 'client'}), +-- Open default program for tag +awful.key({modkey}, 't', function() + awful.spawn(awful.screen.focused().selected_tag.defaultApp, { + tag = _G.mouse.screen.selected_tag, + placement = awful.placement.bottom_right + }) +end, {description = 'open default program for tag/workspace', group = 'tag'}), +-- Custom hotkeys +-- vfio integration +awful.key({'Control', altkey}, 'space', + function() awful.util.spawn_with_shell('vm-attach attach') end), +-- Emoji typing +-- setup info at https://gist.github.com/HikariKnight/8562837d28dec3674dba027c7892e6a5 +awful.key({modkey}, 'e', + function() awful.util.spawn_with_shell('emoji-toggle') end, { + description = 'Toggle the ibus unimoji engine for writing emojis', + group = 'hotkeys' +})) + +-- Bind all key numbers to tags. +-- Be careful: we use keycodes to make it works on any keyboard layout. +-- This should map on the top row of your keyboard, usually 1 to 9. +for i = 1, 9 do + -- Hack to only show tags 1 and 9 in the shortcut window (mod+s) + local descr_view, descr_toggle, descr_move, descr_toggle_focus + if i == 1 or i == 9 then + descr_view = {description = 'view tag #', group = 'tag'} + descr_toggle = {description = 'toggle tag #', group = 'tag'} + descr_move = { + description = 'move focused client to tag #', + group = 'tag' + } + descr_toggle_focus = { + description = 'toggle focused client on tag #', + group = 'tag' + } + end + globalKeys = awful.util.table.join(globalKeys, -- View tag only. + awful.key({modkey}, '#' .. i + 9, function() + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then tag:view_only() end + end, descr_view), -- Toggle tag display. + awful.key({modkey, 'Control'}, '#' .. i + 9, function() + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then awful.tag.viewtoggle(tag) end + end, descr_toggle), -- Move client to tag. + awful.key({modkey, 'Shift'}, '#' .. i + 9, function() + if _G.client.focus then + local tag = _G.client.focus.screen.tags[i] + if tag then _G.client.focus:move_to_tag(tag) end + end + end, descr_move), -- Toggle tag on focused client. + awful.key({modkey, 'Control', 'Shift'}, '#' .. i + 9, function() + if _G.client.focus then + local tag = _G.client.focus.screen.tags[i] + if tag then _G.client.focus:toggle_tag(tag) end + end + end, descr_toggle_focus)) + +end + +return globalKeys + diff --git a/configuration/keys/globald.lua b/configuration/keys/globald.lua new file mode 100644 index 0000000..5d9dccc --- /dev/null +++ b/configuration/keys/globald.lua @@ -0,0 +1,381 @@ +require('awful.autofocus') +local awful = require('awful') +local beautiful = require('beautiful') +local hotkeys_popup = require('awful.hotkeys_popup').widget +local modkey = require('configuration.keys.mod').modKey +local altkey = require('configuration.keys.mod').altKey +local apps = require('configuration.apps') +local dpi = require('beautiful').xresources.apply_dpi +local theme = require('theme') + +-- Key bindings +local globalKeys = awful.util.table.join( -- Hotkeys +awful.key({modkey}, 'h', hotkeys_popup.show_help, { + description = 'show help', + group = 'awesome' +}), awful.key({modkey}, 'F1', hotkeys_popup.show_help, { + description = 'show help', + group = 'awesome' +}), -- Tag browsing +awful.key({modkey}, 'Left', function() + awful.tag.viewprev() + _G._splash_to_current_tag() +end, { + description = 'go to previous workspace', + group = 'tag' +}), awful.key({modkey}, 'Right', function() + awful.tag.viewnext() + _G._splash_to_current_tag() +end, { + description = 'go to next workspace', + group = 'tag' +}), awful.key({modkey}, 'Escape', function() + awful.tag.history.restore() + _G._splash_to_current_tag() +end, { + description = 'go back', + group = 'tag' +}), -- Default client focus +awful.key({modkey}, 'd', function() + awful.client.focus.byidx(1) +end, { + description = 'focus next by index', + group = 'client' +}), awful.key({modkey}, 'a', function() + awful.client.focus.byidx(-1) +end, { + description = 'focus previous by index', + group = 'client' +}), awful.key({modkey}, 'r', function() + _G.awesome.spawn(apps.default.rofi) +end, { + description = 'show rofi menu', + group = 'awesome' +}), awful.key({modkey}, 'u', function() + awful.client.urgent.jumpto() + _G._splash_to_current_tag() +end, { + description = 'jump to urgent client', + group = 'client' +}), awful.key({altkey}, 'Tab', function() + awful.client.focus.byidx(1) + if _G.client.focus then + _G.client.focus:raise() + end +end, { + description = 'switch to next window', + group = 'client' +}), awful.key({modkey}, 'm', function() + focus = not _G.client.focus + if not focus then + _G.client.focus.minimized = true + else + for _, c in ipairs(mouse.screen.selected_tag:clients()) do + c.minimized = false + end + end +end, { + description = 'minimize window in focus / unminimize all', + group = 'client' +}), awful.key({altkey, 'Shift'}, 'Tab', function() + awful.client.focus.byidx(-1) + if _G.client.focus then + _G.client.focus:raise() + end +end, { + description = 'switch to previous window', + group = 'client' +}), awful.key({modkey}, 'l', function() + awful.spawn(apps.default.lock) +end, { + description = 'lock the screen', + group = 'awesome' +}), awful.key({'Control', 'Shift'}, 'Print', function() + awful.util.spawn_with_shell(apps.default.delayed_screenshot) +end, { + description = 'mark an area and screenshot it (clipboard)', + group = 'screenshots (clipboard)' +}), awful.key({altkey}, 'Print', function() + awful.util.spawn_with_shell(apps.default.screenshot) +end, { + description = 'take a screenshot of your active monitor and copy it to clipboard', + group = 'screenshots (clipboard)' +}), awful.key({'Control'}, 'Print', function() + awful.util.spawn_with_shell(apps.default.region_screenshot) +end, { + description = 'mark an area and screenshot it to your clipboard', + group = 'screenshots (clipboard)' +}), awful.key({modkey}, 'c', function() + awful.util.spawn(apps.default.editor) +end, { + description = 'open a text/code editor', + group = 'launcher' +}), awful.key({modkey}, 'b', function() + awful.util.spawn(apps.default.browser) +end, { + description = 'open a browser', + group = 'launcher' +}), awful.key({modkey}, 'Return', function() + awful.util.spawn_with_shell(apps.default.terminal) +end, { + description = 'open a terminal', + group = 'launcher' +}), awful.key({modkey, 'Control'}, 'r', _G.awesome.restart, { + description = 'reload awesome', + group = 'awesome' +}), awful.key({modkey, 'Control'}, 'q', _G.awesome.quit, { + description = 'quit awesome', + group = 'awesome' +}), awful.key({modkey, 'Shift'}, 'g', function(t) + t = t or awful.screen.focused().selected_tag + local current_gap = t.gap + local new_gap + if current_gap == 0 then + new_gap = beautiful.gaps + else + new_gap = 0 + end + t.gap = new_gap +end, { + description = 'toggle gaps', + group = 'awesome' +}), awful.key({modkey}, 'p', function() + awful.util.spawn_with_shell(apps.default.power_command) +end, { + description = 'end session menu', + group = 'awesome' +}), awful.key({altkey, 'Shift'}, 'Right', function() + awful.tag.incmwfact(0.05) +end, { + description = 'increase master width factor', + group = 'layout' +}), awful.key({altkey, 'Shift'}, 'Left', function() + awful.tag.incmwfact(-0.05) +end, { + description = 'decrease master width factor', + group = 'layout' +}), awful.key({altkey, 'Shift'}, 'Down', function() + awful.client.incwfact(0.05) +end, { + description = 'decrease master height factor', + group = 'layout' +}), awful.key({altkey, 'Shift'}, 'Up', function() + awful.client.incwfact(-0.05) +end, { + description = 'increase master height factor', + group = 'layout' +}), awful.key({modkey, 'Shift'}, 'Left', function() + awful.tag.incnmaster(1, nil, true) +end, { + description = 'increase the number of master clients', + group = 'layout' +}), awful.key({modkey, 'Shift'}, 'Right', function() + awful.tag.incnmaster(-1, nil, true) +end, { + description = 'decrease the number of master clients', + group = 'layout' +}), awful.key({modkey, 'Control'}, 'Left', function() + awful.tag.incncol(1, nil, true) +end, { + description = 'increase the number of columns', + group = 'layout' +}), awful.key({modkey, 'Control'}, 'Right', function() + awful.tag.incncol(-1, nil, true) +end, { + description = 'decrease the number of columns', + group = 'layout' +}), awful.key({modkey}, 'space', function() + awful.layout.inc(1) +end, { + description = 'select next layout', + group = 'layout' +}), awful.key({modkey, 'Shift'}, 'space', function() + awful.layout.inc(-1) +end, { + description = 'select previous layout', + group = 'layout' +}), awful.key({altkey, 'Shift'}, 'l', function() + awful.tag.incmwfact(0.05) +end, { + description = 'increase master width factor', + group = 'layout' +}), awful.key({altkey, 'Shift'}, 'h', function() + awful.tag.incmwfact(-0.05) +end, { + description = 'decrease master width factor', + group = 'layout' +}), awful.key({altkey, 'Shift'}, 'j', function() + awful.client.incwfact(0.05) +end, { + description = 'decrease master height factor', + group = 'layout' +}), awful.key({altkey, 'Shift'}, 'k', function() + awful.client.incwfact(-0.05) +end, { + description = 'increase master height factor', + group = 'layout' +}), awful.key({modkey, 'Shift'}, 'h', function() + awful.tag.incnmaster(1, nil, true) +end, { + description = 'increase the number of master clients', + group = 'layout' +}), awful.key({modkey, 'Shift'}, 'l', function() + awful.tag.incnmaster(-1, nil, true) +end, { + description = 'decrease the number of master clients', + group = 'layout' +}), awful.key({modkey, 'Control'}, 'h', function() + awful.tag.incncol(1, nil, true) +end, { + description = 'increase the number of columns', + group = 'layout' +}), awful.key({modkey, 'Control'}, 'l', function() + awful.tag.incncol(-1, nil, true) +end, { + description = 'decrease the number of columns', + group = 'layout' +}), awful.key({modkey, 'Control'}, 'n', function() + local c = awful.client.restore() + -- Focus restored client + if c then + _G.client.focus = c + c:raise() + end +end, { + description = 'restore minimized', + group = 'client' +}), awful.key({modkey}, 'k', function() + _G.toggle_splash() +end, { + description = 'toggle splash terminal', + group = 'launcher' +}), awful.key({modkey}, 'j', function() + _G.toggle_splash_height() +end, { + description = 'toggle splash terminal height', + group = 'launcher' +}), awful.key({}, 'XF86MonBrightnessUp', function() + awful.spawn('xbacklight -inc 10') +end, { + description = '+10%', + group = 'hotkeys' +}), awful.key({}, 'XF86MonBrightnessDown', function() + awful.spawn('xbacklight -dec 10') +end, { + description = '-10%', + group = 'hotkeys' +}), -- ALSA volume control +awful.key({altkey}, 'k', function() + awful.spawn.easy_async('amixer -D pulse sset Master 5%+', function() + _G.update_volume() + end) +end, { + description = 'volume up', + group = 'hotkeys' +}), awful.key({}, 'XF86AudioRaiseVolume', function() + awful.spawn.easy_async('amixer -D pulse sset Master 5%+', function() + _G.update_volume() + end) +end, { + description = 'volume up', + group = 'hotkeys' +}), awful.key({}, 'XF86AudioLowerVolume', function() + awful.spawn.easy_async('amixer -D pulse sset Master 5%-', function() + _G.update_volume() + end) +end, { + description = 'volume down', + group = 'hotkeys' +}), awful.key({altkey}, 'j', function() + awful.spawn.easy_async('amixer -D pulse sset Master 5%-', function() + _G.update_volume() + end) +end, { + description = 'volume down', + group = 'hotkeys' +}), awful.key({altkey}, 'm', function() + awful.spawn('amixer -D pulse set Master 1+ toggle') + _G.update_volume() +end, { + description = 'toggle mute', + group = 'hotkeys' +}), awful.key({}, 'XF86AudioMute', function() + awful.spawn('amixer -D pulse set Master 1+ toggle') + _G.update_volume() +end, { + description = 'toggle mute', + group = 'hotkeys' +}), awful.key({modkey}, 'o', awful.client.movetoscreen, { + description = 'move window to next screen', + group = 'client' +}), awful.key({modkey}, 'n', function() + awful.spawn(awful.screen.focused().selected_tag.defaultApp, { + tag = _G.mouse.screen.selected_tag, + placement = awful.placement.bottom_right + }) +end, { + description = 'open default program for tag/workspace', + group = 'tag' +}), awful.key({'Control', altkey}, 'space', function() + awful.util.spawn_with_shell('vm-attach attach') +end)) + +-- Bind all key numbers to tags. +-- Be careful: we use keycodes to make it works on any keyboard layout. +-- This should map on the top row of your keyboard, usually 1 to 9. +for i = 1, 9 do + -- Hack to only show tags 1 and 9 in the shortcut window (mod+s) + local descr_view, descr_toggle, descr_move, descr_toggle_focus + if i == 1 or i == 9 then + descr_view = { + description = 'view tag #', + group = 'tag' + } + descr_toggle = { + description = 'toggle tag #', + group = 'tag' + } + descr_move = { + description = 'move focused client to tag #', + group = 'tag' + } + descr_toggle_focus = { + description = 'toggle focused client on tag #', + group = 'tag' + } + end + globalKeys = awful.util.table.join(globalKeys, -- View tag only. + awful.key({modkey}, '#' .. i + 9, function() + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then + tag:view_only() + _G._splash_to_current_tag() + end + end, descr_view), -- Toggle tag display. + awful.key({modkey, 'Control'}, '#' .. i + 9, function() + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then + awful.tag.viewtoggle(tag) + end + end, descr_toggle), -- Move client to tag. + awful.key({modkey, 'Shift'}, '#' .. i + 9, function() + if _G.client.focus then + local tag = _G.client.focus.screen.tags[i] + if tag then + _G.client.focus:move_to_tag(tag) + end + end + end, descr_move), -- Toggle tag on focused client. + awful.key({modkey, 'Control', 'Shift'}, '#' .. i + 9, function() + if _G.client.focus then + local tag = _G.client.focus.screen.tags[i] + if tag then + _G.client.focus:toggle_tag(tag) + end + end + end, descr_toggle_focus)) +end + +return globalKeys diff --git a/configuration/keys/init.lua b/configuration/keys/init.lua new file mode 100644 index 0000000..9591667 --- /dev/null +++ b/configuration/keys/init.lua @@ -0,0 +1,4 @@ +return { + mod = require('configuration.keys.mod'), + global = require('configuration.keys.global') +} diff --git a/configuration/keys/mod.lua b/configuration/keys/mod.lua new file mode 100644 index 0000000..1d90897 --- /dev/null +++ b/configuration/keys/mod.lua @@ -0,0 +1,4 @@ +return { + modKey = 'Mod4', + altKey = 'Mod1' +} \ No newline at end of file diff --git a/configuration/picom.conf b/configuration/picom.conf new file mode 100644 index 0000000..f635b82 --- /dev/null +++ b/configuration/picom.conf @@ -0,0 +1,422 @@ +################################# +# Shadows # +################################# + + +# Enabled client-side shadows on windows. Note desktop windows +# (windows with '_NET_WM_WINDOW_TYPE_DESKTOP') never get shadow, +# unless explicitly requested using the wintypes option. +# +# shadow = false +shadow = true; + +# The blur radius for shadows, in pixels. (defaults to 12) +# shadow-radius = 12 +shadow-radius = 7; + +# The opacity of shadows. (0.0 - 1.0, defaults to 0.75) +# shadow-opacity = .75 + +# The left offset for shadows, in pixels. (defaults to -15) +# shadow-offset-x = -15 +shadow-offset-x = -7; + +# The top offset for shadows, in pixels. (defaults to -15) +# shadow-offset-y = -15 +shadow-offset-y = -7; + +# Avoid drawing shadows on dock/panel windows. This option is deprecated, +# you should use the *wintypes* option in your config file instead. +# +# no-dock-shadow = false + +# Don't draw shadows on drag-and-drop windows. This option is deprecated, +# you should use the *wintypes* option in your config file instead. +# +# no-dnd-shadow = false + +# Red color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-red = 0 + +# Green color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-green = 0 + +# Blue color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-blue = 0 + +# Do not paint shadows on shaped windows. Note shaped windows +# here means windows setting its shape through X Shape extension. +# Those using ARGB background is beyond our control. +# Deprecated, use +# shadow-exclude = 'bounding_shaped' +# or +# shadow-exclude = 'bounding_shaped && !rounded_corners' +# instead. +# +# shadow-ignore-shaped = '' + +# Specify a list of conditions of windows that should have no shadow. +# +# examples: +# shadow-exclude = "n:e:Notification"; +# +# shadow-exclude = [] +shadow-exclude = [ + "name = 'Notification'", + "class_g = 'Conky'", + "class_g ?= 'Notify-osd'", + "class_g = 'Cairo-clock'", + "_GTK_FRAME_EXTENTS@:c" +]; + +# Specify a X geometry that describes the region in which shadow should not +# be painted in, such as a dock window region. Use +# shadow-exclude-reg = "x10+0+0" +# for example, if the 10 pixels on the bottom of the screen should not have shadows painted on. +# +# shadow-exclude-reg = "" + +# Crop shadow of a window fully on a particular Xinerama screen to the screen. +# xinerama-shadow-crop = false + + +################################# +# Fading # +################################# + + +# Fade windows in/out when opening/closing and when opacity changes, +# unless no-fading-openclose is used. +# fading = false +fading = true + +# Opacity change between steps while fading in. (0.01 - 1.0, defaults to 0.028) +# fade-in-step = 0.028 +fade-in-step = 0.03; + +# Opacity change between steps while fading out. (0.01 - 1.0, defaults to 0.03) +# fade-out-step = 0.03 +fade-out-step = 0.03; + +# The time between steps in fade step, in milliseconds. (> 0, defaults to 10) +# fade-delta = 10 +fade-delta = 5 + +# Specify a list of conditions of windows that should not be faded. +# fade-exclude = [] + +# Do not fade on window open/close. +# no-fading-openclose = false + +# Do not fade destroyed ARGB windows with WM frame. Workaround of bugs in Openbox, Fluxbox, etc. +# no-fading-destroyed-argb = false + + +################################# +# Transparency / Opacity # +################################# + + +# Opacity of inactive windows. (0.1 - 1.0, defaults to 1.0) +# inactive-opacity = 1 +inactive-opacity = 1.0; + +# Opacity of window titlebars and borders. (0.1 - 1.0, disabled by default) +# frame-opacity = 1.0 +frame-opacity = 0.95; + +# Default opacity for dropdown menus and popup menus. (0.0 - 1.0, defaults to 1.0) +# menu-opacity = 1.0 + +# Let inactive opacity set by -i override the '_NET_WM_OPACITY' values of windows. +# inactive-opacity-override = true +inactive-opacity-override = true; + +# Default opacity for active windows. (0.0 - 1.0, defaults to 1.0) +active-opacity = 1.0 + +# Dim inactive windows. (0.0 - 1.0, defaults to 0.0) +# inactive-dim = 0.0 + +# Specify a list of conditions of windows that should always be considered focused. +# focus-exclude = [] +#focus-exclude = [ "class_g = 'Termite'" ]; + +# Use fixed inactive dim value, instead of adjusting according to window opacity. +# inactive-dim-fixed = 1.0 + +# Specify a list of opacity rules, in the format `PERCENT:PATTERN`, +# like `50:name *= "Firefox"`. picom-trans is recommended over this. +# Note we don't make any guarantee about possible conflicts with other +# programs that set '_NET_WM_WINDOW_OPACITY' on frame or client windows. +# example: +# opacity-rule = [ "80:class_g = 'URxvt'" ]; + + +################################# +# Background-Blurring # +################################# + + +# Parameters for background blurring, see the *BLUR* section for more information. +# blur-method = +# blur-size = 12 +# +# blur-deviation = false + +# Blur background of semi-transparent / ARGB windows. +# Bad in performance, with driver-dependent behavior. +# The name of the switch may change without prior notifications. +# +# blur-background = false + +# Blur background of windows when the window frame is not opaque. +# Implies: +# blur-background +# Bad in performance, with driver-dependent behavior. The name may change. +# +# blur-background-frame = false + + +# Use fixed blur strength rather than adjusting according to window opacity. +# blur-background-fixed = false + + +# Specify the blur convolution kernel, with the following format: +# example: +# blur-kern = "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"; +# +# blur-kern = '' +blur-kern = "3x3box"; + + +# Exclude conditions for background blur. +# blur-background-exclude = [] +blur-background-exclude = [ + "window_type = 'dock'", + "window_type = 'desktop'", + "_GTK_FRAME_EXTENTS@:c" +]; + +################################# +# General Settings # +################################# + +# Daemonize process. Fork to background after initialization. Causes issues with certain (badly-written) drivers. +# daemon = false + +# Specify the backend to use: `xrender`, `glx`, or `xr_glx_hybrid`. +# `xrender` is the default one. +# +# backend = 'glx' +backend = "xrender"; + +# Enable/disable VSync. +# vsync = false +vsync = true + +# Enable remote control via D-Bus. See the *D-BUS API* section below for more details. +# dbus = false + +# Try to detect WM windows (a non-override-redirect window with no +# child that has 'WM_STATE') and mark them as active. +# +# mark-wmwin-focused = false +mark-wmwin-focused = true; + +# Mark override-redirect windows that doesn't have a child window with 'WM_STATE' focused. +# mark-ovredir-focused = false +mark-ovredir-focused = true; + +# Try to detect windows with rounded corners and don't consider them +# shaped windows. The accuracy is not very high, unfortunately. +# +# detect-rounded-corners = false +detect-rounded-corners = true; + +# Detect '_NET_WM_OPACITY' on client windows, useful for window managers +# not passing '_NET_WM_OPACITY' of client windows to frame windows. +# +# detect-client-opacity = false +detect-client-opacity = true; + +# Specify refresh rate of the screen. If not specified or 0, picom will +# try detecting this with X RandR extension. +# +# refresh-rate = 60 +refresh-rate = 60 + +# Limit picom to repaint at most once every 1 / 'refresh_rate' second to +# boost performance. This should not be used with +# vsync drm/opengl/opengl-oml +# as they essentially does sw-opti's job already, +# unless you wish to specify a lower refresh rate than the actual value. +# +# sw-opti = + +# Use EWMH '_NET_ACTIVE_WINDOW' to determine currently focused window, +# rather than listening to 'FocusIn'/'FocusOut' event. Might have more accuracy, +# provided that the WM supports it. +# +# use-ewmh-active-win = false + +# Unredirect all windows if a full-screen opaque window is detected, +# to maximize performance for full-screen windows. Known to cause flickering +# when redirecting/unredirecting windows. +# +# unredir-if-possible = false + +# Delay before unredirecting the window, in milliseconds. Defaults to 0. +# unredir-if-possible-delay = 0 + +# Conditions of windows that shouldn't be considered full-screen for unredirecting screen. +# unredir-if-possible-exclude = [] + +# Use 'WM_TRANSIENT_FOR' to group windows, and consider windows +# in the same group focused at the same time. +# +# detect-transient = false +detect-transient = true + +# Use 'WM_CLIENT_LEADER' to group windows, and consider windows in the same +# group focused at the same time. 'WM_TRANSIENT_FOR' has higher priority if +# detect-transient is enabled, too. +# +# detect-client-leader = false +detect-client-leader = true + +# Resize damaged region by a specific number of pixels. +# A positive value enlarges it while a negative one shrinks it. +# If the value is positive, those additional pixels will not be actually painted +# to screen, only used in blur calculation, and such. (Due to technical limitations, +# with use-damage, those pixels will still be incorrectly painted to screen.) +# Primarily used to fix the line corruption issues of blur, +# in which case you should use the blur radius value here +# (e.g. with a 3x3 kernel, you should use `--resize-damage 1`, +# with a 5x5 one you use `--resize-damage 2`, and so on). +# May or may not work with *--glx-no-stencil*. Shrinking doesn't function correctly. +# +# resize-damage = 1 + +# Specify a list of conditions of windows that should be painted with inverted color. +# Resource-hogging, and is not well tested. +# +# invert-color-include = [] + +# GLX backend: Avoid using stencil buffer, useful if you don't have a stencil buffer. +# Might cause incorrect opacity when rendering transparent content (but never +# practically happened) and may not work with blur-background. +# My tests show a 15% performance boost. Recommended. +# +# glx-no-stencil = false + +# GLX backend: Avoid rebinding pixmap on window damage. +# Probably could improve performance on rapid window content changes, +# but is known to break things on some drivers (LLVMpipe, xf86-video-intel, etc.). +# Recommended if it works. +# +# glx-no-rebind-pixmap = false + +# Disable the use of damage information. +# This cause the whole screen to be redrawn everytime, instead of the part of the screen +# has actually changed. Potentially degrades the performance, but might fix some artifacts. +# The opposing option is use-damage +# +# no-use-damage = false +use-damage = true + +# Use X Sync fence to sync clients' draw calls, to make sure all draw +# calls are finished before picom starts drawing. Needed on nvidia-drivers +# with GLX backend for some users. +# +# xrender-sync-fence = false + +# GLX backend: Use specified GLSL fragment shader for rendering window contents. +# See `compton-default-fshader-win.glsl` and `compton-fake-transparency-fshader-win.glsl` +# in the source tree for examples. +# +# glx-fshader-win = '' + +# Force all windows to be painted with blending. Useful if you +# have a glx-fshader-win that could turn opaque pixels transparent. +# +# force-win-blend = false + +# Do not use EWMH to detect fullscreen windows. +# Reverts to checking if a window is fullscreen based only on its size and coordinates. +# +# no-ewmh-fullscreen = false + +# Dimming bright windows so their brightness doesn't exceed this set value. +# Brightness of a window is estimated by averaging all pixels in the window, +# so this could comes with a performance hit. +# Setting this to 1.0 disables this behaviour. Requires --use-damage to be disabled. (default: 1.0) +# +# max-brightness = 1.0 + +# Make transparent windows clip other windows like non-transparent windows do, +# instead of blending on top of them. +# +# transparent-clipping = false + +# Set the log level. Possible values are: +# "trace", "debug", "info", "warn", "error" +# in increasing level of importance. Case doesn't matter. +# If using the "TRACE" log level, it's better to log into a file +# using *--log-file*, since it can generate a huge stream of logs. +# +# log-level = "debug" +log-level = "warn"; + +# Set the log file. +# If *--log-file* is never specified, logs will be written to stderr. +# Otherwise, logs will to written to the given file, though some of the early +# logs might still be written to the stderr. +# When setting this option from the config file, it is recommended to use an absolute path. +# +# log-file = '/path/to/your/log/file' + +# Show all X errors (for debugging) +# show-all-xerrors = false + +# Write process ID to a file. +# write-pid-path = '/path/to/your/log/file' + +# Window type settings +# +# 'WINDOW_TYPE' is one of the 15 window types defined in EWMH standard: +# "unknown", "desktop", "dock", "toolbar", "menu", "utility", +# "splash", "dialog", "normal", "dropdown_menu", "popup_menu", +# "tooltip", "notification", "combo", and "dnd". +# +# Following per window-type options are available: :: +# +# fade, shadow::: +# Controls window-type-specific shadow and fade settings. +# +# opacity::: +# Controls default opacity of the window type. +# +# focus::: +# Controls whether the window of this type is to be always considered focused. +# (By default, all window types except "normal" and "dialog" has this on.) +# +# full-shadow::: +# Controls whether shadow is drawn under the parts of the window that you +# normally won't be able to see. Useful when the window has parts of it +# transparent, and you want shadows in those areas. +# +# redir-ignore::: +# Controls whether this type of windows should cause screen to become +# redirected again after been unredirected. If you have unredir-if-possible +# set, and doesn't want certain window to cause unnecessary screen redirection, +# you can set this to `true`. +# +wintypes: +{ + tooltip = { fade = true; shadow = true; opacity = 0.75; focus = true; full-shadow = false; }; + dock = { shadow = false; } + dnd = { shadow = false; } + popup_menu = { opacity = 1.0; } + dropdown_menu = { opacity = 1.0; } +}; \ No newline at end of file diff --git a/configuration/rofi.rasi b/configuration/rofi.rasi new file mode 100644 index 0000000..e158e40 --- /dev/null +++ b/configuration/rofi.rasi @@ -0,0 +1,148 @@ +/** + * User: deadguy + * Copyright: deadguy + */ + +configuration { + display-drun: "Activate"; + display-run: "Execute"; + show-icons: true; + sidebar-mode: false; +} + +* { + background-color: rgb(0, 0, 0, 0); + text-color: rgb(255, 255, 255); + selbg: rgb(255, 255, 255, 0.5); + urgbg: rgb(255, 255, 255); + actbg: rgb(255, 255, 255, 0.05); + winbg: rgb(255, 255, 255); + + selected-normal-foreground: @winbg; + normal-foreground: @text-color; + selected-normal-background: @actbg; + normal-background: @background-color; + + selected-urgent-foreground: @background-color; + urgent-foreground: @text-color; + selected-urgent-background: @urgbg; + urgent-background: @background-color; + + selected-active-foreground: @winbg; + active-foreground: @text-color; + selected-active-background: @actbg; + active-background: @selbg; + + line-margin: 2; + line-padding: 2; + separator-style: "none"; + hide-scrollbar: "true"; + margin: 0px; + padding: 0px; + font: "FiraCode Nerd Font Mono Medium 10"; +} + +window { + location: west; + anchor: west; + x-offset: 0px; + height: 100%; + width: 30%; + padding: 0%; + orientation: horizontal; + children: [mainbox]; + background-color: rgb(20, 20, 20, 0.9); +} + +mainbox { + spacing: 0em; + padding: 0px; + width: 100%; + children: [ inputbar, listview ]; + expand: true; +} + +button { padding: 5px 2px; } + +button selected { + background-color: @active-background; + text-color: @background-color; +} + +inputbar { + children: [ entry ]; +} + +textbox-prompt-colon { + text-color: inherit; + expand: false; + margin: 0 0.3em 0em 0em; + } + +listview { + spacing: 0em; + dynamic: false; + cycle: false; +} + +element { + padding: 16px; + border: 0 0 0 0 solid; +} + +entry { + expand: true; + text-color: @normal-foreground; + background-color: rgb(0, 0, 0, 0); + vertical-align: 1; + padding: 12px; + font: "FiraCode Nerd Font Mono Bold 18"; +} + +element normal.normal { + background-color: @normal-background; + text-color: @normal-foreground; +} + +element normal.urgent { + background-color: @urgent-background; + text-color: @urgent-foreground; +} + +element normal.active { + background-color: @active-background; + text-color: @active-foreground; +} + +element selected.normal { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; + padding: 16px; + border: 0 0 0 0 solid; + border-color: @active-background; +} + +element selected.urgent { + background-color: @selected-urgent-background; + text-color: @selected-urgent-foreground; +} + +element selected.active { + background-color: @selected-active-background; + text-color: @selected-active-foreground; +} + +element alternate.normal { + background-color: @normal-background; + text-color: @normal-foreground; +} + +element alternate.urgent { + background-color: @urgent-background; + text-color: @urgent-foreground; +} + +element alternate.active { + background-color: @active-background; + text-color: @active-foreground; +} diff --git a/configuration/tags/init.lua b/configuration/tags/init.lua new file mode 100644 index 0000000..1044d93 --- /dev/null +++ b/configuration/tags/init.lua @@ -0,0 +1,46 @@ +local awful = require('awful') +local beautiful = require('beautiful') +local gears = require('gears') +local apps = require('configuration.apps') +local dpi = require('beautiful').xresources.apply_dpi + +local tags = { + {text = 'web', type = 'web', defaultApp = apps.default.browser, screen = 1}, + {text = 'term', type = 'code', defaultApp = apps.default.terminal, screen = 1}, + {text = 'social', type = 'social', defaultApp = apps.default.social, screen = 1}, + {text = 'video', type = 'video', defaultApp = apps.default.video, screen = 1}, + {text = 'file', type = 'file', defaultApp = apps.default.files, screen = 1}, + {text = 'music', type = 'music', defaultApp = apps.default.music, screen = 1}, + {text = 'misc', type = 'misc', defaultApp = apps.default.vmapp, screen = 1} +} + +awful.layout.layouts = { + + awful.layout.suit.tile, + awful.layout.suit.floating, +-- awful.layout.suit.tile.left, +-- awful.layout.suit.tile.bottom, +-- awful.layout.suit.tile.top, +--[[ awful.layout.suit.fair, +-- awful.layout.suit.fair.horizontal, +-- awful.layout.suit.spiral, + awful.layout.suit.spiral.dwindle, +--]] awful.layout.suit.max, +-- awful.layout.suit.max.fullscreen, +-- awful.layout.suit.magnifier, +-- awful.layout.suit.corner.nw, +} + +awful.screen.connect_for_each_screen(function(s) + for i, tag in pairs(tags) do + awful.tag.add(tag.text, { + icon = tag.icon, + icon_only = false, + layout = awful.layout.suit.tile, + gap = beautiful.gaps, + screen = s, + defaultApp = tag.defaultApp, + selected = i == 1 + }) + end +end) diff --git a/configuration/utils/rofi-power b/configuration/utils/rofi-power new file mode 100755 index 0000000..9716242 --- /dev/null +++ b/configuration/utils/rofi-power @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +# rofi-power +# Use rofi to call systemctl for shutdown, reboot, etc + +# 2016 Oliver Kraitschy - http://okraits.de + +OPTIONS="Poweroff\nExit\nReboot\nSuspend\nHibernate" + +config_path=$(dirname "$0") + +LAUNCHER="rofi -dmenu -i" +USE_LOCKER="true" +LOCKER="i3lock -c 000000" + +option=`echo -e $OPTIONS | $LAUNCHER | awk '{print $1}' | tr -d '\r\n'` +case $option in + Exit) + kill -9 -1 + ;; + Reboot) + systemctl reboot + ;; + Poweroff) + systemctl poweroff + ;; + Suspend) + $($USE_LOCKER) && "$LOCKER"; systemctl suspend + ;; + Hibernate) + $($USE_LOCKER) && "$LOCKER"; systemctl hibernate + ;; + *) + ;; +esac diff --git a/configuration/utils/screenshot b/configuration/utils/screenshot new file mode 100755 index 0000000..d7f947e --- /dev/null +++ b/configuration/utils/screenshot @@ -0,0 +1,8 @@ +#!/bin/bash +if [ $1 == "--delayed" ]; then + spectacle -b -n ${@:2} -o /tmp/screenshot.png ; xclip -selection clipboard -target image/png -i /tmp/screenshot.png ; paplay /usr/share/sounds/freedesktop/stereo/camera-shutter.oga +else + spectacle -b -n $@ -o /tmp/screenshot.png ; xclip -selection clipboard -target image/png -i /tmp/screenshot.png ; paplay /usr/share/sounds/freedesktop/stereo/camera-shutter.oga +fi + + diff --git a/layout/bottom-bar.lua b/layout/bottom-bar.lua new file mode 100644 index 0000000..e42731e --- /dev/null +++ b/layout/bottom-bar.lua @@ -0,0 +1,37 @@ +local beautiful = require('beautiful') +local wibox = require('wibox') +local TaskList = require('widget.task-list') +local dpi = require('beautiful').xresources.apply_dpi + +local BottomBar = function(s, offset) + + -- BOTTOM BAR + -- ======= + local panel_height = dpi(16) + local panel = wibox({ + ontop = false, + screen = s, + height = panel_height, + width = s.geometry.width, + x = s.geometry.x, + y = s.geometry.height - panel_height, + stretch = false, + bg = beautiful.primary.hue_100, + fg = beautiful.fg_normal, + }) + + panel:struts({ + bottom = panel.height + }) + + panel:setup{ + layout = wibox.layout.align.horizontal, + nil, + TaskList(s), + nil, + } + + return panel +end + +return BottomBar diff --git a/layout/init.lua b/layout/init.lua new file mode 100644 index 0000000..6563b10 --- /dev/null +++ b/layout/init.lua @@ -0,0 +1,44 @@ +local awful = require('awful') +local top_bar = require('layout.top-bar') +local bottom_bar = require('layout.bottom-bar') +local left_panel = require('layout.left-panel') + +local key_grabber + +-- Create a wibox for each screen and add it +awful.screen.connect_for_each_screen(function(s) + if s.index == 1 then + s.top_bar = top_bar(s, true) + s.bottom_bar = bottom_bar(s, true) + else + s.top_bar = top_bar(s, false) + s.bottom_bar = bottom_bar(s, false) + end +end) + +-- Hide bars when app go fullscreen +function updateBarsVisibility() + for s in screen do + if s.selected_tag then + local fullscreen = s.selected_tag.fullscreenMode + s.top_bar.visible = not fullscreen + s.bottom_bar.visible = not fullscreen + end + end +end + +_G.tag.connect_signal('property::selected', function(t) + updateBarsVisibility() +end) + +_G.client.connect_signal('property::fullscreen', function(c) + c.screen.selected_tag.fullscreenMode = c.fullscreen + updateBarsVisibility() +end) + +_G.client.connect_signal('unmanage', function(c) + if c.fullscreen then + c.screen.selected_tag.fullscreenMode = false + updateBarsVisibility() + end +end) diff --git a/layout/left-panel/action-bar.lua b/layout/left-panel/action-bar.lua new file mode 100644 index 0000000..db2a612 --- /dev/null +++ b/layout/left-panel/action-bar.lua @@ -0,0 +1,34 @@ +local awful = require('awful') +local beautiful = require('beautiful') +local wibox = require('wibox') +local gears = require('gears') +local mat_icon = require('widget.material.icon') +local dpi = require('beautiful').xresources.apply_dpi +local icons = require('theme.icons') +local clickable_container = require('widget.material.clickable-container') + +return function(screen, panel, action_bar_width) + local menu_icon = wibox.widget { + icon = icons.menu, + size = dpi(16), + widget = mat_icon + } + + local home_button = wibox.widget { + wibox.widget {menu_icon, widget = clickable_container}, + visible = true, + bg = beautiful.primary.hue_700, + widget = wibox.container.background + } + + home_button:buttons(gears.table.join( + awful.button({}, 1, nil, + function() _G.dashboard_show() end))) + + return wibox.widget { + id = 'action_bar', + layout = wibox.layout.align.horizontal, + forced_width = action_bar_width, + {layout = wibox.layout.fixed.horizontal, home_button} + } +end diff --git a/layout/left-panel/dashboard/hardware-monitor.lua b/layout/left-panel/dashboard/hardware-monitor.lua new file mode 100644 index 0000000..41f9930 --- /dev/null +++ b/layout/left-panel/dashboard/hardware-monitor.lua @@ -0,0 +1,18 @@ +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') + +return wibox.widget { + -- wibox.widget { + -- wibox.widget { + -- text = 'Hardware monitor', + -- font = 'Roboto medium 12', + -- widget = wibox.widget.textbox + -- }, + -- widget = mat_list_item + -- }, + require('widget.cpu.cpu-meter'), + require('widget.ram.ram-meter'), + require('widget.temperature.temperature-meter'), + require('widget.harddrive.harddrive-meter'), + layout = wibox.layout.fixed.vertical +} diff --git a/layout/left-panel/dashboard/init.lua b/layout/left-panel/dashboard/init.lua new file mode 100644 index 0000000..e4c77a8 --- /dev/null +++ b/layout/left-panel/dashboard/init.lua @@ -0,0 +1,71 @@ +local awful = require('awful') +local beautiful = require('beautiful') +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') +local mat_icon = require('widget.material.icon') +local dpi = require('beautiful').xresources.apply_dpi +local icons = require('theme.icons') + +return function(_, panel) + local search_button = wibox.widget { + wibox.widget {icon = icons.search, size = dpi(24), widget = mat_icon}, + wibox.widget { + text = 'Search Applications', + font = 'Roboto medium 13', + widget = wibox.widget.textbox + }, + clickable = true, + widget = mat_list_item + } + + search_button:buttons(awful.util.table.join( + awful.button({}, 1, + function() panel:run_rofi() end))) + + local exit_button = wibox.widget { + wibox.widget {icon = icons.logout, size = dpi(24), widget = mat_icon}, + wibox.widget { + text = 'End work session', + font = 'Roboto medium 13', + widget = wibox.widget.textbox + }, + clickable = true, + divider = true, + widget = mat_list_item + } + + exit_button:buttons(awful.util.table.join( + awful.button({}, 1, function() + panel:toggle() + _G.exit_screen_show() + end))) + + return wibox.widget { + layout = wibox.layout.align.vertical, + { + layout = wibox.layout.fixed.vertical, + { + search_button, + bg = beautiful.primary.hue_800, + widget = wibox.container.background + }, + wibox.widget { + orientation = 'horizontal', + forced_height = 0.8, + opacity = 0.3, + widget = wibox.widget.separator + }, + require('layout.left-panel.dashboard.quick-settings'), + require('layout.left-panel.dashboard.hardware-monitor') + }, + nil, + { + layout = wibox.layout.fixed.vertical, + { + exit_button, + bg = beautiful.primary.hue_800, + widget = wibox.container.background + } + } + } +end diff --git a/layout/left-panel/dashboard/quick-settings.lua b/layout/left-panel/dashboard/quick-settings.lua new file mode 100644 index 0000000..4f7139f --- /dev/null +++ b/layout/left-panel/dashboard/quick-settings.lua @@ -0,0 +1,16 @@ +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') + +return wibox.widget { + -- wibox.widget { + -- wibox.widget { + -- text = 'Quick settings', + -- font = 'Roboto medium 12', + -- widget = wibox.widget.textbox + -- }, + -- widget = mat_list_item + -- }, + require('widget.volume.volume-slider'), + require('widget.brightness.brightness-slider'), + layout = wibox.layout.fixed.vertical +} diff --git a/layout/left-panel/init.lua b/layout/left-panel/init.lua new file mode 100644 index 0000000..5decf78 --- /dev/null +++ b/layout/left-panel/init.lua @@ -0,0 +1,98 @@ +local awful = require('awful') +local beautiful = require('beautiful') +local wibox = require('wibox') +local apps = require('configuration.apps') +local dpi = require('beautiful').xresources.apply_dpi + +local left_panel = function(screen) + local action_bar_width = dpi(32) + local panel_content_width = dpi(400) + local offsety = dpi(12) + + local panel = wibox { + screen = screen, + width = dpi(32), + height = dpi(32), + x = screen.geometry.x + 12, + y = screen.geometry.y + offsety, + ontop = false, + bg = beautiful.primary.hue_900, + fg = beautiful.fg_normal + } + + panel.opened = false + + panel:struts({left = dpi(0), top = dpi(48)}) + + local backdrop = wibox { + ontop = true, + screen = screen, + bg = '#00000000', + type = 'dock', + x = screen.geometry.x, + y = screen.geometry.y + offsety, + width = screen.geometry.width, + height = screen.geometry.height + } + + function panel:run_rofi() + _G.awesome.spawn(apps.default.rofi, false, false, false, false, + function() panel:toggle() end) + end + + local openPanel = function(should_run_rofi) + panel.width = panel_content_width + panel.height = screen.geometry.height + backdrop.visible = true + panel.visible = false + panel.visible = true + panel.x = screen.geometry.x + panel.y = screen.geometry.y + panel.ontop = true + panel:get_children_by_id('panel_content')[1].visible = true + if should_run_rofi then panel:run_rofi() end + panel:emit_signal('opened') + end + + local closePanel = function() + panel.width = action_bar_width + panel.height = dpi(32) + panel:get_children_by_id('panel_content')[1].visible = false + backdrop.visible = false + panel.ontop = false + panel.x = screen.geometry.x + 12 + panel.y = screen.geometry.y + offsety + panel:emit_signal('closed') + end + + function panel:toggle(should_run_rofi) + self.opened = not self.opened + if self.opened then + openPanel(should_run_rofi) + else + closePanel() + end + end + + backdrop:buttons(awful.util.table.join( + awful.button({}, 1, function() panel:toggle() end))) + + panel:setup{ + require('layout.left-panel.action-bar')(screen, panel, action_bar_width), + layout = wibox.layout.align.vertical, + { + id = 'panel_content', + bg = beautiful.primary.hue_900, + widget = wibox.container.background, + visible = false, + forced_width = panel_content_width, + { + require('layout.left-panel.dashboard')(screen, panel), + layout = wibox.layout.stack + } + } + } + return panel +end + +return left_panel diff --git a/layout/top-bar.lua b/layout/top-bar.lua new file mode 100644 index 0000000..aaff723 --- /dev/null +++ b/layout/top-bar.lua @@ -0,0 +1,165 @@ +local awful = require('awful') +local beautiful = require('beautiful') +local clickable_container = require('widget.material.clickable-container') +local mat_icon_button = require('widget.material.icon-button') +local wibox = require('wibox') +local TagList = require('widget.tag-list') +local gears = require('gears') +local dpi = require('beautiful').xresources.apply_dpi +local theme = require "theme" +local table = awful.util.table or gears.table + +local separator = wibox.container.margin(wibox.widget { + orientation = 'vertical', + forced_width = dpi(1), + opacity = 0.3, + widget = wibox.widget.separator +}, dpi(0), dpi(0), dpi(4), dpi(4)) + +local TopBar = function(s, offset) + + -- LAYOUT BOX + -- ========== + local function update_txt_layoutbox(s) + -- Writes a string representation of the current layout in a textbox widget + local txt_l = theme["layout_txt_" .. awful.layout.getname(awful.layout.get(s))] or "" + s.layoutbox:set_text(txt_l) + end + + s.layoutbox = wibox.widget.textbox(theme["layout_txt_" .. awful.layout.getname(awful.layout.get(s))]) + s.layoutbox.font = beautiful.icon_font + awful.tag.attached_connect_signal(s, "property::selected", function () update_txt_layoutbox(s) end) + awful.tag.attached_connect_signal(s, "property::layout", function () update_txt_layoutbox(s) end) + s.layoutbox:buttons(table.join( + awful.button({}, 1, function() awful.layout.inc(1) end), + awful.button({}, 2, function () awful.layout.set( awful.layout.layouts[1] ) end), + awful.button({}, 3, function() awful.layout.inc(-1) end), + awful.button({}, 4, function() awful.layout.inc(1) end), + awful.button({}, 5, function() awful.layout.inc(-1) end))) + + -- SYSTEM TRAY + -- =========== + local systray = wibox.widget.systray() + systray:set_horizontal(true) + + -- SYSTEM DETAILS + -- ============== + local volume_widget = require('widget.volume') + local battery_widget = require('widget.battery') + local clock_widget = require('widget.clock') + local mem_widget = require('widget.memory') + local cpu_widget = require('widget.cpu') + local temprature_widget = require('widget.temprature') + local storage_widget = require('widget.storage') + local system_details = wibox.widget { + systray, + separator, + battery, + --separator, + wibox.widget{ + wibox.widget{ + text = 'mem', + font = beautiful.icon_font, + widget = wibox.widget.textbox + }, + fg = beautiful.accent.hue_600, + widget = wibox.container.background + }, + mem_widget, + separator, + wibox.widget{ + wibox.widget{ + text = 'cpu', + font = beautiful.icon_font, + widget = wibox.widget.textbox + }, + fg = beautiful.accent.hue_500, + widget = wibox.container.background + }, + cpu_widget, + separator, + wibox.widget{ + wibox.widget{ + text = 'temp', + font = beautiful.icon_font, + widget = wibox.widget.textbox + }, + fg = beautiful.accent.hue_400, + widget = wibox.container.background + }, + temprature_widget, + separator, + wibox.widget{ + wibox.widget{ + text = 'disk', + font = beautiful.icon_font, + widget = wibox.widget.textbox + }, + fg = beautiful.accent.hue_200, + widget = wibox.container.background + }, + storage_widget, + separator, + wibox.widget{ + wibox.widget{ + text = 'vol', + font = beautiful.icon_font, + widget = wibox.widget.textbox + }, + fg = beautiful.accent.hue_500, + widget = wibox.container.background + }, + volume_widget, + separator, + wibox.widget{ + wibox.widget{ + text = 'date', + font = beautiful.icon_font, + widget = wibox.widget.textbox + }, + fg = beautiful.accent.hue_400, + widget = wibox.container.background + }, + clock_widget, + wibox.widget{ + s.layoutbox, + fg = beautiful.primary.hue_100, + bg = beautiful.accent.hue_200, + widget = wibox.container.background + }, + spacing = dpi(4), + layout = wibox.layout.fixed.horizontal + } + + local calendar = require('widget.calendar') + calendar:attach(clock_widget) + + -- TOP BAR + -- ======= + local panel = wibox({ + ontop = false, + screen = s, + height = dpi(20), + width = s.geometry.width, + x = s.geometry.x, + y = s.geometry.y, + stretch = false, + bg = beautiful.primary.hue_100, + fg = beautiful.fg_normal, + }) + + panel:struts({ + top = panel.height - panel.y + }) + + panel:setup{ + layout = wibox.layout.align.horizontal, + TagList(s), + nil, + system_details, + } + + return panel +end + +return TopBar diff --git a/module/auto-start.lua b/module/auto-start.lua new file mode 100644 index 0000000..b6d0746 --- /dev/null +++ b/module/auto-start.lua @@ -0,0 +1,19 @@ +-- MODULE AUTO-START +-- Run all the apps listed in configuration/apps.lua as run_on_start_up only once when awesome start + +local awful = require('awful') +local apps = require('configuration.apps') + +local function run_once(cmd) + local findme = cmd + local firstspace = cmd:find(' ') + if firstspace then + findme = cmd:sub(0, firstspace - 1) + end + awful.spawn.with_shell(string.format('pgrep -u $USER -x %s > /dev/null || (%s)', findme, cmd)) + --This broke compton ===> awful.spawn.single_instance(string.format('pgrep -u $USER -x %s > /dev/null || (%s)', findme, cmd)) +end + +for _, app in ipairs(apps.run_on_start_up) do + run_once(app) +end diff --git a/module/dashboard.lua b/module/dashboard.lua new file mode 100644 index 0000000..c899ca9 --- /dev/null +++ b/module/dashboard.lua @@ -0,0 +1,545 @@ +local awful = require('awful') +local gears = require('gears') +local wibox = require('wibox') +local beautiful = require('beautiful') +local icons = require('theme.icons') +local mat_list_item = require('widget.material.list-item') +local mat_icon = require('widget.material.icon') +local clickable_container = require('widget.material.clickable-container') +local apps = require('configuration.apps') +local dpi = require('beautiful').xresources.apply_dpi + +local icon_size = beautiful.dashboard_icon_size or dpi(140) +local username = os.getenv("USER") +local panel_style = gears.shape.rounded_rect + +local buildButton = function(icon, name) + local button_text = wibox.widget { + text = name, + font = beautiful.font, + align = 'center', + valign = 'center', + bg = beautiful.primary.hue_900, + fg = beautiful.fg_normal, + widget = wibox.widget.textbox + } + + local a_button = wibox.widget { + { + { + { + {image = icon, widget = wibox.widget.imagebox}, + margins = dpi(16), + widget = wibox.container.margin + }, + bg = beautiful.groups_bg, + widget = wibox.container.background + }, + shape = panel_style, + forced_width = dpi(60), + forced_height = dpi(60), + visible = true, + -- bg = beautiful.bg_normal, + widget = clickable_container + + }, + visible = true, + -- bg = beautiful.bg_normal, + shape = panel_style, + widget = wibox.container.background + } + + local build_a_button = wibox.widget { + layout = wibox.layout.fixed.horizontal, + spacing = dpi(5), + a_button + -- button_text + } + + return build_a_button +end + +local buildLabel = function(name) + local label_text = wibox.widget { + { + text = name, + font = beautiful.font_large, + align = 'center', + valign = 'center', + bg = beautiful.primary.hue_900, + fg = beautiful.fg_normal, + widget = wibox.widget.textbox + }, + shape = panel_style, + forced_height = dpi(56), + visible = true, + -- bg = beautiful.bg_normal, + widget = clickable_container + } + + local build_a_label = wibox.widget { + layout = wibox.layout.flex.horizontal, + spacing = dpi(5), + label_text + } + + return build_a_label +end + +function suspend_command() + dashboard_hide() + awful.spawn.with_shell(apps.default.lock .. ' & systemctl suspend') +end +function exit_command() _G.awesome.quit() end +function lock_command() + dashboard_hide() + awful.spawn.with_shell('sleep 1 && ' .. apps.default.lock) +end +function poweroff_command() + awful.spawn.with_shell('poweroff') + awful.keygrabber.stop(_G.dashboard_grabber) +end +function reboot_command() + awful.spawn.with_shell('reboot') + awful.keygrabber.stop(_G.dashboard_grabber) +end + +local poweroff = buildButton(icons.power, 'Shutdown') +poweroff:connect_signal('button::release', function() poweroff_command() end) + +local reboot = buildButton(icons.restart, 'Restart') +reboot:connect_signal('button::release', function() reboot_command() end) + +local suspend = buildButton(icons.sleep, 'Sleep') +suspend:connect_signal('button::release', function() suspend_command() end) + +local exit = buildButton(icons.logout, 'Logout') +exit:connect_signal('button::release', function() exit_command() end) + +local lock = buildButton(icons.lock, 'Lock') +lock:connect_signal('button::release', function() lock_command() end) + +local search = buildButton(icons.search, 'Search') +search:connect_signal('button::release', function() + -- rofi_command() + dashboard_hide() + _G.awesome.spawn(apps.default.rofi) +end) + +local close = buildButton(icons.close_dark, 'Close') +close:connect_signal('button::release', function() dashboard_hide() end) + +-- Get screen geometry +local screen_geometry = awful.screen.focused().geometry + +-- Create the widget +dashboard = wibox({ + x = screen_geometry.x, + y = screen_geometry.y, + visible = false, + ontop = true, + type = 'splash', + bg = beautiful.accent.hue_800 .. '66', + height = screen_geometry.height, + width = screen_geometry.width +}) + +local dashboard_grabber + +function dashboard_hide() + awful.keygrabber.stop(dashboard_grabber) + dashboard.visible = false +end + +function dashboard_show() + dashboard_grabber = awful.keygrabber.run( + function(_, key, event) + if event == 'release' then return end + + if key == 'Escape' or key == 'q' or key == 'x' or key == 'm' then + dashboard_hide() + end + end) + dashboard.visible = true +end + +dashboard:buttons(gears.table.join( -- Middle click - Hide dashboard +awful.button({}, 2, function() dashboard_hide() end), +awful.button({}, 3, function() dashboard_hide() end))) + +local profile_picture = os.getenv("HOME") .. + "/.face" + +local profile = wibox.widget { + wibox.widget { + { + { + { + { + image = profile_picture, + resize = true, + widget = wibox.widget.imagebox + }, + resize = true, + top = dpi(12), + right = dpi(12), + left = dpi(12), + widget = wibox.container.margin + }, + bg = beautiful.groups_bg, + shape = panel_style, + widget = wibox.container.background + }, + forced_width = dpi(244), + forced_height = dpi(244), + visible = true, + bg = beautiful.bg_normal, + shape = panel_style, + widget = wibox.container.background + }, + wibox.widget { + { + wibox.widget { + text = '@' .. username, + font = beautiful.font_large, + align = 'center', + valign = 'center', + widget = wibox.widget.textbox + }, + bottom = dpi(8), + widget = wibox.container.margin + }, + fg = beautiful.primary.hue_500, + widget = wibox.container.background + }, + layout = wibox.layout.fixed.vertical + }, + visible = true, + bg = beautiful.bg_normal, + shape = panel_style, + widget = wibox.container.background +} + +local power_options = wibox.widget { + { + poweroff, + reboot, + suspend, + exit, + lock, + layout = wibox.layout.flex.horizontal + }, + visible = true, + bg = beautiful.primary.hue_900, + shape = panel_style, + widget = wibox.container.background +} + +local search_button = wibox.widget { + { + search, + bg = beautiful.primary.hue_600, + layout = wibox.layout.fixed.vertical + }, + visible = true, + bg = beautiful.primary.hue_200, + shape = panel_style, + widget = wibox.container.background +} + +local close_button = wibox.widget { + { + close, + bg = beautiful.primary.hue_600, + layout = wibox.layout.fixed.vertical + }, + visible = true, + bg = beautiful.primary.hue_350, + shape = panel_style, + widget = wibox.container.background +} + +local quick_settings = wibox.widget { + { + { + require('layout.left-panel.dashboard.quick-settings'), + right = dpi(16), + bottom = dpi(12), + top = dpi(12), + widget = wibox.container.margin + }, + visible = true, + bg = beautiful.bg_normal, + shape = panel_style, + widget = wibox.container.background + }, + bg = beautiful.bg_normal, + shape = panel_style, + widget = wibox.container.background +} + +local hardware_monitor = wibox.widget { + { + require('layout.left-panel.dashboard.hardware-monitor'), + right = dpi(16), + bottom = dpi(12), + top = dpi(12), + widget = wibox.container.margin + }, + visible = true, + bg = beautiful.bg_normal, + shape = panel_style, + widget = wibox.container.background +} + +local cal = require('widget.calendar') + +--[[local calwidget = wibox.widget { + { + nil, + {cal, margins = dpi(16), widget = wibox.container.margin}, + nil, + layout = wibox.layout.flex.horizontal + }, + resize = true, + shape = panel_style, + bg = beautiful.bg_normal, + widget = wibox.container.background +}]] + +-- Fortune widget Credits: u/EmpressNoodle, github/elenapan +local fortune_command = "fortune -n 140 -s" +local fortune_update_interval = 3600 +-- local fortune_command = "fortune -n 140 -s computers" +local fortune = wibox.widget { + font = "Roboto 11", + text = "You so poor you don't even have a cookie yet...", + widget = wibox.widget.textbox +} + +local update_fortune = function() + awful.spawn.easy_async_with_shell(fortune_command, function(out) + -- Remove trailing whitespaces + out = out:gsub('^%s*(.-)%s*$', '%1') + fortune.markup = "" .. out .. "" + end) +end + +gears.timer { + autostart = true, + timeout = fortune_update_interval, + single_shot = false, + call_now = true, + callback = update_fortune +} + +local fortune_widget = wibox.widget { + { + {fortune, layout = wibox.layout.flex.horizontal}, + margins = dpi(16), + widget = wibox.container.margin + }, + bg = beautiful.primary.hue_700, + fg = beautiful.primary.hue_900, + shape = panel_style, + forced_height = dpi(112), + widget = wibox.container.background +} + +local uptime_text = wibox.widget.textbox() +uptime_text.font = "Roboto 10" +uptime_text.valign = "center" +awful.widget.watch("uptime -p | sed 's/^...//'", 60, function(_, stdout) + local out = stdout:gsub('^%s*(.-)%s*up', '%1') + uptime_text.text = out +end) + +local uptime_widget = wibox.widget { + { + { + { + image = icons.uptime, + resize = true, + forced_width = dpi(24), + widget = wibox.widget.imagebox + }, + uptime_text, + spacing = dpi(8), + layout = wibox.layout.fixed.horizontal + }, + margins = dpi(16), + widget = wibox.container.margin + }, + bg = beautiful.bg_normal, + shape = panel_style, + forced_height = dpi(48), + forced_width = dpi(182), + widget = wibox.container.background +} + +-- Bookmarks +function reddit_command() + dashboard_hide() + awful.spawn(apps.default.browser .. " " .. "reddit.com") +end + +function youtube_command() + dashboard_hide() + awful.spawn(apps.default.browser .. " " .. "youtube.com") +end + +function linkedin_command() + dashboard_hide() + awful.spawn(apps.default.browser .. " " .. "linkedin.com") +end + +function github_command() + dashboard_hide() + awful.spawn(apps.default.browser .. " " .. "github.com") +end + +function deviantart_command() + dashboard_hide() + awful.spawn(apps.default.browser .. " " .. "deviantart.com") +end + +function codeforces_command() + dashboard_hide() + awful.spawn(apps.default.browser .. " " .. "codeforces.com") +end + +function files_command(directory) + dashboard_hide() + awful.spawn(apps.default.files .. " " .. directory) +end + +local reddit = buildButton(icons.reddit, 'Reddit') +reddit:connect_signal('button::release', function() reddit_command() end) + +local youtube = buildButton(icons.youtube, 'Youtube') +youtube:connect_signal('button::release', function() youtube_command() end) + +local linkedin = buildButton(icons.linkedin, 'Linkedin') +linkedin:connect_signal('button::release', function() linkedin_command() end) + +local github = buildButton(icons.github, 'Github') +github:connect_signal('button::release', function() github_command() end) + +local deviantart = buildButton(icons.deviantart, 'Deviantart') +deviantart:connect_signal('button::release', function() deviantart_command() end) + +local codeforces = buildButton(icons.codeforces, 'Codeforces') +codeforces:connect_signal('button::release', function() codeforces_command() end) + +local home = buildLabel('Home') +home:connect_signal('button::release', function() files_command(".") end) + +local downloads = buildLabel('Downloads') +downloads:connect_signal('button::release', + function() files_command("Downloads") end) + +local desktop = buildLabel('Desktop') +desktop:connect_signal('button::release', + function() files_command("Desktop") end) + +local pictures = buildLabel('Pictures') +pictures:connect_signal('button::release', + function() files_command("Pictures") end) + +local videos = buildLabel('Videos') +videos:connect_signal('button::release', function() files_command("Videos") end) + +local documents = buildLabel('Documents') +documents:connect_signal('button::release', + function() files_command("Documents") end) + +local bookmarks = wibox.widget { + { + {reddit, youtube, linkedin, layout = wibox.layout.flex.horizontal}, + {github, deviantart, codeforces, layout = wibox.layout.ratio.horizontal}, + layout = wibox.layout.fixed.vertical + }, + visible = true, + bg = beautiful.bg_normal, + shape = panel_style, + forced_width = dpi(182), + widget = wibox.container.background +} + +local places = wibox.widget { + { + { + home, + desktop, + downloads, + pictures, + documents, + videos, + layout = wibox.layout.fixed.vertical + }, + layout = wibox.layout.fixed.vertical + }, + visible = true, + bg = beautiful.bg_normal, + shape = panel_style, + forced_width = dpi(182), + widget = wibox.container.background +} + +-- Item placement +dashboard:setup{ + nil, + { + nil, + { + { + search_button, + close_button, + spacing = dpi(10), + layout = wibox.layout.fixed.vertical + }, + { + { + { + quick_settings, + hardware_monitor, + fortune_widget, + forced_width = dpi(300), + spacing = dpi(10), + layout = wibox.layout.fixed.vertical + }, + { + bookmarks, + places, + spacing = dpi(10), + layout = wibox.layout.fixed.vertical + }, + spacing = dpi(10), + layout = wibox.layout.fixed.horizontal + }, + { + power_options, + uptime_widget, + spacing = dpi(10), + layout = wibox.layout.fixed.horizontal + }, + spacing = dpi(10), + layout = wibox.layout.fixed.vertical + }, + { + profile, + calWidget, + spacing = dpi(10), + layout = wibox.layout.fixed.vertical + }, + spacing = dpi(10), + layout = wibox.layout.fixed.horizontal + }, + nil, + expand = 'none', + layout = wibox.layout.align.horizontal + }, + {nil, expand = 'none', layout = wibox.layout.align.horizontal}, + expand = 'none', + layout = wibox.layout.align.vertical +} diff --git a/module/decorate-client.lua b/module/decorate-client.lua new file mode 100644 index 0000000..f5c2405 --- /dev/null +++ b/module/decorate-client.lua @@ -0,0 +1,93 @@ +local awful = require('awful') +local gears = require('gears') +local beautiful = require('beautiful') +local dpi = require('beautiful').xresources.apply_dpi + +local function renderClient(client, mode) + if client.skip_decoration or (client.rendering_mode == mode) then + return + end + + client.rendering_mode = mode + client.floating = false + client.maximized = false + client.above = false + client.below = false + client.ontop = false + client.sticky = false + client.maximized_horizontal = false + client.maximized_vertical = false + + client.border_width = beautiful.border_width + client.shape = function(cr, w, h) + gears.shape.rectangle(cr, w, h) + end +end + +local changesOnScreenCalled = false + +local function changesOnScreen(currentScreen) + local tagIsMax = currentScreen.selected_tag ~= nil and currentScreen.selected_tag.layout == awful.layout.suit.max + local clientsToManage = {} + + for _, client in pairs(currentScreen.clients) do + if not client.skip_decoration and not client.hidden then + table.insert(clientsToManage, client) + end + end + + if (tagIsMax or #clientsToManage == 1) then + currentScreen.client_mode = 'maximized' + else + currentScreen.client_mode = 'tiled' + end + + for _, client in pairs(clientsToManage) do + renderClient(client, currentScreen.client_mode) + end + changesOnScreenCalled = false +end + +function clientCallback(client) + if not changesOnScreenCalled then + if not client.skip_decoration and client.screen then + changesOnScreenCalled = true + local screen = client.screen + gears.timer.delayed_call(function() + changesOnScreen(screen) + end) + end + end +end + +function tagCallback(tag) + if not changesOnScreenCalled then + if tag.screen then + changesOnScreenCalled = true + local screen = tag.screen + gears.timer.delayed_call(function() + changesOnScreen(screen) + end) + end + end +end + +_G.client.connect_signal('manage', clientCallback) + +_G.client.connect_signal('unmanage', clientCallback) + +_G.client.connect_signal('property::hidden', clientCallback) + +_G.client.connect_signal('property::minimized', clientCallback) + +_G.client.connect_signal('property::fullscreen', function(c) + if c.fullscreen then + renderClient(c, 'maximized') + else + clientCallback(c) + end +end) + +_G.tag.connect_signal('property::selected', tagCallback) + +_G.tag.connect_signal('property::layout', tagCallback) diff --git a/module/exit-screen.lua b/module/exit-screen.lua new file mode 100644 index 0000000..4af3a31 --- /dev/null +++ b/module/exit-screen.lua @@ -0,0 +1,201 @@ +local awful = require('awful') +local gears = require('gears') +local wibox = require('wibox') +local beautiful = require('beautiful') +local icons = require('theme.icons') +local clickable_container = require('widget.material.clickable-container') +local apps = require('configuration.apps') +local dpi = require('beautiful').xresources.apply_dpi + +-- Appearance +local icon_size = beautiful.exit_screen_icon_size or dpi(140) + +local buildButton = function(icon) + local abutton = + wibox.widget { + wibox.widget { + wibox.widget { + wibox.widget { + image = icon, + widget = wibox.widget.imagebox + }, + top = dpi(16), + bottom = dpi(16), + left = dpi(16), + right = dpi(16), + widget = wibox.container.margin + }, + shape = gears.shape.circle, + forced_width = icon_size, + forced_height = icon_size, + widget = clickable_container + }, + left = dpi(24), + right = dpi(24), + widget = wibox.container.margin + } + + return abutton +end + +function suspend_command() + exit_screen_hide() + awful.spawn.with_shell(apps.default.lock .. ' & systemctl suspend') +end +function exit_command() + _G.awesome.quit() +end +function lock_command() + exit_screen_hide() + awful.spawn.with_shell('sleep 1 && ' .. apps.default.lock) +end +function poweroff_command() + awful.spawn.with_shell('poweroff') + awful.keygrabber.stop(_G.exit_screen_grabber) +end +function reboot_command() + awful.spawn.with_shell('reboot') + awful.keygrabber.stop(_G.exit_screen_grabber) +end + +local poweroff = buildButton(icons.power, 'Shutdown') +poweroff:connect_signal( + 'button::release', + function() + poweroff_command() + end +) + +local reboot = buildButton(icons.restart, 'Restart') +reboot:connect_signal( + 'button::release', + function() + reboot_command() + end +) + +local suspend = buildButton(icons.sleep, 'Sleep') +suspend:connect_signal( + 'button::release', + function() + suspend_command() + end +) + +local exit = buildButton(icons.logout, 'Logout') +exit:connect_signal( + 'button::release', + function() + exit_command() + end +) + +local lock = buildButton(icons.lock, 'Lock') +lock:connect_signal( + 'button::release', + function() + lock_command() + end +) + +-- Get screen geometry +local screen_geometry = awful.screen.focused().geometry + +-- Create the widget +exit_screen = + wibox( + { + x = screen_geometry.x, + y = screen_geometry.y, + visible = false, + ontop = true, + type = 'splash', + height = screen_geometry.height, + width = screen_geometry.width + } +) + +exit_screen.bg = '#212121CC' +--exit_screen.fg = beautiful.exit_screen_fg or beautiful.wibar_fg or '#FEFEFE' + +local exit_screen_grabber + +function exit_screen_hide() + awful.keygrabber.stop(exit_screen_grabber) + exit_screen.visible = false +end + +function exit_screen_show() + -- naughty.notify({text = "starting the keygrabber"}) + exit_screen_grabber = + awful.keygrabber.run( + function(_, key, event) + if event == 'release' then + return + end + + if key == 's' then + suspend_command() + elseif key == 'e' then + exit_command() + elseif key == 'l' then + lock_command() + elseif key == 'p' then + poweroff_command() + elseif key == 'r' then + reboot_command() + elseif key == 'Escape' or key == 'q' or key == 'x' then + -- naughty.notify({text = "Cancel"}) + exit_screen_hide() + -- else awful.keygrabber.stop(exit_screen_grabber) + end + end + ) + exit_screen.visible = true +end + +exit_screen:buttons( + gears.table.join( + -- Middle click - Hide exit_screen + awful.button( + {}, + 2, + function() + exit_screen_hide() + end + ), + -- Right click - Hide exit_screen + awful.button( + {}, + 3, + function() + exit_screen_hide() + end + ) + ) +) + +-- Item placement +exit_screen:setup { + nil, + { + nil, + { + -- { + poweroff, + reboot, + suspend, + exit, + lock, + layout = wibox.layout.fixed.horizontal + -- }, + -- widget = exit_screen_box + }, + nil, + expand = 'none', + layout = wibox.layout.align.horizontal + }, + nil, + expand = 'none', + layout = wibox.layout.align.vertical +} diff --git a/module/notifications.lua b/module/notifications.lua new file mode 100644 index 0000000..c54fac4 --- /dev/null +++ b/module/notifications.lua @@ -0,0 +1,53 @@ +local naughty = require('naughty') +local beautiful = require('beautiful') +local gears = require('gears') +local dpi = require('beautiful').xresources.apply_dpi + +-- Naughty presets +naughty.config.padding = 8 +naughty.config.spacing = 8 + +naughty.config.defaults.timeout = 10 +naughty.config.defaults.screen = 1 +naughty.config.defaults.position = 'top_right' +naughty.config.defaults.margin = dpi(16) +naughty.config.defaults.ontop = true +naughty.config.defaults.font = beautiful.font +--naughty.config.defaults.icon = nil +naughty.config.defaults.icon_size = dpi(32) +naughty.config.defaults.shape = gears.shape.rounded_rect +naughty.config.defaults.border_width = dpi(0) +naughty.config.defaults.hover_timeout = nil + +-- Error handling +if _G.awesome.startup_errors then + naughty.notify({ + preset = naughty.config.presets.critical, + title = 'Oops, there were errors during startup!', + text = _G.awesome.startup_errors + }) +end + +do + local in_error = false + _G.awesome.connect_signal('debug::error', function(err) + if in_error then + return + end + in_error = true + + naughty.notify({ + preset = naughty.config.presets.critical, + title = 'Oops, an error happened!', + text = tostring(err) + }) + in_error = false + end) +end + +function log_this(title, txt) + naughty.notify({ + title = 'log: ' .. title, + text = txt + }) +end diff --git a/module/splash-terminal.lua b/module/splash-terminal.lua new file mode 100644 index 0000000..b522970 --- /dev/null +++ b/module/splash-terminal.lua @@ -0,0 +1,79 @@ +local awful = require('awful') +local app = require('configuration.apps').default.splash +local dpi = require('beautiful').xresources.apply_dpi +local beautiful = require('beautiful') +local screen = awful.screen.focused() + +-- Theme +beautiful.init(require('theme')) + +local splash_id = 'notnil' +local splash_client +local opened = false + +function create_shell() + splash_id = awful.spawn.with_shell(app) +end + +-- Dirty hack to prevent splash from showing up in occupied tags +function _splash_to_current_tag() + if splash_client then + splash_client:move_to_tag(screen.selected_tag) + end +end + +function open_splash() + splash_client.hidden = false +end + +function close_splash() + splash_client.hidden = true +end + +toggle_splash_height = function() + if splash_client and opened then + splash_client.maximized_vertical = not splash_client.maximized_vertical + end +end + +toggle_splash = function() + opened = not opened + if not splash_client then + create_shell() + else + if opened then + open_splash() + client.focus = splash_client + splash_client:raise() + else + close_splash() + end + end +end + +_G.client.connect_signal('manage', function(c) + if (c.pid == splash_id) then + splash_client = c + c.x = c.screen.geometry.x + c.height = (c.screen.geometry.height / 5) * 3 + c.y = c.screen.geometry.height - c.height - beautiful.border_width - dpi(16) + c.floating = true + c.skip_taskbar = true + c.skip_decoration = true + c.ontop = true + c.floating = true + c.above = true + c.sticky = true + c.type = 'splash' + c.hidden = not opened + c.border_width = beautiful.border_width + c.maximized_horizontal = true + end +end) + +_G.client.connect_signal('unmanage', function(c) + if (c.pid == splash_id) then + opened = false + splash_client = nil + end +end) diff --git a/rc.lua b/rc.lua new file mode 100644 index 0000000..6e0bf73 --- /dev/null +++ b/rc.lua @@ -0,0 +1,53 @@ +require('awful.autofocus') +local gears = require('gears') +local awful = require('awful') +local naughty = require('naughty') +local beautiful = require('beautiful') + +-- Theme +beautiful.init(require('theme')) + +-- Layout +require('layout') + +-- Init all modules +require('module.notifications') +require('module.auto-start') +require('module.decorate-client') +require('module.splash-terminal') +require('module.exit-screen') +require('module.dashboard') + +-- Setup all configurations +require('configuration.client') +require('configuration.tags') +_G.root.keys(require('configuration.keys.global')) + +-- Signal function to execute when a new client appears. +_G.client.connect_signal('manage', function(c) + -- Set the windows at the slave, + -- i.e. put it at the end of others instead of setting it master. + if not _G.awesome.startup then + awful.client.setslave(c) + end + + if _G.awesome.startup and not c.size_hints.user_position and not c.size_hints.program_position then + -- Prevent clients from being unreachable after screen count changes. + awful.placement.no_offscreen(c) + end +end) + +--[[ Enable sloppy focus, so that focus follows mouse. +_G.client.connect_signal('mouse::enter', function(c) + c:emit_signal('request::activate', 'mouse_enter', {raise = true}) +end) +--]] + +-- Make the focused window have a glowing border +_G.client.connect_signal('focus', function(c) + c.border_color = beautiful.border_focus +end) +_G.client.connect_signal('unfocus', function(c) + c.border_color = beautiful.border_normal +end) + diff --git a/theme/color-schemes.lua b/theme/color-schemes.lua new file mode 100644 index 0000000..0ef2ab9 --- /dev/null +++ b/theme/color-schemes.lua @@ -0,0 +1,67 @@ +return { + dracula = { + primary = { + hue_100 = '#282a36', + hue_200 = '#44475a' + }, + accent = { + hue_100 = '#f1fa8c', + hue_200 = '#50fa7b', + hue_300 = '#8be9fd', + hue_400 = '#ff5555', + hue_500 = '#6272a4', + hue_600 = '#ff79c6', + hue_700 = '#ffb86c', + hue_800 = '#f8f8f2', + } + }, + gruvbox = { + primary = { + hue_100 = '#282828', + hue_200 = '#3c3c3c' + }, + accent = { + hue_100 = '#fe8019', + hue_200 = '#fabd2f', + hue_300 = '#8ec07c', + hue_400 = '#fb4934', + hue_500 = '#d3869b', + hue_600 = '#b8bb26', + hue_700 = '#458588', + hue_800 = '#fbf1c7', + } + }, + gruvbox_material = { + primary = { + hue_100 = '#212121', + hue_200 = '#3c3c3c' + }, + accent = { + hue_100 = '#e1be7f', -- orange-ish + hue_200 = '#92c96a', -- green - MAIN + hue_300 = '#66aeea', -- light blue + hue_400 = '#f35a5a', -- light red + hue_500 = '#4083bc', -- dark blue + hue_600 = '#c57cda', -- light magenta + hue_700 = '#cd996a', -- light brown + hue_800 = '#d6d6d6', -- light gray + } + }, + flat_remix_teal = { + primary = { + hue_100 = '#212121', + hue_200 = '#3c3c3c' + }, + accent = { + hue_100 = '#e1be7f', -- orange-ish + hue_200 = '#458ECC', -- green - MAIN + --hue_200 = '#06A284', -- green - MAIN + hue_300 = '#66aeea', -- light blue + hue_400 = '#f35a5a', -- light red + hue_500 = '#4083bc', -- dark blue + hue_600 = '#c57cda', -- light magenta + hue_700 = '#25B29B', -- light brown + hue_800 = '#d6d6d6', -- light gray + } + } +} diff --git a/theme/icons/brave.svg b/theme/icons/brave.svg new file mode 100644 index 0000000..f4b0a6a --- /dev/null +++ b/theme/icons/brave.svg @@ -0,0 +1,60 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/theme/icons/brightness-7.svg b/theme/icons/brightness-7.svg new file mode 100644 index 0000000..fe7aa9d --- /dev/null +++ b/theme/icons/brightness-7.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/chart-areaspline.svg b/theme/icons/chart-areaspline.svg new file mode 100644 index 0000000..9941ba5 --- /dev/null +++ b/theme/icons/chart-areaspline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/close.svg b/theme/icons/close.svg new file mode 100644 index 0000000..3f1f88c --- /dev/null +++ b/theme/icons/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/code-braces.svg b/theme/icons/code-braces.svg new file mode 100644 index 0000000..6adb566 --- /dev/null +++ b/theme/icons/code-braces.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/firefox.svg b/theme/icons/firefox.svg new file mode 100644 index 0000000..adfff2a --- /dev/null +++ b/theme/icons/firefox.svg @@ -0,0 +1,52 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/theme/icons/flask.svg b/theme/icons/flask.svg new file mode 100644 index 0000000..dba8a2f --- /dev/null +++ b/theme/icons/flask.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/folder.svg b/theme/icons/folder.svg new file mode 100644 index 0000000..146c65b --- /dev/null +++ b/theme/icons/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/forum.svg b/theme/icons/forum.svg new file mode 100644 index 0000000..08bd17e --- /dev/null +++ b/theme/icons/forum.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/google-chrome.svg b/theme/icons/google-chrome.svg new file mode 100644 index 0000000..6c68b70 --- /dev/null +++ b/theme/icons/google-chrome.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/google-controller.svg b/theme/icons/google-controller.svg new file mode 100644 index 0000000..12c6869 --- /dev/null +++ b/theme/icons/google-controller.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/harddisk.svg b/theme/icons/harddisk.svg new file mode 100644 index 0000000..f0b97b9 --- /dev/null +++ b/theme/icons/harddisk.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/init.lua b/theme/icons/init.lua new file mode 100644 index 0000000..9e27d0d --- /dev/null +++ b/theme/icons/init.lua @@ -0,0 +1,29 @@ +local dir = os.getenv('HOME') .. '/.config/awesome/theme/icons' + +return { + --tags + chrome = dir .. '/firefox.svg', + code = dir .. '/code-braces.svg', + social = dir .. '/forum.svg', + folder = dir .. '/folder.svg', + music = dir .. '/music.svg', + game = dir .. '/google-controller.svg', + lab = dir .. '/flask.svg', + play = dir .. '/play.svg', + --others + menu = dir .. '/menu.svg', + close = dir .. '/close.svg', + logout = dir .. '/logout.svg', + sleep = dir .. '/power-sleep.svg', + power = dir .. '/power.svg', + lock = dir .. '/lock.svg', + restart = dir .. '/restart.svg', + search = dir .. '/magnify.svg', + volume = dir .. '/volume-high.svg', + brightness = dir .. '/brightness-7.svg', + chart = dir .. '/chart-areaspline.svg', + memory = dir .. '/memory.svg', + harddisk = dir .. '/harddisk.svg', + thermometer = dir .. '/thermometer.svg', + plus = dir .. '/plus.svg' +} diff --git a/theme/icons/layouts/arrow-expand-all.png b/theme/icons/layouts/arrow-expand-all.png new file mode 100644 index 0000000..2837ec1 Binary files /dev/null and b/theme/icons/layouts/arrow-expand-all.png differ diff --git a/theme/icons/layouts/view-quilt.png b/theme/icons/layouts/view-quilt.png new file mode 100644 index 0000000..d2e8f5b Binary files /dev/null and b/theme/icons/layouts/view-quilt.png differ diff --git a/theme/icons/lock.svg b/theme/icons/lock.svg new file mode 100644 index 0000000..be008aa --- /dev/null +++ b/theme/icons/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/logout.svg b/theme/icons/logout.svg new file mode 100644 index 0000000..a21eba9 --- /dev/null +++ b/theme/icons/logout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/magnify.svg b/theme/icons/magnify.svg new file mode 100644 index 0000000..bf67346 --- /dev/null +++ b/theme/icons/magnify.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/memory.svg b/theme/icons/memory.svg new file mode 100644 index 0000000..f2ab11c --- /dev/null +++ b/theme/icons/memory.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/menu.svg b/theme/icons/menu.svg new file mode 100644 index 0000000..a6c9c25 --- /dev/null +++ b/theme/icons/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/music.svg b/theme/icons/music.svg new file mode 100644 index 0000000..f9da5f0 --- /dev/null +++ b/theme/icons/music.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/play.svg b/theme/icons/play.svg new file mode 100644 index 0000000..7e75510 --- /dev/null +++ b/theme/icons/play.svg @@ -0,0 +1,97 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/theme/icons/plus.svg b/theme/icons/plus.svg new file mode 100644 index 0000000..e3b6570 --- /dev/null +++ b/theme/icons/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/power-sleep.svg b/theme/icons/power-sleep.svg new file mode 100644 index 0000000..18bb026 --- /dev/null +++ b/theme/icons/power-sleep.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/power.svg b/theme/icons/power.svg new file mode 100644 index 0000000..d0bc700 --- /dev/null +++ b/theme/icons/power.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/restart.svg b/theme/icons/restart.svg new file mode 100644 index 0000000..4a9877e --- /dev/null +++ b/theme/icons/restart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/ship-wheel.svg b/theme/icons/ship-wheel.svg new file mode 100644 index 0000000..dc4ed3e --- /dev/null +++ b/theme/icons/ship-wheel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/tag-list/occupied.png b/theme/icons/tag-list/occupied.png new file mode 100644 index 0000000..e7ccbf0 Binary files /dev/null and b/theme/icons/tag-list/occupied.png differ diff --git a/theme/icons/tag-list/panel.png b/theme/icons/tag-list/panel.png new file mode 100644 index 0000000..d7699ce Binary files /dev/null and b/theme/icons/tag-list/panel.png differ diff --git a/theme/icons/tag-list/selected.png b/theme/icons/tag-list/selected.png new file mode 100644 index 0000000..897f960 Binary files /dev/null and b/theme/icons/tag-list/selected.png differ diff --git a/theme/icons/tag-list/tag/close.png b/theme/icons/tag-list/tag/close.png new file mode 100644 index 0000000..fc93da0 Binary files /dev/null and b/theme/icons/tag-list/tag/close.png differ diff --git a/theme/icons/tag-list/tag/code-braces.png b/theme/icons/tag-list/tag/code-braces.png new file mode 100644 index 0000000..c16729c Binary files /dev/null and b/theme/icons/tag-list/tag/code-braces.png differ diff --git a/theme/icons/tag-list/tag/flask.png b/theme/icons/tag-list/tag/flask.png new file mode 100644 index 0000000..da03025 Binary files /dev/null and b/theme/icons/tag-list/tag/flask.png differ diff --git a/theme/icons/tag-list/tag/folder.png b/theme/icons/tag-list/tag/folder.png new file mode 100644 index 0000000..f9565ef Binary files /dev/null and b/theme/icons/tag-list/tag/folder.png differ diff --git a/theme/icons/tag-list/tag/forum.png b/theme/icons/tag-list/tag/forum.png new file mode 100644 index 0000000..d06a197 Binary files /dev/null and b/theme/icons/tag-list/tag/forum.png differ diff --git a/theme/icons/tag-list/tag/google-chrome.png b/theme/icons/tag-list/tag/google-chrome.png new file mode 100644 index 0000000..6f8f589 Binary files /dev/null and b/theme/icons/tag-list/tag/google-chrome.png differ diff --git a/theme/icons/tag-list/tag/google-controller.png b/theme/icons/tag-list/tag/google-controller.png new file mode 100644 index 0000000..3d37722 Binary files /dev/null and b/theme/icons/tag-list/tag/google-controller.png differ diff --git a/theme/icons/tag-list/tag/home.png b/theme/icons/tag-list/tag/home.png new file mode 100644 index 0000000..d907479 Binary files /dev/null and b/theme/icons/tag-list/tag/home.png differ diff --git a/theme/icons/tag-list/tag/music.png b/theme/icons/tag-list/tag/music.png new file mode 100644 index 0000000..d2ca843 Binary files /dev/null and b/theme/icons/tag-list/tag/music.png differ diff --git a/theme/icons/tag-list/unselected.png b/theme/icons/tag-list/unselected.png new file mode 100644 index 0000000..8e5563c Binary files /dev/null and b/theme/icons/tag-list/unselected.png differ diff --git a/theme/icons/tag-list/urgent.png b/theme/icons/tag-list/urgent.png new file mode 100644 index 0000000..d943de1 Binary files /dev/null and b/theme/icons/tag-list/urgent.png differ diff --git a/theme/icons/thermometer.svg b/theme/icons/thermometer.svg new file mode 100644 index 0000000..d901827 --- /dev/null +++ b/theme/icons/thermometer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/icons/volume-high.svg b/theme/icons/volume-high.svg new file mode 100644 index 0000000..9bee38d --- /dev/null +++ b/theme/icons/volume-high.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/theme/init.lua b/theme/init.lua new file mode 100644 index 0000000..20c672b --- /dev/null +++ b/theme/init.lua @@ -0,0 +1,10 @@ +local gtable = require('gears.table') +local theme = require('theme.theme') + +local final_theme = {} +gtable.crush(final_theme, theme.theme) +gtable.crush(final_theme, theme.theme) +theme.awesome_overrides(final_theme) +theme.awesome_overrides(final_theme) + +return final_theme diff --git a/theme/mat-colors.lua b/theme/mat-colors.lua new file mode 100644 index 0000000..44748f6 --- /dev/null +++ b/theme/mat-colors.lua @@ -0,0 +1,317 @@ +return { + -- Red + red = { + hue_50 = '#FFEBEE', + hue_100 = '#FFCDD2', + hue_200 = '#EF9A9A', + hue_300 = '#E57373', + hue_400 = '#EF5350', + hue_500 = '#F44336', + hue_600 = '#E53935', + hue_700 = '#D32F2F', + hue_800 = '#C62828', + hue_900 = '#B71C1C', + hue_A100 = '#FF8A80', + hue_A200 = '#FF5252', + hue_A400 = '#FF1744', + hue_A700 = '#D50000' + }, + -- Pink + pink = { + hue_50 = '#FCE4EC', + hue_100 = '#F8BBD0', + hue_200 = '#F48FB1', + hue_300 = '#F06292', + hue_400 = '#EC407A', + hue_500 = '#E91E63', + hue_600 = '#D81B60', + hue_700 = '#C2185B', + hue_800 = '#AD1457', + hue_900 = '#880E4F', + hue_A100 = '#FF80AB', + hue_A200 = '#FF4081', + hue_A400 = '#F50057', + hue_A700 = '#C51162' + }, + -- Purple + purle = { + hue_50 = '#F3E5F5', + hue_100 = '#E1BEE7', + hue_200 = '#CE93D8', + hue_300 = '#BA68C8', + hue_400 = '#AB47BC', + hue_500 = '#9C27B0', + hue_600 = '#8E24AA', + hue_700 = '#7B1FA2', + hue_800 = '#6A1B9A', + hue_900 = '#4A148C', + hue_A100 = '#EA80FC', + hue_A200 = '#E040FB', + hue_A400 = '#D500F9', + hue_A700 = '#AA00FF' + }, + -- Deep Purple + hue_purple = { + hue_50 = '#EDE7F6', + hue_100 = '#D1C4E9', + hue_200 = '#B39DDB', + hue_300 = '#9575CD', + hue_400 = '#7E57C2', + hue_500 = '#673AB7', + hue_600 = '#5E35B1', + hue_700 = '#512DA8', + hue_800 = '#4527A0', + hue_900 = '#311B92', + hue_A100 = '#B388FF', + hue_A200 = '#7C4DFF', + hue_A400 = '#651FFF', + hue_A700 = '#6200EA' + }, + -- Indigo + indigo = { + hue_50 = '#E8EAF6', + hue_100 = '#C5CAE9', + hue_200 = '#9FA8DA', + hue_300 = '#7986CB', + hue_400 = '#5C6BC0', + hue_500 = '#3F51B5', + hue_600 = '#3949AB', + hue_700 = '#303F9F', + hue_800 = '#283593', + hue_900 = '#1A237E', + hue_A100 = '#8C9EFF', + hue_A200 = '#536DFE', + hue_A400 = '#3D5AFE', + hue_A700 = '#304FFE' + }, + -- Blue + blue = { + hue_50 = '#E3F2FD', + hue_100 = '#BBDEFB', + hue_200 = '#90CAF9', + hue_300 = '#64B5F6', + hue_400 = '#42A5F5', + hue_500 = '#2196F3', + hue_600 = '#1E88E5', + hue_700 = '#1976D2', + hue_800 = '#1565C0', + hue_900 = '#0D47A1', + hue_A100 = '#82B1FF', + hue_A200 = '#448AFF', + hue_A400 = '#2979FF', + hue_A700 = '#2962FF' + }, + -- Light Blue + hue_blue = { + hue_50 = '#E1F5FE', + hue_100 = '#B3E5FC', + hue_200 = '#81D4FA', + hue_300 = '#4FC3F7', + hue_400 = '#29B6F6', + hue_500 = '#03A9F4', + hue_600 = '#039BE5', + hue_700 = '#0288D1', + hue_800 = '#0277BD', + hue_900 = '#01579B', + hue_A100 = '#80D8FF', + hue_A200 = '#40C4FF', + hue_A400 = '#00B0FF', + hue_A700 = '#0091EA' + }, + -- Cyan + cyan = { + hue_50 = '#E0F7FA', + hue_100 = '#B2EBF2', + hue_200 = '#80DEEA', + hue_300 = '#4DD0E1', + hue_400 = '#26C6DA', + hue_500 = '#00BCD4', + hue_600 = '#00ACC1', + hue_700 = '#0097A7', + hue_800 = '#00838F', + hue_900 = '#006064', + hue_A100 = '#84FFFF', + hue_A200 = '#18FFFF', + hue_A400 = '#00E5FF', + hue_A700 = '#00B8D4' + }, + -- Teal + teal = { + hue_50 = '#E0F2F1', + hue_100 = '#B2DFDB', + hue_200 = '#80CBC4', + hue_300 = '#4DB6AC', + hue_400 = '#26A69A', + hue_500 = '#009688', + hue_600 = '#00897B', + hue_700 = '#00796B', + hue_800 = '#00695C', + hue_900 = '#004D40', + hue_A100 = '#A7FFEB', + hue_A200 = '#64FFDA', + hue_A400 = '#1DE9B6', + hue_A700 = '#00BFA5' + }, + -- Green + green = { + hue_50 = '#E8F5E9', + hue_100 = '#C8E6C9', + hue_200 = '#A5D6A7', + hue_300 = '#81C784', + hue_400 = '#66BB6A', + hue_500 = '#4CAF50', + hue_600 = '#43A047', + hue_700 = '#388E3C', + hue_800 = '#2E7D32', + hue_900 = '#1B5E20', + hue_A100 = '#B9F6CA', + hue_A200 = '#69F0AE', + hue_A400 = '#00E676', + hue_A700 = '#00C853' + }, + -- Light Green + hue_green = { + hue_50 = '#F1F8E9', + hue_100 = '#DCEDC8', + hue_200 = '#C5E1A5', + hue_300 = '#AED581', + hue_400 = '#9CCC65', + hue_500 = '#8BC34A', + hue_600 = '#7CB342', + hue_700 = '#689F38', + hue_800 = '#558B2F', + hue_900 = '#33691E', + hue_A100 = '#CCFF90', + hue_A200 = '#B2FF59', + hue_A400 = '#76FF03', + hue_A700 = '#64DD17' + }, + -- Lime + lime = { + hue_50 = '#F9FBE7', + hue_100 = '#F0F4C3', + hue_200 = '#E6EE9C', + hue_300 = '#DCE775', + hue_400 = '#D4E157', + hue_500 = '#CDDC39', + hue_600 = '#C0CA33', + hue_700 = '#AFB42B', + hue_800 = '#9E9D24', + hue_900 = '#827717', + hue_A100 = '#F4FF81', + hue_A200 = '#EEFF41', + hue_A400 = '#C6FF00', + hue_A700 = '#AEEA00' + }, + -- Yellow + yellow = { + hue_50 = '#FFFDE7', + hue_100 = '#FFF9C4', + hue_200 = '#FFF59D', + hue_300 = '#FFF176', + hue_400 = '#FFEE58', + hue_500 = '#FFEB3B', + hue_600 = '#FDD835', + hue_700 = '#FBC02D', + hue_800 = '#F9A825', + hue_900 = '#F57F17', + hue_A100 = '#FFFF8D', + hue_A200 = '#FFFF00', + hue_A400 = '#FFEA00', + hue_A700 = '#FFD600' + }, + -- Amber + amber = { + hue_50 = '#FFF8E1', + hue_100 = '#FFECB3', + hue_200 = '#FFE082', + hue_300 = '#FFD54F', + hue_400 = '#FFCA28', + hue_500 = '#FFC107', + hue_600 = '#FFB300', + hue_700 = '#FFA000', + hue_800 = '#FF8F00', + hue_900 = '#FF6F00', + hue_A100 = '#FFE57F', + hue_A200 = '#FFD740', + hue_A400 = '#FFC400', + hue_A700 = '#FFAB00' + }, + -- Orange + orange = { + hue_50 = '#FFF3E0', + hue_100 = '#FFE0B2', + hue_200 = '#FFCC80', + hue_300 = '#FFB74D', + hue_400 = '#FFA726', + hue_500 = '#FF9800', + hue_600 = '#FB8C00', + hue_700 = '#F57C00', + hue_800 = '#EF6C00', + hue_900 = '#E65100', + hue_A100 = '#FFD180', + hue_A200 = '#FFAB40', + hue_A400 = '#FF9100', + hue_A700 = '#FF6D00' + }, + -- Deep Orange + deep_orange = { + hue_50 = '#FBE9E7', + hue_100 = '#FFCCBC', + hue_200 = '#FFAB91', + hue_300 = '#FF8A65', + hue_400 = '#FF7043', + hue_500 = '#FF5722', + hue_600 = '#F4511E', + hue_700 = '#E64A19', + hue_800 = '#D84315', + hue_900 = '#BF360C', + hue_A100 = '#FF9E80', + hue_A200 = '#FF6E40', + hue_A400 = '#FF3D00', + hue_A700 = '#DD2C00' + }, + -- Brown + brown = { + hue_50 = '#EFEBE9', + hue_100 = '#D7CCC8', + hue_200 = '#BCAAA4', + hue_300 = '#A1887F', + hue_400 = '#8D6E63', + hue_500 = '#795548', + hue_600 = '#6D4C41', + hue_700 = '#5D4037', + hue_800 = '#4E342E', + hue_900 = '#3E2723' + }, + -- Grey + grey = { + hue_50 = '#FAFAFA', + hue_100 = '#F5F5F5', + hue_200 = '#EEEEEE', + hue_300 = '#E0E0E0', + hue_400 = '#BDBDBD', + hue_500 = '#9E9E9E', + hue_600 = '#757575', + hue_700 = '#616161', + hue_800 = '#424242', + hue_900 = '#212121' + }, + -- Blue Grey + blue_grey = { + hue_50 = '#ECEFF1', + hue_100 = '#CFD8DC', + hue_200 = '#B0BEC5', + hue_300 = '#90A4AE', + hue_400 = '#78909C', + hue_500 = '#607D8B', + hue_600 = '#546E7A', + hue_700 = '#455A64', + hue_800 = '#37474F', + hue_900 = '#263238' + }, + -- Black + black = '#000000', + -- White + white = '#FFFFFF' +} diff --git a/theme/theme.lua b/theme/theme.lua new file mode 100644 index 0000000..a41b58c --- /dev/null +++ b/theme/theme.lua @@ -0,0 +1,62 @@ +local filesystem = require('gears.filesystem') +local color_schemes = require('theme.color-schemes') +local theme_dir = filesystem.get_configuration_dir() .. '/theme' +local gears = require('gears') +local dpi = require('beautiful').xresources.apply_dpi +local theme = {} + +-- Color Scheme +theme.primary = color_schemes.flat_remix_teal.primary +theme.accent = color_schemes.flat_remix_teal.accent + +local awesome_overrides = function(theme) + theme.dir = os.getenv('HOME') .. '/.config/awesome/theme' + + theme.icons = theme.dir .. '/.config/awesome/theme/icons/' + theme.font = 'Product Sans Regular 9' -- Glyphs don't work properly with this (#442) + --theme.font = 'Robotomono nerd font 9' -- Glyphs don't work properly with this (#442) + theme.font_large = 'Product Sans Regular 11' + theme.icon_font = 'Product Sans Medium 10' -- Fira mono patched version + --theme.icon_font = 'firamono nerd font 11' -- Fira mono patched version + + -- Layout icons + theme.layout_txt_tile = "|til|" + theme.layout_txt_max = "|max|" + theme.layout_txt_fair = "|fai|" + theme.layout_txt_spiral_dwindle = "|spi|" + theme.layout_txt_floating = "|flt|" + + -- Taglist + theme.taglist_font = theme.font + theme.taglist_bg_empty = theme.primary.hue_100 + theme.taglist_bg_occupied = 'linear:0,0:0,' .. dpi(32) .. ':0,' .. + theme.primary.hue_200 .. ':0.1,' .. + theme.primary.hue_200 .. ':0.1,' .. + theme.primary.hue_100 .. ':0.9,' .. + theme.primary.hue_100 + theme.taglist_bg_urgent = 'linear:0,0:0,' .. dpi(48) .. ':0,' .. + theme.accent.hue_700 .. ':0.07,' .. + theme.accent.hue_700 .. ':0.07,' .. + theme.primary.hue_100 .. ':1,' .. + theme.primary.hue_100 + theme.taglist_bg_focus = theme.accent.hue_200 + theme.taglist_fg_focus = theme.primary.hue_100 + + -- Tasklist + theme.tasklist_font = theme.font + theme.tasklist_bg_normal = theme.primary.hue_200 + theme.tasklist_bg_focus = theme.primary.hue_100 + theme.tasklist_bg_urgent = theme.primary.hue_200 + + -- Icons + theme.icon_theme = 'Flat-Remix-Green-Dark' + + -- Client + theme.gaps = dpi(2) + theme.border_width = dpi(2) + theme.border_focus = theme.accent.hue_200 + theme.border_normal = theme.primary.hue_100 + theme.gap_single_client = true + theme.bg_normal = theme.primary.hue_100 +end +return {theme = theme, awesome_overrides = awesome_overrides} diff --git a/theme/wallpapers/1.png b/theme/wallpapers/1.png new file mode 100644 index 0000000..d0266a6 Binary files /dev/null and b/theme/wallpapers/1.png differ diff --git a/theme/wallpapers/10.png b/theme/wallpapers/10.png new file mode 100644 index 0000000..d0ae5ff Binary files /dev/null and b/theme/wallpapers/10.png differ diff --git a/theme/wallpapers/11.png b/theme/wallpapers/11.png new file mode 100644 index 0000000..a23a943 Binary files /dev/null and b/theme/wallpapers/11.png differ diff --git a/theme/wallpapers/12.png b/theme/wallpapers/12.png new file mode 100644 index 0000000..6c3f5db Binary files /dev/null and b/theme/wallpapers/12.png differ diff --git a/theme/wallpapers/2.png b/theme/wallpapers/2.png new file mode 100644 index 0000000..ac28a97 Binary files /dev/null and b/theme/wallpapers/2.png differ diff --git a/theme/wallpapers/3.png b/theme/wallpapers/3.png new file mode 100644 index 0000000..623191c Binary files /dev/null and b/theme/wallpapers/3.png differ diff --git a/theme/wallpapers/4.png b/theme/wallpapers/4.png new file mode 100644 index 0000000..23f35b8 Binary files /dev/null and b/theme/wallpapers/4.png differ diff --git a/theme/wallpapers/5.png b/theme/wallpapers/5.png new file mode 100644 index 0000000..ebd1729 Binary files /dev/null and b/theme/wallpapers/5.png differ diff --git a/theme/wallpapers/6.png b/theme/wallpapers/6.png new file mode 100644 index 0000000..5704a13 Binary files /dev/null and b/theme/wallpapers/6.png differ diff --git a/theme/wallpapers/6499ef5228c032a70c26e139ab60e6c0.jpeg b/theme/wallpapers/6499ef5228c032a70c26e139ab60e6c0.jpeg new file mode 100644 index 0000000..25f1e3f Binary files /dev/null and b/theme/wallpapers/6499ef5228c032a70c26e139ab60e6c0.jpeg differ diff --git a/theme/wallpapers/7.png b/theme/wallpapers/7.png new file mode 100644 index 0000000..45d6eab Binary files /dev/null and b/theme/wallpapers/7.png differ diff --git a/theme/wallpapers/8.png b/theme/wallpapers/8.png new file mode 100644 index 0000000..ef821ca Binary files /dev/null and b/theme/wallpapers/8.png differ diff --git a/theme/wallpapers/9.png b/theme/wallpapers/9.png new file mode 100644 index 0000000..bb2595b Binary files /dev/null and b/theme/wallpapers/9.png differ diff --git a/widget/battery-d.lua b/widget/battery-d.lua new file mode 100644 index 0000000..c45505d --- /dev/null +++ b/widget/battery-d.lua @@ -0,0 +1,124 @@ +------------------------------------------------- +-- Battery Widget for Awesome Window Manager +-- Shows the battery status using the ACPI tool +-- More details could be found here: +-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/battery-widget +-- @author Pavel Makhov +-- @copyright 2017 Pavel Makhov +------------------------------------------------- +local awful = require('awful') +local watch = require('awful.widget.watch') +local wibox = require('wibox') +local beautiful = require('beautiful') +local dpi = require('beautiful').xresources.apply_dpi + +-- acpi sample outputs +-- Battery 0: Discharging, 75%, 01:51:38 remaining +-- Battery 0: Charging, 53%, 00:57:43 until charged + +local percentage = wibox.widget.textbox() +local battery_icon = wibox.widget.textbox() +battery_icon.font = beautiful.icon_font + +local battery_popup = awful.tooltip({ + objects = {percentage}, + mode = 'outside', + align = 'left', + preferred_positions = {'right', 'left', 'top', 'bottom'} +}) + +watch('acpi -i', 10, function(_, stdout) + local battery_info = {} + local capacities = {} + for s in stdout:gmatch('[^\r\n]+') do + local status, charge_str, time = string.match(s, '.+: (%a+), (%d?%d?%d)%%,?.*') + if status ~= nil then + table.insert(battery_info, { + status = status, + charge = tonumber(charge_str) + }) + else + local cap_str = string.match(s, '.+:.+last full capacity (%d+)') + table.insert(capacities, tonumber(cap_str)) + end + end + + local capacity = 0 + for _, cap in ipairs(capacities) do + capacity = capacity + cap + end + + local charge = 0 + local status + for i, batt in ipairs(battery_info) do + if batt.charge >= charge then + status = batt.status -- use most charged battery status + -- this is arbitrary, and maybe another metric should be used + end + + charge = charge + batt.charge * capacities[i] + end + charge = charge / capacity + + battery_popup.text = string.gsub(stdout, '\n$', '') + percentage.text = math.floor(charge) + + if status == 'Charging' then + battery_icon.text = '' + if math.floor(charge) <= 20 then + battery_icon.text = '' + elseif math.floor(charge) <= 30 then + battery_icon.text = '' + elseif math.floor(charge) <= 40 then + battery_icon.text = '' + elseif math.floor(charge) <= 60 then + battery_icon.text = '' + elseif math.floor(charge) <= 80 then + battery_icon.text = '' + elseif math.floor(charge) <= 90 then + --battery_icon.text = '' + battery_icon.text = '90' + elseif math.floor(charge) <= 100 then + --battery_icon.text = '' + battery_icon.text = '90' + end + elseif status == 'Full' then + battery_icon.text = '' + else + if math.floor(charge) <= 10 then + battery_icon.text = '' + elseif math.floor(charge) <= 20 then + battery_icon.text = '' + elseif math.floor(charge) <= 30 then + battery_icon.text = '' + elseif math.floor(charge) <= 40 then + battery_icon.text = '' + elseif math.floor(charge) <= 50 then + battery_icon.text = '' + elseif math.floor(charge) <= 60 then + battery_icon.text = '' + elseif math.floor(charge) <= 60 then + battery_icon.text = '' + elseif math.floor(charge) <= 80 then + battery_icon.text = '' + elseif math.floor(charge) <= 90 then + battery_icon.text = '' + battery_icon.text = '90' + elseif math.floor(charge) <= 100 then + battery_icon.text = '' + battery_icon.text = '90' + end + end + collectgarbage('collect') +end) + +return wibox.widget { + wibox.widget{ + battery_icon, + fg = beautiful.accent.hue_300, + widget = wibox.container.background + }, + percentage, + spacing = dpi(2), + layout = wibox.layout.fixed.horizontal +} diff --git a/widget/battery.lua b/widget/battery.lua new file mode 100644 index 0000000..81770e9 --- /dev/null +++ b/widget/battery.lua @@ -0,0 +1,191 @@ +------------------------------------------------- +-- Battery Widget for Awesome Window Manager +-- Shows the battery status using the ACPI tool +-- More details could be found here: +-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/battery-widget + +-- @author Pavel Makhov +-- @copyright 2017 Pavel Makhov +------------------------------------------------- + +local awful = require("awful") +local naughty = require("naughty") +local watch = require("awful.widget.watch") +local wibox = require("wibox") +local gfs = require("gears.filesystem") +local dpi = require('beautiful').xresources.apply_dpi + +-- acpi sample outputs +-- Battery 0: Discharging, 75%, 01:51:38 remaining +-- Battery 0: Charging, 53%, 00:57:43 until charged + +local HOME = os.getenv("HOME") + +local battery_widget = {} +local function worker(args) + local args = args or {} + + local bat_num = '1' + local font = args.font or 'Play 8' + local path_to_icons = args.path_to_icons or "/usr/share/icons/Arc/status/symbolic/" + local show_current_level = args.show_current_level or false + local margin_left = args.margin_left or 0 + local margin_right = args.margin_right or 0 + + local display_notification = args.display_notification or false + local position = args.notification_position or "top_right" + local timeout = args.timeout or 10 + + local warning_msg_title = args.warning_msg_title or 'Huston, we have a problem' + local warning_msg_text = args.warning_msg_text or 'Battery is dying' + local warning_msg_position = args.warning_msg_position or 'bottom_right' + local warning_msg_icon = args.warning_msg_icon or HOME .. '/.config/awesome/awesome-wm-widgets/batteryarc-widget/spaceman.jpg' + local enable_battery_warning = args.enable_battery_warning + if enable_battery_warning == nil then + enable_battery_warning = true + end + + local bat_expr = 'Battery ' .. bat_num + if not gfs.dir_readable(path_to_icons) then + naughty.notify{ + title = "Battery Widget", + text = "Folder with icons doesn't exist: " .. path_to_icons, + preset = naughty.config.presets.critical + } + end + + local icon_widget = wibox.widget { + { + id = "icon", + widget = wibox.widget.imagebox, + resize = false + }, + layout = wibox.container.margin(_, 0, 0, 3) + } + local level_widget = wibox.widget { + font = font, + widget = wibox.widget.textbox + } + + battery_widget = wibox.widget { + icon_widget, + level_widget, + layout = wibox.layout.fixed.horizontal, + } + -- Popup with battery info + -- One way of creating a pop-up notification - naughty.notify + local notification + local function show_battery_status(batteryType) + awful.spawn.easy_async('bash -c "acpi | grep \'' .. bat_expr .. '\'"', + function(stdout, _, _, _) + naughty.destroy(notification) + notification = naughty.notify{ + text = stdout, + title = "Battery status", + icon = path_to_icons .. batteryType .. ".svg", + icon_size = dpi(16), + position = position, + timeout = 5, hover_timeout = 0.5, + width = 200, + screen = mouse.screen + } + end + ) + end + + -- Alternative to naughty.notify - tooltip. You can compare both and choose the preferred one + --battery_popup = awful.tooltip({objects = {battery_widget}}) + + -- To use colors from beautiful theme put + -- following lines in rc.lua before require("battery"): + -- beautiful.tooltip_fg = beautiful.fg_normal + -- beautiful.tooltip_bg = beautiful.bg_normal + + local function show_battery_warning() + naughty.notify { + icon = warning_msg_icon, + icon_size = 100, + text = warning_msg_text, + title = warning_msg_title, + timeout = 25, -- show the warning for a longer time + hover_timeout = 0.5, + position = warning_msg_position, + bg = "#F06060", + fg = "#EEE9EF", + width = 300, + screen = mouse.screen + } + end + local last_battery_check = os.time() + local batteryType = "battery-good-symbolic" + + watch('bash -c "acpi -i | grep \'' .. bat_expr .. '\'"', timeout, + function(widget, stdout, stderr, exitreason, exitcode) + local battery_info = {} + local capacities = {} + for s in stdout:gmatch("[^\r\n]+") do + local status, charge_str, time = string.match(s, '.+: (%a+), (%d?%d?%d)%%,?(.*)') + if status ~= nil then + table.insert(battery_info, {status = status, charge = tonumber(charge_str)}) + else + local cap_str = string.match(s, '.+:.+last full capacity (%d+)') + table.insert(capacities, tonumber(cap_str)) + end + end + + local capacity = 0 + for i, cap in ipairs(capacities) do + capacity = capacity + cap + end + + local charge = 0 + local status + for i, batt in ipairs(battery_info) do + if batt.charge >= charge then + status = batt.status -- use most charged battery status + -- this is arbitrary, and maybe another metric should be used + end + + charge = charge + batt.charge * capacities[i] + end + charge = charge / capacity + + if show_current_level then + level_widget.text = string.format('%d%%', charge) + end + + if (charge >= 0 and charge < 15) then + batteryType = "battery-empty%s-symbolic" + if enable_battery_warning and status ~= 'Charging' and os.difftime(os.time(), last_battery_check) > 300 then + -- if 5 minutes have elapsed since the last warning + last_battery_check = os.time() + + show_battery_warning() + end + elseif (charge >= 15 and charge < 40) then batteryType = "battery-caution%s-symbolic" + elseif (charge >= 40 and charge < 60) then batteryType = "battery-low%s-symbolic" + elseif (charge >= 60 and charge < 80) then batteryType = "battery-good%s-symbolic" + elseif (charge >= 80 and charge <= 100) then batteryType = "battery-full%s-symbolic" + end + + if status == 'Charging' then + batteryType = string.format(batteryType, '-charging') + else + batteryType = string.format(batteryType, '') + end + + widget.icon:set_image(path_to_icons .. batteryType .. ".svg") + + -- Update popup text + -- battery_popup.text = string.gsub(stdout, "\n$", "") + end, + icon_widget) + + if display_notification then + battery_widget:connect_signal("mouse::enter", function() show_battery_status(batteryType) end) + battery_widget:connect_signal("mouse::leave", function() naughty.destroy(notification) end) + end + return wibox.container.margin(battery_widget, margin_left, margin_right) +end + +return setmetatable(battery_widget, { __call = function(_, ...) return worker(...) end }) \ No newline at end of file diff --git a/widget/brightness/brightness-slider.lua b/widget/brightness/brightness-slider.lua new file mode 100644 index 0000000..e67fc8b --- /dev/null +++ b/widget/brightness/brightness-slider.lua @@ -0,0 +1,49 @@ +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') +local mat_slider = require('widget.material.slider') +local mat_icon_button = require('widget.material.icon-button') +local clickable_container = require('widget.material.clickable-container') +local icons = require('theme.icons') +local watch = require('awful.widget.watch') +local spawn = require('awful.spawn') + +local slider = + wibox.widget { + read_only = false, + widget = mat_slider +} + +slider:connect_signal( + 'property::value', + function() + spawn('xbacklight -set ' .. math.max(slider.value, 5)) + end +) + +watch( + [[bash -c "xbacklight -get"]], + 1, + function(widget, stdout, stderr, exitreason, exitcode) + local brightness = string.match(stdout, '(%d+)') + + slider:set_value(tonumber(brightness)) + collectgarbage('collect') + end +) + +local icon = + wibox.widget { + image = icons.brightness, + widget = wibox.widget.imagebox +} + +local button = mat_icon_button(icon) + +local brightness_setting = + wibox.widget { + button, + slider, + widget = mat_list_item +} + +return brightness_setting diff --git a/widget/calendar-widget/README.md b/widget/calendar-widget/README.md new file mode 100644 index 0000000..c30fef6 --- /dev/null +++ b/widget/calendar-widget/README.md @@ -0,0 +1,53 @@ +# Calendar Widget + +Calendar widget for Awesome WM - slightly improved version of the `wibox.widget.calendar`. + +## Features + + - mouse support: scroll up - shows next month, scroll down - previous + - themes: + + | Name | Screenshot | + |---|---| + |nord (default) | ![nord_theme](./nord.png) | + | outrun | ![outrun_theme](./outrun.png) | + | light | ![outrun_theme](./light.png) | + | dark | ![outrun_theme](./dark.png) | + + - setup widget placement + + top center - in case you clock is centered: + + ![calendar_top](./calendar_top.png) + + top right - for default awesome config: + + ![calendar_top_right](./calendar_top_right.png) + + bottom right - in case your wibar at the bottom: + + ![calendar_bottom_right](./calendar_bottom_right.png) + + +## How to use + +This widget needs an 'anchor' - another widget which triggers visibility of the calendar. Default `mytextclock` is the perfect candidate! +Just after mytextclock is instantiated, create the widget and add the mouse listener to it. + +```lua +local calendar_widget = require("awesome-wm-widgets.calendar-widget.calendar") +-- ... +-- Create a textclock widget +mytextclock = wibox.widget.textclock() +-- default +local cw = calendar_widget() +-- or customized +local cw = calendar_widget({ + theme = 'outrun', + placement = 'bottom_right' +}) +mytextclock:connect_signal("button::press", + function(_, _, _, button) + if button == 1 then cw.toggle() end + end) +``` diff --git a/widget/calendar-widget/calendar.lua b/widget/calendar-widget/calendar.lua new file mode 100644 index 0000000..e15d094 --- /dev/null +++ b/widget/calendar-widget/calendar.lua @@ -0,0 +1,235 @@ +------------------------------------------------- +-- Calendar Widget for Awesome Window Manager +-- Shows the current month and supports scroll up/down to switch month +-- More details could be found here: +-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/calendar-widget + +-- @author Pavel Makhov +-- @copyright 2019 Pavel Makhov +------------------------------------------------- + +local awful = require("awful") +local beautiful = require("beautiful") +local wibox = require("wibox") +local gears = require("gears") +local naughty = require("naughty") + +local calendar_widget = {} + +local function worker(args) + + local calendar_themes = { + nord = { + bg = '#2E3440', + fg = '#D8DEE9', + focus_date_bg = '#88C0D0', + focus_date_fg = '#000000', + weekend_day_bg = '#3B4252', + weekday_fg = '#88C0D0', + header_fg = '#E5E9F0', + border = '#4C566A' + }, + outrun = { + bg = '#0d0221', + fg = '#D8DEE9', + focus_date_bg = '#650d89', + focus_date_fg = '#2de6e2', + weekend_day_bg = '#261447', + weekday_fg = '#2de6e2', + header_fg = '#f6019d', + border = '#261447' + }, + dark = { + bg = '#000000', + fg = '#ffffff', + focus_date_bg = '#ffffff', + focus_date_fg = '#000000', + weekend_day_bg = '#444444', + weekday_fg = '#ffffff', + header_fg = '#ffffff', + border = '#333333' + }, + light = { + bg = '#ffffff', + fg = '#000000', + focus_date_bg = '#000000', + focus_date_fg = '#ffffff', + weekend_day_bg = '#AAAAAA', + weekday_fg = '#000000', + header_fg = '#000000', + border = '#CCCCCC' + }, + monokai = { + bg = '#272822', + fg = '#F8F8F2', + focus_date_bg = '#AE81FF', + focus_date_fg = '#ffffff', + weekend_day_bg = '#75715E', + weekday_fg = '#FD971F', + header_fg = '#F92672', + border = '#75715E' + } + } + + local args = args or {} + + if args.theme ~= nil and calendar_themes[args.theme] == nil then + naughty.notify({ + preset = naughty.config.presets.critical, + title = 'Calendar Widget', + text = 'Theme "' .. args.theme .. '" not found, fallback to default'}) + args.theme = 'nord' + end + + local theme = args.theme or 'nord' + local placement = args.placement or 'top' + + + local styles = {} + local function rounded_shape(size) + return function(cr, width, height) + gears.shape.rounded_rect(cr, width, height, size) + end + end + + styles.month = { + padding = 4, + bg_color = calendar_themes[theme].bg, + border_width = 0, + } + + styles.normal = { + markup = function(t) return t end, + shape = rounded_shape(4) + } + + styles.focus = { + fg_color = calendar_themes[theme].focus_date_fg, + bg_color = calendar_themes[theme].focus_date_bg, + markup = function(t) return '' .. t .. '' end, + shape = rounded_shape(4) + } + + styles.header = { + fg_color = calendar_themes[theme].header_fg, + bg_color = calendar_themes[theme].bg, + markup = function(t) return '' .. t .. '' end + } + + styles.weekday = { + fg_color = calendar_themes[theme].weekday_fg, + bg_color = calendar_themes[theme].bg, + markup = function(t) return '' .. t .. '' end, + } + + local function decorate_cell(widget, flag, date) + if flag == 'monthheader' and not styles.monthheader then + flag = 'header' + end + + -- highlight only today's day + if flag == 'focus' then + local today = os.date('*t') + if today.month ~= date.month then + flag = 'normal' + end + end + + local props = styles[flag] or {} + if props.markup and widget.get_text and widget.set_markup then + widget:set_markup(props.markup(widget:get_text())) + end + -- Change bg color for weekends + local d = { year = date.year, month = (date.month or 1), day = (date.day or 1) } + local weekday = tonumber(os.date('%w', os.time(d))) + local default_bg = (weekday == 0 or weekday == 6) and calendar_themes[theme].weekend_day_bg or calendar_themes[theme].bg + local ret = wibox.widget { + { + { + widget, + halign = 'center', + widget = wibox.container.place + }, + margins = (props.padding or 2) + (props.border_width or 0), + widget = wibox.container.margin + }, + shape = props.shape, + shape_border_color = props.border_color or '#000000', + shape_border_width = props.border_width or 0, + fg = props.fg_color or calendar_themes[theme].fg, + bg = props.bg_color or default_bg, + widget = wibox.container.background + } + + return ret + end + + local cal = wibox.widget { + date = os.date('*t'), + font = beautiful.get_font(), + fn_embed = decorate_cell, + long_weekdays = true, + widget = wibox.widget.calendar.month + } + + local popup = awful.popup { + ontop = true, + visible = false, + shape = gears.shape.rounded_rect, + offset = { y = 5 }, + border_width = 1, + border_color = calendar_themes[theme].border, + widget = cal + } + + popup:buttons( + awful.util.table.join( + awful.button({}, 4, function() + local a = cal:get_date() + a.month = a.month + 1 + cal:set_date(nil) + cal:set_date(a) + popup:set_widget(cal) + end), + awful.button({}, 5, function() + local a = cal:get_date() + a.month = a.month - 1 + cal:set_date(nil) + cal:set_date(a) + popup:set_widget(cal) + end) + ) + ) + + function calendar_widget.toggle() + + if popup.visible then + -- to faster render the calendar refresh it and just hide + cal:set_date(nil) -- the new date is not set without removing the old one + cal:set_date(os.date('*t')) + popup:set_widget(nil) -- just in case + popup:set_widget(cal) + popup.visible = not popup.visible + else + if placement == 'top' then + awful.placement.top(popup, { margins = { top = 30 }, parent = awful.screen.focused() }) + elseif placement == 'top_right' then + awful.placement.top_right(popup, { margins = { top = 30, right = 10}, parent = awful.screen.focused() }) + elseif placement == 'bottom_right' then + awful.placement.bottom_right(popup, { margins = { bottom = 30, right = 10}, parent = awful.screen.focused() }) + else + awful.placement.top(popup, { margins = { top = 30 }, parent = awful.screen.focused() }) + end + + popup.visible = true + + end + end + + return calendar_widget + +end + +return setmetatable(calendar_widget, { __call = function(_, ...) + return worker(...) +end }) diff --git a/widget/calendar-widget/calendar_bottom_right.png b/widget/calendar-widget/calendar_bottom_right.png new file mode 100644 index 0000000..2bc2e82 Binary files /dev/null and b/widget/calendar-widget/calendar_bottom_right.png differ diff --git a/widget/calendar-widget/calendar_top.png b/widget/calendar-widget/calendar_top.png new file mode 100644 index 0000000..3e6b66b Binary files /dev/null and b/widget/calendar-widget/calendar_top.png differ diff --git a/widget/calendar-widget/calendar_top_right.png b/widget/calendar-widget/calendar_top_right.png new file mode 100644 index 0000000..4a29022 Binary files /dev/null and b/widget/calendar-widget/calendar_top_right.png differ diff --git a/widget/calendar-widget/dark.png b/widget/calendar-widget/dark.png new file mode 100644 index 0000000..540289f Binary files /dev/null and b/widget/calendar-widget/dark.png differ diff --git a/widget/calendar-widget/light.png b/widget/calendar-widget/light.png new file mode 100644 index 0000000..ab675d1 Binary files /dev/null and b/widget/calendar-widget/light.png differ diff --git a/widget/calendar-widget/nord.png b/widget/calendar-widget/nord.png new file mode 100644 index 0000000..94f9f7e Binary files /dev/null and b/widget/calendar-widget/nord.png differ diff --git a/widget/calendar-widget/outrun.png b/widget/calendar-widget/outrun.png new file mode 100644 index 0000000..d59c123 Binary files /dev/null and b/widget/calendar-widget/outrun.png differ diff --git a/widget/calendar.lua b/widget/calendar.lua new file mode 100644 index 0000000..c5e10b9 --- /dev/null +++ b/widget/calendar.lua @@ -0,0 +1,31 @@ +local awful = require('awful') +local wibox = require('wibox') +local beautiful = require('beautiful') +local dpi = require('beautiful').xresources.apply_dpi + +local month_calendar = awful.widget.calendar_popup.month({ + start_sunday = true, + style_month = { + border_width = dpi(0), + bg_color = beautiful.primary.hue_100, + padding = dpi(20) + }, + style_header = { + border_width = 0, + fg_color = beautiful.accent.hue_400 + }, + style_weekday = { + border_width = 0 + }, + style_normal = { + border_width = 0 + }, + style_focus = { + border_width = dpi(0), + border_color = beautiful.fg_normal, + fg_color = beautiful.accent.hue_200, + bg_color = beautiful.primary.hue_100 + } +}) + +return month_calendar diff --git a/widget/calendar/init.lua b/widget/calendar/init.lua new file mode 100644 index 0000000..6c85a43 --- /dev/null +++ b/widget/calendar/init.lua @@ -0,0 +1,70 @@ +local awful = require('awful') +local gears = require('gears') +local wibox = require('wibox') +local beautiful = require('beautiful') +local icons = require('theme.icons') +local clickable_container = require('widget.material.clickable-container') +local dpi = require('beautiful').xresources.apply_dpi + +local styles = {} +local function rounded_shape(size, partial) + if partial then + return function(cr, width, height) + gears.shape.rectangle(cr, width + 5, height, 11) + end + else + return function(cr, width, height) + gears.shape.rectangle(cr, width, height, size) + end + end +end +styles.month = {padding = 5, bg_color = '#555555', shape = rounded_shape(10)} +styles.normal = {shape = rounded_shape(5)} +styles.focus = { + fg_color = beautiful.primary.hue_400, -- Current day Color + markup = function(t) return '' .. t .. '' end, + shape = rounded_shape(5, true) +} +styles.header = { + fg_color = beautiful.primary.hue_200, -- Month Name Color + markup = function(t) return '' .. t .. '' end, + shape = rounded_shape(10) +} +styles.weekday = { + fg_color = beautiful.background.hue_50, -- Day Color + markup = function(t) return '' .. t .. '' end, + shape = rounded_shape(5) +} +local function decorate_cell(widget, flag, date) + if flag == 'monthheader' and not styles.monthheader then flag = 'header' end + local props = styles[flag] or {} + if props.markup and widget.get_text and widget.set_markup then + widget:set_markup(props.markup(widget:get_text())) + end + local d = { + year = date.year, + month = (date.month or 1), + day = (date.day or 1) + } + local weekday = tonumber(os.date('%w', os.time(d))) + local ret = wibox.widget { + { + widget, + margins = (props.padding or 2) + (props.border_width or 0), + widget = wibox.container.margin + }, + fg = props.fg_color or '#999999', + widget = wibox.container.background + } + return ret +end + +local cal = wibox.widget { + date = os.date('*t'), + font = 'Roboto 10', + fn_embed = decorate_cell, + start_sunday = true, + widget = wibox.widget.calendar.month +} + +return cal diff --git a/widget/clock.lua b/widget/clock.lua new file mode 100644 index 0000000..4cb7324 --- /dev/null +++ b/widget/clock.lua @@ -0,0 +1,5 @@ +local wibox = require('wibox') +local beautiful = require('beautiful') + +local clock = wibox.widget.textclock('%d/%m %H:%M') +return clock diff --git a/widget/cpu.lua b/widget/cpu.lua new file mode 100644 index 0000000..5cd3d62 --- /dev/null +++ b/widget/cpu.lua @@ -0,0 +1,27 @@ +local wibox = require('wibox') +local beautiful = require('beautiful') +local dpi = require('beautiful').xresources.apply_dpi +local watch = require('awful.widget.watch') + +local cpu = wibox.widget.textbox() +local total_prev = 0 +local idle_prev = 0 + +watch([[bash -c "cat /proc/stat | grep '^cpu '"]], 1, function(_, stdout) + local user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice = + stdout:match('(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s') + + local total = user + nice + system + idle + iowait + irq + softirq + steal + + local diff_idle = idle - idle_prev + local diff_total = total - total_prev + local diff_usage = (1000 * (diff_total - diff_idle) / diff_total + 5) / 10 + + cpu.text = math.floor(diff_usage) .. '%' + + total_prev = total + idle_prev = idle + collectgarbage('collect') +end) + +return cpu diff --git a/widget/cpu/cpu-meter.lua b/widget/cpu/cpu-meter.lua new file mode 100644 index 0000000..f112e2a --- /dev/null +++ b/widget/cpu/cpu-meter.lua @@ -0,0 +1,50 @@ +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') +local mat_slider = require('widget.material.slider') +local mat_icon = require('widget.material.icon') +local icons = require('theme.icons') +local watch = require('awful.widget.watch') +local dpi = require('beautiful').xresources.apply_dpi + +local total_prev = 0 +local idle_prev = 0 + +local slider = + wibox.widget { + read_only = true, + widget = mat_slider +} + +watch( + [[bash -c "cat /proc/stat | grep '^cpu '"]], + 1, + function(_, stdout) + local user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice = + stdout:match('(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s') + + local total = user + nice + system + idle + iowait + irq + softirq + steal + + local diff_idle = idle - idle_prev + local diff_total = total - total_prev + local diff_usage = (1000 * (diff_total - diff_idle) / diff_total + 5) / 10 + + slider:set_value(diff_usage) + + total_prev = total + idle_prev = idle + collectgarbage('collect') + end +) + +local cpu_meter = + wibox.widget { + wibox.widget { + icon = icons.chart, + size = dpi(24), + widget = mat_icon + }, + slider, + widget = mat_list_item +} + +return cpu_meter diff --git a/widget/harddrive/harddrive-meter.lua b/widget/harddrive/harddrive-meter.lua new file mode 100644 index 0000000..6ca0f09 --- /dev/null +++ b/widget/harddrive/harddrive-meter.lua @@ -0,0 +1,36 @@ +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') +local mat_slider = require('widget.material.slider') +local mat_icon = require('widget.material.icon') +local icons = require('theme.icons') +local watch = require('awful.widget.watch') +local dpi = require('beautiful').xresources.apply_dpi + +local slider = + wibox.widget { + read_only = true, + widget = mat_slider +} + +watch( + [[bash -c "df -h /home|grep '^/' | awk '{print $5}'"]], + 10, + function(_, stdout) + local space_consumed = stdout:match('(%d+)') + slider:set_value(tonumber(space_consumed)) + collectgarbage('collect') + end +) + +local harddrive_meter = + wibox.widget { + wibox.widget { + icon = icons.harddisk, + size = dpi(24), + widget = mat_icon + }, + slider, + widget = mat_list_item +} + +return harddrive_meter diff --git a/widget/material/clickable-container.lua b/widget/material/clickable-container.lua new file mode 100644 index 0000000..1b466db --- /dev/null +++ b/widget/material/clickable-container.lua @@ -0,0 +1,43 @@ +local wibox = require('wibox') + +function build(widget, label) + local container = wibox.widget { + -- widget, + wibox.widget { + text = label, + widget = wibox.widget.textbox, + }, + widget = wibox.container.background + } + local old_cursor, old_wibox + + container:connect_signal('mouse::enter', function() + container.bg = '#ffffff11' + -- Hm, no idea how to get the wibox from this signal's arguments... + local w = _G.mouse.current_wibox + if w then + old_cursor, old_wibox = w.cursor, w + w.cursor = 'hand1' + end + end) + + container:connect_signal('mouse::leave', function() + container.bg = '#ffffff00' + if old_wibox then + old_wibox.cursor = old_cursor + old_wibox = nil + end + end) + + container:connect_signal('button::press', function() + container.bg = '#ffffff22' + end) + + container:connect_signal('button::release', function() + container.bg = '#ffffff11' + end) + + return container +end + +return build diff --git a/widget/material/icon-button.lua b/widget/material/icon-button.lua new file mode 100644 index 0000000..c4a03bf --- /dev/null +++ b/widget/material/icon-button.lua @@ -0,0 +1,14 @@ +local wibox = require('wibox') +local gears = require('gears') +local clickable_container = require('widget.material.clickable-container') +local dpi = require('beautiful').xresources.apply_dpi + +function build(imagebox, args) + return wibox.widget { + imagebox, + shape = gears.shape.circle, + widget = clickable_container + } +end + +return build diff --git a/widget/material/icon.lua b/widget/material/icon.lua new file mode 100644 index 0000000..82ce50f --- /dev/null +++ b/widget/material/icon.lua @@ -0,0 +1,80 @@ +-- Default widget requirements +local base = require('wibox.widget.base') +local gtable = require('gears.table') +local setmetatable = setmetatable + +-- Commons requirements +local wibox = require('wibox') + +-- Local declarations + +local mat_list_item = {mt = {}} + +function mat_list_item:layout(_, width, height) + local layout = {} + + -- Add divider if present + if self._private.icon then + table.insert( + layout, + base.place_widget_at( + self._private.imagebox, + width / 2 - self._private.size / 2, + height / 2 - self._private.size / 2, + self._private.size, + self._private.size + ) + ) + end + return layout +end + +function mat_list_item:fit(_, width, height) + local min = math.min(width, height) + return min, min +end + +function mat_list_item:set_icon(icon) + self._private.icon = icon + self._private.imagebox.image = icon +end + +function mat_list_item:get_icon() + return self._private.icon +end + +function mat_list_item:set_size(size) + self._private.size = size + self:emit_signal('widget::layout_changed') +end + +function mat_list_item:get_size() + return self._private.size +end + +local function new(icon, size) + local ret = + base.make_widget( + nil, + nil, + { + enable_properties = true + } + ) + + gtable.crush(ret, mat_list_item, true) + ret._private.icon = icon + ret._private.imagebox = wibox.widget.imagebox(icon) + ret._private.size = size + return ret +end + +function mat_list_item.mt:__call(...) + return new(...) +end + +--@DOC_widget_COMMON@ + +--@DOC_object_COMMON@ + +return setmetatable(mat_list_item, mat_list_item.mt) diff --git a/widget/material/list-item.lua b/widget/material/list-item.lua new file mode 100644 index 0000000..f549bf4 --- /dev/null +++ b/widget/material/list-item.lua @@ -0,0 +1,186 @@ +-- Default widget requirements +local base = require('wibox.widget.base') +local gtable = require('gears.table') +local setmetatable = setmetatable +local dpi = require('beautiful').xresources.apply_dpi + +-- Commons requirements +local wibox = require('wibox') +local clickable_container = require('widget.material.clickable-container') +-- Local declarations + +local mat_list_item = { + mt = {} +} + +function mat_list_item:build_separator() + self._private.separator = wibox.widget { + orientation = 'horizontal', + forced_height = 1, + opacity = 0.08, + widget = wibox.widget.separator + } + self:emit_signal('widget::layout_changed') +end + +function mat_list_item:build_clickable_container() + self._private.clickable_container = wibox.widget { + wibox.widget { + widget = wibox.widget.textbox + }, + widget = clickable_container + } + self:emit_signal('widget::layout_changed') +end + +function mat_list_item:layout(_, width, height) + local content_width = width - dpi(32) + local content_x = dpi(dpi(16)) + local layout = {} + + -- Add divider if present + if self._private.divider then + table.insert(layout, base.place_widget_at(self._private.separator, 0, 0, width, 1)) + end + + -- Add clickable_container if clickable + if self._private.clickable then + table.insert(layout, base.place_widget_at(self._private.clickable_container, 0, 0, width, height)) + end + + if self._private.prefix then + content_x = content_x + dpi(54) + content_width = content_width - dpi(54) + table.insert(layout, base.place_widget_at(self._private.prefix, dpi(16), 0, dpi(48), height)) + end + + if self._private.suffix then + content_width = content_width - dpi(54) + table.insert(layout, base.place_widget_at(self._private.suffix, width - dpi(40), dpi(12), width, height)) + end + table.insert(layout, base.place_widget_at(self._private.content, content_x, 0, content_width, height)) + return layout +end + +function mat_list_item:fit(_, width) + return width, dpi(48) +end + +---- Properties ---- + +-- Property clickable +function mat_list_item:set_clickable(value) + if self._private.clickable ~= value then + self._private.clickable = value + self:emit_signal('property::clickable') + self:emit_signal('widget::layout_changed') + + if self._private.clickable and not self._private.clickable_container then + self:build_clickable_container() + end + end +end + +function mat_list_item:get_clickable() + return self._private.clickable +end + +-- Property divider + +function mat_list_item:set_divider(value) + if self._private.divider ~= value then + self._private.divider = value + self:emit_signal('property::divider') + self:emit_signal('widget::layout_changed') + + if self._private.divider and not self._private.separator then + self:build_separator() + end + end +end + +function mat_list_item:get_divider() + return self._private.divider +end + +function mat_list_item:set_prefix(widget) + if widget then + base.check_widget(widget) + end + self._private.prefix = widget + self:emit_signal('widget::layout_changed') +end + +function mat_list_item:get_prefix() + return self._private.prefix +end + +function mat_list_item:set_suffix(widget) + if widget then + base.check_widget(widget) + end + self._private.suffix = widget + self:emit_signal('widget::layout_changed') +end + +function mat_list_item:get_suffix() + return self._private.suffix +end + +--- The widget who will be the content. +-- @property content +-- @tparam widget widget The widget + +function mat_list_item:set_content(widget) + if widget then + base.check_widget(widget) + end + self._private.content = widget + self:emit_signal('widget::layout_changed') +end + +function mat_list_item:get_content() + return self._private.content +end + +-- Get the number of children element +-- @treturn table The children +function mat_list_item:get_children() + return {self._private.widget} +end + +-- Replace the layout children +-- This layout only accept one children, all others will be ignored +-- @tparam table children A table composed of valid widgets +function mat_list_item:set_children(children) + if not children[2] then + self:set_content(children[1]) + else + self:set_prefix(children[1]) + self:set_content(children[2]) + end + if children[3] then + self:set_suffix(children[3]) + end +end + +local function new(widget) + local ret = base.make_widget(nil, nil, { + enable_properties = true + }) + + gtable.crush(ret, mat_list_item, true) + + ret._private.content = widget + return ret +end + +function mat_list_item.mt:__call(...) + return new(...) +end + +-- @DOC_widget_COMMON@ + +-- @DOC_object_COMMON@ + +return setmetatable(mat_list_item, mat_list_item.mt) diff --git a/widget/material/slider.lua b/widget/material/slider.lua new file mode 100644 index 0000000..9dfe756 --- /dev/null +++ b/widget/material/slider.lua @@ -0,0 +1,117 @@ +-- Default widget requirements +local base = require('wibox.widget.base') +local gtable = require('gears.table') +local setmetatable = setmetatable +local dpi = require('beautiful').xresources.apply_dpi + +-- Commons requirements +local wibox = require('wibox') +local gears = require('gears') +local beautiful = require('beautiful') +local mat_colors = require('theme.mat-colors') +-- Local declarations + +local mat_slider = { + mt = {} +} + +local properties = { + read_only = false +} + +function mat_slider:set_value(value) + if self._private.value ~= value then + self._private.value = value + self._private.progress_bar:set_value(self._private.value) + self._private.slider:set_value(self._private.value) + self:emit_signal('property::value') + -- self:emit_signal('widget::layout_changed') + end +end + +function mat_slider:get_value(value) + return self._private.value +end + +function mat_slider:set_read_only(value) + if self._private.read_only ~= value then + self._private.read_only = value + self:emit_signal('property::read_only') + self:emit_signal('widget::layout_changed') + end +end + +function mat_slider:get_read_only(value) + return self._private.read_only +end + +function mat_slider:layout(_, width, height) + local layout = {} + table.insert(layout, base.place_widget_at(self._private.progress_bar, 0, dpi(21), width, height - dpi(42))) + if (not self._private.read_only) then + table.insert(layout, base.place_widget_at(self._private.slider, 0, dpi(6), width, height - dpi(12))) + end + return layout +end + +function mat_slider:draw(_, cr, width, height) + if (self._private.read_only) then + self._private.slider.forced_height = 0 + end +end + +function mat_slider:fit(_, width, height) + return width, height +end + +local function new(args) + local ret = base.make_widget(nil, nil, { + enable_properties = true + }) + + gtable.crush(ret._private, args or {}) + + gtable.crush(ret, mat_slider, true) + + ret._private.progress_bar = wibox.widget { + max_value = 100, + value = 25, + forced_height = dpi(6), + paddings = 0, + shape = gears.shape.rounded_rect, + background_color = beautiful.primary.hue_100, + color = beautiful.accent.hue_400, + widget = wibox.widget.progressbar + } + + ret._private.slider = wibox.widget { + forced_height = dpi(8), + bar_shape = gears.shape.rounded_rect, + bar_height = 0, + bar_color = beautiful.accent.hue_500, + handle_color = beautiful.accent.hue_300, + handle_shape = gears.shape.circle, + handle_border_color = '#00000012', + handle_border_width = dpi(3), + value = 25, + widget = wibox.widget.slider + } + + ret._private.slider:connect_signal('property::value', function() + ret:set_value(ret._private.slider.value) + end) + + ret._private.read_only = false + + return ret +end + +function mat_slider.mt:__call(...) + return new(...) +end + +-- @DOC_widget_COMMON@ + +-- @DOC_object_COMMON@ + +return setmetatable(mat_slider, mat_slider.mt) diff --git a/widget/memory.lua b/widget/memory.lua new file mode 100644 index 0000000..9260f65 --- /dev/null +++ b/widget/memory.lua @@ -0,0 +1,21 @@ +local wibox = require('wibox') +local beautiful = require('beautiful') +local watch = require('awful.widget.watch') + +local memory = wibox.widget.textbox() +memory.font = beautiful.font + +function round(exact, quantum) + local quant,frac = math.modf(exact/quantum) + return quantum * (quant + (frac > 0.5 and 1 or 0)) +end + +watch('bash -c "free | grep -z Mem.*Swap.*"', 1, function(_, stdout) + local total, used, free, shared, buff_cache, available, total_swap, used_swap, free_swap = + stdout:match('(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*Swap:%s*(%d+)%s*(%d+)%s*(%d+)') + + memory.text = round((used / 1048576), 0.01) .. 'GB' + collectgarbage('collect') +end) + +return memory diff --git a/widget/ram/ram-meter.lua b/widget/ram/ram-meter.lua new file mode 100644 index 0000000..970e185 --- /dev/null +++ b/widget/ram/ram-meter.lua @@ -0,0 +1,37 @@ +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') +local mat_slider = require('widget.material.slider') +local mat_icon = require('widget.material.icon') +local icons = require('theme.icons') +local watch = require('awful.widget.watch') +local dpi = require('beautiful').xresources.apply_dpi + +local slider = + wibox.widget { + read_only = true, + widget = mat_slider +} + +watch( + 'bash -c "free | grep -z Mem.*Swap.*"', + 1, + function(_, stdout) + local total, used, free, shared, buff_cache, available, total_swap, used_swap, free_swap = + stdout:match('(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*Swap:%s*(%d+)%s*(%d+)%s*(%d+)') + slider:set_value(used / total * 100) + collectgarbage('collect') + end +) + +local ram_meter = + wibox.widget { + wibox.widget { + icon = icons.memory, + size = dpi(24), + widget = mat_icon + }, + slider, + widget = mat_list_item +} + +return ram_meter diff --git a/widget/storage.lua b/widget/storage.lua new file mode 100644 index 0000000..af13fe9 --- /dev/null +++ b/widget/storage.lua @@ -0,0 +1,12 @@ +local wibox = require('wibox') +local watch = require('awful.widget.watch') +local beautiful = require('beautiful') + +local storage = wibox.widget.textbox() +storage.font = beautiful.font + +watch('bash -c "df -h $HOME | awk \'/[0-9]/ {print $2-$3}\'"', 30, function(_, stdout) + storage.text = stdout +end) + +return storage diff --git a/widget/tag-list.lua b/widget/tag-list.lua new file mode 100644 index 0000000..399373d --- /dev/null +++ b/widget/tag-list.lua @@ -0,0 +1,133 @@ +local awful = require('awful') +local wibox = require('wibox') +local dpi = require('beautiful').xresources.apply_dpi +local capi = { + button = _G.button +} +local clickable_container = require('widget.material.clickable-container') +local modkey = require('configuration.keys.mod').modKey +--- Common method to create buttons. +-- @tab buttons +-- @param object +-- @treturn table +local function create_buttons(buttons, object) + if buttons then + local btns = {} + for _, b in ipairs(buttons) do + -- Create a proxy button object: it will receive the real + -- press and release events, and will propagate them to the + -- button object the user provided, but with the object as + -- argument. + local btn = capi.button { + modifiers = b.modifiers, + button = b.button + } + btn:connect_signal('press', function() + b:emit_signal('press', object) + end) + btn:connect_signal('release', function() + b:emit_signal('release', object) + end) + btns[#btns + 1] = btn + end + + return btns + end +end + +local function list_update(w, buttons, label, data, objects) + -- update the widgets, creating them if needed + w:reset() + for i, o in ipairs(objects) do + local cache = data[o] + local ib, tb, bgb, tbm, ibm, l, bg_clickable + if cache then + ib = cache.ib + tb = cache.tb + bgb = cache.bgb + tbm = cache.tbm + ibm = cache.ibm + else + ib = wibox.widget.imagebox() + tb = wibox.widget.textbox() + bgb = wibox.container.background() + tbm = wibox.container.margin(tb, dpi(6), dpi(6), dpi(4), dpi(4)) + ibm = wibox.container.margin(ib, dpi(8), dpi(8), dpi(9), dpi(9)) + l = wibox.layout.fixed.horizontal() + bg_clickable = clickable_container() + + -- All of this is added in a fixed widget + l:fill_space(true) + -- l:add(ibm) + l:add(tbm) + bg_clickable:set_widget(l) + + -- And all of this gets a background + bgb:set_widget(bg_clickable) + + bgb:buttons(create_buttons(buttons, o)) + + data[o] = { + ib = ib, + tb = tb, + bgb = bgb, + tbm = tbm, + ibm = ibm + } + end + + local text, bg, bg_image, icon, args = label(o, tb) + args = args or {} + + if text == nil or text == '' then + tbm:set_margins(0) + else + if not tb:set_markup_silently(text) then + tb:set_markup('<Invalid text>') + end + end + bgb:set_bg(bg) + if type(bg_image) == 'function' then + bg_image = bg_image(tb, o, nil, objects, i) + end + bgb:set_bgimage(bg_image) + if icon then + ib.image = icon + else + ibm:set_margins(0) + end + + bgb.shape = args.shape + + w:add(bgb) + end +end + +local TagList = function(s) + return awful.widget.taglist(s, awful.widget.taglist.filter.all, + awful.util.table.join(awful.button({}, 1, function(t) + t:view_only() + _G._splash_to_current_tag() + end), awful.button({modkey}, 1, function(t) + if _G.client.focus then + _G.client.focus:move_to_tag(t) + t:view_only() + end + _G._splash_to_current_tag() + end), awful.button({}, 3, function() + awful.tag.viewtoggle() + _G._splash_to_current_tag() + end), awful.button({modkey}, 3, function(t) + if _G.client.focus then + _G.client.focus:toggle_tag(t) + end + _G._splash_to_current_tag() + end), awful.button({}, 4, function(t) + awful.tag.viewprev(t.screen) + _G._splash_to_current_tag() + end), awful.button({}, 5, function(t) + awful.tag.viewnext(t.screen) + _G._splash_to_current_tag() + end)), {}, list_update, wibox.layout.fixed.horizontal()) +end +return TagList diff --git a/widget/task-list.lua b/widget/task-list.lua new file mode 100644 index 0000000..e905bf4 --- /dev/null +++ b/widget/task-list.lua @@ -0,0 +1,147 @@ +local awful = require('awful') +local wibox = require('wibox') +local dpi = require('beautiful').xresources.apply_dpi +local capi = { + button = _G.button +} +local gears = require('gears') +local clickable_container = require('widget.material.clickable-container') +local tasklist_mode = 'text' +local beautiful = require('beautiful') +--- Common method to create buttons. +-- @tab buttons +-- @param object +-- @treturn table +local function create_buttons(buttons, object) + if buttons then + local btns = {} + for _, b in ipairs(buttons) do + -- Create a proxy button object: it will receive the real + -- press and release events, and will propagate them to the + -- button object the user provided, but with the object as + -- argument. + local btn = capi.button { + modifiers = b.modifiers, + button = b.button + } + btn:connect_signal('press', function() + b:emit_signal('press', object) + end) + btn:connect_signal('release', function() + b:emit_signal('release', object) + end) + btns[#btns + 1] = btn + end + + return btns + end +end + +local function list_update(w, buttons, label, data, objects) + -- update the widgets, creating them if needed + w:reset() + for i, o in ipairs(objects) do + local cache = data[o] + local ib, tb, bgb, tbm, ibm, l, ll, bg_clickable + if cache then + ib = cache.ib + tb = cache.tb + bgb = cache.bgb + tbm = cache.tbm + ibm = cache.ibm + else + ib = wibox.widget.imagebox() + tb = wibox.widget.textbox() + bg_clickable = clickable_container() + bgb = wibox.container.background() + tbm = wibox.container.margin(tb, dpi(4), dpi(4), dpi(1), dpi(1)) + ibm = wibox.container.margin(ib, dpi(1), dpi(1), dpi(1), dpi(1)) + l = wibox.layout.fixed.horizontal() + ll = wibox.layout.flex.horizontal() + + -- All of this is added in a fixed widget + l:fill_space(true) + l:add(ibm) + l:add(tbm) + ll:add(l) + + bg_clickable:set_widget(ll) + -- And all of this gets a background + bgb:set_widget(bg_clickable) + + l:buttons(create_buttons(buttons, o)) + + data[o] = { + ib = ib, + tb = tb, + bgb = bgb, + tbm = tbm, + ibm = ibm + } + end + + local text, bg, bg_image, icon, args = label(o, tb) + args = args or {} + + -- The text might be invalid, so use pcall. + if tasklist_mode == 'icon' then + text = nil + elseif tasklist_mode == 'text' then + icon = nil + end + if text == nil or text == '' then + tbm:set_margins(0) + else + if not tb:set_markup_silently(text) then + tb:set_markup('<Invalid text>') + end + end + bgb:set_bg(bg) + if type(bg_image) == 'function' then + bg_image = bg_image(tb, o, nil, objects, i) + end + bgb:set_bgimage(bg_image) + if icon then + ib.image = icon + ib.resize = true + else + ibm:set_margins(0) + end + + bgb.shape = args.shape + bgb.shape_border_width = args.shape_border_width + bgb.shape_border_color = args.shape_border_color + tb.align = 'center' + + w:add(bgb) + end +end + +local tasklist_buttons = awful.util.table.join(awful.button({}, 1, function(c) + if c == _G.client.focus then + c.minimized = true + else + -- Without this, the following + -- :isvisible() makes no sense + c.minimized = false + if not c:isvisible() and c.first_tag then + c.first_tag:view_only() + end + -- This will also un-minimize + -- the client, if needed + _G.client.focus = c + c:raise() + end +end), awful.button({}, 4, function() + awful.client.focus.byidx(1) +end), awful.button({}, 5, function() + awful.client.focus.byidx(-1) +end), awful.button({}, 2, function(c) + c.kill(c) +end)) + +local TaskList = function(s) + return awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, tasklist_buttons, nil, list_update) +end + +return TaskList diff --git a/widget/temperature/temperature-meter.lua b/widget/temperature/temperature-meter.lua new file mode 100644 index 0000000..52162c2 --- /dev/null +++ b/widget/temperature/temperature-meter.lua @@ -0,0 +1,37 @@ +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') +local mat_slider = require('widget.material.slider') +local mat_icon = require('widget.material.icon') +local icons = require('theme.icons') +local watch = require('awful.widget.watch') +local dpi = require('beautiful').xresources.apply_dpi + +local slider = + wibox.widget { + read_only = true, + widget = mat_slider +} + +local max_temp = 80 +watch( + 'bash -c "cat /sys/class/thermal/thermal_zone0/temp"', + 1, + function(_, stdout) + local temp = stdout:match('(%d+)') + slider:set_value((temp / 1000) / max_temp * 100) + collectgarbage('collect') + end +) + +local temperature_meter = + wibox.widget { + wibox.widget { + icon = icons.thermometer, + size = dpi(24), + widget = mat_icon + }, + slider, + widget = mat_list_item +} + +return temperature_meter diff --git a/widget/temprature.lua b/widget/temprature.lua new file mode 100644 index 0000000..caeabf3 --- /dev/null +++ b/widget/temprature.lua @@ -0,0 +1,12 @@ +local wibox = require('wibox') +local watch = require('awful.widget.watch') +local beautiful = require('beautiful') + +local temprature = wibox.widget.textbox() +temprature.font = beautiful.font + +watch('bash -c "sensors | awk \'/Core 0/ {print substr($3, 2) }\'"', 30, function(_, stdout) + temprature.text = stdout +end) + +return temprature diff --git a/widget/volume.lua b/widget/volume.lua new file mode 100644 index 0000000..aa3fe5d --- /dev/null +++ b/widget/volume.lua @@ -0,0 +1,50 @@ +local awful = require("awful") +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') +local dpi = require('beautiful').xresources.apply_dpi +local watch = require('awful.widget.watch') +local beautiful = require('beautiful') + +local volume_icon = wibox.widget.textbox() +volume_icon.font = beautiful.icon_font +local volume_widget = wibox.widget.textbox() +volume_widget.align = 'center' +volume_widget.valign = 'center' +volume_widget.font = beautiful.font + +local volume + +function update_volume() + awful.spawn.easy_async_with_shell("bash -c 'amixer -D pulse sget Master'", function(stdout) + volume = string.match(stdout, '(%d?%d?%d)%%') + awful.spawn.easy_async_with_shell("bash -c 'pacmd list-sinks | awk '/muted/ { print $2 }''", function(muted) + muted = string.gsub(muted, "%s+", "") + if muted == 'muted:no' and (volume > '50' or volume == '100') then + volume_icon.text = '墳' + elseif muted == 'muted:no' and volume <= '50' and volume > '0' then + volume_icon.text = '奔' + elseif muted == 'muted:yes' then + volume_icon.text = '婢' + elseif volume == '0' then + volume_icon.text = '奄' + end + volume_widget.text = volume + end) + collectgarbage('collect') + end) +end + +watch('bash -c', 3, function(_, stdout) + update_volume() +end) + +return wibox.widget { + wibox.widget{ + volume_icon, + fg = beautiful.accent.hue_100, + widget = wibox.container.background + }, + volume_widget, + spacing = dpi(2), + layout = wibox.layout.fixed.horizontal +} diff --git a/widget/volume/volume-slider.lua b/widget/volume/volume-slider.lua new file mode 100644 index 0000000..a833cb3 --- /dev/null +++ b/widget/volume/volume-slider.lua @@ -0,0 +1,28 @@ +local wibox = require('wibox') +local mat_list_item = require('widget.material.list-item') +local mat_slider = require('widget.material.slider') +local mat_icon_button = require('widget.material.icon-button') +local icons = require('theme.icons') +local watch = require('awful.widget.watch') +local spawn = require('awful.spawn') + +local slider = wibox.widget {read_only = false, widget = mat_slider} + +slider:connect_signal('property::value', function() + spawn('amixer -D pulse sset Master ' .. slider.value .. '%') +end) + +watch([[bash -c "amixer -D pulse sget Master"]], 1, function(_, stdout) + local mute = string.match(stdout, '%[(o%D%D?)%]') + local volume = string.match(stdout, '(%d?%d?%d)%%') + slider:set_value(tonumber(volume)) + collectgarbage('collect') +end) + +local icon = wibox.widget {image = icons.volume, widget = wibox.widget.imagebox} + +local button = mat_icon_button(icon) + +local volume_setting = wibox.widget {button, slider, widget = mat_list_item} + +return volume_setting diff --git a/widget/weather.lua b/widget/weather.lua new file mode 100644 index 0000000..715c974 --- /dev/null +++ b/widget/weather.lua @@ -0,0 +1,560 @@ +------------------------------------------------- +-- Weather Widget based on the OpenWeatherMap +-- https://openweathermap.org/ +-- +-- @author Pavel Makhov +-- @copyright 2020 Pavel Makhov +------------------------------------------------- +local awful = require("awful") +local watch = require("awful.widget.watch") +local json = require("json") +local naughty = require("naughty") +local wibox = require("wibox") +local gears = require("gears") +local beautiful = require("beautiful") + +local HOME_DIR = os.getenv("HOME") +local WIDGET_DIR = HOME_DIR .. '/.config/awesome/awesome-wm-widgets/weather-widget' +local GET_FORECAST_CMD = [[bash -c "curl -s --show-error -X GET '%s'"]] + +local function show_warning(message) + naughty.notify { + preset = naughty.config.presets.critical, + title = 'Weather Widget', + text = message + } +end + +local weather_widget = {} +local warning_shown = false +local tooltip = awful.tooltip { + mode = 'outside', + preferred_positions = {'bottom'} +} + +local weather_popup = awful.popup { + ontop = true, + visible = false, + shape = gears.shape.rounded_rect, + border_width = 1, + border_color = beautiful.bg_focus, + maximum_width = 400, + offset = {y = 5}, + widget = {} +} + +--- Maps openWeatherMap icon name to file name w/o extension +local icon_map = { + ["01d"] = "clear-sky", + ["02d"] = "few-clouds", + ["03d"] = "scattered-clouds", + ["04d"] = "broken-clouds", + ["09d"] = "shower-rain", + ["10d"] = "rain", + ["11d"] = "thunderstorm", + ["13d"] = "snow", + ["50d"] = "mist", + ["01n"] = "clear-sky-night", + ["02n"] = "few-clouds-night", + ["03n"] = "scattered-clouds-night", + ["04n"] = "broken-clouds-night", + ["09n"] = "shower-rain-night", + ["10n"] = "rain-night", + ["11n"] = "thunderstorm-night", + ["13n"] = "snow-night", + ["50n"] = "mist-night" +} + +--- Return wind direction as a string +local function to_direction(degrees) + -- Ref: https://www.campbellsci.eu/blog/convert-wind-directions + if degrees == nil then return "Unknown dir" end + local directions = { + "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", + "WSW", "W", "WNW", "NW", "NNW", "N" + } + return directions[math.floor((degrees % 360) / 22.5) + 1] +end + +--- Convert degrees Celsius to Fahrenheit +local function celsius_to_fahrenheit(c) return c * 9 / 5 + 32 end + +-- Convert degrees Fahrenheit to Celsius +local function fahrenheit_to_celsius(f) return (f - 32) * 5 / 9 end + +local function gen_temperature_str(temp, fmt_str, show_other_units, units) + local temp_str = string.format(fmt_str, temp) + local s = temp_str .. '°' .. (units == 'metric' and 'C' or 'F') + + if (show_other_units) then + local temp_conv, units_conv + if (units == 'metric') then + temp_conv = celsius_to_fahrenheit(temp) + units_conv = 'F' + else + temp_conv = fahrenheit_to_celsius(temp) + units_conv = 'C' + end + + local temp_conv_str = string.format(fmt_str, temp_conv) + s = s .. ' ' .. '(' .. temp_conv_str .. '°' .. units_conv .. ')' + end + return s +end + +local function uvi_index_color(uvi) + local color + if uvi >= 0 and uvi < 3 then color = '#A3BE8C' + elseif uvi >= 3 and uvi < 6 then color = '#EBCB8B' + elseif uvi >= 6 and uvi < 8 then color = '#D08770' + elseif uvi >= 8 and uvi < 11 then color = '#BF616A' + elseif uvi >= 11 then color = '#B48EAD' + end + + return '' .. uvi .. '' +end + +local function worker(user_args) + + local args = user_args or {} + + --- Validate required parameters + if args.coordinates == nil or args.api_key == nil then + show_warning('Required parameters are not set: ' .. + (args.coordinates == nil and 'coordinates' or '') .. + (args.api_key == nil and ', api_key ' or '')) + return + end + + local coordinates = args.coordinates + local api_key = args.api_key + local font_name = args.font_name or beautiful.font:gsub("%s%d+$", "") + local units = args.units or 'metric' + local time_format_12h = args.time_format_12h + local both_units_widget = args.both_units_widget or false + local show_hourly_forecast = args.show_hourly_forecast + local show_daily_forecast = args.show_daily_forecast + local icon_pack_name = args.icons or 'weather-underground-icons' + local icons_extension = args.icons_extension or '.png' + local timeout = args.timeout or 120 + + local ICONS_DIR = WIDGET_DIR .. '/icons/' .. icon_pack_name .. '/' + local owm_one_cal_api = + ('https://api.openweathermap.org/data/2.5/onecall' .. + '?lat=' .. coordinates[1] .. '&lon=' .. coordinates[2] .. '&appid=' .. api_key .. + '&units=' .. units .. '&exclude=minutely' .. + (show_hourly_forecast == false and ',hourly' or '') .. + (show_daily_forecast == false and ',daily' or '')) + + weather_widget = wibox.widget { + { + { + { + { + id = 'icon', + resize = true, + widget = wibox.widget.imagebox + }, + valign = 'center', + widget = wibox.container.place, + }, + { + id = 'txt', + widget = wibox.widget.textbox + }, + layout = wibox.layout.fixed.horizontal, + }, + margins = 4, + layout = wibox.container.margin + }, + shape = function(cr, width, height) + gears.shape.rounded_rect(cr, width, height, 4) + end, + widget = wibox.container.background, + set_image = function(self, path) + self:get_children_by_id('icon')[1].image = path + end, + set_text = function(self, text) + self:get_children_by_id('txt')[1].text = text + end, + is_ok = function(self, is_ok) + if is_ok then + self:get_children_by_id('icon')[1]:set_opacity(1) + self:get_children_by_id('icon')[1]:emit_signal('widget:redraw_needed') + else + self:get_children_by_id('icon')[1]:set_opacity(0.2) + self:get_children_by_id('icon')[1]:emit_signal('widget:redraw_needed') + end + end + } + + local current_weather_widget = wibox.widget { + { + { + { + id = 'icon', + resize = true, + forced_width = 128, + forced_height = 128, + widget = wibox.widget.imagebox + }, + align = 'center', + widget = wibox.container.place + }, + { + id = 'description', + font = font_name .. ' 10', + align = 'center', + widget = wibox.widget.textbox + }, + forced_width = 128, + layout = wibox.layout.align.vertical + }, + { + { + { + id = 'temp', + font = font_name .. ' 36', + widget = wibox.widget.textbox + }, + { + id = 'feels_like_temp', + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + layout = wibox.layout.fixed.vertical + }, + { + { + id = 'wind', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + { + id = 'humidity', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + { + id = 'uv', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + expand = 'inside', + layout = wibox.layout.align.vertical + }, + spacing = 16, + forced_width = 150, + layout = wibox.layout.fixed.vertical + }, + forced_width = 300, + layout = wibox.layout.flex.horizontal, + update = function(self, weather) + self:get_children_by_id('icon')[1]:set_image( + ICONS_DIR .. icon_map[weather.weather[1].icon] .. icons_extension) + self:get_children_by_id('temp')[1]:set_text(gen_temperature_str(weather.temp, '%.0f', false, units)) + self:get_children_by_id('feels_like_temp')[1]:set_text( + 'Feels like ' .. gen_temperature_str(weather.feels_like, '%.0f', false, units)) + self:get_children_by_id('description')[1]:set_text(weather.weather[1].description) + self:get_children_by_id('wind')[1]:set_markup( + 'Wind: ' .. weather.wind_speed .. 'm/s (' .. to_direction(weather.wind_deg) .. ')') + self:get_children_by_id('humidity')[1]:set_markup('Humidity: ' .. weather.humidity .. '%') + self:get_children_by_id('uv')[1]:set_markup('UV: ' .. uvi_index_color(weather.uvi)) + end + } + + + local daily_forecast_widget = { + forced_width = 300, + layout = wibox.layout.flex.horizontal, + update = function(self, forecast, timezone_offset) + local count = #self + for i = 0, count do self[i]=nil end + for i, day in ipairs(forecast) do + if i > 5 then break end + local day_forecast = wibox.widget { + { + text = os.date('%a', tonumber(day.dt) + tonumber(timezone_offset)), + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + { + { + { + image = ICONS_DIR .. icon_map[day.weather[1].icon] .. icons_extension, + resize = true, + forced_width = 48, + forced_height = 48, + widget = wibox.widget.imagebox + }, + align = 'center', + layout = wibox.container.place + }, + { + text = day.weather[1].description, + font = font_name .. ' 8', + align = 'center', + forced_height = 50, + widget = wibox.widget.textbox + }, + layout = wibox.layout.fixed.vertical + }, + { + { + text = gen_temperature_str(day.temp.day, '%.0f', false, units), + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + { + text = gen_temperature_str(day.temp.night, '%.0f', false, units), + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + layout = wibox.layout.fixed.vertical + }, + spacing = 8, + layout = wibox.layout.fixed.vertical + } + table.insert(self, day_forecast) + end + end + } + + local hourly_forecast_graph = wibox.widget { + step_width = 12, + color = '#EBCB8B', + background_color = beautiful.bg_normal, + forced_height = 100, + forced_width = 300, + widget = wibox.widget.graph, + set_max_value = function(self, new_max_value) + self.max_value = new_max_value + end, + set_min_value = function(self, new_min_value) + self.min_value = new_min_value + end + } + local hourly_forecast_negative_graph = wibox.widget { + step_width = 12, + color = '#5E81AC', + background_color = beautiful.bg_normal, + forced_height = 100, + forced_width = 300, + widget = wibox.widget.graph, + set_max_value = function(self, new_max_value) + self.max_value = new_max_value + end, + set_min_value = function(self, new_min_value) + self.min_value = new_min_value + end + } + + local hourly_forecast_widget = { + layout = wibox.layout.fixed.vertical, + update = function(self, hourly) + local hours_below = { + id = 'hours', + forced_width = 300, + layout = wibox.layout.flex.horizontal + } + local temp_below = { + id = 'temp', + forced_width = 300, + layout = wibox.layout.flex.horizontal + } + + local max_temp = -1000 + local min_temp = 1000 + local values = {} + for i, hour in ipairs(hourly) do + if i > 25 then break end + values[i] = hour.temp + if max_temp < hour.temp then max_temp = hour.temp end + if min_temp > hour.temp then min_temp = hour.temp end + if (i - 1) % 5 == 0 then + table.insert(hours_below, wibox.widget { + text = os.date(time_format_12h and '%I%p' or '%H:00', tonumber(hour.dt)), + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }) + table.insert(temp_below, wibox.widget { + markup = '' + .. string.format('%.0f', hour.temp) .. '°' .. '', + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }) + end + end + + hourly_forecast_graph:set_max_value(math.max(max_temp, math.abs(min_temp))) + hourly_forecast_graph:set_min_value(min_temp > 0 and min_temp * 0.7 or 0) -- move graph a bit up + + hourly_forecast_negative_graph:set_max_value(math.abs(min_temp)) + hourly_forecast_negative_graph:set_min_value(max_temp < 0 and math.abs(max_temp) * 0.7 or 0) + + for _, value in ipairs(values) do + if value >= 0 then + hourly_forecast_graph:add_value(value) + hourly_forecast_negative_graph:add_value(0) + else + hourly_forecast_graph:add_value(0) + hourly_forecast_negative_graph:add_value(math.abs(value)) + end + end + + local count = #self + for i = 0, count do self[i]=nil end + + -- all temperatures are positive + if min_temp > 0 then + table.insert(self, wibox.widget{ + { + hourly_forecast_graph, + reflection = {horizontal = true}, + widget = wibox.container.mirror + }, + { + temp_below, + valign = 'bottom', + widget = wibox.container.place + }, + id = 'graph', + layout = wibox.layout.stack + }) + table.insert(self, hours_below) + + -- all temperatures are negative + elseif max_temp < 0 then + table.insert(self, hours_below) + table.insert(self, wibox.widget{ + { + hourly_forecast_negative_graph, + reflection = {horizontal = true, vertical = true}, + widget = wibox.container.mirror + }, + { + temp_below, + valign = 'top', + widget = wibox.container.place + }, + id = 'graph', + layout = wibox.layout.stack + }) + + -- there are both negative and positive temperatures + else + table.insert(self, wibox.widget{ + { + hourly_forecast_graph, + reflection = {horizontal = true}, + widget = wibox.container.mirror + }, + { + temp_below, + valign = 'bottom', + widget = wibox.container.place + }, + id = 'graph', + layout = wibox.layout.stack + }) + table.insert(self, wibox.widget{ + { + hourly_forecast_negative_graph, + reflection = {horizontal = true, vertical = true}, + widget = wibox.container.mirror + }, + { + hours_below, + valign = 'top', + widget = wibox.container.place + }, + id = 'graph', + layout = wibox.layout.stack + }) + end + end + } + + local function update_widget(widget, stdout, stderr) + if stderr ~= '' then + if not warning_shown then + if (stderr ~= 'curl: (52) Empty reply from server' + and stderr ~= 'curl: (28) Failed to connect to api.openweathermap.org port 443: Connection timed out' + and stderr:find('^curl: %(18%) transfer closed with %d+ bytes remaining to read$') ~= nil + ) then + show_warning(stderr) + end + warning_shown = true + widget:is_ok(false) + tooltip:add_to_object(widget) + + widget:connect_signal('mouse::enter', function() tooltip.text = stderr end) + end + return + end + + warning_shown = false + tooltip:remove_from_object(widget) + widget:is_ok(true) + + local result = json.decode(stdout) + + widget:set_image(ICONS_DIR .. icon_map[result.current.weather[1].icon] .. icons_extension) + widget:set_text(gen_temperature_str(result.current.temp, '%.0f', both_units_widget, units)) + + current_weather_widget:update(result.current) + + local final_widget = { + current_weather_widget, + spacing = 16, + layout = wibox.layout.fixed.vertical + } + + if show_hourly_forecast then + hourly_forecast_widget:update(result.hourly) + table.insert(final_widget, hourly_forecast_widget) + end + + if show_daily_forecast then + daily_forecast_widget:update(result.daily, result.timezone_offset) + table.insert(final_widget, daily_forecast_widget) + end + + weather_popup:setup({ + { + final_widget, + margins = 10, + widget = wibox.container.margin + }, + bg = beautiful.bg_normal, + widget = wibox.container.background + }) + end + + weather_widget:buttons(gears.table.join(awful.button({}, 1, function() + if weather_popup.visible then + weather_widget:set_bg('#00000000') + weather_popup.visible = not weather_popup.visible + else + weather_widget:set_bg(beautiful.bg_focus) + weather_popup:move_next_to(mouse.current_widget_geometry) + end + end))) + + watch( + string.format(GET_FORECAST_CMD, owm_one_cal_api), + timeout, -- API limit is 1k req/day; day has 1440 min; every 2 min is good + update_widget, weather_widget + ) + + return weather_widget +end + +return setmetatable(weather_widget, {__call = function(_, ...) return worker(...) end})