diff --git a/awesome/src/assets/cache/rules.txt b/awesome/src/assets/cache/rules.txt index 2d47ca5..e69de29 100644 --- a/awesome/src/assets/cache/rules.txt +++ b/awesome/src/assets/cache/rules.txt @@ -1 +0,0 @@ -Lutris;Io.elementary.appcenter;Repoman;Com.github.donadigo.eddy;Sysmontask;join?action=join&confno=9992624875&confid=dXRpZD1VVElEXzM0ODYxOTgyYzg0YzQ1Y2NiYmM0YWNiMzczODNiYjgxJnVzcz1TaU1YUnNEWG5BQWNBYnRpYklBNWE0MjRDNkpBMzMyVXRUc2pCX1YxVm5JY0hWeVRybGN5WjZZS2VBa1pvNkszOXdNWEVkVE9hTU54Z3BROFZFckhPR3Y4eGo0MlB0emNCZjNRLnNlM28yNy13YWpGYy1ReXEmdGlkPTcyNjEzNGRjYWJkZTQyYTNhNzJmZjVjYjVkNTU2YTYw&browser=join?action=join&confno=9992624875&confid=dXRpZD1VVElEXzM0ODYxOTgyYzg0YzQ1Y2NiYmM0YWNiMzczODNiYjgxJnVzcz1TaU1YUnNEWG5BQWNBYnRpYklBNWE0MjRDNkpBMzMyVXRUc2pCX1YxVm5JY0hWeVRybGN5WjZZS2VBa1pvNkszOXdNWEVkVE9hTU54Z3BROFZFckhPR3Y4eGo0MlB0emNCZjNRLnNlM28yNy13YWpGYy1ReXEmdGlkPTcyNjEzNGRjYWJkZTQyYTNhNzJmZjVjYjVkNTU2YTYw&browser=Gnome-calculator;Virt-manager;Gwe;whatsdesk;Totem;steam_app_431960;Viewer,;Viewer,;Nvidia-settings;openrgb;Minecraft;Pavucontrol;jamesdsp; \ No newline at end of file diff --git a/awesome/src/assets/userpfp/crylia.png b/awesome/src/assets/userpfp/crylia.png index 671fbe2..44f69c6 100644 Binary files a/awesome/src/assets/userpfp/crylia.png and b/awesome/src/assets/userpfp/crylia.png differ diff --git a/awesome/src/bindings/global_keys.lua b/awesome/src/bindings/global_keys.lua index 40e30dc..2e12be0 100644 --- a/awesome/src/bindings/global_keys.lua +++ b/awesome/src/bindings/global_keys.lua @@ -235,7 +235,7 @@ return gears.table.join( awful.key( {}, "XF86AudioMute", - function(c) + function() awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") awesome.emit_signal("widget::volume_osd:rerun") end, @@ -244,11 +244,11 @@ return gears.table.join( awful.key( {}, "XF86MonBrightnessUp", - function(c) + function() awful.spawn.easy_async_with_shell( - "pkexec xfpm-power-backlight-helper --get-brightness", + "xfpm-power-backlight-helper --get-brightness", function(stdout) - awful.spawn("pkexec xfpm-power-backlight-helper --set-brightness " .. + awful.spawn(awful.util.getdir("config") .. "src/scripts/backlight.sh set " .. tostring(tonumber(stdout) + BACKLIGHT_SEPS)) awesome.emit_signal("brightness::update") end @@ -259,12 +259,11 @@ return gears.table.join( awful.key( {}, "XF86MonBrightnessDown", - function(c) + function() awful.spawn.easy_async_with_shell( - "pkexec xfpm-power-backlight-helper --get-brightness", + "xfpm-power-backlight-helper --get-brightness", function(stdout) - awful.spawn( - "pkexec xfpm-power-backlight-helper --set-brightness " .. + awful.spawn(awful.util.getdir("config") .. "src/scripts/backlight.sh set " .. tostring(tonumber(stdout) - BACKLIGHT_SEPS)) awesome.emit_signal("brightness::update") end diff --git a/awesome/src/config/dock.json b/awesome/src/config/dock.json index 1d118c6..5173dac 100644 --- a/awesome/src/config/dock.json +++ b/awesome/src/config/dock.json @@ -1 +1 @@ -[{"actions":["New"],"categories":"System;TerminalEmulator;","comment":"A fast, cross-platform, OpenGL terminal emulator","desktop_file":"/usr/share/applications/com.alacritty.Alacritty.desktop","exec":"alacritty","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/com.alacritty.Alacritty.svg","keywords":"","name":"Alacritty","terminal":""},{"actions":["new-window","new-private-window"],"categories":"Network;WebBrowser;","comment":"Access the Internet","desktop_file":"/var/lib/flatpak/exports/share/applications/com.brave.Browser.desktop","exec":"/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=brave --file-forwarding com.brave.Browser @@u %U @@","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/com.brave.Browser.svg","keywords":"","name":"Brave","terminal":""},{"actions":["new-empty-window"],"categories":"TextEditor;Development;IDE;","comment":"Code Editing. Redefined.","desktop_file":"/usr/share/applications/code.desktop","exec":"/usr/share/code/code --unity-launch %F","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/com.visualstudio.code.svg","keywords":"vscode;","name":"Visual Studio Code","terminal":""},{"actions":[],"categories":"Audio;Music;Player;AudioVideo;","comment":"","desktop_file":"/usr/local/share/applications/spotify.desktop","exec":"spotify %U","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/spotify-client.svg","keywords":"","name":"Spotify","terminal":""},{"actions":[],"categories":"Network;InstantMessaging;","comment":"All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone.","desktop_file":"/usr/share/applications/discord.desktop","exec":"/usr/share/discord/Discord","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/discord.svg","keywords":"","name":"Discord","terminal":""},{"actions":["Store","Community","Library","Servers","Screenshots","News","Settings","BigPicture","Friends"],"categories":"Network;FileTransfer;Game;","comment":"Application for managing and playing games on Steam","desktop_file":"/usr/share/applications/steam.desktop","exec":"/usr/games/steam %U","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/steam.svg","keywords":"Games","name":"Steam","terminal":""},{"actions":["Remove"],"categories":"Graphics;","comment":"Cura converts 3D models into paths for a 3D printer. It prepares your print for maximum accuracy, minimum printing time and good reliability with many extra features that make your print come out great.","desktop_file":"/home/crylia/.local/share/applications/appimagekit_5de59b772d786d6e98102a035c80e40c-Ultimaker_Cura.desktop","exec":"/home/crylia/Applications/Ultimaker-Cura-5.0.0-linux_07ecc3f54905e865167d2bcd7cfe459c.AppImage %F","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/appimagekit-cura-icon.svg","keywords":"3D;Printing;","name":"Ultimaker Cura (5.0.0)","terminal":""},{"actions":[],"categories":"Game;","comment":"video game preservation platform","desktop_file":"/usr/share/applications/net.lutris.Lutris.desktop","exec":"lutris %U","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/lutris.svg","keywords":"gaming;wine;emulator;","name":"Lutris","terminal":""},{"actions":[],"categories":"Graphics;Science;Engineering","comment":"Feature based Parametric Modeler","desktop_file":"/usr/share/applications/freecad.desktop","exec":"/usr/bin/freecad --single-instance %F","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/freecad.svg","keywords":"","name":"FreeCAD","terminal":""},{"actions":[],"categories":"Graphics;3DGraphics;","comment":"3D modeling, animation, rendering and post-production","desktop_file":"/usr/share/applications/blender.desktop","exec":"blender %f","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/blender.svg","keywords":"3d;cg;modeling;animation;painting;sculpting;texturing;video editing;video tracking;rendering;render engine;cycles;game engine;python;","name":"Blender","terminal":""},{"actions":[],"categories":"Game;","comment":"Play this game on Steam","desktop_file":"/home/crylia/.local/share/applications/The Witcher 3 Wild Hunt.desktop","exec":"steam steam://rungameid/292030","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/steam_icon_292030.svg","keywords":"","name":"The Witcher 3: Wild Hunt","terminal":""},{"actions":[],"categories":"Game;","comment":"Play this game on Steam","desktop_file":"/home/crylia/.local/share/applications/Hearts of Iron IV.desktop","exec":"steam steam://rungameid/394360","icon":"/home/crylia/.local/share/icons/hicolor/64x64/apps/steam_icon_394360.png","keywords":"","name":"Hearts of Iron IV","terminal":""},{"actions":["Compose","Contacts"],"categories":"Application;Network;Email;","comment":"Send and receive mail with Thunderbird","desktop_file":"/usr/share/applications/thunderbird.desktop","exec":"thunderbird %u","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/thunderbird.svg","keywords":"Email;E-mail;Newsgroup;Feed;RSS","name":"Thunderbird-E-Mail und -Nachrichten","terminal":""}] \ No newline at end of file +[{"actions":["New"],"categories":"System;TerminalEmulator;","comment":"A fast, cross-platform, OpenGL terminal emulator","desktop_file":"/usr/share/applications/com.alacritty.Alacritty.desktop","exec":"alacritty","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/com.alacritty.Alacritty.svg","keywords":"","name":"Alacritty","terminal":""},{"actions":["new-empty-window"],"categories":"TextEditor;Development;IDE;","comment":"Code Editing. Redefined.","desktop_file":"/usr/share/applications/code.desktop","exec":"/usr/share/code/code --unity-launch %F","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/com.visualstudio.code.svg","keywords":"vscode;","name":"Visual Studio Code","terminal":""},{"actions":[],"categories":"Audio;Music;Player;AudioVideo;","comment":"","desktop_file":"/usr/share/applications/spotify.desktop","exec":"spotify %U","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/spotify-client.svg","keywords":"","name":"Spotify","terminal":""},{"actions":[],"categories":"Network;InstantMessaging;","comment":"All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone.","desktop_file":"/usr/share/applications/discord.desktop","exec":"/usr/share/discord/Discord","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/discord.svg","keywords":"","name":"Discord","terminal":""},{"actions":[],"categories":"Network;InstantMessaging;","comment":"Mattermost Desktop application for Linux","desktop_file":"/home/crylia/.local/share/flatpak/exports/share/applications/com.mattermost.Desktop.desktop","exec":"/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=mattermost-flatpak --file-forwarding com.mattermost.Desktop --enable-features=WebRTCPipeWireCapturer @@u %U @@","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/com.mattermost.Desktop.svg","keywords":"","name":"Mattermost","terminal":""},{"actions":[],"categories":"Graphics;Science;Engineering","comment":"Feature based Parametric Modeler","desktop_file":"/usr/share/applications/freecad.desktop","exec":"/usr/bin/freecad --single-instance %F","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/freecad.svg","keywords":"","name":"FreeCAD","terminal":""},{"actions":["Compose","Contacts"],"categories":"Application;Network;Email;","comment":"Send and receive mail with Thunderbird","desktop_file":"/usr/share/applications/thunderbird.desktop","exec":"thunderbird %u","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/thunderbird.svg","keywords":"Email;E-mail;Newsgroup;Feed;RSS","name":"Thunderbird-E-Mail und -Nachrichten","terminal":""},{"actions":["new-window","new-private-window"],"categories":"Network;WebBrowser;","comment":"Access the Internet","desktop_file":"/usr/share/applications/brave-browser.desktop","exec":"/usr/bin/brave-browser-stable %U","icon":"/usr/share/icons/Papirus-Dark/64x64/categories/brave-browser.svg","keywords":"","name":"Brave Web Browser","terminal":""}] \ No newline at end of file diff --git a/awesome/src/config/floating.json b/awesome/src/config/floating.json index 392b837..bb4cd42 100644 --- a/awesome/src/config/floating.json +++ b/awesome/src/config/floating.json @@ -1 +1 @@ -[{"WM_CLASS":"Paradox Launcher","WM_INSTANCE":"paradox launcher","WM_NAME":"Paradox Launcher"},{"WM_CLASS":"Com.github.donadigo.eddy","WM_INSTANCE":"com.github.donadigo.eddy","WM_NAME":"Eddy"},{"WM_CLASS":"jamesdsp","WM_INSTANCE":"jamesdsp","WM_NAME":"JamesDSP for Linux"},{"WM_CLASS":"Gwe","WM_INSTANCE":"gwe","WM_NAME":"GWE"},{"WM_CLASS":"Steam","WM_INSTANCE":"Steam","WM_NAME":"Freundesliste"},{"WM_CLASS":"Thunderbird","WM_INSTANCE":"Calendar","WM_NAME":"New Event:"},{"WM_CLASS":"Thunderbird","WM_INSTANCE":"Mail","WM_NAME":"Calendar - Mozilla Thunderbird"},{"WM_CLASS":"Proton Mail Bridge","WM_INSTANCE":"proton-bridge","WM_NAME":"Proton Mail Bridge"}] \ No newline at end of file +[{"WM_CLASS":"Com.github.donadigo.eddy","WM_INSTANCE":"com.github.donadigo.eddy","WM_NAME":"Eddy"},{"WM_CLASS":"Proton Mail Bridge","WM_INSTANCE":"proton-bridge","WM_NAME":"Proton Mail Bridge"},{"WM_CLASS":"Thunderbird","WM_INSTANCE":"Mail","WM_NAME":"Account Setup - Mozilla Thunderbird"},{"WM_CLASS":"Protonvpn","WM_INSTANCE":"protonvpn","WM_NAME":"Proton VPN"}] \ No newline at end of file diff --git a/awesome/src/modules/crylia_bar/dock.lua b/awesome/src/modules/crylia_bar/dock.lua index 8971db8..b26c236 100644 --- a/awesome/src/modules/crylia_bar/dock.lua +++ b/awesome/src/modules/crylia_bar/dock.lua @@ -3,7 +3,6 @@ -------------------------------------------------------------------------------------------------------------- -- Awesome Libs local awful = require("awful") -local async = require("async") local dpi = require("beautiful").xresources.apply_dpi local Gio = require("lgi").Gio local gears = require("gears") @@ -26,7 +25,7 @@ return function(screen) ---@param size number The size of the widget ---@return widox.widget | nil The widget or nil if the program is not found local function create_dock_element(program, size) - + if not program then return end local dock_element = wibox.widget { { { @@ -165,13 +164,15 @@ return function(screen) end local prog = json:decode(data:read("a")) + if (not prog) or prog == "" then return end for _, pr in ipairs(prog) do local indicators = { layout = wibox.layout.flex.horizontal, spacing = dpi(5) } local col = Theme_config.dock.indicator_bg for _, c in ipairs(client.get()) do local icon_name = pr.icon - if icon_name:match(string.lower(c.class or c.name)) or c.class:match(string.lower(icon_name)) or - c.name:match(string.lower(icon_name)) then + if not c.class then return end + if icon_name:match(string.lower(c.class)) or c.class:match(string.lower(icon_name)) or + (string.lower(c.name) == string.lower(icon_name)) or c.name:match(string.lower(icon_name)) then if c == client.focus then col = Theme_config.dock.indicator_focused_bg elseif c.urgent then @@ -252,6 +253,9 @@ return function(screen) return end local dock_data = json:decode(data:read("a")) + if (not dock_data) or dock_data == "" then + return + end for _, program in ipairs(dock_data) do table.insert(dock_elements, create_dock_element(program, User_config.dock_icon_size)) end diff --git a/awesome/src/modules/network_controller/init.lua b/awesome/src/modules/network_controller/init.lua new file mode 100644 index 0000000..510e618 --- /dev/null +++ b/awesome/src/modules/network_controller/init.lua @@ -0,0 +1,130 @@ +------------------------------------ +-- This is the network controller -- +------------------------------------ + +-- Awesome Libs +local awful = require("awful") +local dpi = require("beautiful").xresources.apply_dpi +local gears = require("gears") +local wibox = require("wibox") + +local rubato = require("src.lib.rubato") + +local icondir = awful.util.getdir("config") .. "src/assets/icons/network/" + +return function(s) + + local function get_connected_network() + + end + + local network_controller = wibox.widget { + { + { + { -- Connected + { --Connected header + { + { + text = "Connected to", + widget = wibox.widget.textbox + }, + widget = wibox.container.background + }, + widget = wibox.container.margin + }, + { -- Connected network + { + get_connected_network(), + widget = wibox.container.background + }, + widget = wibox.container.margin + }, + layout = wibox.layout.fixed.vertical + }, + { -- Discovered networks + { --Discovered header + { + { + text = "Available networks", + widget = wibox.widget.textbox + }, + widget = wibox.container.background + }, + widget = wibox.container.margin + }, + { -- Discovered networks list + + }, + spacing = dpi(10), + layout = wibox.layout.fixed.vertical + }, + { -- Airplanemode/Refresh buttons + { -- Airplane mode toggle + { + { + { + -- TODO: Replace with image + text = "Airplane mode", + widget = wibox.widgeet.textbox + }, + widget = wibox.container.margin + }, + shape = function(cr, width, height) + gears.shape.rounded_rect(cr, width, height, dpi(5)) + end, + widget = wibox.container.background + }, + widget = wibox.container.margin + }, + { -- Refresh button + { + { + { + -- TODO: Replace with image + text = "Refresh", + widget = wibox.widgeet.textbox + }, + widget = wibox.container.margin + }, + shape = function(cr, width, height) + gears.shape.rounded_rect(cr, width, height, dpi(5)) + end, + widget = wibox.container.background + }, + widget = wibox.container.margin + }, + layout = wibox.layout.align.horizontal + }, + layout = wibox.layout.fixed.vertical + }, + margins = dpi(10), + widget = wibox.container.margin + }, + width = dpi(400), + strategy = "exact", + widget = wibox.container.constraint + } + + local network_controller_container = awful.popup { + widget = wibox.container.background, + bg = Theme_config.network_controller.bg, + border_color = Theme_config.network_controller.border_color, + border_width = Theme_config.network_controller.border_width, + screen = s, + stretch = false, + visible = false, + ontop = true, + placement = function(c) awful.placement.align(c, + { position = "top_right", margins = { right = dpi(350), top = dpi(60) } }) + end, + shape = function(cr, width, height) + gears.shape.rounded_rect(cr, width, height, dpi(12)) + end + } + + network_controller_container:setup { + network_controller, + layout = wibox.layout.fixed.vertical + } + +end diff --git a/awesome/src/modules/notification-center/status_bars.lua b/awesome/src/modules/notification-center/status_bars.lua index 8862cba..abe2b98 100644 --- a/awesome/src/modules/notification-center/status_bars.lua +++ b/awesome/src/modules/notification-center/status_bars.lua @@ -649,12 +649,20 @@ return function() } awesome.connect_signal( - "update::backlight", - function(backlight, backlight_icon) - w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(backlight_icon, + "brightness::get", + function(brightness) + local icon = icondir .. "brightness/brightness" + if brightness >= 0 and brightness < 34 then + icon = icon .. "-low" + elseif brightness >= 34 and brightness < 67 then + icon = icon .. "-medium" + elseif brightness >= 67 then + icon = icon .. "-high" + end + w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(icon .. ".svg", Theme_config.notification_center.status_bar.backlight_color) - tooltip.text = "Backlight: " .. backlight .. "%" - rubato_timer.target = backlight + tooltip.text = "Backlight: " .. brightness .. "%" + rubato_timer.target = brightness end ) elseif widget == "battery" then diff --git a/awesome/src/scripts/backlight.sh b/awesome/src/scripts/backlight.sh new file mode 100755 index 0000000..47bbb54 --- /dev/null +++ b/awesome/src/scripts/backlight.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +case $1 in + "get") + echo $(xfpm-power-backlight-helper --get-brightness) + ;; + "set") + echo $(pkexec xfpm-power-backlight-helper --set-brightness $2) + ;; +esac diff --git a/awesome/src/theme/user_config.lua b/awesome/src/theme/user_config.lua index a14fe93..c5c42aa 100644 --- a/awesome/src/theme/user_config.lua +++ b/awesome/src/theme/user_config.lua @@ -20,11 +20,9 @@ User_config = { "picom --experimental-backends", "xfce4-power-manager", "light-locker --lock-on-suspend --lock-on-lid &", - "spotify", - "discord", "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1", "setxkbmap -option caps:swapescape", - "jamesdsp" + "protonmail-bridge" }, --[[ @@ -47,7 +45,7 @@ User_config = { "MEDIA_PLAYER" More information at: https://lazka.github.io/pgi-docs/UPowerGlib-1.0/enums.html#UPowerGlib.DeviceKind.KEYBOARD ]] -- - battery_kind = "LINE_POWER", + battery_kind = "BATTERY", --[[ If your battery is not found you can specify its path here. @@ -193,8 +191,8 @@ User_config = { "ram_usage", "microphone", "volume", - "gpu_temp", - "gpu_usage" + "backlight", + "battery" }, --[[ @@ -277,10 +275,8 @@ User_config = { "Tasklist" }, right_bar = { - "Gpu Usage", - "Gpu Temperature", - "Cpu Usage", - "Cpu Temperature", + "Battery", + "Bluetooth", "Audio", "Keyboard Layout", "Date", diff --git a/awesome/src/tools/gio_icon_lookup.lua b/awesome/src/tools/gio_icon_lookup.lua index c43411a..b0479d8 100644 --- a/awesome/src/tools/gio_icon_lookup.lua +++ b/awesome/src/tools/gio_icon_lookup.lua @@ -17,6 +17,7 @@ Gtk.IconTheme.set_custom_theme(gtk_theme, User_config.icon_theme) ---@param app Gio.AppInfo ---@return string path function Get_gicon_path(app) + if not app then return "" end local icon_info = gtk_theme:lookup_by_gicon(app, 64, 0) if icon_info then local path = icon_info:get_filename() @@ -36,12 +37,12 @@ function Get_icon(class, name) name = string.lower(name or "") for _, app in ipairs(app_list) do local desktop_app_info = Gio.DesktopAppInfo.new(app_info.get_id(app)) - local icon_string = Gio.DesktopAppInfo.get_string(desktop_app_info, "Icon") + local icon_string = Gio.DesktopAppInfo.get_string(desktop_app_info, "Name") if icon_string then icon_string = string.lower(icon_string) if icon_string:match(class) or class:match(icon_string) then return Get_gicon_path(app_info.get_icon(app)) - elseif icon_string:match(name) or name:match(icon_string) then + elseif (icon_string == name) or icon_string:match(name) or name:match(icon_string) then return Get_gicon_path(app_info.get_icon(app)) end end diff --git a/awesome/src/tools/helpers/backlight.lua b/awesome/src/tools/helpers/backlight.lua index c80388c..66a814f 100644 --- a/awesome/src/tools/helpers/backlight.lua +++ b/awesome/src/tools/helpers/backlight.lua @@ -3,7 +3,7 @@ local awful = require("awful") BACKLIGHT_MAX_BRIGHTNESS = 0 BACKLIGHT_SEPS = 0 awful.spawn.easy_async_with_shell( - "pkexec xfpm-power-backlight-helper --get-max-brightness", + "xfpm-power-backlight-helper --get-max-brightness", function(stdout) BACKLIGHT_MAX_BRIGHTNESS = tonumber(stdout) BACKLIGHT_SEPS = BACKLIGHT_MAX_BRIGHTNESS / 100 @@ -15,7 +15,7 @@ awesome.connect_signal( "brightness::update", function() awful.spawn.easy_async_with_shell( - "pkexec xfpm-power-backlight-helper --get-brightness", + "xfpm-power-backlight-helper --get-brightness", function(value) awesome.emit_signal("brightness::get", math.floor((tonumber(value) - 1) / (BACKLIGHT_MAX_BRIGHTNESS - 1) * 100)) awesome.emit_signal("brightness::rerun") @@ -23,3 +23,5 @@ awesome.connect_signal( ) end ) + +awesome.emit_signal("brightness::update") diff --git a/awesome/src/tools/helpers/init.lua b/awesome/src/tools/helpers/init.lua index 87470cb..ac312c2 100644 --- a/awesome/src/tools/helpers/init.lua +++ b/awesome/src/tools/helpers/init.lua @@ -5,4 +5,4 @@ require("src.tools.helpers.ram") require("src.tools.helpers.gpu_usage") require("src.tools.helpers.gpu_temp") require("src.tools.helpers.audio") ---require("src.tools.helpers.backlight") +require("src.tools.helpers.backlight") diff --git a/awesome/src/tools/helpers/network_manager.lua b/awesome/src/tools/helpers/network_manager.lua new file mode 100644 index 0000000..4e51f90 --- /dev/null +++ b/awesome/src/tools/helpers/network_manager.lua @@ -0,0 +1,441 @@ +------------------------------------------- +-- @author https://github.com/Kasper24 +-- @copyright 2021-2022 Kasper24 +------------------------------------------- + +local lgi = require("lgi") +local NM = lgi.NM +local awful = require("awful") +local gobject = require("gears.object") +local gtable = require("gears.table") +local gtimer = require("gears.timer") +local helpers = require("helpers") +local dbus_proxy = require("services.dbus_proxy") + +local network = {} +local instance = nil + +network.NMState = { + UNKNOWN = 0, -- Networking state is unknown. This indicates a daemon error that + -- makes it unable to reasonably assess the state. In such event the applications + -- are expected to assume Internet connectivity might be present and not disable + -- controls that require network access. The graphical shells may hide the network + -- accessibility indicator altogether since no meaningful status indication can be provided. + ASLEEP = 10, -- Networking is not enabled, the system is being suspended or resumed from suspend. + DISCONNECTED = 20, -- There is no active network connection. The graphical + -- shell should indicate no network connectivity and the applications + -- should not attempt to access the network. + DISCONNECTING = 30, -- Network connections are being cleaned up. + -- The applications should tear down their network sessions. + CONNECTING = 40, -- A network connection is being started The graphical + -- shell should indicate the network is being connected while the + -- applications should still make no attempts to connect the network. + CONNECTED_LOCAL = 50, -- There is only local IPv4 and/or IPv6 connectivity, + -- but no default route to access the Internet. The graphical + -- shell should indicate no network connectivity. + CONNECTED_SITE = 60, -- There is only site-wide IPv4 and/or IPv6 connectivity. + -- This means a default route is available, but the Internet connectivity check + -- (see "Connectivity" property) did not succeed. The graphical shell + -- should indicate limited network connectivity. + CONNECTED_GLOBAL = 70, -- There is global IPv4 and/or IPv6 Internet connectivity + -- This means the Internet connectivity check succeeded, the graphical shell should + -- indicate full network connectivity. +} + +network.DeviceType = { + ETHERNET = 1, + WIFI = 2 +} + +network.DeviceState = { + UNKNOWN = 0, -- the device's state is unknown + UNMANAGED = 10, -- the device is recognized, but not managed by NetworkManager + UNAVAILABLE = 20, --the device is managed by NetworkManager, + --but is not available for use. Reasons may include the wireless switched off, + --missing firmware, no ethernet carrier, missing supplicant or modem manager, etc. + DISCONNECTED = 30, -- the device can be activated, + --but is currently idle and not connected to a network. + PREPARE = 40, -- the device is preparing the connection to the network. + -- This may include operations like changing the MAC address, + -- setting physical link properties, and anything else required + -- to connect to the requested network. + CONFIG = 50, -- the device is connecting to the requested network. + -- This may include operations like associating with the Wi-Fi AP, + -- dialing the modem, connecting to the remote Bluetooth device, etc. + NEED_AUTH = 60, -- the device requires more information to continue + -- connecting to the requested network. This includes secrets like WiFi passphrases, + -- login passwords, PIN codes, etc. + IP_CONFIG = 70, -- the device is requesting IPv4 and/or IPv6 addresses + -- and routing information from the network. + IP_CHECK = 80, -- the device is checking whether further action + -- is required for the requested network connection. + -- This may include checking whether only local network access is available, + -- whether a captive portal is blocking access to the Internet, etc. + SECONDARIES = 90, -- the device is waiting for a secondary connection + -- (like a VPN) which must activated before the device can be activated + ACTIVATED = 100, -- the device has a network connection, either local or global. + DEACTIVATING = 110, -- a disconnection from the current network connection + -- was requested, and the device is cleaning up resources used for that connection. + -- The network connection may still be valid. + FAILED = 120 -- the device failed to connect to + -- the requested network and is cleaning up the connection request +} + +function network.device_state_to_string(state) + local device_state_to_string = + { + [0] = "Unknown", + [10] = "Unmanaged", + [20] = "Unavailable", + [30] = "Disconnected", + [40] = "Prepare", + [50] = "Config", + [60] = "Need Auth", + [70] = "IP Config", + [80] = "IP Check", + [90] = "Secondaries", + [100] = "Activated", + [110] = "Deactivated", + [120] = "Failed" + } + + return device_state_to_string[state] +end + +local function flags_to_security(flags, wpa_flags, rsn_flags) + local str = "" + if flags == 1 and wpa_flags == 0 and rsn_flags == 0 then + str = str .. " WEP" + end + if wpa_flags ~= 0 then + str = str .. " WPA1" + end + if not rsn_flags ~= 0 then + str = str .. " WPA2" + end + if wpa_flags == 512 or rsn_flags == 512 then + str = str .. " 802.1X" + end + + return (str:gsub("^%s", "")) +end + +local function generate_uuid() + local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' + local uuid = string.gsub(template, '[xy]', function(c) + local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) + return string.format('%x', v) + end) + return uuid +end + +local function create_profile(access_point, password, auto_connect) + local s_con = + { + -- ["interface-name"] = lgi.GLib.Variant("s", access_point.device_interface), + ["uuid"] = lgi.GLib.Variant("s", generate_uuid()), + ["id"] = lgi.GLib.Variant("s", access_point.ssid), + ["type"] = lgi.GLib.Variant("s", "802-11-wireless"), + ["autoconnect"] = lgi.GLib.Variant("b", auto_connect), + } + + local s_ip4 = + { + ["method"] = lgi.GLib.Variant("s", "auto") + } + + local s_ip6 = + { + ["method"] = lgi.GLib.Variant("s", "auto"), + } + + local s_wifi = + { + ["mode"] = lgi.GLib.Variant("s", "infrastructure"), + } + + local s_wsec = {} + if access_point.security ~= "" then + if access_point.security:match("WPA") ~= nil then + s_wsec["key-mgmt"] = lgi.GLib.Variant("s", "wpa-psk") + s_wsec["auth-alg"] = lgi.GLib.Variant("s", "open") + s_wsec["psk"] = lgi.GLib.Variant("s", helpers.string.trim(password)) + else + s_wsec["key-mgmt"] = lgi.GLib.Variant("s", "None") + s_wsec["wep-key-type"] = lgi.GLib.Variant("s", NM.WepKeyType.PASSPHRASE) + s_wsec["wep-key0"] = lgi.GLib.Variant("s", helpers.string.trim(password)) + end + end + + return { + ["connection"] = s_con, + ["ipv4"] = s_ip4, + ["ipv6"] = s_ip6, + ["802-11-wireless"] = s_wifi, + ["802-11-wireless-security"] = s_wsec + } +end + +local function on_wifi_device_state_changed(self, proxy, new_state, old_state, reason) + local active_access_point_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.NetworkManager.AccessPoint", + path = self._private.wifi_proxy.ActiveAccessPoint + } + + self:emit_signal(tostring(active_access_point_proxy.HwAddress) .. "::state", new_state, old_state) + if new_state == network.DeviceState.ACTIVATED then + local ssid = NM.utils_ssid_to_utf8(active_access_point_proxy.Ssid) + self:emit_signal("access_point::connected", ssid, active_access_point_proxy.Strength) + end +end + +local function get_access_point_connections(self, ssid) + local connection_proxies = {} + + local connections = self._private.settings_proxy:ListConnections() + for _, connection_path in ipairs(connections) do + local connection_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.NetworkManager.Settings.Connection", + path = connection_path + } + + if string.find(connection_proxy.Filename, ssid) then + table.insert(connection_proxies, connection_proxy) + end + end + + return connection_proxies +end + +local function get_wifi_proxy(self) + local devices = self._private.client_proxy:GetDevices() + for _, device_path in ipairs(devices) do + local device_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.NetworkManager.Device", + path = device_path + } + + if device_proxy.DeviceType == network.DeviceType.WIFI then + self._private.device_proxy = device_proxy + self._private.wifi_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.NetworkManager.Device.Wireless", + path = device_path + } + + self._private.device_proxy:connect_signal("StateChanged", function(proxy, new_state, old_state, reason) + on_wifi_device_state_changed(self, proxy, new_state, old_state, reason) + end) + end + end +end + +function network:scan_access_points() + self._private.access_points = {} + + self._private.wifi_proxy:RequestScanAsync(function(proxy, context, success, failure) + if failure ~= nil then + print("Rescan wifi failed: ", failure) + print("Rescan wifi failed error code: ", failure.code) + self:emit_signal("scan_access_points::failed", tostring(failure), tostring(failure.code)) + return + end + + local access_points = self._private.wifi_proxy:GetAccessPoints() + for _, access_point_path in ipairs(access_points) do + local access_point_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.NetworkManager.AccessPoint", + path = access_point_path + } + + -- for _, access_point in ipairs(self._private.access_points) do + -- if access_point.hw_address == access_point_proxy.HwAddress then + -- print("duplicates") + -- return + -- end + -- end + + if access_point_proxy.Ssid ~= nil then + local ssid = NM.utils_ssid_to_utf8(access_point_proxy.Ssid) + local security = flags_to_security(access_point_proxy.Flags, access_point_proxy.WpaFlags, + access_point_proxy.RsnFlags) + local password = "" + local connections = get_access_point_connections(self, ssid) + + for _, connection in ipairs(connections) do + if string.find(connection.Filename, ssid) then + local secrets = connection:GetSecrets("802-11-wireless-security") + if secrets ~= nil then + password = secrets["802-11-wireless-security"].psk + end + end + end + + table.insert(self._private.access_points, { + raw_ssid = access_point_proxy.Ssid, + ssid = ssid, + security = security, + password = password, + strength = access_point_proxy.Strength, + path = access_point_path, + hw_address = access_point_proxy.HwAddress, + device_interface = self._private.device_proxy.Interface, + device_proxy_path = self._private.device_proxy.object_path, + }) + end + end + + table.sort(self._private.access_points, function(a, b) + return a.strength > b.strength + end) + + self:emit_signal("scan_access_points::success", self._private.access_points) + end, { call_id = "my-id" }, {}) +end + +function network:connect_to_access_point(access_point, password, auto_connect) + local connections = get_access_point_connections(self, access_point.ssid) + local profile = create_profile(access_point, password, auto_connect) + + -- No connection profiles, need to create one + if #connections == 0 then + -- AddAndActivateConnectionAsync doesn't actually verify that the profile is valid + -- The NetworkManager libary has methods to verify manually, but they are not exposed to DBus + -- so instead I'm using the 2 seperate methods + self._private.client_proxy:AddAndActivateConnectionAsync(function(proxy, context, success, failure) + if failure ~= nil then + print("Failed to activate connection: ", failure) + print("Failed to activate connection error code: ", failure.code) + self:emit_signal("activate_access_point::failed", tostring(failure), tostring(failure.code)) + return + end + + self:emit_signal("activate_access_point::success", access_point.ssid) + end, { call_id = "my-id" }, profile, access_point.device_proxy_path, access_point.path) + else + connections[1]:Update(profile) + self._private.client_proxy:ActivateConnectionAsync(function(proxy, context, success, failure) + if failure ~= nil then + print("Failed to activate connection: ", failure) + print("Failed to activate connection error code: ", failure.code) + self:emit_signal("activate_access_point::failed", tostring(failure), tostring(failure.code)) + return + end + + self:emit_signal("activate_access_point::success", access_point.ssid) + + end, { call_id = "my-id" }, connections[1].object_path, access_point.device_proxy_path, access_point.path) + end +end + +function network:is_access_point_active(access_point) + return access_point.path == self._private.wifi_proxy.ActiveAccessPoint +end + +function network:disconnect_from_access_point() + self._private.client_proxy:DeactivateConnection(self._private.device_proxy.ActiveConnection) +end + +function network:toggle_access_point(access_point, password, auto_connect) + if self:is_access_point_active(access_point) then + self:disconnect_from_access_point() + else + self:connect_to_access_point(access_point, password, auto_connect) + end +end + +function network:toggle_wireless_state() + local enable = not self._private.client_proxy.WirelessEnabled + if enable == true then + self:set_network_state(true) + end + + self._private.client_proxy:Set("org.freedesktop.NetworkManager", "WirelessEnabled", lgi.GLib.Variant("b", enable)) + self._private.client_proxy.WirelessEnabled = { signature = "b", value = enable } +end + +function network:set_network_state(state) + self._private.client_proxy:Enable(state) +end + +function network:open_settings() + awful.spawn("nm-connection-editor", false) +end + +local function new() + local ret = gobject {} + gtable.crush(ret, network, true) + + ret._private = {} + ret._private.access_points = {} + + ret._private.client_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.NetworkManager", + path = "/org/freedesktop/NetworkManager" + } + + ret._private.settings_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.NetworkManager.Settings", + path = "/org/freedesktop/NetworkManager/Settings" + } + + local client_properties_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.DBus.Properties", + path = "/org/freedesktop/NetworkManager" + } + + client_properties_proxy:connect_signal("PropertiesChanged", function(self, interface, data) + if data.WirelessEnabled ~= nil and ret._private.WirelessEnabled ~= data.WirelessEnabled then + ret._private.WirelessEnabled = data.WirelessEnabled + ret:emit_signal("wireless_state", data.WirelessEnabled) + + if data.WirelessEnabled == true then + gtimer { timeout = 5, autostart = true, call_now = false, single_shot = true, callback = function() + ret:scan_access_points() + end } + end + end + end) + + get_wifi_proxy(ret) + ret:scan_access_points() + + gtimer.delayed_call(function() + ret:emit_signal("wireless_state", ret._private.client_proxy.WirelessEnabled) + + local active_access_point = ret._private.wifi_proxy.ActiveAccessPoint + if ret._private.device_proxy.State == network.DeviceState.ACTIVATED and active_access_point ~= "/" then + local active_access_point_proxy = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = "org.freedesktop.NetworkManager", + interface = "org.freedesktop.NetworkManager.AccessPoint", + path = active_access_point + } + + local ssid = NM.utils_ssid_to_utf8(active_access_point_proxy.Ssid) + ret:emit_signal("access_point::connected", ssid, active_access_point_proxy.Strength) + end + end) + + return ret +end + +if not instance then + instance = new() +end +return instance