add waybar and notifcaitons

This commit is contained in:
2026-09-23 00:44:36 +05:00
parent 12fea5c39e
commit 51b4b123dd
14 changed files with 1503 additions and 1 deletions
+7 -1
View File
@@ -129,7 +129,7 @@ exec dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DE
exec blueman-applet
exec wl-paste -t text --watch clipman store # Clipboard manager
exec mako # Notification daemon
exec swaync # Notification daemon (see home/swaync.nix)
exec nm-applet # Network Manager applet
exec kdeconnect-indicator
@@ -157,4 +157,10 @@ exec xfce4-power-manager
#exec /usr/bin/uxplay -avdec
bindsym $mod+l exec /home/shihaam/scripts/lock.sh
# Notification centre: $mod+n opens the panel (past notifications, mpris,
# DND toggle), $mod+Shift+n flips do-not-disturb. -sw closes it again on the
# second press instead of stacking.
bindsym $mod+n exec swaync-client -t -sw
bindsym $mod+Shift+n exec swaync-client -d -sw
exec_always export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
+54
View File
@@ -0,0 +1,54 @@
{
"positionX": "right",
"positionY": "top",
"layer": "overlay",
"control-center-layer": "top",
"layer-shell": true,
"cssPriority": "user",
"notification-window-width": 420,
"notification-icon-size": 48,
"notification-body-image-height": 160,
"notification-body-image-width": 200,
"image-visibility": "when-available",
"transition-time": 200,
"timeout": 8,
"timeout-low": 4,
"timeout-critical": 0,
"control-center-width": 440,
"control-center-height": 700,
"control-center-margin-top": 8,
"control-center-margin-bottom": 8,
"control-center-margin-right": 8,
"control-center-margin-left": 0,
"fit-to-screen": true,
"keyboard-shortcuts": true,
"hide-on-clear": false,
"hide-on-action": true,
"script-fail-notify": true,
"widgets": [
"title",
"dnd",
"mpris",
"notifications"
],
"widget-config": {
"title": {
"text": "Notifications",
"clear-all-button": true,
"button-text": "Clear all"
},
"dnd": {
"text": "Do not disturb"
},
"mpris": {
"image-size": 88,
"image-radius": 8
}
}
}
+218
View File
@@ -0,0 +1,218 @@
/* Material Design SwayNC theme -- same palette as config/waybar/style.css:
#1E1E1E background, #2D2D2D surface, #E1E1E1 text, #90CAF9 accent,
#CF6679 critical. */
* {
font-family: "Roboto", "JetBrainsMono Nerd Font", "Material Design Icons", sans-serif;
font-size: 14px;
}
/* ============= Popup notifications ============= */
/* The toplevel window must stay transparent or the whole layer surface paints
a rectangle around the rounded cards. */
.control-center,
.notification-row,
.notification-background,
.floating-notifications.background {
background: transparent;
}
.notification {
margin: 8px;
padding: 0;
border-radius: 12px;
background: #2D2D2D;
color: #E1E1E1;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4);
}
.notification-content {
padding: 12px;
}
.summary {
font-size: 14px;
font-weight: 500;
color: #E1E1E1;
}
.time {
font-size: 12px;
color: #B0B0B0;
}
.body {
font-size: 13px;
color: #B0B0B0;
}
.notification.critical {
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4), inset 3px 0 0 #CF6679;
}
.notification.low .summary {
color: #B0B0B0;
}
/* ============= Action buttons =============
What bluetooth pairing prompts, Nextcloud-style "Accept/Reject" and browser
notifications render into. .notification-action is one button per action;
the first child gets the left rounding, the last the right. */
.notification-action {
margin: 0;
padding: 8px 12px;
border-top: 1px solid #383838;
background: #2D2D2D;
color: #90CAF9;
font-weight: 500;
transition: background 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
.notification-action:hover {
background: rgba(144, 202, 249, 0.12);
color: #90CAF9;
}
.notification-action:active {
background: rgba(144, 202, 249, 0.2);
}
.notification-action:first-child {
border-radius: 0 0 0 12px;
}
.notification-action:last-child {
border-radius: 0 0 12px 0;
border-right: none;
}
.notification-default-action {
border-radius: 12px;
}
/* Rounding only collapses on the bottom when action buttons sit below. */
.notification-default-action:not(:only-child) {
border-radius: 12px 12px 0 0;
}
.close-button {
margin: 6px;
padding: 0;
min-width: 24px;
min-height: 24px;
border-radius: 12px;
background: transparent;
color: #B0B0B0;
box-shadow: none;
}
.close-button:hover {
background: #CF6679;
color: #1E1E1E;
}
.inline-reply {
margin-top: 8px;
}
.inline-reply-entry {
padding: 6px 8px;
border: 1px solid #383838;
border-radius: 6px;
background: #1E1E1E;
color: #E1E1E1;
}
.inline-reply-button {
margin-left: 4px;
padding: 6px 12px;
border: none;
border-radius: 6px;
background: #90CAF9;
color: #1E1E1E;
}
/* ============= Control center ============= */
.control-center {
margin: 8px;
padding: 8px;
border-radius: 12px;
background: #1E1E1E;
color: #E1E1E1;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}
.control-center .notification {
margin: 4px 0;
}
.widget-title {
margin: 8px 8px 4px 8px;
font-size: 15px;
font-weight: 500;
color: #E1E1E1;
}
.widget-title > button {
padding: 4px 12px;
border: none;
border-radius: 6px;
background: #2D2D2D;
color: #90CAF9;
font-size: 13px;
}
.widget-title > button:hover {
background: rgba(144, 202, 249, 0.12);
}
.widget-dnd {
margin: 4px 8px 8px 8px;
font-size: 13px;
color: #B0B0B0;
}
.widget-dnd > switch {
border-radius: 12px;
background: #383838;
box-shadow: none;
}
.widget-dnd > switch:checked {
background: #90CAF9;
}
.widget-dnd > switch slider {
border-radius: 12px;
background: #E1E1E1;
}
.widget-mpris {
margin: 4px 0;
padding: 8px;
border-radius: 12px;
background: #2D2D2D;
color: #E1E1E1;
}
.widget-mpris-player {
padding: 8px;
}
.widget-mpris-title {
font-size: 14px;
font-weight: 500;
}
.widget-mpris-subtitle {
font-size: 12px;
color: #B0B0B0;
}
.widget-mpris button:hover {
background: rgba(144, 202, 249, 0.12);
color: #90CAF9;
}
+576
View File
@@ -0,0 +1,576 @@
[
{
"output": "DP-1",
"position": "bottom",
"height": 42,
"layer": "top",
"spacing": 4,
"modules-left": [
"sway/workspaces",
"sway/mode",
"custom/media"
],
"modules-center": [
"sway/window"
],
"modules-right": [
"idle_inhibitor",
"privacy",
"custom/updates",
"custom/weather",
"bluetooth",
"network",
"custom/vpn",
"pulseaudio",
"custom/monitor-brightness",
"cpu",
"memory",
"temperature",
"battery",
"custom/ibus",
"tray",
"clock",
"custom/power"
],
"sway/workspaces": {
"disable-scroll": false,
"all-outputs": false,
"format": "{name}"
},
"sway/mode": {
"format": "<span style=\"italic\"> {}</span>",
"tooltip": false
},
"sway/window": {
"format": "{}",
"max-length": 50,
"icon": true,
"icon-size": 16,
"rewrite": {
"(.*) — Mozilla Firefox": "󰈹 $1",
"(.*) - Visual Studio Code": "󰨞 $1",
"(.*) - vim": " $1",
"(.*) - zsh": " $1"
}
},
"custom/media": {
"format": " {}",
"return-type": "json",
"max-length": 40,
"escape": true,
"exec": "$HOME/.config/waybar/scripts/mediaplayer.py 2> /dev/null",
"on-click": "playerctl play-pause",
"on-click-right": "playerctl next",
"on-scroll-up": "playerctl previous",
"on-scroll-down": "playerctl next"
},
"clock": {
"interval": 1,
"format": "{:%H:%M:%S}",
"format-alt": "{:%A, %B %d, %Y (%R)}",
"tooltip-format": "<tt><small>{calendar}</small></tt>",
"calendar": {
"mode": "year",
"mode-mon-col": 3,
"weeks-pos": "right",
"on-scroll": 1,
"on-click-right": "mode",
"format": {
"months": "<span color='#ffead3'><b>{}</b></span>",
"days": "<span color='#ecc6d9'><b>{}</b></span>",
"weeks": "<span color='#99ffdd'><b>W{}</b></span>",
"weekdays": "<span color='#ffcc66'><b>{}</b></span>",
"today": "<span color='#ff6699'><b><u>{}</u></b></span>"
}
},
"actions": {
"on-click-right": "mode",
"on-scroll-up": "shift_up",
"on-scroll-down": "shift_down"
}
},
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "",
"deactivated": ""
},
"tooltip-format-activated": "Idle inhibitor: ON",
"tooltip-format-deactivated": "Idle inhibitor: OFF"
},
"privacy": {
"icon-spacing": 4,
"icon-size": 18,
"transition-duration": 250,
"modules": [
{
"type": "screenshare",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-in",
"tooltip": true,
"tooltip-icon-size": 24
}
]
},
"custom/updates": {
"format": "{} ",
"interval": 3600,
"exec": "checkupdates 2>/dev/null | wc -l",
"exec-if": "exit 0",
"on-click": "alacritty -e paru -Syu",
"tooltip": true,
"tooltip-format": "{} pending updates"
},
"custom/weather": {
"format": "{}",
"tooltip": true,
"interval": 1800,
"exec": "$HOME/.config/waybar/scripts/weather.sh",
"return-type": "json",
"on-click": "xdg-open https://weather.com"
},
"bluetooth": {
"format": " {status}",
"format-disabled": "",
"format-connected": " {num_connections}",
"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": "blueman-manager"
},
"network": {
"interval": 5,
"format-wifi": "📶 {signalStrength}%",
"format-ethernet": "🔌 {ipaddr}",
"format-linked": "🔌 {ifname} (No IP)",
"format-disconnected": "❌ Disconnected",
"tooltip-format": "{ifname}: {ipaddr}/{cidr}\nGateway: {gwaddr}\nStrength: {signalStrength}%\nFrequency: {frequency}MHz\nUp: {bandwidthUpBits} Down: {bandwidthDownBits}",
"tooltip-format-wifi": "📶 {essid} ({signalStrength}%)\n{ipaddr}/{cidr}\nGateway: {gwaddr}\nFrequency: {frequency}MHz\nUp: {bandwidthUpBits} Down: {bandwidthDownBits}",
"tooltip-format-ethernet": "🔌 {ifname}\n{ipaddr}/{cidr}\nGateway: {gwaddr}\nUp: {bandwidthUpBits} Down: {bandwidthDownBits}",
"on-click": "nm-connection-editor",
"on-click-right": "alacritty -e nmtui"
},
"custom/vpn": {
"format": "{}",
"interval": 5,
"exec": "$HOME/.config/waybar/scripts/vpn-check.sh",
"return-type": "json",
"on-click": "nm-connection-editor",
"tooltip": true
},
"pulseaudio": {
"scroll-step": 5,
"format": "{icon} {volume}%",
"format-bluetooth": "{icon} {volume}%",
"format-bluetooth-muted": " {icon}",
"format-muted": " {volume}%",
"format-icons": {
"headphone": "",
"hands-free": "",
"headset": "",
"phone": "",
"portable": "",
"car": "",
"default": ["", "", ""]
},
"on-click": "if pgrep -x pavucontrol > /dev/null; then pkill pavucontrol; else pavucontrol; fi",
"on-click-right": "pactl set-sink-mute @DEFAULT_SINK@ toggle",
"on-scroll-up": "pactl set-sink-volume @DEFAULT_SINK@ +5%",
"on-scroll-down": "pactl set-sink-volume @DEFAULT_SINK@ -5%",
"tooltip-format": "{desc}\nVolume: {volume}%"
},
"custom/monitor-brightness": {
"format": " {}%",
"interval": 2,
"exec": "$HOME/.config/waybar/scripts/monitor-brightness.sh get",
"on-click": "gddccontrol",
"on-scroll-up": "$HOME/.config/waybar/scripts/monitor-brightness.sh up && pkill -RTMIN+10 waybar",
"on-scroll-down": "$HOME/.config/waybar/scripts/monitor-brightness.sh down && pkill -RTMIN+10 waybar",
"signal": 10,
"tooltip": true,
"tooltip-format": "Monitor Brightness: {}%"
},
"cpu": {
"interval": 2,
"format": " {usage}%",
"max-length": 10,
"on-click": "alacritty -e htop",
"tooltip": true
},
"memory": {
"interval": 5,
"format": " {}%",
"tooltip-format": "RAM: {used:0.1f}G / {total:0.1f}G\nSwap: {swapUsed:0.1f}G / {swapTotal:0.1f}G",
"on-click": "alacritty -e htop"
},
"temperature": {
"thermal-zone": 2,
"hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
"critical-threshold": 80,
"interval": 5,
"format": "{icon} {temperatureC}°C",
"format-icons": ["", "", "", "", ""],
"tooltip": true
},
"battery": {
"states": {
"good": 95,
"warning": 30,
"critical": 15
},
"interval": 30,
"format": "{icon} {capacity}%",
"format-charging": " {capacity}%",
"format-plugged": " {capacity}%",
"format-alt": "{icon} {time}",
"format-icons": ["", "", "", "", ""],
"tooltip-format": "{timeTo}\nCapacity: {capacity}%\nHealth: {health}%\nPower: {power}W"
},
"custom/ibus": {
"exec": "ibus engine",
"interval": 1,
"format": "⌨ {}",
"on-click": "ibus engine Thaana",
"tooltip-format": "Current keyboard: {}"
},
"tray": {
"icon-size": 18,
"spacing": 8,
"show-passive-items": true
},
"custom/power": {
"format": "⏻",
"on-click": "$HOME/.config/waybar/scripts/power-menu.sh",
"tooltip": false
}
},
{
"output": ["DP-2", "DP-3", "DP-4", "DP-5", "DP-6", "DP-7", "DP-8", "HDMI-A-1", "HDMI-A-2", "HDMI-A-3"],
"position": "bottom",
"height": 42,
"layer": "top",
"spacing": 4,
"modules-left": [
"sway/workspaces",
"sway/mode"
],
"modules-center": [
"sway/window"
],
"modules-right": [
"privacy",
"network",
"pulseaudio",
"battery",
"tray",
"clock",
"custom/power"
],
"sway/workspaces": {
"disable-scroll": false,
"all-outputs": false,
"format": "{name}"
},
"sway/mode": {
"format": "<span style=\"italic\"> {}</span>",
"tooltip": false
},
"sway/window": {
"format": "{}",
"max-length": 50,
"icon": true,
"icon-size": 16,
"rewrite": {
"(.*) — Mozilla Firefox": "󰈹 $1",
"(.*) - Visual Studio Code": "󰨞 $1",
"(.*) - vim": " $1",
"(.*) - zsh": " $1"
}
},
"privacy": {
"icon-spacing": 4,
"icon-size": 18,
"transition-duration": 250,
"modules": [
{
"type": "screenshare",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-in",
"tooltip": true,
"tooltip-icon-size": 24
}
]
},
"network": {
"interval": 5,
"format-wifi": "📶 {signalStrength}%",
"format-ethernet": "🔌 {ipaddr}",
"format-linked": "🔌 {ifname} (No IP)",
"format-disconnected": "❌ Disconnected",
"tooltip-format": "{ifname}: {ipaddr}/{cidr}\nGateway: {gwaddr}\nStrength: {signalStrength}%\nFrequency: {frequency}MHz\nUp: {bandwidthUpBits} Down: {bandwidthDownBits}",
"tooltip-format-wifi": "📶 {essid} ({signalStrength}%)\n{ipaddr}/{cidr}\nGateway: {gwaddr}\nFrequency: {frequency}MHz\nUp: {bandwidthUpBits} Down: {bandwidthDownBits}",
"tooltip-format-ethernet": "🔌 {ifname}\n{ipaddr}/{cidr}\nGateway: {gwaddr}\nUp: {bandwidthUpBits} Down: {bandwidthDownBits}",
"on-click": "nm-connection-editor",
"on-click-right": "alacritty -e nmtui"
},
"pulseaudio": {
"scroll-step": 5,
"format": "{icon} {volume}%",
"format-bluetooth": "{icon} {volume}%",
"format-bluetooth-muted": " {icon}",
"format-muted": " {volume}%",
"format-icons": {
"headphone": "",
"hands-free": "",
"headset": "",
"phone": "",
"portable": "",
"car": "",
"default": ["", "", ""]
},
"on-click": "if pgrep -x pavucontrol > /dev/null; then pkill pavucontrol; else pavucontrol; fi",
"on-click-right": "pactl set-sink-mute @DEFAULT_SINK@ toggle",
"on-scroll-up": "pactl set-sink-volume @DEFAULT_SINK@ +5%",
"on-scroll-down": "pactl set-sink-volume @DEFAULT_SINK@ -5%",
"tooltip-format": "{desc}\nVolume: {volume}%"
},
"battery": {
"states": {
"good": 95,
"warning": 30,
"critical": 15
},
"interval": 30,
"format": "{icon} {capacity}%",
"format-charging": " {capacity}%",
"format-plugged": " {capacity}%",
"format-alt": "{icon} {time}",
"format-icons": ["", "", "", "", ""],
"tooltip-format": "{timeTo}\nCapacity: {capacity}%\nHealth: {health}%\nPower: {power}W"
},
"clock": {
"interval": 1,
"format": "{:%H:%M:%S}",
"format-alt": "{:%A, %B %d, %Y (%R)}",
"tooltip-format": "<tt><small>{calendar}</small></tt>",
"calendar": {
"mode": "year",
"mode-mon-col": 3,
"weeks-pos": "right",
"on-scroll": 1,
"on-click-right": "mode",
"format": {
"months": "<span color='#ffead3'><b>{}</b></span>",
"days": "<span color='#ecc6d9'><b>{}</b></span>",
"weeks": "<span color='#99ffdd'><b>W{}</b></span>",
"weekdays": "<span color='#ffcc66'><b>{}</b></span>",
"today": "<span color='#ff6699'><b><u>{}</u></b></span>"
}
},
"actions": {
"on-click-right": "mode",
"on-scroll-up": "shift_up",
"on-scroll-down": "shift_down"
}
},
"tray": {
"icon-size": 18,
"spacing": 8,
"show-passive-items": true
},
"custom/power": {
"format": "⏻",
"on-click": "$HOME/.config/waybar/scripts/power-menu.sh",
"tooltip": false
}
},
{
"output": "eDP-1",
"position": "bottom",
"height": 42,
"layer": "top",
"spacing": 4,
"modules-left": [
"sway/workspaces"
],
"modules-center": [
"sway/window"
],
"modules-right": [
"privacy",
"pulseaudio",
"backlight",
"battery",
"tray",
"clock",
"custom/power"
],
"sway/workspaces": {
"disable-scroll": false,
"all-outputs": false,
"format": "{name}"
},
"sway/window": {
"format": "{}",
"max-length": 50,
"icon": true,
"icon-size": 16,
"rewrite": {
"(.*) — Mozilla Firefox": "󰈹 $1",
"(.*) - Visual Studio Code": "󰨞 $1",
"(.*) - vim": " $1",
"(.*) - zsh": " $1"
}
},
"privacy": {
"icon-spacing": 4,
"icon-size": 18,
"transition-duration": 250,
"modules": [
{
"type": "screenshare",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-in",
"tooltip": true,
"tooltip-icon-size": 24
}
]
},
"pulseaudio": {
"scroll-step": 5,
"format": "{icon} {volume}%",
"format-bluetooth": "{icon} {volume}%",
"format-bluetooth-muted": " {icon}",
"format-muted": " {volume}%",
"format-icons": {
"headphone": "",
"hands-free": "",
"headset": "",
"phone": "",
"portable": "",
"car": "",
"default": ["", "", ""]
},
"on-click": "if pgrep -x pavucontrol > /dev/null; then pkill pavucontrol; else pavucontrol; fi",
"on-click-right": "pactl set-sink-mute @DEFAULT_SINK@ toggle",
"on-scroll-up": "pactl set-sink-volume @DEFAULT_SINK@ +5%",
"on-scroll-down": "pactl set-sink-volume @DEFAULT_SINK@ -5%",
"tooltip-format": "{desc}\nVolume: {volume}%"
},
"backlight": {
"device": "intel_backlight",
"format": "{icon} {percent}%",
"format-icons": ["", "", "", "", "", "", "", "", ""],
"on-scroll-up": "brightnessctl set +5%",
"on-scroll-down": "[ $(brightnessctl -m | cut -d',' -f4 | tr -d '%') -le 5 ] && brightnessctl set 1% || brightnessctl set 5%-",
"tooltip-format": "Brightness: {percent}%"
},
"battery": {
"states": {
"good": 95,
"warning": 30,
"critical": 15
},
"interval": 30,
"format": "{icon} {capacity}%",
"format-charging": " {capacity}%",
"format-plugged": " {capacity}%",
"format-alt": "{icon} {time}",
"format-icons": ["", "", "", "", ""],
"tooltip-format": "{timeTo}\nCapacity: {capacity}%\nHealth: {health}%\nPower: {power}W"
},
"clock": {
"interval": 1,
"format": "{:%H:%M:%S}",
"format-alt": "{:%A, %B %d, %Y (%R)}",
"tooltip-format": "<tt><small>{calendar}</small></tt>",
"calendar": {
"mode": "year",
"mode-mon-col": 3,
"weeks-pos": "right",
"on-scroll": 1,
"on-click-right": "mode",
"format": {
"months": "<span color='#ffead3'><b>{}</b></span>",
"days": "<span color='#ecc6d9'><b>{}</b></span>",
"weeks": "<span color='#99ffdd'><b>W{}</b></span>",
"weekdays": "<span color='#ffcc66'><b>{}</b></span>",
"today": "<span color='#ff6699'><b><u>{}</u></b></span>"
}
},
"actions": {
"on-click-right": "mode",
"on-scroll-up": "shift_up",
"on-scroll-down": "shift_down"
}
},
"tray": {
"icon-size": 18,
"spacing": 8,
"show-passive-items": true
},
"custom/power": {
"format": "⏻",
"on-click": "$HOME/.config/waybar/scripts/power-menu.sh",
"tooltip": false
}
}
]
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
import json
import subprocess
import sys
import signal
def signal_handler(sig, frame):
sys.exit(0)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
def get_output(status, artist, title, player):
if not status or status == "Stopped" or not title:
return {"text": "", "tooltip": "No media playing", "class": "stopped"}
if artist and title:
text = f"{artist} - {title}"
elif title:
text = title
else:
return {"text": "", "tooltip": "No media playing", "class": "stopped"}
if status == "Playing":
tooltip = f"▶ {text}"
display = text
elif status == "Paused":
tooltip = f"⏸ {text}"
display = f"⏸ {text}"
else:
tooltip = text
display = text
return {
"text": display[:40] + "..." if len(display) > 40 else display,
"tooltip": tooltip,
"class": status.lower() if status else "stopped"
}
def main():
# Use playerctl follow to get real-time updates
try:
proc = subprocess.Popen(
['playerctl', '--follow', 'metadata', '--format', '{{status}}|||{{artist}}|||{{title}}|||{{playerName}}'],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True
)
for line in proc.stdout:
line = line.strip()
if not line:
output = {"text": "", "tooltip": "No media playing", "class": "stopped"}
else:
parts = line.split('|||')
if len(parts) >= 4:
status, artist, title, player = parts[0], parts[1], parts[2], parts[3]
output = get_output(status, artist, title, player)
else:
output = {"text": "", "tooltip": "No media playing", "class": "stopped"}
print(json.dumps(output), flush=True)
except Exception as e:
print(json.dumps({"text": "", "tooltip": "No media playing", "class": "stopped"}), flush=True)
if __name__ == "__main__":
main()
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
CACHE_FILE="/tmp/monitor-brightness-cache"
PID_FILE="/tmp/monitor-brightness-pid"
SCROLL_FILE="/tmp/monitor-brightness-scroll"
LOCK_FILE="/tmp/monitor-brightness-lock"
get_actual() {
# Prevent concurrent ddcutil calls
exec 9>"$LOCK_FILE"
flock -n 9 || { cat "$CACHE_FILE" 2>/dev/null || echo "50"; return; }
val=$(ddcutil getvcp 10 --display 1 2>/dev/null | grep -oP 'current value =\s*\K[0-9]+')
exec 9>&-
echo "$val"
}
# Initialize cache if missing
[ ! -f "$CACHE_FILE" ] && echo "50" > "$CACHE_FILE"
apply_brightness() {
local value=$1
[ -f "$PID_FILE" ] && kill "$(cat "$PID_FILE")" 2>/dev/null
(
echo $$ > "$PID_FILE"
sleep 0.3
exec 9>"$LOCK_FILE"
flock 9
ddcutil setvcp 10 "$value" --display 1 --noverify 2>/dev/null
exec 9>&-
rm -f "$PID_FILE"
) &
}
case "$1" in
get)
# If scrolled recently, use cache for instant feedback
if [ -f "$SCROLL_FILE" ]; then
age=$(( $(date +%s) - $(stat -c %Y "$SCROLL_FILE") ))
if [ "$age" -lt 3 ]; then
cat "$CACHE_FILE"
exit 0
fi
rm -f "$SCROLL_FILE"
fi
# Otherwise fetch actual value
val=$(get_actual)
if [ -n "$val" ]; then
echo "$val" > "$CACHE_FILE"
echo "$val"
else
cat "$CACHE_FILE"
fi
;;
up)
touch "$SCROLL_FILE"
current=$(cat "$CACHE_FILE")
new=$((current + 5))
[ "$new" -gt 100 ] && new=100
echo "$new" > "$CACHE_FILE"
apply_brightness "$new"
;;
down)
touch "$SCROLL_FILE"
current=$(cat "$CACHE_FILE")
new=$((current - 5))
[ "$new" -lt 0 ] && new=0
echo "$new" > "$CACHE_FILE"
apply_brightness "$new"
;;
esac
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Power menu using rofi or wofi
# Detect which one is available
if command -v rofi &> /dev/null; then
MENU="rofi -dmenu -i -p Power"
elif command -v wofi &> /dev/null; then
MENU="wofi --dmenu -i -p Power"
else
notify-send "Power Menu" "Neither rofi nor wofi is installed"
exit 1
fi
# Menu options
OPTIONS="⏻ Shutdown\n⟳ Reboot\n⏾ Suspend\n Lock\n Logout"
# Show menu and get choice
CHOICE=$(echo -e "$OPTIONS" | $MENU)
# Execute based on choice
case $CHOICE in
*Shutdown)
systemctl poweroff
;;
*Reboot)
systemctl reboot
;;
*Suspend)
systemctl suspend
;;
*Lock)
# Try different lock commands
if command -v swaylock &> /dev/null; then
swaylock -f -c 000000
elif command -v gtklock &> /dev/null; then
gtklock
else
notify-send "Lock" "No lock screen program found"
fi
;;
*Logout)
swaymsg exit
;;
esac
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# Check for VPN connections using nmcli device show
# Initialize variables
vpn_status=""
vpn_tooltip=""
vpn_class="disconnected"
vpn_count=0
# Get all VPN devices and their details
while IFS= read -r device; do
if [ -n "$device" ]; then
# Get device type and connection
device_info=$(nmcli device show "$device" 2>/dev/null)
connection=$(echo "$device_info" | grep "GENERAL.CONNECTION:" | awk -F: '{print $2}' | xargs)
device_type=$(echo "$device_info" | grep "GENERAL.TYPE:" | awk -F: '{print $2}' | xargs)
ip_addr=$(echo "$device_info" | grep "IP4.ADDRESS" | head -1 | awk -F: '{print $2}' | xargs)
if [ -n "$connection" ] && [ "$connection" != "--" ]; then
((vpn_count++))
# Determine VPN type
if [[ "$device" == wg* ]]; then
vpn_type="WG"
vpn_icon="🔒"
elif [[ "$device" == tun* ]]; then
vpn_type="OVPN"
vpn_icon="🔒"
else
vpn_type="VPN"
vpn_icon="🔒"
fi
# Build status text
if [ -z "$vpn_status" ]; then
vpn_status="$vpn_icon $vpn_type"
vpn_tooltip="$vpn_type: $connection"
else
vpn_status="$vpn_status | $vpn_icon $vpn_type"
vpn_tooltip="$vpn_tooltip\n$vpn_type: $connection"
fi
# Add IP if available
if [ -n "$ip_addr" ]; then
vpn_tooltip="$vpn_tooltip\nIP: $ip_addr"
fi
# Set class based on first VPN type found
if [ "$vpn_class" = "disconnected" ]; then
if [[ "$device" == wg* ]]; then
vpn_class="connected-wg"
elif [[ "$device" == tun* ]]; then
vpn_class="connected-ovpn"
else
vpn_class="connected"
fi
fi
fi
fi
done < <(nmcli -t -f DEVICE device status | grep -E '^(tun|wg)' | cut -d: -f1)
# If no VPN found, show empty
if [ $vpn_count -eq 0 ]; then
echo "{\"text\":\"\", \"tooltip\":\"No VPN connected\", \"class\":\"disconnected\"}"
else
echo "{\"text\":\"$vpn_status\", \"tooltip\":\"$vpn_tooltip\", \"class\":\"$vpn_class\"}"
fi
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Get weather data from wttr.in with geolocation from ipinfo.io
# You can override with WEATHER_LOCATION environment variable
LOCATION="${WEATHER_LOCATION:-}"
# If no location is set, fetch it from ipinfo.io
if [ -z "$LOCATION" ]; then
LOCATION=$(curl -s "https://ipinfo.io/" | jq -r '.city // empty')
fi
# Fetch weather using wttr.in
if [ -n "$LOCATION" ]; then
WEATHER_DATA=$(curl -s "wttr.in/$LOCATION?format=%c+%t")
TOOLTIP=$(curl -s "wttr.in/$LOCATION?format=%l:+%c+%t+%w+%p+%h")
else
WEATHER_DATA=$(curl -s "wttr.in/?format=%c+%t")
TOOLTIP=$(curl -s "wttr.in/?format=%l:+%c+%t+%w+%p+%h")
fi
# Check if curl was successful
if [ $? -eq 0 ] && [ -n "$WEATHER_DATA" ]; then
echo "{\"text\":\"$WEATHER_DATA\", \"tooltip\":\"$TOOLTIP\"}"
else
echo "{\"text\":\"🌡 N/A\", \"tooltip\":\"Weather data unavailable\"}"
fi
+329
View File
@@ -0,0 +1,329 @@
/* Material Design Waybar Theme */
* {
font-family: "Roboto", "JetBrainsMono Nerd Font", "Material Design Icons", sans-serif;
font-size: 13px;
font-weight: 500;
border: none;
border-radius: 0;
min-height: 0;
}
window#waybar {
background: #1E1E1E;
color: #E1E1E1;
}
window#waybar.hidden {
opacity: 0;
}
tooltip {
background: #2D2D2D;
border-radius: 8px;
padding: 12px 16px;
color: #E1E1E1;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4);
}
tooltip label {
color: #E1E1E1;
}
/* ============= Workspaces ============= */
#workspaces {
margin: 4px 8px;
padding: 0;
background: #2D2D2D;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
#workspaces button {
padding: 0 16px;
margin: 4px;
background: transparent;
color: #B0B0B0;
border-radius: 6px;
transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
#workspaces button:hover {
background: rgba(144, 202, 249, 0.12);
color: #90CAF9;
}
#workspaces button.active,
#workspaces button.focused {
background: #90CAF9;
color: #1E1E1E;
box-shadow: 0 2px 4px rgba(144, 202, 249, 0.3);
}
#workspaces button.urgent {
background: #CF6679;
color: #1E1E1E;
}
/* ============= Mode & Window ============= */
#mode {
margin: 4px 8px;
padding: 0 16px;
background: #CF6679;
color: #1E1E1E;
border-radius: 8px;
font-weight: 500;
}
#window {
margin: 4px 8px;
padding: 0 16px;
color: #B0B0B0;
}
/* ============= Module Cards ============= */
#battery,
#cpu,
#memory,
#temperature,
#backlight,
#network,
#pulseaudio,
#bluetooth,
#idle_inhibitor,
#privacy,
#tray,
#custom-media,
#custom-updates,
#custom-weather,
#custom-vpn,
#custom-ibus,
#custom-monitor-brightness {
margin: 4px 2px;
padding: 0 12px;
background: #2D2D2D;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
#battery:hover,
#cpu:hover,
#memory:hover,
#temperature:hover,
#backlight:hover,
#network:hover,
#pulseaudio:hover,
#bluetooth:hover,
#idle_inhibitor:hover,
#custom-media:hover,
#custom-updates:hover,
#custom-weather:hover,
#custom-vpn:hover,
#custom-ibus:hover,
#custom-monitor-brightness:hover {
background: #383838;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
}
/* ============= Clock - Elevated Card ============= */
#clock {
margin: 4px 8px;
padding: 0 20px;
background: #2D2D2D;
color: #E1E1E1;
border-radius: 8px;
font-weight: 500;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
#clock:hover {
background: #383838;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
}
/* ============= Idle Inhibitor ============= */
#idle_inhibitor {
color: #B0B0B0;
}
#idle_inhibitor.activated {
background: #03DAC6;
color: #1E1E1E;
}
/* ============= Privacy ============= */
#privacy {
padding: 0 8px;
}
#privacy-item {
padding: 0 8px;
margin: 0 2px;
}
#privacy-item.screenshare {
color: #CF6679;
}
#privacy-item.audio-in {
color: #03DAC6;
}
#privacy-item.audio-out {
color: #90CAF9;
}
/* ============= Updates ============= */
#custom-updates {
color: #FFB74D;
}
/* ============= Weather ============= */
#custom-weather {
color: #90CAF9;
}
/* ============= Bluetooth ============= */
#bluetooth {
color: #90CAF9;
}
#bluetooth.disabled {
color: #666666;
}
#bluetooth.connected {
background: #90CAF9;
color: #1E1E1E;
}
/* ============= Network ============= */
#network {
color: #03DAC6;
}
#network.disconnected {
color: #CF6679;
}
/* ============= VPN ============= */
#custom-vpn {
color: #81C784;
}
#custom-vpn.connected,
#custom-vpn.connected-ovpn,
#custom-vpn.connected-wg {
background: #81C784;
color: #1E1E1E;
}
#custom-vpn.disconnected {
background: transparent;
box-shadow: none;
}
/* ============= Pulseaudio ============= */
#pulseaudio {
color: #CE93D8;
}
#pulseaudio.muted {
color: #666666;
}
/* ============= Backlight & Monitor Brightness ============= */
#backlight,
#custom-monitor-brightness {
color: #FFE082;
}
/* ============= CPU ============= */
#cpu {
color: #81C784;
}
/* ============= Memory ============= */
#memory {
color: #CE93D8;
}
/* ============= Temperature ============= */
#temperature {
color: #FFAB91;
}
#temperature.critical {
background: #CF6679;
color: #1E1E1E;
}
/* ============= Battery ============= */
#battery {
color: #81C784;
}
#battery.charging,
#battery.plugged {
background: #81C784;
color: #1E1E1E;
}
#battery.warning:not(.charging) {
color: #FFB74D;
}
#battery.critical:not(.charging) {
background: #CF6679;
color: #1E1E1E;
animation: blink 1s ease-in-out infinite;
}
@keyframes blink {
50% { opacity: 0.6; }
}
/* ============= Media ============= */
#custom-media {
color: #F48FB1;
min-width: 100px;
}
/* ============= IBus ============= */
#custom-ibus {
color: #90CAF9;
}
/* ============= Tray ============= */
#tray {
padding: 0 8px;
}
#tray > .passive {
-gtk-icon-effect: dim;
}
#tray > .needs-attention {
-gtk-icon-effect: highlight;
background: rgba(207, 102, 121, 0.3);
border-radius: 6px;
}
/* ============= Power Button ============= */
#custom-power {
margin: 4px 8px 4px 2px;
padding: 0 14px;
background: #2D2D2D;
color: #CF6679;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
#custom-power:hover {
background: #CF6679;
color: #1E1E1E;
box-shadow: 0 4px 8px rgba(207, 102, 121, 0.4);
}