commit d876d4fae438fef2993eeceed0ff7a5003844472 Author: Thomas Forgione Date: Mon Sep 15 10:54:03 2025 +0200 Initial commit 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; +}