diff --git a/.config/colors/hyprland.conf b/.config/colors/hyprland.conf
index a49eee5..e563860 100644
--- a/.config/colors/hyprland.conf
+++ b/.config/colors/hyprland.conf
@@ -1,2 +1,3 @@
-$active_color = rgba(98C1D9FF)
+#$active_color = rgba(f55c20ff)
+$active_color = rgba(de3c3cff)
$inactive_color = rgba(595959aa)
diff --git a/.config/hypr/config/environment.conf b/.config/hypr/config/environment.conf
index f0b8fdf..4a2e550 100644
--- a/.config/hypr/config/environment.conf
+++ b/.config/hypr/config/environment.conf
@@ -5,10 +5,11 @@
# See https://wiki.hyprland.org/Configuring/Keywords/
# Set programs that you use
-$terminal = kitty
+$terminal = foot
#$fileManager = cosmic-files
$fileManager = nautilus
-$menu = albert toggle
+# $menu = albert toggle
+$menu = rofi -show drun
$notificationManager = swaync-client -t
diff --git a/.config/hypr/config/input.conf b/.config/hypr/config/input.conf
index 36248c9..ca3b6c4 100644
--- a/.config/hypr/config/input.conf
+++ b/.config/hypr/config/input.conf
@@ -18,9 +18,7 @@ input {
}
# https://wiki.hyprland.org/Configuring/Variables/#gestures
-gestures {
- workspace_swipe = true
-}
+gesture = 3, horizontal, workspace
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
@@ -55,7 +53,7 @@ bind = $mainMod, X, exec, $terminal # Absolutely not because I dislocated my arm
bind = $mainMod, SPACE, exec, $menu
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, A, exec, $notificationManager
-bindel = , XF86Launch1, exec, kitty vim ~/.config/hypr/config
+bindel = , XF86Launch1, exec, $terminal hx ~/.config/hypr/config # Replace by default editor
# Move focus with mainMod + arrow keys
bind = $mainMod, left, movefocus, l
@@ -63,6 +61,12 @@ bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d
+# Move windows with mainMod + shift + arrow keys
+bind = $mainMod SHIFT, left, movewindow, l
+bind = $mainMod SHIFT, right, movewindow, r
+bind = $mainMod SHIFT, up, movewindow, u
+bind = $mainMod SHIFT, down, movewindow, d
+
# Layout
bind = $mainMod, F, fullscreen,
bind = $mainMod, V, togglesplit, # Horizontal/vertical split
diff --git a/.config/hypr/hyprlock.conf b/.config/hypr/hyprlock.conf
index de83a38..03b7e53 100644
--- a/.config/hypr/hyprlock.conf
+++ b/.config/hypr/hyprlock.conf
@@ -1,12 +1,24 @@
# BACKGROUND
+## Old config
+# background {
+# monitor =
+# path = ~/.config/hypr/images/lockscreen.jpg
+# blur_passes = 0
+# #contrast = 0.8916
+# #brightness = 0.8172
+# #vibrancy = 0.1696
+# #vibrancy_darkness = 0.0
+# }
background {
monitor =
- path = ~/.config/hypr/images/lockscreen.jpg
- blur_passes = 0
- #contrast = 0.8916
- #brightness = 0.8172
- #vibrancy = 0.1696
- #vibrancy_darkness = 0.0
+ path = screenshot # 'screenshot' = auto-capture screen and blur it
+ blur_passes = 3
+ blur_size = 4
+ noise = 0.0
+ contrast = 0.7
+ brightness = 0.8172
+ vibrancy = 0.2
+ vibrancy_darkness = 0.0
}
# GENERAL
@@ -31,7 +43,7 @@ input-field {
font_color = rgb(200, 200, 200)
fade_on_empty = false
font_family = DejaVu Sans
- placeholder_text = Enter Pass
+ placeholder_text = Enter password
hide_input = false
position = 0, -350
halign = center
@@ -83,16 +95,40 @@ label {
#}
# USER
-#label {
-# monitor =
-# text = Hi, Guillem #$USER
-# color = rgba(216, 222, 233, 0.70)
-# font_size = 20
-# font_family = DejaVu Sans
-# position = 0, -200
-# halign = center
-# valign = center
-#}
+label {
+ monitor =
+ text = $USER
+ color = rgba(216, 222, 233, 0.70)
+ font_size = 20
+ font_family = JetbrainsMonoNL NF
+ position = 0, -200
+ halign = center
+ valign = center
+}
+
+# Timer
+label {
+ monitor =
+ text = cmd[update:0] echo "Locked since $TIME"
+ color = rgba(216, 222, 233, 0.40)
+ font_size = 20
+ font_family = JetbrainsMonoNL NF
+ position = 0, -250
+ halign = center
+ valign = center
+}
+
+# # Failed login attempts
+# label {
+# monitor =
+# text = cmd[update:1000] echo "$ATTEMPTS Failed attempts"
+# color = rgba(216, 222, 233, 0.40)
+# font_size = 20
+# font_family = JetbrainsMonoNL NF
+# position = 0, -250
+# halign = center
+# valign = center
+# }
# CURRENT SONG
label {
@@ -100,7 +136,7 @@ label {
text = cmd[update:1000] echo "$(~/.config/hypr/scripts/songdetails.sh)"
color = rgba(255, 255, 255, 0.7)
font_size = 16
- font_family = DejaVu Sans
+ font_family = JetbrainsMonoNL NF
position = 0, 20
halign = center
valign = bottom
diff --git a/.config/hypr/hyprpaper.conf b/.config/hypr/hyprpaper.conf
index 51bf3ef..246b059 100644
--- a/.config/hypr/hyprpaper.conf
+++ b/.config/hypr/hyprpaper.conf
@@ -1,2 +1,2 @@
-preload = ~/.config/hypr/images/wallpaper.JPG
-wallpaper = , ~/.config/hypr/images/wallpaper.JPG
+preload = ~/.config/hypr/images/wallpaper.jpg
+wallpaper = , ~/.config/hypr/images/wallpaper.jpg
diff --git a/.config/hypr/images/lockscreen.jpg b/.config/hypr/images/lockscreen.jpg
deleted file mode 100644
index c9c6b41..0000000
Binary files a/.config/hypr/images/lockscreen.jpg and /dev/null differ
diff --git a/.config/hypr/images/wallpaper.jpg b/.config/hypr/images/wallpaper.jpg
index 4f3b069..4167f89 100644
Binary files a/.config/hypr/images/wallpaper.jpg and b/.config/hypr/images/wallpaper.jpg differ
diff --git a/.config/kitty/seventy-nine.conf b/.config/kitty/seventy-nine.conf
index 0d75685..6b93975 100644
--- a/.config/kitty/seventy-nine.conf
+++ b/.config/kitty/seventy-nine.conf
@@ -7,7 +7,8 @@
#: The basic colors
foreground #adbac7
-background #14171F
+background #0d1117
+#background #14171F
#background #111317
selection_foreground #EE6C4D
selection_background #3D5A80
diff --git a/.config/rofi/config.rasi b/.config/rofi/config.rasi
new file mode 100644
index 0000000..4c9d9d5
--- /dev/null
+++ b/.config/rofi/config.rasi
@@ -0,0 +1 @@
+@theme "~/.local/share/rofi/themes/boussole.rasi"
diff --git a/.config/rofi/wifi/config.rasi b/.config/rofi/wifi/config.rasi
new file mode 100644
index 0000000..7c698e0
--- /dev/null
+++ b/.config/rofi/wifi/config.rasi
@@ -0,0 +1,5 @@
+/* @theme "./themes/rosepine.rasi" */
+@theme "~/.local/share/rofi/themes/boussole.rasi"
+ configuration {
+ terminal: "foot";
+ }
diff --git a/.config/waybar/Atlas/config.jsonc b/.config/waybar/Atlas/config.jsonc
new file mode 100644
index 0000000..a147e99
--- /dev/null
+++ b/.config/waybar/Atlas/config.jsonc
@@ -0,0 +1,508 @@
+{
+ "layer": "top",
+ "position": "right",
+ "margin": "1 1 1 2",
+ "reload_style_on_change": true,
+
+ // Modules display
+
+ "modules-left": [
+ //"custom/updates",
+ "hyprland/workspaces",
+ "hyprland/submap"
+ //"group/info",
+ //"hyprland/window"
+ ],
+
+ "modules-right": [
+ "custom/recorder",
+ "privacy",
+ "group/brightness",
+ "group/sound",
+ "group/connection",
+ "tray",
+ "group/together",
+ //"group/cnoti",
+ "group/power"
+ ],
+
+
+ // Modules definition
+
+ // Up
+
+ "hyprland/workspaces": {
+ "format": "{icon}",
+ "on-click": "activate",
+ "all-outputs": true,
+ "format-icons": {
+ "1": "1",
+ "2": "2",
+ "3": "3",
+ "4": "4",
+ "5": "5",
+ "6": "6",
+ "7": "7",
+ "8": "8",
+ "9": "9",
+ "10": "10"
+ }
+ },
+ "hyprland/submap": {
+ "format": "",
+ "max-length": 8,
+ "tooltip": true
+ },
+ "group/info": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 500,
+ "transition-left-to-right": false
+ },
+ "modules": [
+ "custom/dmark",
+ "group/gcpu",
+ "memory",
+ "disk",
+ "hyprland/window"
+ ]
+ },
+ "hyprland/window": {
+ "orientation": "vertical",
+ "format":"{class}",
+ "spearate-outputs": true,
+ "icon": false
+ },
+ "custom/dmark": {
+ "format": "",
+ "tooltip": false
+ },
+ "group/gcpu": {
+ "orientation": "inherit",
+ "modules": [
+ "custom/cpu-icon",
+ "custom/cputemp",
+ "cpu"
+ ]
+ },
+ "custom/cpu-icon": {
+ "format": "",
+ "tooltip": false
+ },
+ "custom/cputemp": {
+ "format": "{}",
+ "exec": "~/.config/waybar/bin/cputemp",
+ "interval": 10,
+ "return-type": "json"
+ },
+ "cpu": {
+ "format": "{usage}",
+ "on-click": "foot btop"
+ },
+ "memory": {
+ "format": " \n{:2}"
+ },
+ "disk": {
+ "interval": 600,
+ "format": " \n{percentage_used}",
+ "path": "/"
+ },
+
+ // Bottom
+
+ "custom/recorder": {
+ "format": "{}",
+ "interval": "once",
+ "exec": "echo ''",
+ "tooltip": "false",
+ "exec-if": "pgrep 'wl-screenrec'",
+ "on-click": "recorder",
+ "signal": 4
+ },
+ "privacy": {
+ "orientation": "vertical",
+ "icon-spacing": 4,
+ "icon-size": 14,
+ "transition-duration": 250,
+ "modules": [
+ {
+ "type": "screenshare",
+ "tooltip": true,
+ "tooltip-icon-size": 24
+ }
+ ]
+ },
+ "group/brightness": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 500,
+ "transition-left-to-right": false
+ },
+ "modules": [
+ "backlight"
+ //"backlight/slider"
+ ]
+ },
+ "backlight": {
+ "device": "intel_backlight",
+ "format": "{icon}",
+ "format-icons": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ],
+ "on-scroll-down": "brightnessctl s 5%-",
+ "on-scroll-up": "brightnessctl s +5%",
+ "tooltip": true,
+ "tooltip-format": "Brightness: {percent}% ",
+ "smooth-scrolling-threshold": 1
+ },
+ "backlight/slider": {
+ "min": 1,
+ "max": 100,
+ "orientation": "vertical",
+ "device": "intel_backlight"
+ },
+ "group/sound": {
+ "orientation": "inherit",
+ "modules": [
+ "group/audio",
+ "custom/notifications"
+ ]
+ },
+ "group/audio": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 500,
+ "transition-left-to-right": false
+ },
+ "modules": [
+ "pulseaudio",
+ "pulseaudio#mic",
+ "pulseaudio/slider"
+ ]
+ },
+ "group/cnoti": {
+ "orientation": "inherit",
+ "modules": [
+ "custom/github"
+ ]
+ },
+ "group/connection": {
+ "orientation": "inherit",
+ "modules": [
+ //"custom/vpn",
+ "custom/hotspot",
+ "group/network"
+ //"group/bluetooth"
+ ]
+ },
+ "group/together": {
+ "orientation": "inherit",
+ "modules": [
+ "group/utils",
+ "clock"
+ ]
+ },
+ "group/utils": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 500,
+ "transition-left-to-right": true
+ },
+ "modules": [
+ "custom/mark",
+ "custom/weather",
+ "custom/colorpicker",
+ "custom/hyprshade",
+ "idle_inhibitor"
+ //"custom/hyprkill"
+ ]
+ },
+ "group/network": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 500,
+ "transition-left-to-right": false
+ },
+ "modules": [
+ "network",
+ "network#speed"
+ ]
+ },
+ "group/bluetooth": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 500,
+ "transition-left-to-right": true
+ },
+ "modules": [
+ "bluetooth",
+ "bluetooth#status"
+ ]
+ },
+ "group/battery": {
+ "orientation":"vertical",
+ "modules": [
+ "battery",
+ "custom/battery_percentage",
+ ]
+ },
+ "group/power": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 500,
+ "transition-left-to-right": false
+ },
+ "modules": [
+ "group/battery",
+ "power-profiles-daemon",
+ ]
+ },
+ "tray": {
+ "icon-size": 18,
+ "spacing": 10
+ },
+ "pulseaudio": {
+ "format": "{icon}",
+ "format-bluetooth": "{icon}",
+ "tooltip-format": "{volume}% {icon} | {desc}",
+ "format-muted": "",
+ "format-icons": {
+ "headphones": "",
+ "handsfree": "",
+ "headset": "",
+ "phone": "",
+ "portable": "",
+ "car": " ",
+ "default": [
+ "",
+ "",
+ ""
+ ]
+ },
+ "on-click": "volume mute",
+ //"on-click-middle": "pavucontrol",
+ "on-scroll-up": "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+",
+ "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ -5%",
+ "smooth-scrolling-threshold": 1
+ },
+ "pulseaudio#mic": {
+ "format": "{format_source}",
+ "format-source": "",
+ "format-source-muted": "",
+ "tooltip-format": "{volume}% {format_source} ",
+ "on-click": "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle",
+ "on-scroll-down": "wpctl set-volume @DEFAULT_SOURCE@ 5%-",
+ "on-scroll-up": "wpctl set-volume -l 1 @DEFAULT_SOURCE@ 5%+"
+ },
+ "pulseaudio/slider": {
+ "min": 0,
+ "max": 100,
+ "orientation": "vertical"
+ },
+ "network": {
+ "format": "{icon}",
+ "format-icons": {
+ "wifi": [
+ ""
+ ],
+ "ethernet": [
+ ""
+ ],
+ "disconnected": [
+ ""
+ ]
+ },
+ "format-wifi": "",
+ "format-ethernet": "",
+ "format-disconnected": "",
+ "format-linked": "",
+ "tooltip": false,
+ //"on-click": "pgrep -x rofi &>/dev/null && notify-send rofi || networkmanager_dmenu"
+ "on-click": "kitty nmtui"
+ },
+ "network#speed": {
+ "format": " {bandwidthDownBits} ",
+ "rotate": 90,
+ "interval": 5,
+ "tooltip-format": "{ipaddr}",
+ "tooltip-format-wifi": "{essid} ({signalStrength}%) \n{ipaddr} | {frequency} MHz{icon} ",
+ "tooltip-format-ethernet": "{ifname} \n{ipaddr} | {frequency} MHz{icon} ",
+ "tooltip-format-disconnected": "Not Connected to any type of Network",
+ "tooltip": true,
+ "on-click": "pgrep -x rofi &>/dev/null && notify-send rofi || networkmanager_dmenu"
+ },
+ "bluetooth": {
+ "format-on": "",
+ "format-off": "",
+ "format-disabled": "",
+ "format-connected": "",
+ "tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected",
+ "tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}",
+ "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}",
+ "tooltip-format-enumerate-connected-battery": "{device_alias}\t{device_address}\t{device_battery_percentage}%",
+ //"on-click": "rofi-bluetooth -config ~/.config/rofi/menu.d/network.rasi -i"
+ "on-click": "toggle-bluetooth"
+ },
+ "bluetooth#status": {
+ "format-on": "",
+ "format-off": "",
+ "format-disabled": "",
+ "format-connected": "{num_connections}",
+ "format-connected-battery": "{device_battery_percentage}%",
+ "tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected",
+ "tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}",
+ "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}",
+ "tooltip-format-enumerate-connected-battery": "{device_alias}\t{device_address}\t{device_battery_percentage}%",
+ "on-click": "rofi-bluetooth -config ~/.config/rofi/menu.d/network.rasi -i"
+ },
+ "battery": {
+ "rotate": 270,
+ "states": {
+ "good": 95,
+ "warning": 16,
+ "critical": 8
+ },
+ "format": "{icon}",
+ "interval": 1,
+ "format-charging": "",
+ "format-full": "{icon}",
+ "format-icons": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ],
+ "tooltip-format": "{timeTo} {capacity} % | {power} W"
+ },
+ "custom/battery_percentage": {
+ "format": "{}",
+ //"exec": "cat /sys/class/power_supply/BAT*/capacity",
+
+ // Makes battery like if 85% was the maximum capacity (100%).
+ // Useful for people that limit charge up to a certain percentage but like having real percentage
+ "exec": "echo $(( $(cat /sys/class/power_supply/BAT*/capacity) * 100 / 85 ))",
+ "interval": 10,
+ "tooltip": false
+ },
+ "clock": {
+ "format": "{:%H\n%M}",
+ "tooltip-format": "{calendar}",
+ "calendar": {
+ "mode": "month",
+ "mode-mon-col": 3,
+ "weeks-pos": "right",
+ "on-scroll": 1,
+ "on-click-right": "mode",
+ "on-click": "swaync-client -t",
+ "format": {
+ "today": "{}"
+ }
+ }
+ },
+ "power-profiles-daemon": {
+ "format": "{icon}",
+ "tooltip-format": "Power profile: {profile}\nDriver: {driver}",
+ "tooltip": true,
+ "format-icons": {
+ "default": "",
+ "performance": "",
+ "balanced": " ",
+ "power-saver": ""
+
+ }
+ },
+ "custom/hyprshade": {
+ "format": "{}",
+ "tooltip": true,
+ "signal": 11,
+ "exec": "toggle-hyprshade status",
+ "on-click": "toggle-hyprshade",
+ "return-type": "json"
+ },
+ "custom/weather": {
+ "format": "{}",
+ "tooltip": true,
+ "interval": 3600,
+ "exec": "wttrbar --custom-indicator '{ICON}\n{temp_C}' --location noida",
+ "return-type": "json"
+ },
+ "custom/updates": {
+ "format": "{}",
+ "interval": 10800,
+ "exec": "~/.config/waybar/bin/updatecheck",
+ "return-type": "json",
+ "exec-if": "exit 0",
+ "signal": 8
+ },
+ "custom/vpn": {
+ "format": "{} ",
+ "exec": "~/.config/waybar/bin/vpn",
+ "return-type": "json",
+ "interval": 5
+ },
+ "custom/hotspot": {
+ "format": "{} ",
+ "exec": "~/.config/waybar/bin/hotspot",
+ "return-type": "json",
+ "on-click": "hash wihotspot && wihotspot",
+ "interval": 5
+ },
+ "custom/mark": {
+ "format": "",
+ "tooltip": false
+ },
+ "custom/colorpicker": {
+ "format": "{}",
+ "interval": "once",
+ "on-click": "hyprpicker",
+ "signal": 1
+ },
+ "custom/hyprkill": {
+ "format": "{}",
+ "interval": "once",
+ "exec": "echo '\nKill clients using hyrpctl kill'",
+ "on-click": "sleep 1 && hyprctl kill"
+ },
+ "custom/notifications": {
+ "format": "{} ",
+ "exec": "noti-cycle -j",
+ "on-click": "noti-cycle",
+ "on-click-right": "noti-cycle rofi",
+ "return-type": "json",
+ "interval": "once",
+ "signal": 2
+ },
+ "custom/github": {
+ "format": "{}",
+ "return-type": "json",
+ "interval": 3600,
+ "signal": 9,
+ "exec": "$HOME/.config/waybar/bin/github.sh",
+ "on-click": "xdg-open https://github.com/notifications;pkill -RTMIN+9 waybar"
+ },
+ "idle_inhibitor": {
+ "format": "{icon}",
+ "tooltip-format-activated": "Idle Inhibitor is active",
+ "tooltip-format-deactivated": "Idle Inhibitor is not active",
+ "format-icons": {
+ "activated": "",
+ "deactivated": ""
+ }
+ }
+}
diff --git a/.config/waybar/Atlas/style.css b/.config/waybar/Atlas/style.css
new file mode 100644
index 0000000..93653d9
--- /dev/null
+++ b/.config/waybar/Atlas/style.css
@@ -0,0 +1,305 @@
+@import "colors.css";
+@define-color active @foreground;
+
+* {
+ font-size: 17px;
+ font-family: "JetBrainsMono Nerd Font Propo";
+ min-width: 8px;
+ min-height: 0px;
+ border: none;
+ border-radius: 0;
+ box-shadow: none;
+ text-shadow: none;
+ padding: 0px;
+
+}
+
+window#waybar {
+ transition-property: background-color;
+ transition-duration: 0.5s;
+ border-radius: 4px;
+ border: 1px solid alpha(@active, 0.2);
+ background: @background;
+ background: alpha(@background, 0.8);
+ color: @foreground;
+}
+
+menu,
+tooltip {
+ border-radius: 2px;
+ padding: 2px;
+ border: 1px solid @active;
+ background: @background;
+
+ color: @foreground;
+}
+
+menu label,
+tooltip label {
+ font-size: 14px;
+ color: @foreground;
+}
+
+#submap,
+#tray>.needs-attention {
+ animation-name: blink-active;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+}
+
+.modules-right {
+ margin: 0px 6px 4px 6px;
+ border-radius: 4px;
+ background: alpha(@background, 0);
+ color: @foreground;
+}
+
+.modules-left {
+ transition-property: background-color;
+ transition-duration: 0.5s;
+ margin: 6px 5px 6px 5px; /* Testing with 5 pixels on left/right */
+ border-radius: 4px;
+ background: alpha(@background, 0.5);
+ color: @foreground;
+ border: 1px solid alpha(@active, 0.1);
+}
+
+#gcpu,
+#custom-github,
+#memory,
+#disk,
+#together,
+#submap,
+#custom-weather,
+#custom-recorder,
+#connection,
+#cnoti,
+#brightness,
+#power,
+#custom-updates,
+#tray,
+/*#audio,*/ /* Duplicate with #sound */
+#sound,
+#privacy { /*Controls all the right modules for some reason*/
+ border-radius: 0.15em;
+ margin: 2px 1px 3px 1px;
+ background: alpha(darker(@active), 0.25);
+ border: 1px solid alpha(darker(@active), 0.0);
+}
+
+/* Override specific parameters*/
+
+#brightness,
+#sound {
+ padding: 1px 0px;
+}
+
+#custom-notifications {
+ padding-left: 4px;
+}
+
+#custom-hotspot,
+#custom-github,
+#custom-notifications {
+ font-size: 14px;
+}
+
+#custom-vpn,
+#custom-hotspot {
+ background: alpha(darker(@active), 0.3);
+}
+
+#privacy-item {
+ padding: 6px 0px 6px 6px;
+}
+
+#gcpu {
+ padding: 8px 0px 8px 0px;
+}
+
+#custom-cpu-icon {
+ font-size: 25px;
+}
+
+#custom-cputemp,
+#disk,
+#memory,
+#cpu {
+ font-size: 14px;
+ font-weight: bold;
+}
+
+#custom-github {
+ padding-top: 2px;
+}
+
+#custom-dmark {
+ color: alpha(@foreground, 0.3);
+}
+
+#submap {
+ margin-bottom: 0px;
+}
+
+#workspaces {
+ margin: 0px 2px;
+ padding: 2px 0px;
+ border-radius: 8px;
+}
+
+#workspaces button {
+ transition-property: background-color;
+ transition-duration: 0.1s;
+ color: @foreground;
+ background: transparent;
+ border-radius: 4px;
+ color: alpha(@foreground, 0.3);
+ padding: 2px 0px;
+}
+
+#workspaces button.urgent {
+ font-weight: bold;
+ color: @foreground;
+}
+
+#workspaces button.active {
+ padding: 2px 0px;
+ background: alpha(@active, 0.4);
+ color: @foreground;
+ border-radius: 2px;
+}
+
+#network.wifi {
+ margin: 2px;
+}
+
+#network.disconnected {
+ margin: 2px;
+}
+
+#network.ethernet {
+ margin: 2px;
+}
+
+#submap {
+ min-width: 0px;
+ margin: 4px 6px 4px 6px;
+}
+
+#custom-weather,
+#tray {
+ padding: 4px 0px 4px 0px;
+}
+
+#bluetooth {
+ padding-top: 2px;
+}
+
+#group-battery {
+ /* border-radius: 8px; */
+ /* padding: 4px 0px; */
+ margin: 4px 2px 4px 2px;
+}
+
+#battery {
+ font-size: 1.5rem;
+ border-radius: 3px;
+ padding: 4px 0px;
+ margin: 0 0px;
+}
+
+#battery.charging {
+ color: @charging;
+}
+
+#battery.discharging.warning {
+ background-color: #cf9022;
+ /*animation-name: blink-yellow;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ animation-direction: alternate; */
+}
+
+#battery.discharging.critical {
+ background-color: #c64d4f;
+ /*animation-name: blink-red;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;*/
+}
+
+#custom-battery_percentage {
+ font-size: 1.1rem;
+ border-radius: 100px;
+ /* padding: 0 2px; */
+ margin: 1px 0;
+ /* margin: 4px 2px 4px 2px; */
+}
+
+#clock {
+ font-weight: bold;
+ padding: 4px 2px 2px 2px;
+}
+
+#pulseaudio.mic {
+ border-radius: 4px;
+ color: @foreground;
+ padding-left: 2px;
+}
+
+#backlight-slider slider,
+#pulseaudio-slider slider {
+ background-color: transparent;
+ box-shadow: none;
+}
+
+#backlight-slider trough,
+#pulseaudio-slider trough {
+ margin-top: 4px;
+ min-width: 6px;
+ min-height: 60px;
+ border-radius: 8px;
+ background-color: alpha(@background, 0.6);
+}
+
+#backlight-slider highlight,
+#pulseaudio-slider highlight {
+ border-radius: 8px;
+ background-color: @foreground;
+}
+
+#bluetooth.discoverable,
+#bluetooth.discovering,
+#bluetooth.pairable {
+ border-radius: 8px;
+ animation-name: blink-active;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+}
+
+@keyframes blink-active {
+ to {
+ background-color: @active;
+ color: @foreground;
+ }
+}
+
+@keyframes blink-red {
+ to {
+ background-color: #c64d4f;
+ color: @foreground;
+ }
+}
+
+@keyframes blink-yellow {
+ to {
+ background-color: #cf9022;
+ color: @foreground;
+ }
+}
diff --git a/.config/waybar/style_minimal.css b/.config/waybar/Atlas/style_minimal.css
similarity index 100%
rename from .config/waybar/style_minimal.css
rename to .config/waybar/Atlas/style_minimal.css
diff --git a/.config/waybar/Boussole/config.jsonc b/.config/waybar/Boussole/config.jsonc
new file mode 100644
index 0000000..b24f6cd
--- /dev/null
+++ b/.config/waybar/Boussole/config.jsonc
@@ -0,0 +1,224 @@
+{
+ "layer": "top",
+ "position": "bottom",
+ "height": 24,
+ "spacing": 5,
+
+ "modules-left": ["hyprland/workspaces"],
+ "modules-center": ["clock"],
+ "modules-right": ["tray", "group/audio", "bluetooth", "group/network_grp", "idle_inhibitor", "group/power" ],
+
+
+ "group/network_grp": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 300,
+ "transition-left-to-right": false
+ },
+ "modules": [
+ "network",
+ "network#speed"
+ ]
+ },
+
+ "group/audio": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 300,
+ "transition-left-to-right": false
+ },
+ "modules": [
+ "pulseaudio",
+ "pulseaudio#mic",
+ "pulseaudio#volume",
+ ]
+ },
+
+ "group/power": {
+ "orientation": "inherit",
+ "drawer": {
+ "transition-duration": 300,
+ "transition-left-to-right": true
+ },
+ "modules": [
+ "battery",
+ "custom/battery_percentage",
+ "power-profiles-daemon",
+ ]
+ },
+
+ "hyprland/workspaces": {
+ "format": "{icon}",
+ "on-click": "activate",
+ "format-icons": {
+ "active": "\uf444",
+ "default": "\uf4c3"
+ },
+ "icon-size": 10,
+ "sort-by-number": true,
+ "persistent-workspaces": {
+ "1": [],
+ "2": [],
+ "3": [],
+ "4": [],
+ "5": [],
+ }
+ },
+
+ "clock": {
+ "format": "{:%d.%m.%Y | %H:%M}"
+ },
+
+ //"wireplumber": {
+ // "format": "\udb81\udd7e {volume}%",
+ // "max-volume": 100,
+ // "scroll-step": 5
+ //},
+
+ "pulseaudio": {
+ "format": "{icon} ",
+ "format-bluetooth": "{icon}",
+ "tooltip-format": "{volume}% {icon} | {desc}",
+ "format-muted": "",
+ "format-icons": {
+ "headphones": "",
+ "handsfree": "",
+ "headset": "",
+ "phone": "",
+ "portable": "",
+ "car": " ",
+ "default": [
+ "",
+ "",
+ ""
+ ]
+ },
+ "on-click": "volume mute",
+ //"on-click-middle": "pavucontrol",
+ "on-scroll-up": "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+",
+ "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ -5%",
+ "smooth-scrolling-threshold": 1
+ },
+ "pulseaudio#volume": {
+ "format": " {volume}% "
+ },
+ // TODO missing
+ "pulseaudio#mic": {
+ "format": "{format_source}",
+ "format-source": "",
+ "format-source-muted": "",
+ "tooltip-format": "{volume}% {format_source} ",
+ "on-click": "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle",
+ "on-scroll-down": "wpctl set-volume @DEFAULT_SOURCE@ 5%-",
+ "on-scroll-up": "wpctl set-volume -l 1 @DEFAULT_SOURCE@ 5%+"
+ },
+
+// "battery": {
+// "bat": "BAT1",
+// "interval": 60,
+// "format": "{icon} {capacity}%",
+// "format-icons": ["\uf244", "\uf243", "\uf242", "\uf241", "\uf240"],
+// },
+ "battery": {
+ "rotate": 270,
+ "states": {
+ "good": 95,
+ "warning": 16,
+ "critical": 8
+ },
+ "format": "{icon}",
+ "interval": 1,
+ "format-charging": "",
+ "format-full": "{icon}",
+ "format-icons": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ],
+ "tooltip-format": "{timeTo} {capacity} % | {power} W"
+ },
+ "custom/battery_percentage": {
+ "format": "{}",
+ //"exec": "cat /sys/class/power_supply/BAT*/capacity",
+
+ // Makes battery like if 85% was the maximum capacity (100%).
+ // Useful for people that limit charge up to a certain percentage but like having real percentage
+ "exec": "echo $(( $(cat /sys/class/power_supply/BAT*/capacity) * 100 / 85 ))%",
+ "interval": 10,
+ "tooltip": false
+ },
+
+
+ "memory": {
+ "interval": 30,
+ "format": "\uf4bc {used:0.1f}G"
+ },
+
+ "temperature": {
+ "format": "{temperatureC}°C"
+ },
+
+ "network": {
+ "format": "",
+ "format-ethernet": "\udb83\udc9d",
+ "format-wifi": "{icon}",
+ "format-disconnected": "\udb83\udc9c",
+ "format-icons": ["\udb82\udd2f", "\udb82\udd1f", "\udb82\udd22", "\udb82\udd25", "\udb82\udd28"],
+ "tooltip-format-wifi": "{essid} ({signalStrength}%)",
+ "tooltip-format-ethernet": "{ifname}",
+ "tooltip-format-disconnected": "Disconnected",
+ "on-click": "python ~/.local/bin/rofi-wifi",
+ },
+ "network#speed": {
+ "format": "{bandwidthDownBits}",
+ "interval": 5,
+ "tooltip-format": "{ipaddr}",
+ "tooltip-format-wifi": "{essid} ({signalStrength}%) \n{ipaddr} | {frequency} MHz{icon} ",
+ "tooltip-format-ethernet": "{ifname} \n{ipaddr} | {frequency} MHz{icon}",
+ "tooltip-format-disconnected": "Disconnected",
+ "tooltip": true
+ },
+
+ "bluetooth": {
+ "format": "\udb80\udcaf",
+ "format-disabled": "\udb80\udcb2",
+ "format-connected": "\udb80\udcb1",
+ "tooltip-format": "{controller_alias}\t{controller_address}",
+ "tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{device_enumerate}",
+ "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}",
+ "on-click": "rofi-bluetooth"
+ },
+
+ "power-profiles-daemon": {
+ "format": "{icon}",
+ "tooltip-format": "Power profile: {profile}\nDriver: {driver}",
+ "tooltip": true,
+ "format-icons": {
+ "default": "",
+ "performance": "",
+ "balanced": " ",
+ "power-saver": ""
+
+ }
+ },
+
+ "hyprland/language": {
+ "format": "{short}"
+ },
+
+ "tray": {
+ "icon-size": 16,
+ "spacing": 16
+ },
+
+ "idle_inhibitor": {
+ "format": "{icon}",
+ "format-icons": {
+ "activated": "\udb80\udd76",
+ "deactivated": "\udb83\udfaa"
+ }
+ }
+}
diff --git a/.config/waybar/Boussole/style.css b/.config/waybar/Boussole/style.css
new file mode 100644
index 0000000..ed52bfa
--- /dev/null
+++ b/.config/waybar/Boussole/style.css
@@ -0,0 +1,60 @@
+@define-color foreground #eeeeee;
+@define-color foreground-inactive #aaaaaa;
+@define-color background #000000;
+
+* {
+ font-family: JetBrainsMono Nerd Font Propo;
+ font-size: 17px;
+ padding: 0;
+ margin: 0;
+}
+
+#waybar {
+ color: @foreground;
+ background-color: @background;
+}
+
+#workspaces button {
+ color: @foreground;
+ padding: 0 0.2em;
+}
+
+#workspaces button.empty {
+ color: @foreground-inactive;
+}
+
+#memory,
+#wireplumber,
+#audio,
+#language,
+#network,
+#bluetooth
+ {
+ padding-right: 1em
+}
+
+#custom-battery_percentage,
+#battery {
+ padding-right: 0.3em
+}
+
+#power-profiles-daemon {
+ padding-right: 0.7em;
+ padding-left: 0.4em
+}
+
+#idle_inhibitor {
+ padding-right: 0.6em
+}
+
+#tray {
+ padding-right: 1em
+}
+
+#network_grp {
+ padding: 0em
+}
+
+#pulseaudio.mic {
+ padding-left: .7em
+}
diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc
deleted file mode 100644
index a147e99..0000000
--- a/.config/waybar/config.jsonc
+++ /dev/null
@@ -1,508 +0,0 @@
-{
- "layer": "top",
- "position": "right",
- "margin": "1 1 1 2",
- "reload_style_on_change": true,
-
- // Modules display
-
- "modules-left": [
- //"custom/updates",
- "hyprland/workspaces",
- "hyprland/submap"
- //"group/info",
- //"hyprland/window"
- ],
-
- "modules-right": [
- "custom/recorder",
- "privacy",
- "group/brightness",
- "group/sound",
- "group/connection",
- "tray",
- "group/together",
- //"group/cnoti",
- "group/power"
- ],
-
-
- // Modules definition
-
- // Up
-
- "hyprland/workspaces": {
- "format": "{icon}",
- "on-click": "activate",
- "all-outputs": true,
- "format-icons": {
- "1": "1",
- "2": "2",
- "3": "3",
- "4": "4",
- "5": "5",
- "6": "6",
- "7": "7",
- "8": "8",
- "9": "9",
- "10": "10"
- }
- },
- "hyprland/submap": {
- "format": "",
- "max-length": 8,
- "tooltip": true
- },
- "group/info": {
- "orientation": "inherit",
- "drawer": {
- "transition-duration": 500,
- "transition-left-to-right": false
- },
- "modules": [
- "custom/dmark",
- "group/gcpu",
- "memory",
- "disk",
- "hyprland/window"
- ]
- },
- "hyprland/window": {
- "orientation": "vertical",
- "format":"{class}",
- "spearate-outputs": true,
- "icon": false
- },
- "custom/dmark": {
- "format": "",
- "tooltip": false
- },
- "group/gcpu": {
- "orientation": "inherit",
- "modules": [
- "custom/cpu-icon",
- "custom/cputemp",
- "cpu"
- ]
- },
- "custom/cpu-icon": {
- "format": "",
- "tooltip": false
- },
- "custom/cputemp": {
- "format": "{}",
- "exec": "~/.config/waybar/bin/cputemp",
- "interval": 10,
- "return-type": "json"
- },
- "cpu": {
- "format": "{usage}",
- "on-click": "foot btop"
- },
- "memory": {
- "format": " \n{:2}"
- },
- "disk": {
- "interval": 600,
- "format": " \n{percentage_used}",
- "path": "/"
- },
-
- // Bottom
-
- "custom/recorder": {
- "format": "{}",
- "interval": "once",
- "exec": "echo ''",
- "tooltip": "false",
- "exec-if": "pgrep 'wl-screenrec'",
- "on-click": "recorder",
- "signal": 4
- },
- "privacy": {
- "orientation": "vertical",
- "icon-spacing": 4,
- "icon-size": 14,
- "transition-duration": 250,
- "modules": [
- {
- "type": "screenshare",
- "tooltip": true,
- "tooltip-icon-size": 24
- }
- ]
- },
- "group/brightness": {
- "orientation": "inherit",
- "drawer": {
- "transition-duration": 500,
- "transition-left-to-right": false
- },
- "modules": [
- "backlight"
- //"backlight/slider"
- ]
- },
- "backlight": {
- "device": "intel_backlight",
- "format": "{icon}",
- "format-icons": [
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- ""
- ],
- "on-scroll-down": "brightnessctl s 5%-",
- "on-scroll-up": "brightnessctl s +5%",
- "tooltip": true,
- "tooltip-format": "Brightness: {percent}% ",
- "smooth-scrolling-threshold": 1
- },
- "backlight/slider": {
- "min": 1,
- "max": 100,
- "orientation": "vertical",
- "device": "intel_backlight"
- },
- "group/sound": {
- "orientation": "inherit",
- "modules": [
- "group/audio",
- "custom/notifications"
- ]
- },
- "group/audio": {
- "orientation": "inherit",
- "drawer": {
- "transition-duration": 500,
- "transition-left-to-right": false
- },
- "modules": [
- "pulseaudio",
- "pulseaudio#mic",
- "pulseaudio/slider"
- ]
- },
- "group/cnoti": {
- "orientation": "inherit",
- "modules": [
- "custom/github"
- ]
- },
- "group/connection": {
- "orientation": "inherit",
- "modules": [
- //"custom/vpn",
- "custom/hotspot",
- "group/network"
- //"group/bluetooth"
- ]
- },
- "group/together": {
- "orientation": "inherit",
- "modules": [
- "group/utils",
- "clock"
- ]
- },
- "group/utils": {
- "orientation": "inherit",
- "drawer": {
- "transition-duration": 500,
- "transition-left-to-right": true
- },
- "modules": [
- "custom/mark",
- "custom/weather",
- "custom/colorpicker",
- "custom/hyprshade",
- "idle_inhibitor"
- //"custom/hyprkill"
- ]
- },
- "group/network": {
- "orientation": "inherit",
- "drawer": {
- "transition-duration": 500,
- "transition-left-to-right": false
- },
- "modules": [
- "network",
- "network#speed"
- ]
- },
- "group/bluetooth": {
- "orientation": "inherit",
- "drawer": {
- "transition-duration": 500,
- "transition-left-to-right": true
- },
- "modules": [
- "bluetooth",
- "bluetooth#status"
- ]
- },
- "group/battery": {
- "orientation":"vertical",
- "modules": [
- "battery",
- "custom/battery_percentage",
- ]
- },
- "group/power": {
- "orientation": "inherit",
- "drawer": {
- "transition-duration": 500,
- "transition-left-to-right": false
- },
- "modules": [
- "group/battery",
- "power-profiles-daemon",
- ]
- },
- "tray": {
- "icon-size": 18,
- "spacing": 10
- },
- "pulseaudio": {
- "format": "{icon}",
- "format-bluetooth": "{icon}",
- "tooltip-format": "{volume}% {icon} | {desc}",
- "format-muted": "",
- "format-icons": {
- "headphones": "",
- "handsfree": "",
- "headset": "",
- "phone": "",
- "portable": "",
- "car": " ",
- "default": [
- "",
- "",
- ""
- ]
- },
- "on-click": "volume mute",
- //"on-click-middle": "pavucontrol",
- "on-scroll-up": "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+",
- "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ -5%",
- "smooth-scrolling-threshold": 1
- },
- "pulseaudio#mic": {
- "format": "{format_source}",
- "format-source": "",
- "format-source-muted": "",
- "tooltip-format": "{volume}% {format_source} ",
- "on-click": "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle",
- "on-scroll-down": "wpctl set-volume @DEFAULT_SOURCE@ 5%-",
- "on-scroll-up": "wpctl set-volume -l 1 @DEFAULT_SOURCE@ 5%+"
- },
- "pulseaudio/slider": {
- "min": 0,
- "max": 100,
- "orientation": "vertical"
- },
- "network": {
- "format": "{icon}",
- "format-icons": {
- "wifi": [
- ""
- ],
- "ethernet": [
- ""
- ],
- "disconnected": [
- ""
- ]
- },
- "format-wifi": "",
- "format-ethernet": "",
- "format-disconnected": "",
- "format-linked": "",
- "tooltip": false,
- //"on-click": "pgrep -x rofi &>/dev/null && notify-send rofi || networkmanager_dmenu"
- "on-click": "kitty nmtui"
- },
- "network#speed": {
- "format": " {bandwidthDownBits} ",
- "rotate": 90,
- "interval": 5,
- "tooltip-format": "{ipaddr}",
- "tooltip-format-wifi": "{essid} ({signalStrength}%) \n{ipaddr} | {frequency} MHz{icon} ",
- "tooltip-format-ethernet": "{ifname} \n{ipaddr} | {frequency} MHz{icon} ",
- "tooltip-format-disconnected": "Not Connected to any type of Network",
- "tooltip": true,
- "on-click": "pgrep -x rofi &>/dev/null && notify-send rofi || networkmanager_dmenu"
- },
- "bluetooth": {
- "format-on": "",
- "format-off": "",
- "format-disabled": "",
- "format-connected": "",
- "tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected",
- "tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}",
- "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}",
- "tooltip-format-enumerate-connected-battery": "{device_alias}\t{device_address}\t{device_battery_percentage}%",
- //"on-click": "rofi-bluetooth -config ~/.config/rofi/menu.d/network.rasi -i"
- "on-click": "toggle-bluetooth"
- },
- "bluetooth#status": {
- "format-on": "",
- "format-off": "",
- "format-disabled": "",
- "format-connected": "{num_connections}",
- "format-connected-battery": "{device_battery_percentage}%",
- "tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected",
- "tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}",
- "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}",
- "tooltip-format-enumerate-connected-battery": "{device_alias}\t{device_address}\t{device_battery_percentage}%",
- "on-click": "rofi-bluetooth -config ~/.config/rofi/menu.d/network.rasi -i"
- },
- "battery": {
- "rotate": 270,
- "states": {
- "good": 95,
- "warning": 16,
- "critical": 8
- },
- "format": "{icon}",
- "interval": 1,
- "format-charging": "",
- "format-full": "{icon}",
- "format-icons": [
- "",
- "",
- "",
- "",
- "",
- ""
- ],
- "tooltip-format": "{timeTo} {capacity} % | {power} W"
- },
- "custom/battery_percentage": {
- "format": "{}",
- //"exec": "cat /sys/class/power_supply/BAT*/capacity",
-
- // Makes battery like if 85% was the maximum capacity (100%).
- // Useful for people that limit charge up to a certain percentage but like having real percentage
- "exec": "echo $(( $(cat /sys/class/power_supply/BAT*/capacity) * 100 / 85 ))",
- "interval": 10,
- "tooltip": false
- },
- "clock": {
- "format": "{:%H\n%M}",
- "tooltip-format": "{calendar}",
- "calendar": {
- "mode": "month",
- "mode-mon-col": 3,
- "weeks-pos": "right",
- "on-scroll": 1,
- "on-click-right": "mode",
- "on-click": "swaync-client -t",
- "format": {
- "today": "{}"
- }
- }
- },
- "power-profiles-daemon": {
- "format": "{icon}",
- "tooltip-format": "Power profile: {profile}\nDriver: {driver}",
- "tooltip": true,
- "format-icons": {
- "default": "",
- "performance": "",
- "balanced": " ",
- "power-saver": ""
-
- }
- },
- "custom/hyprshade": {
- "format": "{}",
- "tooltip": true,
- "signal": 11,
- "exec": "toggle-hyprshade status",
- "on-click": "toggle-hyprshade",
- "return-type": "json"
- },
- "custom/weather": {
- "format": "{}",
- "tooltip": true,
- "interval": 3600,
- "exec": "wttrbar --custom-indicator '{ICON}\n{temp_C}' --location noida",
- "return-type": "json"
- },
- "custom/updates": {
- "format": "{}",
- "interval": 10800,
- "exec": "~/.config/waybar/bin/updatecheck",
- "return-type": "json",
- "exec-if": "exit 0",
- "signal": 8
- },
- "custom/vpn": {
- "format": "{} ",
- "exec": "~/.config/waybar/bin/vpn",
- "return-type": "json",
- "interval": 5
- },
- "custom/hotspot": {
- "format": "{} ",
- "exec": "~/.config/waybar/bin/hotspot",
- "return-type": "json",
- "on-click": "hash wihotspot && wihotspot",
- "interval": 5
- },
- "custom/mark": {
- "format": "",
- "tooltip": false
- },
- "custom/colorpicker": {
- "format": "{}",
- "interval": "once",
- "on-click": "hyprpicker",
- "signal": 1
- },
- "custom/hyprkill": {
- "format": "{}",
- "interval": "once",
- "exec": "echo '\nKill clients using hyrpctl kill'",
- "on-click": "sleep 1 && hyprctl kill"
- },
- "custom/notifications": {
- "format": "{} ",
- "exec": "noti-cycle -j",
- "on-click": "noti-cycle",
- "on-click-right": "noti-cycle rofi",
- "return-type": "json",
- "interval": "once",
- "signal": 2
- },
- "custom/github": {
- "format": "{}",
- "return-type": "json",
- "interval": 3600,
- "signal": 9,
- "exec": "$HOME/.config/waybar/bin/github.sh",
- "on-click": "xdg-open https://github.com/notifications;pkill -RTMIN+9 waybar"
- },
- "idle_inhibitor": {
- "format": "{icon}",
- "tooltip-format-activated": "Idle Inhibitor is active",
- "tooltip-format-deactivated": "Idle Inhibitor is not active",
- "format-icons": {
- "activated": "",
- "deactivated": ""
- }
- }
-}
diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc
new file mode 120000
index 0000000..1b9ff12
--- /dev/null
+++ b/.config/waybar/config.jsonc
@@ -0,0 +1 @@
+Boussole/config.jsonc
\ No newline at end of file
diff --git a/.config/waybar/style.css b/.config/waybar/style.css
deleted file mode 100644
index 93653d9..0000000
--- a/.config/waybar/style.css
+++ /dev/null
@@ -1,305 +0,0 @@
-@import "colors.css";
-@define-color active @foreground;
-
-* {
- font-size: 17px;
- font-family: "JetBrainsMono Nerd Font Propo";
- min-width: 8px;
- min-height: 0px;
- border: none;
- border-radius: 0;
- box-shadow: none;
- text-shadow: none;
- padding: 0px;
-
-}
-
-window#waybar {
- transition-property: background-color;
- transition-duration: 0.5s;
- border-radius: 4px;
- border: 1px solid alpha(@active, 0.2);
- background: @background;
- background: alpha(@background, 0.8);
- color: @foreground;
-}
-
-menu,
-tooltip {
- border-radius: 2px;
- padding: 2px;
- border: 1px solid @active;
- background: @background;
-
- color: @foreground;
-}
-
-menu label,
-tooltip label {
- font-size: 14px;
- color: @foreground;
-}
-
-#submap,
-#tray>.needs-attention {
- animation-name: blink-active;
- animation-duration: 1s;
- animation-timing-function: linear;
- animation-iteration-count: infinite;
- animation-direction: alternate;
-}
-
-.modules-right {
- margin: 0px 6px 4px 6px;
- border-radius: 4px;
- background: alpha(@background, 0);
- color: @foreground;
-}
-
-.modules-left {
- transition-property: background-color;
- transition-duration: 0.5s;
- margin: 6px 5px 6px 5px; /* Testing with 5 pixels on left/right */
- border-radius: 4px;
- background: alpha(@background, 0.5);
- color: @foreground;
- border: 1px solid alpha(@active, 0.1);
-}
-
-#gcpu,
-#custom-github,
-#memory,
-#disk,
-#together,
-#submap,
-#custom-weather,
-#custom-recorder,
-#connection,
-#cnoti,
-#brightness,
-#power,
-#custom-updates,
-#tray,
-/*#audio,*/ /* Duplicate with #sound */
-#sound,
-#privacy { /*Controls all the right modules for some reason*/
- border-radius: 0.15em;
- margin: 2px 1px 3px 1px;
- background: alpha(darker(@active), 0.25);
- border: 1px solid alpha(darker(@active), 0.0);
-}
-
-/* Override specific parameters*/
-
-#brightness,
-#sound {
- padding: 1px 0px;
-}
-
-#custom-notifications {
- padding-left: 4px;
-}
-
-#custom-hotspot,
-#custom-github,
-#custom-notifications {
- font-size: 14px;
-}
-
-#custom-vpn,
-#custom-hotspot {
- background: alpha(darker(@active), 0.3);
-}
-
-#privacy-item {
- padding: 6px 0px 6px 6px;
-}
-
-#gcpu {
- padding: 8px 0px 8px 0px;
-}
-
-#custom-cpu-icon {
- font-size: 25px;
-}
-
-#custom-cputemp,
-#disk,
-#memory,
-#cpu {
- font-size: 14px;
- font-weight: bold;
-}
-
-#custom-github {
- padding-top: 2px;
-}
-
-#custom-dmark {
- color: alpha(@foreground, 0.3);
-}
-
-#submap {
- margin-bottom: 0px;
-}
-
-#workspaces {
- margin: 0px 2px;
- padding: 2px 0px;
- border-radius: 8px;
-}
-
-#workspaces button {
- transition-property: background-color;
- transition-duration: 0.1s;
- color: @foreground;
- background: transparent;
- border-radius: 4px;
- color: alpha(@foreground, 0.3);
- padding: 2px 0px;
-}
-
-#workspaces button.urgent {
- font-weight: bold;
- color: @foreground;
-}
-
-#workspaces button.active {
- padding: 2px 0px;
- background: alpha(@active, 0.4);
- color: @foreground;
- border-radius: 2px;
-}
-
-#network.wifi {
- margin: 2px;
-}
-
-#network.disconnected {
- margin: 2px;
-}
-
-#network.ethernet {
- margin: 2px;
-}
-
-#submap {
- min-width: 0px;
- margin: 4px 6px 4px 6px;
-}
-
-#custom-weather,
-#tray {
- padding: 4px 0px 4px 0px;
-}
-
-#bluetooth {
- padding-top: 2px;
-}
-
-#group-battery {
- /* border-radius: 8px; */
- /* padding: 4px 0px; */
- margin: 4px 2px 4px 2px;
-}
-
-#battery {
- font-size: 1.5rem;
- border-radius: 3px;
- padding: 4px 0px;
- margin: 0 0px;
-}
-
-#battery.charging {
- color: @charging;
-}
-
-#battery.discharging.warning {
- background-color: #cf9022;
- /*animation-name: blink-yellow;
- animation-duration: 1s;
- animation-timing-function: linear;
- animation-iteration-count: infinite;
- animation-direction: alternate; */
-}
-
-#battery.discharging.critical {
- background-color: #c64d4f;
- /*animation-name: blink-red;
- animation-duration: 1s;
- animation-timing-function: linear;
- animation-iteration-count: infinite;
- animation-direction: alternate;*/
-}
-
-#custom-battery_percentage {
- font-size: 1.1rem;
- border-radius: 100px;
- /* padding: 0 2px; */
- margin: 1px 0;
- /* margin: 4px 2px 4px 2px; */
-}
-
-#clock {
- font-weight: bold;
- padding: 4px 2px 2px 2px;
-}
-
-#pulseaudio.mic {
- border-radius: 4px;
- color: @foreground;
- padding-left: 2px;
-}
-
-#backlight-slider slider,
-#pulseaudio-slider slider {
- background-color: transparent;
- box-shadow: none;
-}
-
-#backlight-slider trough,
-#pulseaudio-slider trough {
- margin-top: 4px;
- min-width: 6px;
- min-height: 60px;
- border-radius: 8px;
- background-color: alpha(@background, 0.6);
-}
-
-#backlight-slider highlight,
-#pulseaudio-slider highlight {
- border-radius: 8px;
- background-color: @foreground;
-}
-
-#bluetooth.discoverable,
-#bluetooth.discovering,
-#bluetooth.pairable {
- border-radius: 8px;
- animation-name: blink-active;
- animation-duration: 1s;
- animation-timing-function: linear;
- animation-iteration-count: infinite;
- animation-direction: alternate;
-}
-
-@keyframes blink-active {
- to {
- background-color: @active;
- color: @foreground;
- }
-}
-
-@keyframes blink-red {
- to {
- background-color: #c64d4f;
- color: @foreground;
- }
-}
-
-@keyframes blink-yellow {
- to {
- background-color: #cf9022;
- color: @foreground;
- }
-}
diff --git a/.config/waybar/style.css b/.config/waybar/style.css
new file mode 120000
index 0000000..e7230cf
--- /dev/null
+++ b/.config/waybar/style.css
@@ -0,0 +1 @@
+Boussole/style.css
\ No newline at end of file
diff --git a/.config/waybar/wifi_menu/config.ini b/.config/waybar/wifi_menu/config.ini
new file mode 100644
index 0000000..fa5fcb7
--- /dev/null
+++ b/.config/waybar/wifi_menu/config.ini
@@ -0,0 +1,28 @@
+[dmenu]
+dmenu_command = rofi -dmenu -theme ~/.config/rofi/wifi/config.rasi -i -no-history -matching fuzzy -no-tokenize -hover-select
+# compact = # (Default: False). Remove extra spacing from display
+# pinentry = # (Default: None) e.g. `pinentry-gtk`
+pinentry = pinentry-gtk
+wifi_icons =
+# format =
+format = {name} {icon}
+list_saved=False
+[dmenu_passphrase]
+# # Uses the -password flag for Rofi, -x for bemenu. For dmenu, sets -nb and
+# # -nf to the same color or uses -P if the dmenu password patch is applied
+# # https://tools.suckless.org/dmenu/patches/password/
+# obscure = True
+# obscure_color = #222222
+
+[pinentry]
+# description = (Default: Get network password)
+prompt = Password:
+
+[editor]
+terminal = kitty
+# terminal =
+# gui_if_available = (Default: True)
+# gui = (Default: nm-connection-editor)
+
+[nmdm]
+# rescan_delay = # (seconds to wait after a wifi rescan before redisplaying the results)
diff --git a/.config/waybar/wifi_menu/networkmanager/config.ini b/.config/waybar/wifi_menu/networkmanager/config.ini
new file mode 100644
index 0000000..fa5fcb7
--- /dev/null
+++ b/.config/waybar/wifi_menu/networkmanager/config.ini
@@ -0,0 +1,28 @@
+[dmenu]
+dmenu_command = rofi -dmenu -theme ~/.config/rofi/wifi/config.rasi -i -no-history -matching fuzzy -no-tokenize -hover-select
+# compact = # (Default: False). Remove extra spacing from display
+# pinentry = # (Default: None) e.g. `pinentry-gtk`
+pinentry = pinentry-gtk
+wifi_icons =
+# format =
+format = {name} {icon}
+list_saved=False
+[dmenu_passphrase]
+# # Uses the -password flag for Rofi, -x for bemenu. For dmenu, sets -nb and
+# # -nf to the same color or uses -P if the dmenu password patch is applied
+# # https://tools.suckless.org/dmenu/patches/password/
+# obscure = True
+# obscure_color = #222222
+
+[pinentry]
+# description = (Default: Get network password)
+prompt = Password:
+
+[editor]
+terminal = kitty
+# terminal =
+# gui_if_available = (Default: True)
+# gui = (Default: nm-connection-editor)
+
+[nmdm]
+# rescan_delay = # (seconds to wait after a wifi rescan before redisplaying the results)
diff --git a/.local/bin/rofi-wifi b/.local/bin/rofi-wifi
new file mode 100755
index 0000000..4256251
--- /dev/null
+++ b/.local/bin/rofi-wifi
@@ -0,0 +1,1073 @@
+#!/usr/bin/env python3
+# encoding:utf8
+"""NetworkManager command line dmenu script.
+
+To add new connections or enable/disable networking requires policykit
+permissions setup per:
+https://wiki.archlinux.org/index.php/NetworkManager#Set_up_PolicyKit_permissions
+
+OR running the script as root
+
+Add dmenu options and default terminal if desired to
+~/.config/networkmanager-dmenu/config.ini
+
+"""
+import pathlib
+import struct
+import configparser
+import locale
+import os
+from os.path import basename, expanduser
+import shlex
+from shutil import which
+import sys
+from time import sleep
+import uuid
+import subprocess
+
+import gi
+gi.require_version('NM', '1.0')
+from gi.repository import GLib, NM # noqa pylint: disable=wrong-import-position
+
+ENV = os.environ.copy()
+ENC = locale.getpreferredencoding()
+
+CONF = configparser.ConfigParser()
+CONF.read(expanduser("~/.config/waybar/wifi_menu/config.ini"))
+
+
+def cli_args():
+ """ Don't override dmenu_cmd function arguments with CLI args. Removes -l
+ and -p if those are passed on the command line.
+
+ Exception: if -l is passed and dmenu_command is not defined, assume that the
+ user wants to switch dmenu to the vertical layout and include -l.
+
+ Returns: List of additional CLI arguments
+
+ """
+ args = sys.argv[1:]
+ cmd = CONF.get('dmenu', 'dmenu_command', fallback=False)
+ if "-l" in args or "-p" in args:
+ for nope in ['-l', '-p'] if cmd is not False else ['-p']:
+ try:
+ nope_idx = args.index(nope)
+ del args[nope_idx]
+ del args[nope_idx]
+ except ValueError:
+ pass
+ return args
+
+
+def dmenu_pass(command, color):
+ """Check if dmenu passphrase patch is applied and return the correct command
+ line arg list
+
+ Args: command - string
+ color - obscure color string
+ Returns: list or None
+
+ """
+ if command != 'dmenu':
+ return None
+ try:
+ # Check for dmenu password patch
+ dm_patch = b'P' in subprocess.run(["dmenu", "-h"],
+ capture_output=True,
+ check=False).stderr
+ except FileNotFoundError:
+ dm_patch = False
+ return ["-P"] if dm_patch else ["-nb", color, "-nf", color]
+
+
+def dmenu_cmd(num_lines, prompt="Networks", active_lines=None):
+ """Parse config.ini for menu options
+
+ Args: args - num_lines: number of lines to display
+ prompt: prompt to show
+ active_lines: list of line numbers to tag as active
+ Returns: command invocation (as a list of strings) for example
+ ["dmenu", "-l", "", "-p", "", "-i"]
+
+ """
+ # Create command string
+ commands = {"dmenu": ["-p", str(prompt)],
+ "rofi": ["-dmenu", "-p", str(prompt)],
+ "bemenu": ["-p", str(prompt)],
+ "wofi": ["-p", str(prompt)],
+ "fuzzel": ["-p", str(prompt), "--log-level", "none"]}
+ command = shlex.split(CONF.get('dmenu', 'dmenu_command', fallback="dmenu"))
+ cmd_base = basename(command[0])
+ command.extend(cli_args())
+ command.extend(commands.get(cmd_base, []))
+ # Highlighting
+ highlight = CONF.getboolean('dmenu', 'highlight', fallback=False)
+ if highlight is True:
+ # Rofi
+ if cmd_base == "rofi" and active_lines:
+ command.extend(["-a", ",".join([str(num) for num in active_lines])])
+ # Wofi
+ if cmd_base == "wofi" and active_lines:
+ # add '-q' to prevent tag name and properties of pango markup from searchable
+ command.extend(["-m", "-q"])
+ # Passphrase prompts
+ obscure = CONF.getboolean('dmenu_passphrase', 'obscure', fallback=False)
+ if prompt == "Passphrase" and obscure is True:
+ obscure_color = CONF.get('dmenu_passphrase', 'obscure_color', fallback='#222222')
+ pass_prompts = {"dmenu": dmenu_pass(cmd_base, obscure_color),
+ "rofi": ['-password'],
+ "bemenu": ['-x'],
+ "wofi": ['-P'],
+ "fuzzel": ['--password']}
+ command.extend(pass_prompts.get(cmd_base, []))
+ return command
+
+
+def choose_adapter(client):
+ """If there is more than one wifi adapter installed, ask which one to use
+
+ """
+ devices = client.get_devices()
+ devices = [i for i in devices if i.get_device_type() == NM.DeviceType.WIFI]
+ if not devices:
+ return None
+ if len(devices) == 1:
+ return devices[0]
+ device_names = "\n".join([d.get_iface() for d in devices])
+ sel = subprocess.run(dmenu_cmd(len(devices), "CHOOSE ADAPTER:"),
+ capture_output=True,
+ check=False,
+ env=ENV,
+ input=device_names,
+ encoding=ENC).stdout
+ if not sel.strip():
+ sys.exit()
+ devices = [i for i in devices if i.get_iface() == sel.strip()]
+ if len(devices) != 1:
+ raise ValueError(f"Selection was ambiguous: '{str(sel.strip())}'")
+ return devices[0]
+
+
+def is_installed(cmd):
+ """Check if a utility is installed"""
+ return which(cmd) is not None
+
+
+def is_running(cmd):
+ try:
+ subprocess.check_output(["pidof", cmd])
+ except subprocess.CalledProcessError:
+ return False
+ else:
+ return True
+
+
+def bluetooth_get_enabled():
+ """Check if bluetooth is enabled. Try bluetoothctl first, then rfkill.
+
+ Returns None if no bluetooth device was found.
+ """
+ if is_installed('bluetoothctl') and is_running('bluetoothd'):
+ # Times out in 2 seconds, otherwise bluetoothctl will hang if bluetooth
+ # service isn't running.
+ try:
+ res = subprocess.run(['bluetoothctl', 'show'],
+ timeout=2,
+ capture_output=True,
+ text=True)
+ return "Powered: yes" in res.stdout
+ except subprocess.TimeoutExpired:
+ pass
+ # See https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-rfkill
+ for path in pathlib.Path('/sys/class/rfkill/').glob('rfkill*'):
+ if (path / 'type').read_text().strip() == 'bluetooth':
+ return (path / 'soft').read_text().strip() == '0'
+ return None
+
+
+def create_other_actions(client):
+ """Return list of other actions that can be taken
+
+ """
+ networking_enabled = client.networking_get_enabled()
+ networking_action = "Disable" if networking_enabled else "Enable"
+
+ wifi_enabled = client.wireless_get_enabled()
+ wifi_action = "Disable" if wifi_enabled else "Enable"
+
+ bluetooth_enabled = bluetooth_get_enabled()
+ bluetooth_action = "Disable" if bluetooth_enabled else "Enable"
+
+ actions = [Action(f"{wifi_action} Wifi", toggle_wifi,
+ not wifi_enabled),
+ Action(f"{networking_action} Networking",
+ toggle_networking, not networking_enabled)]
+ if bluetooth_enabled is not None:
+ actions.append(Action(f"{bluetooth_action} Bluetooth",
+ toggle_bluetooth, not bluetooth_enabled))
+ actions += [Action("Launch Connection Manager", launch_connection_editor),
+ Action("Delete a Connection", delete_connection)]
+ if wifi_enabled:
+ actions.append(Action("Rescan Wifi Networks", rescan_wifi))
+ actions.append(Action("Show WiFi password", show_wifi_password))
+ return actions
+
+
+def rescan_wifi():
+ """
+ Rescan Wifi Access Points
+ """
+ delay = CONF.getint('nmdm', 'rescan_delay', fallback=5)
+ for dev in CLIENT.get_devices():
+ if isinstance(dev, gi.repository.NM.DeviceWifi):
+ try:
+ dev.request_scan_async(None, rescan_cb, None)
+ LOOP.run()
+ sleep(delay)
+ notify("Wifi scan complete")
+ main()
+ except gi.repository.GLib.Error as err:
+ # Too frequent rescan error
+ notify("Wifi rescan failed", urgency="critical")
+ if not err.code == 6: # pylint: disable=no-member
+ raise err
+
+
+def rescan_cb(dev, res, data):
+ """Callback for rescan_wifi. Just for notifications
+
+ """
+ if dev.request_scan_finish(res) is True:
+ notify("Wifi scan running...")
+ else:
+ notify("Wifi scan failed", urgency="critical")
+ LOOP.quit()
+
+
+def ssid_to_utf8(nm_ap):
+ """ Convert binary ssid to utf-8 """
+ ssid = nm_ap.get_ssid()
+ if not ssid:
+ return ""
+ ret = NM.utils_ssid_to_utf8(ssid.get_data())
+ return ret
+
+
+def prompt_saved(saved_cons):
+ """Prompt for a saved connection."""
+ actions = create_saved_actions(saved_cons)
+ sel = get_selection(actions)
+ sel()
+
+
+def ap_security(nm_ap):
+ """Parse the security flags to return a string with 'WPA2', etc. """
+ flags = nm_ap.get_flags()
+ wpa_flags = nm_ap.get_wpa_flags()
+ rsn_flags = nm_ap.get_rsn_flags()
+ sec_str = ""
+ if ((flags & getattr(NM, '80211ApFlags').PRIVACY) and
+ (wpa_flags == 0) and (rsn_flags == 0)):
+ sec_str = " WEP"
+ if wpa_flags:
+ sec_str = " WPA1"
+ if rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_PSK:
+ sec_str += " WPA2"
+ if rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_SAE:
+ sec_str += " WPA3"
+ if ((wpa_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_802_1X) or
+ (rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_802_1X)):
+ sec_str += " 802.1X"
+ if ((wpa_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_OWE) or
+ (rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_OWE)):
+ sec_str += " OWE"
+
+ # If there is no security use "--"
+ if sec_str == "":
+ sec_str = "--"
+ return sec_str.lstrip()
+
+
+class Action(): # pylint: disable=too-few-public-methods
+ """Helper class to execute functions from a string variable"""
+ def __init__(self,
+ name,
+ func,
+ args=None,
+ active=False):
+ self.name = name
+ self.func = func
+ self.is_active = active
+ if args is None:
+ self.args = None
+ elif isinstance(args, list):
+ self.args = args
+ else:
+ self.args = [args]
+
+ def __str__(self):
+ return self.name
+
+ def __call__(self):
+ if self.args is None:
+ self.func()
+ else:
+ self.func(*self.args)
+
+
+def conn_matches_adapter(conn, adapter):
+ """Return True if the connection is applicable for the given adapter.
+
+ There seem to be two ways for a connection specify what interface it belongs
+ to:
+
+ - By setting 'mac-address' in [wifi] to the adapter's MAC
+ - By setting 'interface-name` in [connection] to the adapter's name.
+
+ Depending on how the connection was added, it seems like either
+ 'mac-address', 'interface-name' or neither of both is set.
+ """
+ # [wifi] mac-address
+ setting_wireless = conn.get_setting_wireless()
+ mac = setting_wireless.get_mac_address()
+ if mac is not None:
+ return mac == adapter.get_permanent_hw_address()
+
+ # [connection] interface-name
+ setting_connection = conn.get_setting_connection()
+ interface = setting_connection.get_interface_name()
+ if interface is not None:
+ return interface == adapter.get_iface()
+
+ # Neither is set, let's assume this connection is for multiple/all adapters.
+ return True
+
+
+def process_ap(nm_ap, is_active, adapter):
+ """Activate/Deactivate a connection and get password if required"""
+ if is_active:
+ CLIENT.deactivate_connection_async(nm_ap, None, deactivate_cb, nm_ap)
+ LOOP.run()
+ else:
+ conns_cur = [i for i in CONNS if
+ i.get_setting_wireless() is not None and
+ conn_matches_adapter(i, adapter)]
+ con = nm_ap.filter_connections(conns_cur)
+ if len(con) > 1:
+ raise ValueError("There are multiple connections possible")
+
+ if len(con) == 1:
+ CLIENT.activate_connection_async(con[0], adapter, nm_ap.get_path(),
+ None, activate_cb, nm_ap)
+ LOOP.run()
+ else:
+ if ap_security(nm_ap) != "--":
+ password = get_passphrase()
+ else:
+ password = ""
+ set_new_connection(nm_ap, password, adapter)
+
+
+def activate_cb(dev, res, data):
+ """Notification if activate connection completed successfully
+
+ """
+ try:
+ conn = dev.activate_connection_finish(res)
+ except GLib.Error:
+ conn = None
+ if conn is not None:
+ notify(f"Activated {conn.get_id()}")
+ else:
+ notify(f"Problem activating {data.get_id()}", urgency="critical")
+ LOOP.quit()
+
+
+def deactivate_cb(dev, res, data):
+ """Notification if deactivate connection completed successfully
+
+ """
+ if dev.deactivate_connection_finish(res) is True:
+ notify(f"Deactivated {data.get_id()}")
+ else:
+ notify(f"Problem deactivating {data.get_id()}", urgency="critical")
+ LOOP.quit()
+
+
+def process_vpngsm(con, activate):
+ """Activate/deactive VPN or GSM connections"""
+ if activate:
+ CLIENT.activate_connection_async(con, None, None,
+ None, activate_cb, con)
+ else:
+ CLIENT.deactivate_connection_async(con, None, deactivate_cb, con)
+ LOOP.run()
+
+def strength_bars(signal_strength):
+ bars = NM.utils_wifi_strength_bars(signal_strength)
+ wifi_chars = CONF.get("dmenu", "wifi_chars", fallback=False)
+ if wifi_chars:
+ bars = "".join([wifi_chars[i] for i, j in enumerate(bars) if j == '*'])
+ return bars
+
+
+def strength_icon(signal_strength):
+ wifi_icons = CONF.get("dmenu", "wifi_icons", fallback=False)
+ if wifi_icons:
+ return wifi_icons[round(signal_strength / 100 * (len(wifi_icons) - 1))]
+ return ""
+
+
+def create_ap_actions(aps, active_ap, active_connection, adapter): # noqa pylint: disable=too-many-locals,line-too-long
+ """For each AP in a list, create the string and its attached function
+ (activate/deactivate)
+
+ """
+ active_ap_bssid = active_ap.get_bssid() if active_ap is not None else ""
+
+ names = [ssid_to_utf8(ap) for ap in aps]
+ max_len_name = max([len(name) for name in names]) if names else 0
+ secs = [ap_security(ap) for ap in aps]
+ max_len_sec = max([len(sec) for sec in secs]) if secs else 0
+
+ ap_actions = []
+
+ if CONF.getboolean("dmenu", "compact", fallback=False):
+ format = CONF.get("dmenu", "format", fallback="{name} {sec} {bars}")
+ else:
+ format = CONF.get("dmenu", "format", fallback="{name:<{max_len_name}s} {sec:<{max_len_sec}s} {bars:>4}")
+
+ for nm_ap, name, sec in zip(aps, names, secs):
+ is_active = nm_ap.get_bssid() == active_ap_bssid
+ signal_strength = nm_ap.get_strength()
+ bars = strength_bars(signal_strength)
+ icon = strength_icon(signal_strength)
+ action_name = format.format(name=name, sec=sec, signal=signal_strength, bars=bars, icon=icon,
+ max_len_name=max_len_name, max_len_sec=max_len_sec)
+ if is_active:
+ ap_actions.append(Action(action_name, process_ap,
+ [active_connection, True, adapter],
+ active=True))
+ else:
+ ap_actions.append(Action(action_name, process_ap,
+ [nm_ap, False, adapter]))
+ return ap_actions
+
+
+def create_hotspot_actions(hotspots, active):
+ """Create the list of strings to display with associated function
+ (activate/deactivate) for NetworkManager Hotspots.
+
+ """
+ active_hotspot = [i for i in active if i.get_connection_type() == "802-11-wireless"
+ and i.get_connection().get_setting_wireless().get_mode() == "ap"]
+ return _create_vpngsm_actions(hotspots, active_hotspot, "Hotspot")
+
+
+def create_vpn_actions(vpns, active):
+ """Create the list of strings to display with associated function
+ (activate/deactivate) for VPN connections.
+
+ """
+ active_vpns = [i for i in active if i.get_vpn()]
+ return _create_vpngsm_actions(vpns, active_vpns, "VPN")
+
+
+def create_vlan_actions(vlans, active):
+ """Create the list of strings to display with associated function
+ (activate/deactivate) for VLAN connections.
+
+ """
+ active_vlans = [i for i in active if "vlan" == i.get_connection_type()]
+ return _create_vpngsm_actions(vlans, active_vlans, "VLAN")
+
+
+def create_wireguard_actions(wgs, active):
+ """Create the list of strings to display with associated function
+ (activate/deactivate) for Wireguard connections.
+
+ """
+ active_wgs = [i for i in active if i.get_connection_type() == "wireguard"]
+ return _create_vpngsm_actions(wgs, active_wgs, "Wireguard")
+
+
+def create_eth_actions(eths, active):
+ """Create the list of strings to display with associated function
+ (activate/deactivate) for Ethernet connections.
+
+ """
+ active_eths = [i for i in active if 'ethernet' in i.get_connection_type()]
+ return _create_vpngsm_actions(eths, active_eths, "Eth")
+
+
+def create_gsm_actions(gsms, active):
+ """Create the list of strings to display with associated function
+ (activate/deactivate) GSM connections."""
+ active_gsms = [i for i in active if
+ i.get_connection() is not None and
+ i.get_connection().is_type(NM.SETTING_GSM_SETTING_NAME)]
+ return _create_vpngsm_actions(gsms, active_gsms, "GSM")
+
+
+def create_blue_actions(blues, active):
+ """Create the list of strings to display with associated function
+ (activate/deactivate) Bluetooth connections."""
+ active_blues = [i for i in active if
+ i.get_connection() is not None and
+ i.get_connection().is_type(NM.SETTING_BLUETOOTH_SETTING_NAME)]
+ return _create_vpngsm_actions(blues, active_blues, "Bluetooth")
+
+
+def create_saved_actions(saved):
+ """Create the list of strings to display with associated function
+ (activate/deactivate) for VPN connections.
+
+ """
+ return _create_vpngsm_actions(saved, [], "SAVED")
+
+
+def _create_vpngsm_actions(cons, active_cons, label):
+ active_con_ids = [a.get_id() for a in active_cons]
+ actions = []
+ for con in cons:
+ is_active = con.get_id() in active_con_ids
+ try:
+ # Get hotspot ssid
+ if con.get_setting_wireless().get_mode() == 'ap':
+ hotspot = f" '{ssid_to_utf8(con.get_setting_wireless())}'"
+ else:
+ hotspot = ""
+ except AttributeError:
+ hotspot = ""
+ action_name = f"{con.get_id()}{hotspot}:{label}"
+ if is_active:
+ active_connection = [a for a in active_cons
+ if a.get_id() == con.get_id()]
+ if len(active_connection) != 1:
+ raise ValueError(f"Multiple active connections match {con.get_id()}")
+ active_connection = active_connection[0]
+
+ actions.append(Action(action_name, process_vpngsm,
+ [active_connection, False], active=True))
+ else:
+ actions.append(Action(action_name, process_vpngsm,
+ [con, True]))
+ return actions
+
+
+def create_wwan_actions(client):
+ """Create WWWAN actions
+
+ """
+ wwan_enabled = client.wwan_get_enabled()
+ wwan_action = "Disable" if wwan_enabled else "Enable"
+ return [Action(f"{wwan_action} WWAN", toggle_wwan, not wwan_enabled)]
+
+
+def combine_actions(eths, aps, vlans, vpns, wgs, gsms, blues, wwan, hotspots, others, saved):
+ # pylint: disable=too-many-arguments
+ """Combine all given actions into a list of actions.
+
+ Args: args - eths: list of Actions
+ aps: list of Actions
+ vpns: list of Actions
+ gsms: list of Actions
+ blues: list of Actions
+ wwan: list of Actions
+ hotspots: list of Actions
+ others: list of Actions
+ """
+ compact = CONF.getboolean("dmenu", "compact", fallback=False)
+ empty_action = [Action('', None)] if not compact else []
+ all_actions = []
+ all_actions += eths + empty_action if eths else []
+ all_actions += aps + empty_action if aps else []
+ all_actions += vlans + empty_action if vlans else []
+ all_actions += vpns + empty_action if vpns else []
+ all_actions += wgs + empty_action if wgs else []
+ all_actions += gsms + empty_action if (gsms and wwan) else []
+ all_actions += blues + empty_action if blues else []
+ all_actions += wwan + empty_action if wwan else []
+ all_actions += hotspots + empty_action if hotspots else []
+ all_actions += others + empty_action if others else []
+ all_actions += saved + empty_action if saved else []
+ return all_actions
+
+
+def get_wofi_highlight_markup(action):
+ highlight_fg = CONF.get('dmenu', 'highlight_fg', fallback=None)
+ highlight_bg = CONF.get('dmenu', 'highlight_bg', fallback=None)
+ highlight_bold = CONF.getboolean('dmenu', 'highlight_bold', fallback=True)
+
+ style = ""
+ if highlight_fg:
+ style += f'foreground="{highlight_fg}" '
+ if highlight_bg:
+ style += f'background="{highlight_bg}" '
+ if highlight_bold:
+ style += 'weight="bold" '
+
+ return f"" + str(action) + ""
+
+
+def get_selection(all_actions):
+ """Spawn dmenu for selection and execute the associated action."""
+ command = shlex.split(CONF.get("dmenu", "dmenu_command", fallback="dmenu"))
+ cmd_base = basename(command[0])
+ active_chars = CONF.get("dmenu", "active_chars", fallback="==")
+ highlight = CONF.getboolean("dmenu", "highlight", fallback=False)
+ inp = []
+
+ if highlight is True and cmd_base == "rofi":
+ inp = [str(action) for action in all_actions]
+ elif highlight is True and cmd_base == "wofi":
+ inp = [get_wofi_highlight_markup(action) if action.is_active else str(action)
+ for action in all_actions]
+ else:
+ inp = [(active_chars if action.is_active else " " * len(active_chars)) + " " + str(action)
+ for action in all_actions]
+ active_lines = [index for index, action in enumerate(all_actions)
+ if action.is_active]
+
+ command = dmenu_cmd(len(inp), active_lines=active_lines)
+ sel = subprocess.run(command,
+ capture_output=True,
+ check=False,
+ input="\n".join(inp),
+ encoding=ENC,
+ env=ENV).stdout
+
+ if not sel.rstrip():
+ sys.exit()
+
+ if highlight is True and cmd_base == "rofi":
+ action = [i for i in all_actions if str(i).strip() == sel.strip()]
+ elif highlight is True and cmd_base == "wofi":
+ action = [i for i in all_actions
+ if str(i).strip() == sel.strip() or
+ get_wofi_highlight_markup(i) == sel.strip()]
+ else:
+ action = [i for i in all_actions
+ if ((str(i).strip() == str(sel.strip())
+ and not i.is_active) or
+ (active_chars + " " + str(i) == str(sel.rstrip('\n'))
+ and i.is_active))]
+ if len(action) != 1:
+ raise ValueError(f"Selection was ambiguous: '{str(sel.strip())}'")
+ return action[0]
+
+
+def toggle_networking(enable):
+ """Enable/disable networking
+
+ Args: enable - boolean
+
+ """
+ toggle = GLib.Variant.new_tuple(GLib.Variant.new_boolean(enable))
+ try:
+ CLIENT.dbus_call(NM.DBUS_PATH, NM.DBUS_INTERFACE, "Enable", toggle,
+ None, -1, None, None, None)
+ except AttributeError:
+ # Workaround for older versions of python-gobject
+ CLIENT.networking_set_enabled(enable)
+ notify(f"Networking {'enabled' if enable is True else 'disabled'}")
+
+
+def toggle_wifi(enable):
+ """Enable/disable Wifi
+
+ Args: enable - boolean
+
+ """
+ toggle = GLib.Variant.new_boolean(enable)
+ try:
+ CLIENT.dbus_set_property(NM.DBUS_PATH, NM.DBUS_INTERFACE, "WirelessEnabled", toggle,
+ -1, None, None, None)
+ except AttributeError:
+ # Workaround for older versions of python-gobject
+ CLIENT.wireless_set_enabled(enable)
+ notify(f"Wifi {'enabled' if enable is True else 'disabled'}")
+
+
+def toggle_wwan(enable):
+ """Enable/disable WWAN
+
+ Args: enable - boolean
+
+ """
+ toggle = GLib.Variant.new_boolean(enable)
+ try:
+ CLIENT.dbus_set_property(NM.DBUS_PATH, NM.DBUS_INTERFACE, "WwanEnabled", toggle,
+ -1, None, None, None)
+ except AttributeError:
+ # Workaround for older versions of python-gobject
+ CLIENT.wwan_set_enabled(enable)
+ notify(f"Wwan {'enabled' if enable is True else 'disabled'}")
+
+
+def toggle_bluetooth(enable):
+ """Enable/disable Bluetooth
+
+ Try bluetoothctl first, then drop to rfkill if it's not installed or
+ bluetooth service isn't running.
+
+ Args: enable - boolean
+
+ References:
+ https://github.com/blueman-project/blueman/blob/master/blueman/plugins/mechanism/RfKill.py
+ https://www.kernel.org/doc/html/latest/driver-api/rfkill.html
+ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/uapi/linux/rfkill.h?h=v5.8.9
+
+ """
+ if is_installed('bluetoothctl') and is_running('bluetoothd'):
+ # Times out in 2 seconds, otherwise bluetoothctl will hang if bluetooth
+ # service isn't running.
+ try:
+ res = subprocess.run(['bluetoothctl', 'power', 'on' if enable is True else 'off'],
+ timeout=2,
+ capture_output=True)
+ except subprocess.TimeoutExpired:
+ pass
+ try:
+ res = subprocess.run(['bluetoothctl', 'show'],
+ timeout=2,
+ capture_output=True,
+ text=True)
+ if "Powered: yes" in res.stdout:
+ notify("Bluetooth enabled")
+ return
+ except subprocess.TimeoutExpired:
+ pass
+ # Now try using rfkill
+ type_bluetooth = 2
+ op_change_all = 3
+ idx = 0
+ soft_state = 0 if enable else 1
+ hard_state = 0
+
+ data = struct.pack("IBBBB", idx, type_bluetooth, op_change_all,
+ soft_state, hard_state)
+
+ try:
+ with open('/dev/rfkill', 'r+b', buffering=0) as rff:
+ rff.write(data)
+ except PermissionError:
+ notify("Lacking permission to write to /dev/rfkill.",
+ "Check README for configuration options.",
+ urgency="critical")
+ else:
+ notify(f"Bluetooth {'enabled' if enable else 'disabled'}")
+
+
+def launch_connection_editor():
+ """Launch nmtui or the gui nm-connection-editor
+
+ """
+ terminal = shlex.split(CONF.get("editor", "terminal", fallback="xterm"))
+ gui_if_available = CONF.getboolean("editor", "gui_if_available", fallback=True)
+ gui = CONF.get("editor", "gui", fallback="nm-connection-editor")
+ if gui_if_available is True:
+ if is_installed(gui):
+ subprocess.run(gui, check=False)
+ return
+ if is_installed("nmtui"):
+ subprocess.run(terminal + ["-e", "nmtui"], check=False)
+ return
+ notify("No network connection editor installed", urgency="critical")
+
+
+def show_wifi_password():
+ """Run `nmcli device wifi show-password` for current connection
+
+ """
+ terminal = CONF.get("editor", "terminal", fallback="xterm")
+ subprocess.run([terminal, "-e", "nmcli", "device", "wifi", "show-password;",
+ "exec", "bash"], check=False)
+
+
+def get_passphrase():
+ """Get a password
+
+ Returns: string
+
+ """
+ pinentry = CONF.get("dmenu", "pinentry", fallback=None)
+ if pinentry:
+ description = CONF.get("pinentry", "description", fallback="Get network password")
+ prompt = CONF.get("pinentry", "prompt", fallback="Password: ")
+ pin = ""
+ out = subprocess.run(pinentry,
+ capture_output=True,
+ check=False,
+ encoding=ENC,
+ input=f"setdesc {description}\nsetprompt {prompt}\ngetpin\n").stdout
+ if out:
+ res = [i for i in out.split("\n") if i.startswith("D ")]
+ if res and res[0].startswith("D "):
+ pin = res[0].split("D ")[1]
+ return pin
+ return subprocess.run(dmenu_cmd(0, "Passphrase"),
+ stdin=subprocess.DEVNULL,
+ capture_output=True,
+ check=False,
+ encoding=ENC).stdout
+
+
+def delete_connection():
+ """Display list of NM connections and delete the selected one
+
+ """
+ conn_acts = [Action(i.get_id(), i.delete_async, args=[None, delete_cb, None]) for i in CONNS]
+ conn_names = "\n".join([str(i) for i in conn_acts])
+ sel = subprocess.run(dmenu_cmd(len(conn_acts), "CHOOSE CONNECTION TO DELETE:"),
+ capture_output=True,
+ check=False,
+ input=conn_names,
+ encoding=ENC,
+ env=ENV).stdout
+ if not sel.strip():
+ sys.exit()
+ action = [i for i in conn_acts if str(i) == sel.rstrip("\n")]
+ if len(action) != 1:
+ raise ValueError(f"Selection was ambiguous: {str(sel)}")
+ action[0]()
+ LOOP.run()
+
+
+def delete_cb(dev, res, data):
+ """Notification if delete completed successfully
+
+ """
+ if dev.delete_finish(res) is True:
+ notify(f"Deleted {dev.get_id()}")
+ else:
+ notify(f"Problem deleting {dev.get_id()}", urgency="critical")
+ LOOP.quit()
+
+
+def set_new_connection(nm_ap, nm_pw, adapter):
+ """Setup a new NetworkManager connection
+
+ Args: ap - NM.AccessPoint
+ pw - string
+
+ """
+ nm_pw = str(nm_pw).strip()
+ profile = create_wifi_profile(nm_ap, nm_pw, adapter)
+ CLIENT.add_and_activate_connection_async(profile, adapter, nm_ap.get_path(),
+ None, verify_conn, profile)
+ LOOP.run()
+
+
+def create_wifi_profile(nm_ap, password, adapter):
+ # pylint: disable=line-too-long
+ # noqa From https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/examples/python/gi/add_connection.py
+ # noqa and https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/examples/python/dbus/add-wifi-psk-connection.py
+ # pylint: enable=line-too-long
+ """Create the NM profile given the AP and passphrase"""
+ ap_sec = ap_security(nm_ap)
+ profile = NM.SimpleConnection.new()
+
+ s_con = NM.SettingConnection.new()
+ s_con.set_property(NM.SETTING_CONNECTION_ID, ssid_to_utf8(nm_ap))
+ s_con.set_property(NM.SETTING_CONNECTION_UUID, str(uuid.uuid4()))
+ s_con.set_property(NM.SETTING_CONNECTION_TYPE, "802-11-wireless")
+ profile.add_setting(s_con)
+
+ s_wifi = NM.SettingWireless.new()
+ s_wifi.set_property(NM.SETTING_WIRELESS_SSID, nm_ap.get_ssid())
+ s_wifi.set_property(NM.SETTING_WIRELESS_MODE, 'infrastructure')
+ s_wifi.set_property(NM.SETTING_WIRELESS_MAC_ADDRESS, adapter.get_permanent_hw_address())
+ profile.add_setting(s_wifi)
+
+ s_ip4 = NM.SettingIP4Config.new()
+ s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto")
+ profile.add_setting(s_ip4)
+
+ s_ip6 = NM.SettingIP6Config.new()
+ s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto")
+ profile.add_setting(s_ip6)
+
+ if ap_sec != "--":
+ s_wifi_sec = NM.SettingWirelessSecurity.new()
+ if "WPA" in ap_sec:
+ if "WPA3" in ap_sec:
+ s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT,
+ "sae")
+ else:
+ s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT,
+ "wpa-psk")
+ s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_AUTH_ALG,
+ "open")
+ s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_PSK, password)
+ elif "WEP" in ap_sec:
+ s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT,
+ "None")
+ s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
+ NM.WepKeyType.PASSPHRASE)
+ s_wifi_sec.set_wep_key(0, password)
+ profile.add_setting(s_wifi_sec)
+
+ return profile
+
+
+def verify_conn(client, result, data):
+ """Callback function for add_and_activate_connection_async
+
+ Check if connection completes successfully. Delete the connection if there
+ is an error.
+
+ """
+ try:
+ act_conn = client.add_and_activate_connection_finish(result)
+ conn = act_conn.get_connection()
+ if not all([conn.verify(),
+ conn.verify_secrets(),
+ data.verify(),
+ data.verify_secrets()]):
+ raise GLib.Error
+ notify(f"Added {conn.get_id()}")
+ except GLib.Error:
+ try:
+ notify(f"Connection to {conn.get_id()} failed",
+ urgency="critical")
+ conn.delete_async(None, None, None)
+ except UnboundLocalError:
+ pass
+ finally:
+ LOOP.quit()
+
+
+def create_ap_list(adapter, active_connections):
+ """Generate list of access points. Remove duplicate APs and hotspots,
+ keeping strongest ones and the active AP
+
+ Args: adapter
+ active_connections - list of all active connections
+ Returns: aps - list of access points
+ active_ap - active AP
+ active_ap_con - active Connection
+ adapter
+
+ """
+ aps = []
+ ap_names = []
+ active_ap = adapter.get_active_access_point()
+ aps_all = sorted(adapter.get_access_points(),
+ key=lambda a: a.get_strength(), reverse=True)
+ if adapter.get_mode() == getattr(NM, "80211Mode").AP:
+ # Remove active hotspot from AP list
+ aps_all.remove(active_ap)
+ active_ap = None
+ conns_cur = [i for i in CONNS if
+ i.get_setting_wireless() is not None and
+ i.get_setting_wireless().get_mode() != "ap" and # filter out hotspots
+ conn_matches_adapter(i, adapter)]
+ try:
+ ap_conns = active_ap.filter_connections(conns_cur)
+ active_ap_name = ssid_to_utf8(active_ap)
+ active_ap_con = [active_conn for active_conn in active_connections
+ if active_conn.get_connection() in ap_conns]
+ except AttributeError:
+ active_ap_name = None
+ active_ap_con = []
+ if len(active_ap_con) > 1:
+ raise ValueError("Multiple connection profiles match"
+ " the wireless AP")
+ active_ap_con = active_ap_con[0] if active_ap_con else None
+ for nm_ap in aps_all:
+ ap_name = ssid_to_utf8(nm_ap)
+ if nm_ap != active_ap and ap_name == active_ap_name:
+ # Skip adding AP if it's not active but same name as active AP
+ continue
+ if ap_name not in ap_names:
+ ap_names.append(ap_name)
+ aps.append(nm_ap)
+ return aps, active_ap, active_ap_con, adapter
+
+
+def notify(message, details=None, urgency="low"):
+ """Use notify-send if available for notifications
+
+ """
+ delay = CONF.getint('nmdm', 'rescan_delay', fallback=5)
+ args = ["-u", urgency, "-a", "networkmanager-dmenu",
+ "-t", str(delay * 1000), message]
+ if details is not None:
+ args.append(details)
+ if is_installed("notify-send"):
+ subprocess.run(["notify-send"] + args, check=False)
+
+
+def run(): # pylint: disable=too-many-locals
+ """Main script entrypoint"""
+ try:
+ subprocess.check_output(["pidof", "NetworkManager"])
+ except subprocess.CalledProcessError:
+ notify("WARNING: NetworkManager don't seems to be running")
+ print("WARNING: NetworkManager don't seems to be running")
+ active = CLIENT.get_active_connections()
+ adapter = choose_adapter(CLIENT)
+ if adapter:
+ ap_actions = create_ap_actions(*create_ap_list(adapter, active))
+ else:
+ ap_actions = []
+
+ vpns = [i for i in CONNS if i.is_type(NM.SETTING_VPN_SETTING_NAME)]
+ try:
+ wgs = [i for i in CONNS if i.is_type(NM.SETTING_WIREGUARD_SETTING_NAME)]
+ except AttributeError:
+ # Workaround for older versions of python-gobject with no wireguard support
+ wgs = []
+ hotspots = [i for i in CONNS if i.get_setting_wireless() and
+ i.get_setting_wireless().get_mode() == "ap"]
+ eths = [i for i in CONNS if i.is_type(NM.SETTING_WIRED_SETTING_NAME)]
+ vlans = [i for i in CONNS if i.is_type(NM.SETTING_VLAN_SETTING_NAME)]
+ blues = [i for i in CONNS if i.is_type(NM.SETTING_BLUETOOTH_SETTING_NAME)]
+
+ vpn_actions = create_vpn_actions(vpns, active)
+ wg_actions = create_wireguard_actions(wgs, active)
+ eth_actions = create_eth_actions(eths, active)
+ vlan_actions = create_vlan_actions(vlans, active)
+ blue_actions = create_blue_actions(blues, active)
+ hotspot_actions = create_hotspot_actions(hotspots, active)
+ other_actions = create_other_actions(CLIENT)
+ wwan_installed = is_installed("ModemManager")
+ if wwan_installed:
+ gsms = [i for i in CONNS if i.is_type(NM.SETTING_GSM_SETTING_NAME)]
+ gsm_actions = create_gsm_actions(gsms, active)
+ wwan_actions = create_wwan_actions(CLIENT)
+ else:
+ gsm_actions = []
+ wwan_actions = []
+
+ list_saved = CONF.getboolean('dmenu', 'list_saved', fallback=False)
+ saved_cons = [i for i in CONNS if i not in vpns + wgs + eths + blues]
+ if list_saved:
+ saved_actions = create_saved_actions(saved_cons)
+ else:
+ saved_actions = [Action("Saved connections", prompt_saved, [saved_cons])]
+
+
+ actions = combine_actions(eth_actions, ap_actions, vlan_actions, vpn_actions,
+ wg_actions, gsm_actions, blue_actions, wwan_actions,
+ hotspot_actions, other_actions, saved_actions)
+ sel = get_selection(actions)
+ sel()
+
+
+def main():
+ """Main. Enables script to be re-run after a wifi rescan
+
+ """
+ global CLIENT, CONNS, LOOP # noqa pylint: disable=global-variable-undefined
+ CLIENT = NM.Client.new(None)
+ LOOP = GLib.MainLoop()
+ CONNS = CLIENT.get_connections()
+ run()
+
+
+if __name__ == '__main__':
+ main()
+
+# vim: set et ts=4 sw=4 :
diff --git a/.local/share/rofi/themes/boussole.rasi b/.local/share/rofi/themes/boussole.rasi
new file mode 100644
index 0000000..1b12a3a
--- /dev/null
+++ b/.local/share/rofi/themes/boussole.rasi
@@ -0,0 +1,114 @@
+/* Boussole theme by Gu://em_*/
+/* Based on work done by */
+/* Newman Sanchez (https://github.com/newmanls) */
+
+configuration {
+
+ modi: "drun,run";
+ display-drun: "Applications";
+ display-run: "Run";
+ drun-display-format: "{icon} {name}";
+ sort: true;
+ sorting-method: "fzf";
+
+ /* Icons */
+ show-icons: true;
+ /* icon-theme: "Gruvbox-Plus-Dark"; */
+}
+
+* {
+ /*font: "FiraCode Nerd Font Medium 12";*/
+ font: "JetBrainsMono Nerd Font Propo Regular 12";
+
+ bg0: #0d1117;
+ bg1: #1a2330;
+ fg0: #eeffff;
+
+ accent-color: #e64e4e;
+ urgent-color: #ffcb6b;
+
+ background-color: transparent;
+ text-color: @fg0;
+
+ margin: 0;
+ padding: 0;
+ spacing: 0;
+}
+
+window {
+ location: center;
+ width: 600;
+
+ background-color: @bg0;
+
+ /*border-radius: 4px;*/
+}
+
+inputbar {
+ spacing: 8px;
+ padding: 8px;
+
+ background-color: @bg1;
+}
+
+prompt, entry, element-icon, element-text {
+ vertical-align: 0.5;
+}
+
+prompt {
+ text-color: @accent-color;
+}
+
+textbox {
+ padding: 8px;
+ background-color: @bg1;
+}
+
+listview {
+ padding: 4px 0;
+ lines: 8;
+ columns: 1;
+
+ fixed-height: false;
+}
+
+element {
+ padding: 8px;
+ spacing: 8px;
+}
+
+element normal normal {
+ text-color: @fg0;
+}
+
+element normal urgent {
+ text-color: @urgent-color;
+}
+
+element normal active {
+ text-color: @accent-color;
+}
+
+element alternate active {
+ text-color: @accent-color;
+}
+
+element selected {
+ text-color: @bg0;
+}
+
+element selected normal, element selected active {
+ background-color: @accent-color;
+}
+
+element selected urgent {
+ background-color: @urgent-color;
+}
+
+element-icon {
+ size: 0.8em;
+}
+
+element-text {
+ text-color: inherit;
+}
diff --git a/.zshrc b/.zshrc
index b838f64..805c5d8 100644
--- a/.zshrc
+++ b/.zshrc
@@ -89,6 +89,8 @@ alias hx='helix'
alias cg='cargo'
alias rqr='rust-quick-run.sh'
alias vm='quickemu --vm *.conf'
+alias paclist="pacman -Qq | fzf --preview 'pacman -Qil {}' --layout=reverse --bind 'enter:execute(pacman -Qil {} | less)'
+"
# Power management
alias pprof='cat /sys/firmware/acpi/platform_profile' # Get current performance profile
alias pprof-list='cat /sys/firmware/acpi/platform_profile_choices' # Lists the available performance profiles