From d876d4fae438fef2993eeceed0ff7a5003844472 Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Mon, 15 Sep 2025 10:54:03 +0200 Subject: [PATCH] Initial commit --- .gitignore | 4 + hypridle.conf | 19 +++ hyprland.conf | 335 ++++++++++++++++++++++++++++++++++++++++++ hyprlock.conf | 95 ++++++++++++ hyprpaper.conf | 2 + hyprscript | 304 ++++++++++++++++++++++++++++++++++++++ monitors.example.conf | 17 +++ waybar/config | 166 +++++++++++++++++++++ waybar/macchiato.css | 26 ++++ waybar/style.css | 179 ++++++++++++++++++++++ 10 files changed, 1147 insertions(+) create mode 100644 .gitignore create mode 100644 hypridle.conf create mode 100644 hyprland.conf create mode 100644 hyprlock.conf create mode 100644 hyprpaper.conf create mode 100755 hyprscript create mode 100644 monitors.example.conf create mode 100644 waybar/config create mode 100644 waybar/macchiato.css create mode 100644 waybar/style.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa7feaa --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.stat.txt +.mypy_cache +monitors.conf +exec-once.conf diff --git a/hypridle.conf b/hypridle.conf new file mode 100644 index 0000000..f78e0d8 --- /dev/null +++ b/hypridle.conf @@ -0,0 +1,19 @@ +# sample hypridle.conf +# for more configuration options, refer https://wiki.hyprland.org/Hypr-Ecosystem/hypridle + +general { + lock_cmd = ~/.config/dotfiles/hypr/hyprscript start-hyprlock + before_sleep_cmd = ~/.config/dotfiles/hypr/hyprscript lock-session + after_sleep_cmd = hyprctl dispatch dpms on +} + +listener { + timeout = 300 + on-timeout = ~/.config/dotfiles/hypr/hyprscript lock-session +} + +listener { + timeout = 350 + on-timeout = hyprctl dispatch dpms off + on-resume = hyprctl dispatch dpms on +} diff --git a/hyprland.conf b/hyprland.conf new file mode 100644 index 0000000..8cbba49 --- /dev/null +++ b/hyprland.conf @@ -0,0 +1,335 @@ +# This is an example Hyprland config file. +# Refer to the wiki for more information. +# https://wiki.hyprland.org/Configuring/ + +# Please note not all available settings / options are set here. +# For a full list, see the wiki + +# You can split this configuration into multiple files +# Create your files separately and then link them to this file like this: +# source = ~/.config/hypr/myColors.conf + + +################ +### MONITORS ### +################ + +source = ~/.config/dotfiles/hypr/monitors.conf + + +################### +### MY PROGRAMS ### +################### + +# See https://wiki.hyprland.org/Configuring/Keywords/ + +# Set programs that you use +$terminal = new-terminal +$fileManager = dolphin +$menu = rofi -show drun -theme ~/.config/rofi/theme.rasi +$hyprscript = ~/.config/dotfiles/hypr/hyprscript +$social = firefox "http://jdb.localhost/" "https://web.telegram.org" "https://web.whatsapp.com/" "https://discord.com/app" "https://nuage.polymny.studio/index.php/apps/calendar/" + + +################# +### AUTOSTART ### +################# + +# Autostart necessary processes (like notifications daemons, status bars, etc.) +# Or execute your favorite apps at launch like this: + +exec-once = $hyprscript stat +exec-once = hyprpaper +exec-once = hypridle +exec-once = nm-applet +exec-once = flameshot +exec-once = blueberry-tray +exec-once = nextcloud --background +exec-once = [workspace special:a_social silent] $social +exec-once = [workspace special:b_mail silent] thunderbird + +source = ~/.config/dotfiles/hypr/exec-once.conf + +############################# +### ENVIRONMENT VARIABLES ### +############################# + +# See https://wiki.hyprland.org/Configuring/Environment-variables/ + +env = XCURSOR_SIZE,18 +env = HYPRCURSOR_SIZE,18 + + +##################### +### LOOK AND FEEL ### +##################### + +# Refer to https://wiki.hyprland.org/Configuring/Variables/ + +# https://wiki.hyprland.org/Configuring/Variables/#general +general { + gaps_in = 0 + gaps_out = 0 + + border_size = 1 + + # https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors + col.active_border = rgba(ffffffaa) + col.inactive_border = rgba(ffffff22) + + # Set to true enable resizing windows by clicking and dragging on borders and gaps + resize_on_border = false + + # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on + allow_tearing = false + + layout = dwindle +} + +# https://wiki.hyprland.org/Configuring/Variables/#decoration +decoration { + rounding = 0 + rounding_power = 2 + + # Change transparency of focused and unfocused windows + active_opacity = 1.0 + inactive_opacity = 1.0 + + shadow { + enabled = false + range = 4 + render_power = 3 + color = rgba(1a1a1aee) + } + + # https://wiki.hyprland.org/Configuring/Variables/#blur + blur { + enabled = true + size = 3 + passes = 1 + + vibrancy = 0.1696 + } +} + +# https://wiki.hyprland.org/Configuring/Variables/#animations +animations { + enabled = yes, please :) + + # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more + + bezier = easeOutQuint,0.23,1,0.32,1 + bezier = easeInOutCubic,0.65,0.05,0.36,1 + bezier = linear,0,0,1,1 + bezier = almostLinear,0.5,0.5,0.75,1.0 + bezier = quick,0.15,0,0.1,1 + + animation = global, 1, 10, default + animation = border, 1, 5.39, easeOutQuint + animation = windows, 1, 4.79, easeOutQuint + animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% + animation = windowsOut, 1, 1.49, linear, popin 87% + animation = fadeIn, 1, 1.73, almostLinear + animation = fadeOut, 1, 1.46, almostLinear + animation = fade, 1, 3.03, quick + animation = layers, 1, 3.81, easeOutQuint + animation = layersIn, 1, 4, easeOutQuint, fade + animation = layersOut, 1, 1.5, linear, fade + animation = fadeLayersIn, 1, 1.79, almostLinear + animation = fadeLayersOut, 1, 1.39, almostLinear + animation = workspaces, 1, 1.94, almostLinear, fade + animation = workspacesIn, 1, 1.21, almostLinear, fade + animation = workspacesOut, 1, 1.94, almostLinear, fade +} + +# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ +# "Smart gaps" / "No gaps when only" +# uncomment all if you wish to use that. +# workspace = w[tv1], gapsout:0, gapsin:0 +# workspace = f[1], gapsout:0, gapsin:0 +# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] +# windowrule = rounding 0, floating:0, onworkspace:w[tv1] +# windowrule = bordersize 0, floating:0, onworkspace:f[1] +# windowrule = rounding 0, floating:0, onworkspace:f[1] + +# Borders only on alacritty +windowrule = noborder, class:negative:Alacritty + +# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more +dwindle { + pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below + preserve_split = true # You probably want this + force_split = 2 # split to the right / bottom +} + +# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more +master { + new_status = master +} + +# https://wiki.hyprland.org/Configuring/Variables/#misc +misc { + force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers + disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( + focus_on_activate = true + mouse_move_enables_dpms = true + key_press_enables_dpms = true +} + + +############# +### INPUT ### +############# + +# https://wiki.hyprland.org/Configuring/Variables/#input +input { + kb_layout = fr + kb_variant = + kb_model = + kb_options = + kb_rules = + + follow_mouse = 1 + + sensitivity = 0 # -1.0 - 1.0, 0 means no modification. + numlock_by_default = true + + touchpad { + natural_scroll = false + tap-to-click = false + } +} + +# Example per-device config +# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more +device { + name = epic-mouse-v1 + sensitivity = -0.5 +} + +################# +### ECOSYSTEM ### +################# +ecosystem { + no_update_news = true + no_donation_nag = true +} + + +################### +### KEYBINDINGS ### +################### + +# See https://wiki.hyprland.org/Configuring/Keywords/ +$mainMod = SUPER # Sets "Windows" key as main modifier + +# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more +bind = $mainMod, return, exec, $terminal +bind = $mainMod, A, exec, firefox +bind = $mainMod SHIFT, A, exec, firefox -P Yuzzit +bind = $mainMod SHIFT, C, killactive, +bind = $mainMod, V, togglefloating, +bind = $mainMod, R, exec, $menu +bind = $mainMod, J, exec, $hyprscript focusnextmonitor + +bind = $mainMod, O, exec, $hyprscript movewindow +bind = $mainMod, Tab, cyclenext + +bind = $mainMod CTRL, R, exec, $hyprscript reload +bind = $mainMod SHIFT, Q, exec, hyprctl dispatch exit + +bind = $mainMod, Z, exec, $social +bind = $mainMod, E, exec, firefox "-P" "Yuzzit" "https://mail.google.com/mail/u/0/" "https://app.slack.com/client/T03UFFGJK/D07KS0S1LDT" "https://app.gather.town/app/bZRkf3gh7MIximOa/ytopenspace" "https://yip.atlassian.net/wiki/spaces/Y/overview" "https://yip.atlassian.net/" + +bind = $mainMod, C, exec, alacritty -e numbat +bind = $mainMod, P, exec, pavucontrol +bind = $mainMod, B, exec, blueberry + +bind = $mainMod, L, exec, sleep 0.5s && hyprctl dispatch dpms off +bind = $mainMod SHIFT, L, exec, loginctl lock-session && sleep 0.5s && (pidof hyprlock || hyprlock) && hyprctl dispatch dpms off + +bind = $mainMod SHIFT, M, exec, sleep 0.5s && wtype "thomas@forgione.fr" +bind = $mainMod SHIFT, code:48, exec, sleep 0.5s && wtype "thomas@polymny.studio" +bind = $mainMod SHIFT, code:51, exec, sleep 0.5s && wtype "thomas.forgione@yuzzitpro.com" + +# Move focus with mainMod + arrow keys +# bind = $mainMod, left, movefocus, l +# bind = $mainMod, right, movefocus, r +# bind = $mainMod, up, movefocus, u +# bind = $mainMod, down, movefocus, d + +bind = $mainMod, left, exec, $hyprscript workspace previous +bind = $mainMod, right, exec, $hyprscript workspace next + +# Switch workspaces with mainMod + [0-9] +bind = $mainMod, code:10, exec, $hyprscript workspace 1 +bind = $mainMod, code:11, exec, $hyprscript workspace 2 +bind = $mainMod, code:12, exec, $hyprscript workspace 3 +bind = $mainMod, code:13, exec, $hyprscript workspace 4 +bind = $mainMod, code:14, exec, $hyprscript workspace 5 +bind = $mainMod, code:15, exec, $hyprscript workspace 6 +bind = $mainMod, code:16, exec, $hyprscript workspace 7 +bind = $mainMod, code:17, exec, $hyprscript workspace 8 +bind = $mainMod, code:18, exec, $hyprscript workspace 9 +bind = $mainMod, code:19, exec, $hyprscript workspace 10 + +# Move active window to a workspace with mainMod + SHIFT + [0-9] +bind = $mainMod SHIFT, code:10, exec, $hyprscript movetoworkspace 1 +bind = $mainMod SHIFT, code:11, exec, $hyprscript movetoworkspace 2 +bind = $mainMod SHIFT, code:12, exec, $hyprscript movetoworkspace 3 +bind = $mainMod SHIFT, code:13, exec, $hyprscript movetoworkspace 4 +bind = $mainMod SHIFT, code:14, exec, $hyprscript movetoworkspace 5 +bind = $mainMod SHIFT, code:15, exec, $hyprscript movetoworkspace 6 +bind = $mainMod SHIFT, code:16, exec, $hyprscript movetoworkspace 7 +bind = $mainMod SHIFT, code:17, exec, $hyprscript movetoworkspace 8 +bind = $mainMod SHIFT, code:18, exec, $hyprscript movetoworkspace 9 +bind = $mainMod SHIFT, code:19, exec, $hyprscript movetoworkspace 10 + +# Screenshot +bind = , Print, exec, grim -g "$(slurp -d)" - | wl-copy + +# Example special workspace (scratchpad) +bind = $mainMod, Q, togglespecialworkspace, a_social +bind = $mainMod, S, togglespecialworkspace, b_mail + +# Scroll through existing workspaces with mainMod + scroll +bind = $mainMod, mouse_down, workspace, e+1 +bind = $mainMod, mouse_up, workspace, e-1 + +# Move/resize windows with mainMod + LMB/RMB and dragging +bindm = $mainMod, mouse:272, movewindow +bindm = $mainMod, mouse:273, resizewindow + +# Laptop multimedia keys for volume and LCD brightness +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ +bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 2%+ +bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 2%- + +# Requires playerctl +bindl = , XF86AudioNext, exec, playerctl next +bindl = , XF86AudioPause, exec, playerctl play-pause +bindl = , XF86AudioPlay, exec, playerctl play-pause +bindl = , XF86AudioPrev, exec, playerctl previous + +############################## +### WINDOWS AND WORKSPACES ### +############################## + +# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more +# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules + +# Example windowrule +# windowrule = float,class:^(kitty)$,title:^(kitty)$ + +# Ignore maximize requests from apps. You'll probably like this. +windowrule = suppressevent maximize, class:.* + +# Fix some dragging issues with XWayland +windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 + +# Nvidia config +env = LIBVA_DRIVER_NAME,nvidia +env = __GLX_VENDOR_LIBRARY_NAME,nvidia diff --git a/hyprlock.conf b/hyprlock.conf new file mode 100644 index 0000000..fb488e9 --- /dev/null +++ b/hyprlock.conf @@ -0,0 +1,95 @@ +# sample hyprlock.conf +# for more configuration options, refer https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock +# +# rendered text in all widgets supports pango markup (e.g. or tags) +# ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#general-remarks +# +# shortcuts to clear password buffer: ESC, Ctrl+U, Ctrl+Backspace +# +# you can get started by copying this config to ~/.config/hypr/hyprlock.conf +# + +$font = Monospace + +general { + hide_cursor = false +} + +# uncomment to enable fingerprint authentication +# auth { +# fingerprint { +# enabled = true +# ready_message = Scan fingerprint to unlock +# present_message = Scanning... +# retry_delay = 250 # in milliseconds +# } +# } + +animations { + enabled = true + bezier = linear, 1, 1, 0, 0 + animation = fadeIn, 1, 5, linear + animation = fadeOut, 1, 5, linear + animation = inputFieldDots, 1, 2, linear +} + +background { + monitor = + path = screenshot + blur_passes = 3 +} + +input-field { + monitor = + size = 20%, 5% + outline_thickness = 3 + inner_color = rgba(0, 0, 0, 0.0) # no fill + + outer_color = rgba(33ccffee) rgba(00ff99ee) 45deg + check_color = rgba(00ff99ee) rgba(ff6633ee) 120deg + fail_color = rgba(ff6633ee) rgba(ff0066ee) 40deg + + font_color = rgb(143, 143, 143) + fade_on_empty = false + rounding = 15 + + font_family = $font + placeholder_text = Input password... + fail_text = $PAMFAIL + + # uncomment to use a letter instead of a dot to indicate the typed password + # dots_text_format = * + # dots_size = 0.4 + dots_spacing = 0.3 + + # uncomment to use an input indicator that does not show the password length (similar to swaylock's input indicator) + # hide_input = true + + position = 0, -20 + halign = center + valign = center +} + +# TIME +label { + monitor = + text = $TIME # ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#variable-substitution + font_size = 90 + font_family = $font + + position = -30, 0 + halign = right + valign = top +} + +# DATE +label { + monitor = + text = cmd[update:60000] date +"%A, %d %B %Y" # update every 60 seconds + font_size = 25 + font_family = $font + + position = -30, -150 + halign = right + valign = top +} diff --git a/hyprpaper.conf b/hyprpaper.conf new file mode 100644 index 0000000..22a23b0 --- /dev/null +++ b/hyprpaper.conf @@ -0,0 +1,2 @@ +preload = /home/thomas/.config/awesome/Wallpapers/cobra-kai-1.png +wallpaper = , /home/thomas/.config/awesome/Wallpapers/cobra-kai-1.png diff --git a/hyprscript b/hyprscript new file mode 100755 index 0000000..0f89a24 --- /dev/null +++ b/hyprscript @@ -0,0 +1,304 @@ +#!/usr/bin/env python + +import json +import os +import os.path +import subprocess +import sys +import typing + +os.chdir(os.path.expanduser('~/.config/hypr')) +bars = "_▂▃▄▅▆▇█" +batteries = "󰂎󰁺󰁻󰁼󰁽󰁾󰁿󰂀󰂁󰂁󰁹" +batteries_charging = "󰢟󰢜󰂆󰂇󰂈󰢝󰂉󰢞󰂊󰂋󰂅" + + +class Monitor: + """ + A monitor on which many workspaces can appear. + """ + + def __init__(self, id: int, name: str, special_workspace: typing.Optional['Workspace']): + """ + Constructs a monitor from its id and its name. + """ + self.id = id + self.name = name + self.special_workspace = special_workspace + + def __eq__(self, other): + """ + Returns true if the monitors are the same. + """ + self.id == other.id + + @staticmethod + def active(monitors: list['Monitor']) -> 'Monitor': + """ + Returns the active monitor. + """ + proc = subprocess.run(['hyprctl', 'activeworkspace', '-j'], capture_output=True) + result = json.loads(proc.stdout) + return next((monitor for monitor in monitors if monitor.id == result['monitorID'])) + + @staticmethod + def all() -> list['Monitor']: + """ + Returns the list of available monitors. + """ + monitors: list['Monitor'] = [] + + proc = subprocess.run(['hyprctl', 'monitors', '-j'], capture_output=True) + result = json.loads(proc.stdout) + + for mon in result: + if mon['specialWorkspace']['id'] == 0: + monitors.append(Monitor(mon['id'], mon['name'], None)) + else: + special_workspace = Workspace(mon['specialWorkspace']['id'], mon['specialWorkspace']['name']) + monitors.append(Monitor(mon['id'], mon['name'], special_workspace)) + + return monitors + + def previous(self, monitors: list['Monitor'], move: bool = False): + """ + Moves the focus to the previous monitor. + + Params: + move: whether you want to move the active window to the new monitor. + """ + mon = monitors[(monitors.index(self) - 1) % len(monitors)] + + if move: + subprocess.run(['hyprctl', 'dispatch', 'movewindow', 'mon:' + str(mon.id)]) + else: + subprocess.run(['hyprctl', 'dispatch', 'focusmonitor', str(mon.id)]) + + def next(self, monitors: list['Monitor'], move: bool = False): + """ + Moves the focus to the next monitor. + + Params: + move: whether you want to move the active window to the new monitor. + """ + mon = monitors[(monitors.index(self) + 1) % len(monitors)] + + if move: + subprocess.run(['hyprctl', 'dispatch', 'movewindow', 'mon:' + str(mon.name)]) + else: + subprocess.run(['hyprctl', 'dispatch', 'focusmonitor', str(mon.name)]) + + +class Workspace: + """ + A workspace bound to a monitor. + + Workspaces with id from 10 * n + k belongs to the same monitor for k in [1, 10]. + """ + + def __init__(self, id: int, name: str): + """ + Constructs a workspace from its id and its name. + """ + self.id = id + self.name = name + + def is_special(self) -> bool: + """ + Returns true if the workspace is a magic workspace. + """ + return self.id < 0 + + def special_name(self) -> typing.Optional[str]: + """ + Returns the part after the : if the workspace is special, none otherwise. + """ + if self.is_special(): + return ':'.join(self.name.split(':')[1:]) + else: + return None + + @staticmethod + def active() -> 'Workspace': + """ + Returns the active workspace. + """ + proc = subprocess.run(['hyprctl', 'activeworkspace', '-j'], capture_output=True) + result = json.loads(proc.stdout) + return Workspace(result['id'], result['name']) + + def nth(self, n: int, monitor: Monitor, move: bool = False): + """ + Goes to the nth workspace on the same monitor as the current workspace. + + Params: + n: workspace to go to, between 1 and 10. + monitor: active monitor. + move: whether you want to move the active window to the new workspace. + """ + new_id = (self.id - 1) // 10 * 10 + n + + current = monitor.special_workspace + if current is not None: + subprocess.run(['hyprctl', 'dispatch', 'togglespecialworkspace', current.special_name()]) + + subprocess.run(['hyprctl', 'dispatch', 'movetoworkspace' if move else 'workspace', str(new_id)]) + + def previous(self, monitor: Monitor, move: bool = False): + """ + Goes to the previous workspace on the same monitor, or the last if we're on the first. + + Params: + monitor: active monitor. + move: whether you want to move the active window to the new workspace. + """ + new_id = self.id - 1 + + if new_id % 10 == 0: + new_id += 10 + + current = monitor.special_workspace + if current is not None: + subprocess.run(['hyprctl', 'dispatch', 'togglespecialworkspace', current.special_name()]) + + subprocess.run(['hyprctl', 'dispatch', 'movetoworkspace' if move else 'workspace', str(new_id)]) + + def next(self, monitor: Monitor, move: bool = False): + """ + Goes to the next workspace on the same monitor, or the first if we're on the last. + + Params: + monitor: active monitor. + move: whether you want to move the active window to the new workspace. + """ + new_id = self.id + 1 + + if new_id % 10 == 1: + new_id -= 10 + + current = monitor.special_workspace + if current is not None: + subprocess.run(['hyprctl', 'dispatch', 'togglespecialworkspace', current.special_name()]) + + subprocess.run(['hyprctl', 'dispatch', 'movetoworkspace' if move else 'workspace', str(new_id)]) + + +def to_bar(x): + return bars[round((len(bars) - 1) * x / 100)] + + +def monitor_stats(): + """ + Monitors CPU and MEM usage and prints info in file. + """ + + try: + import psutil + except ModuleNotFoundError: + print('Stats requires psutil (run `pip install psutil`)', file=sys.stderr) + sys.exit(1) + + cpu_values = [0] * 10 + mem_values = [0] * 10 + + while True: + cpu_percent = psutil.cpu_percent(interval=2) + mem_percent = psutil.virtual_memory().percent + battery = psutil.sensors_battery() + + for i in range(len(cpu_values) - 1): + cpu_values[i] = cpu_values[i+1] + mem_values[i] = mem_values[i+1] + + cpu_values[-1] = cpu_percent + mem_values[-1] = mem_percent + + if battery is None: + battery_json = '{"text": "", "class": "hidden"}' + else: + battery_index = round(battery.percent / 10) + battery_icon = batteries_charging[battery_index] if battery.power_plugged else batteries[battery_index] + + if battery.power_plugged: + battery_class = 'charging' + elif battery.percent < 30.0: + battery_class = 'low' + elif battery.percent < 15.0: + battery_class = 'critical' + else: + battery_class = None + + battery_json = f', "class": "{battery_class}"' if battery_class else '' + battery_json = '{"text": "' + battery_icon + ' ' + "% 4.0f" % battery.percent + '%"' + battery_json + '}' + + with open('.stat.txt', 'w') as f: + f.write( + ' ' + ''.join([to_bar(x) for x in cpu_values]) + ' ' + "% 5.1f" % cpu_percent + '%\n' + + ' ' + ''.join([to_bar(x) for x in mem_values]) + ' ' + "% 5.1f" % mem_percent + '%\n' + + battery_json + ) + + +def start_hyprlock(): + proc = subprocess.run(['pidof', 'hyprlock']) + if proc.returncode != 0: + # We need to start this in the background so that the screen turns off afterwards + subprocess.Popen(['hyprlock'], start_new_session=True) + + +def lock_session(): + if os.environ.get('HYPR_DISABLE_LOCK', None) is None: + subprocess.run(['loginctl', 'lock-session']) + + +def main(): + if len(sys.argv) < 2: + return + + if sys.argv[1] == 'workspace' or sys.argv[1] == 'movetoworkspace': + monitors = Monitor.all() + monitor = Monitor.active(monitors) + + workspace = Workspace.active() + move = sys.argv[1] == 'movetoworkspace' + + if sys.argv[2] == 'next': + workspace.next(monitor, move) + + elif sys.argv[2] == 'previous': + workspace.previous(monitor, move) + + else: + new_workspace = int(sys.argv[2]) + workspace.nth(new_workspace, monitor, move) + + elif sys.argv[1] in ['movewindow', 'focusnextmonitor', 'focuspreviousmonitor']: + monitors = Monitor.all() + monitor = Monitor.active(monitors) + + if sys.argv[1] == 'movewindow': + monitor.next(monitors, True) + elif sys.argv[1] == 'focusnextmonitor': + monitor.next(monitors) + elif sys.argv[1] == 'focuspreviousmonitor': + monitor.previous(monitors) + + elif sys.argv[1] == 'reload': + subprocess.run(['systemctl', 'restart', 'waybar', '--user']) + + elif sys.argv[1] == 'stat': + monitor_stats() + + elif sys.argv[1] == 'start-hyprlock': + start_hyprlock() + + elif sys.argv[1] == 'lock-session': + lock_session() + + else: + print(f'Command not found: {sys.argv[1]}', file=sys.stderr) + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/monitors.example.conf b/monitors.example.conf new file mode 100644 index 0000000..a24a064 --- /dev/null +++ b/monitors.example.conf @@ -0,0 +1,17 @@ +$mainMonitorName = eDP-1 +$mainMonitorResolution = 1920x1080@59.99900 +$mainMonitorPosition = 0x0 +$mainMonitorScale = 1 + +workspace = 11, monitor:$mainMonitorName, default:true +workspace = 12, monitor:$mainMonitorName +workspace = 13, monitor:$mainMonitorName +workspace = 14, monitor:$mainMonitorName +workspace = 15, monitor:$mainMonitorName +workspace = 16, monitor:$mainMonitorName +workspace = 17, monitor:$mainMonitorName +workspace = 18, monitor:$mainMonitorName +workspace = 19, monitor:$mainMonitorName +workspace = 20, monitor:$mainMonitorName + +monitor = $mainMonitorName, $mainMonitorResolution, $mainMonitorPosition, $mainMonitorScale diff --git a/waybar/config b/waybar/config new file mode 100644 index 0000000..72f8d2c --- /dev/null +++ b/waybar/config @@ -0,0 +1,166 @@ +{ + "name": "float", + "layer": "top", + "position": "bottom", + "exclusive": false, + "passthrough": false, + "gtk-layer-shell": true, + "margin-right": 10, + "margin-bottom": 0, + "margin-top" : 0, + "margin-left": 0, + "margin-right": 0, + "height" : 16, + "modules-left": [ + ], + "modules-center": [ + ], + "modules-right": [ + "hyprland/workspaces", + "custom/cpu", + "custom/mem", + "custom/battery", + "tray", + "clock" + ], + "hyprland/window": { + "format": "{}", + "max-length": 35, + "rewrite": { + "": "Harsh" + }, + "separate-outputs": true, + }, + "hyprland/workspaces": { + "format": "{icon}", + "format-icons": { + "a_social": "󰍥 ", + "b_mail": " ", + "c_terminal": " ", + "11": "1", + "12": "2", + "13": "3", + "14": "4", + "15": "5", + "16": "6", + "17": "7", + "18": "8", + "19": "9", + "20": "0", + "21": "1", + "22": "2", + "23": "3", + "24": "4", + "25": "5", + "26": "6", + "27": "7", + "28": "8", + "29": "9", + "30": "0", + "31": "1", + "32": "2", + "33": "3", + "34": "4", + "35": "5", + "36": "6", + "37": "7", + "38": "8", + "39": "9", + "40": "0", + }, + "on-click": "activate", + "sort-by-number": true, + "persistent-workspaces": { + "eDP-1": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + "DP-3": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + "DP-2": [21, 22, 23, 24, 25, 26, 27, 28, 29, 30], + "HDMI-A-1": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40] + }, + "show-special": true + }, + "clock": { + "format": "{:L%A %d %B %H:%M}", + "tooltip-format": "{:%Y %B}\n{calendar}", + "format-alt": "{}", + "interval": 1 + }, + "battery": { + "states": { + "warning": 30, + "critical": 15 + }, + "format": "{capacity}% {icon}", + "format-full": "{icon} {capacity}%", + "format-charging": " {capacity}%", + "format-plugged": " {capacity}%", + "format-alt": "{time} {icon}", + "format-icons": ["", "", "", "", ""] + }, + "pulseaudio#1": { + "format": "{volume}% {icon}", + "format-bluetooth": "{volume}% {icon} {format_source}", + "format-bluetooth-muted": " {icon} {format_source}", + "format-muted": "", + "format-icons": { + "headphone": "", + "hands-free": "", + "headset": "", + "phone": "", + "portable": "", + "car": "", + "default": ["", "", ""] + }, + "on-click-right": "pavucontrol", + "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", + "on-scroll-up": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+", + "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-" + }, + "pulseaudio#2": { + "format": "{format_source}", + "format-bluetooth": "{volume}% {icon}", + "format-muted": "{format_source}", + "format-source": "{volume}% ", + "format-source-muted": "", + "format-icons": { + "headphones": "", + "handsfree": "", + "headset": "", + "phone": "", + "portable": "", + "car": "", + "default": [ + "", + "", + "" + ] + }, + "on-click-right": "pavucontrol", + "on-click": "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle", + "on-scroll-up": "wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%+", + "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%-" + }, + "idle_inhibitor": { + "format": "{icon}", + "format-icons": { + "activated": "", + "deactivated": "" + } + }, + "tray": { + "icon-size": 16, + "spacing": 5 + }, + "custom/cpu": { + "exec": "sed '1q;d' ~/.config/dotfiles/hypr/.stat.txt", + "restart-interval": 2 + }, + "custom/mem": { + "exec": "sed '2q;d' ~/.config/dotfiles/hypr/.stat.txt", + "restart-interval": 2 + }, + "custom/battery": { + "exec": "sed '3q;d' ~/.config/dotfiles/hypr/.stat.txt", + "return-type": "json", + "restart-interval": 2 + } +} diff --git a/waybar/macchiato.css b/waybar/macchiato.css new file mode 100644 index 0000000..112ee32 --- /dev/null +++ b/waybar/macchiato.css @@ -0,0 +1,26 @@ +@define-color rosewater #f4dbd6; +@define-color flamingo #f0c6c6; +@define-color pink #f5bde6; +@define-color mauve #c6a0f6; +@define-color red #ed8796; +@define-color maroon #ee99a0; +@define-color peach #f5a97f; +@define-color yellow #eed49f; +@define-color green #a6da95; +@define-color teal #8bd5ca; +@define-color sky #91d7e3; +@define-color sapphire #7dc4e4; +@define-color blue #8aadf4; +@define-color lavender #b7bdf8; +@define-color text #cad3f5; +@define-color subtext1 #b8c0e0; +@define-color subtext0 #a5adcb; +@define-color overlay2 #939ab7; +@define-color overlay1 #8087a2; +@define-color overlay0 #6e738d; +@define-color surface2 #5b6078; +@define-color surface1 #494d64; +@define-color surface0 #363a4f; +@define-color base #24273a; +@define-color mantle #1e2030; +@define-color crust #181926; diff --git a/waybar/style.css b/waybar/style.css new file mode 100644 index 0000000..e3eaed2 --- /dev/null +++ b/waybar/style.css @@ -0,0 +1,179 @@ +@import "macchiato.css"; + +window#waybar { + opacity: 0.3; +} + + +window#waybar.full { + background: @bar-bg; +} + +window#waybar.float { + background-color: transparent; +} + +* { + font-family: "Ubuntu Mono Nerd Font", Roboto, Helvetica, Arial, sans-serif; + font-size: 14px; + min-height: 0px; +} + +window#waybar { + background-color: rgba(0, 0, 0, 0); + border-radius: 13px; + transition-property: background-color; + transition-duration: .5s; +} + +button { + /* Use box-shadow instead of border so the text isn't offset */ + box-shadow: inset 0 -3px transparent; + /* Avoid rounded borders under each button name */ + border: none; + border-radius: 0; +} + +/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ +button:hover { + background: inherit; +} + +#workspaces button { + padding: 0px 2px; + background-color: white; + color: #000000; + border-radius: 50px; + border-color: transparent; + border: 1px solid; + border-color: transparent; +} + +#workspaces button.empty { + color: white; + background-color: transparent; +} + +#workspaces button.active { + color: black; + font-weight: bold; + background-color: @green; +} + +#workspaces button.active.empty { + font-weight: bold; + background-color: transparent; + border-color: @green; + color: @green; +} + +#workspaces button.active:hover { + background-color: @green; +} + +#workspaces button.focused { + background-color: @lavender; + box-shadow: inset 0 -3px #ffffff; +} + +#workspaces button.urgent { + background-color: #eb4d4b; +} + +#mode { + background-color: #64727D; + box-shadow: inset 0 -3px #ffffff; +} + +#clock, +#battery, +#cpu, +#memory, +#temperature, +#network, +#pulseaudio, +#idle_inhibitor, +#custom-cpu, +#custom-mem, +#custom-battery { + padding: 0 10px; +} + +#custom-cpu { + color: @red; +} + +#custom-mem { + color: @blue; +} + +#custom-battery.charging { + color: @green; +} + +#custom-battery.low { + color: @yellow; +} + +#custom-battery.critical { + color: @red; +} + +#custom-battery.hidden { + padding: 0; +} + +#network { + color: @yellow; +} + +#temperature { + color: @sky; +} + +#battery { + color: @green; +} + +#clock { + color: @white; +} + +#window { + color: @rosewater; +} + +#idle_inhibitor { + color: @teal; +} + +.modules-right { + background-color: @base; + border-radius: 15px; +} + +#battery.charging, +#battery.plugged { + color: @sapphire; +} + +@keyframes blink { + to { + color: #000000; + } +} + +/* Using steps() instead of linear as a timing function to limit cpu usage */ +#battery.critical:not(.charging) { + background-color: #f53c3c; + color: #ffffff; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: steps(12); + animation-iteration-count: infinite; + animation-direction: alternate; +} + +label:focus { + background-color: #000000; +}