From 6aaea9cf4b283d41016e60735f52c8feb3cd0c9e Mon Sep 17 00:00:00 2001 From: Justine Smithies Date: Tue, 22 Aug 2023 19:46:15 +0100 Subject: Initial commit --- .config/qtile/autostart.sh | 41 +++++ .config/qtile/colors.py | 51 ++++++ .config/qtile/config.py | 43 +++++ .config/qtile/groups.py | 58 +++++++ .config/qtile/hooks.py | 82 +++++++++ .config/qtile/keys.py | 277 ++++++++++++++++++++++++++++++ .config/qtile/layouts.py | 56 ++++++ .config/qtile/mouse.py | 28 +++ .config/qtile/ordinaldate.py | 20 +++ .config/qtile/screens.py | 24 +++ .config/qtile/statusbar/battery.py | 89 ++++++++++ .config/qtile/statusbar/brightnesscontrol | 44 +++++ .config/qtile/statusbar/calendar.sh | 26 +++ .config/qtile/statusbar/idleinhibit | 32 ++++ .config/qtile/statusbar/network.sh | 45 +++++ .config/qtile/statusbar/void-updates.sh | 13 ++ .config/qtile/statusbar/volumecontrol | 107 ++++++++++++ .config/qtile/widgets.py | 106 ++++++++++++ .config/qtile/workspaces.py | 93 ++++++++++ 19 files changed, 1235 insertions(+) create mode 100755 .config/qtile/autostart.sh create mode 100644 .config/qtile/colors.py create mode 100644 .config/qtile/config.py create mode 100644 .config/qtile/groups.py create mode 100644 .config/qtile/hooks.py create mode 100644 .config/qtile/keys.py create mode 100644 .config/qtile/layouts.py create mode 100644 .config/qtile/mouse.py create mode 100644 .config/qtile/ordinaldate.py create mode 100644 .config/qtile/screens.py create mode 100755 .config/qtile/statusbar/battery.py create mode 100755 .config/qtile/statusbar/brightnesscontrol create mode 100755 .config/qtile/statusbar/calendar.sh create mode 100755 .config/qtile/statusbar/idleinhibit create mode 100755 .config/qtile/statusbar/network.sh create mode 100755 .config/qtile/statusbar/void-updates.sh create mode 100755 .config/qtile/statusbar/volumecontrol create mode 100644 .config/qtile/widgets.py create mode 100644 .config/qtile/workspaces.py diff --git a/.config/qtile/autostart.sh b/.config/qtile/autostart.sh new file mode 100755 index 0000000..ebd7534 --- /dev/null +++ b/.config/qtile/autostart.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +# Autostart script for Qtile + +export wallpaper='~/.cache/wallpaper' + +dbus-update-activation-environment --systemd \ + WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=$XDG_CURRENT_DESKTOP + +# Authentication dialog + +pkill -f /usr/libexec/polkit-gnome-authentication-agent-1 +/usr/libexec/polkit-gnome-authentication-agent-1 & + +# Kill any existing pipewire / wireplumber daemons and only then try to start a new set. + +pkill -u "${USER}" -x pipewire\|wireplumber 1>/dev/null 2>&1 +dbus-run-session pipewire &> /dev/null & + +# Kanshi + +pkill -f kanshi +kanshi & + +# Notification daemon + +pkill -f dunst +dunst & + +# wlsunset + +pkill -f wlsunset +wlsunset -l 57.4 -L -1.9 & + +# Swayidle daemon + +pkill -f swayidle +swayidle \ + timeout 5 'qtile cmd-obj -o core -f hide_cursor' resume 'qtile cmd-obj -o core -f unhide_cursor' \ + timeout 300 'swaylock -f -i $wallpaper' \ + timeout 600 'wlopm --off \*' resume 'wlopm --on \*' & diff --git a/.config/qtile/colors.py b/.config/qtile/colors.py new file mode 100644 index 0000000..749b12f --- /dev/null +++ b/.config/qtile/colors.py @@ -0,0 +1,51 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# gruvbox color configuration +# https://github.com/morhetz/gruvbox/blob/master/colors/gruvbox.vim +colors = { + 'dark0_hard': '#1d2021', + 'dark0': '#282828', + 'dark0_soft': '#32302f', + 'dark1': '#3c3836', + 'dark2': '#504945', + 'dark3': '#665c54', + 'dark4': '#7c6f64', + 'dark4_256': '#7c6f64', + + 'gray_245': '#928374', + 'gray_244': '#928374', + + 'light0_hard': '#f9f5d7', + 'light0': '#fbf1c7', + 'light0_soft': '#f2e5bc', + 'light1': '#ebdbb2', + 'light2': '#d5c4a1', + 'light3': '#bdae93', + 'light4': '#a89984', + 'light4_256': '#a89984', + + 'bright_red': '#fb4934', + 'bright_green': '#b8bb26', + 'bright_yellow': '#fabd2f', + 'bright_blue': '#83a598', + 'bright_purple': '#d3869b', + 'bright_aqua': '#8ec07c', + 'bright_orange': '#fe8019', + + 'neutral_red': '#cc241d', + 'neutral_green': '#98971a', + 'neutral_yellow': '#d79921', + 'neutral_blue': '#458588', + 'neutral_purple': '#b16286', + 'neutral_aqua': '#689d6a', + 'neutral_orange': '#d65d0e', + + 'faded_red': '#9d0006', + 'faded_green': '#79740e', + 'faded_yellow': '#b57614', + 'faded_blue': '#076678', + 'faded_purple': '#8f3f71', + 'faded_aqua': '#427b58', + 'faded_orange': '#af3a03', +} diff --git a/.config/qtile/config.py b/.config/qtile/config.py new file mode 100644 index 0000000..122d63a --- /dev/null +++ b/.config/qtile/config.py @@ -0,0 +1,43 @@ +# Qtile Config File +# http://www.qtile.org/ + +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +from typing import List # noqa: F401 +import hooks +from keys import mod, keys, home +from workspaces import workspaces +from groups import groups +from layouts import layouts, floating_layout +from widgets import widget_defaults, extension_defaults +from screens import screens +from mouse import mouse +from libqtile.backend.wayland import InputConfig + +# Configure input devices + +wl_input_rules = { + "type:keyboard": InputConfig( + kb_layout='us', + ), +} + +dgroups_key_binder = None +dgroups_app_rules = [] # type: List +follow_mouse_focus = True +bring_front_click = False +cursor_warp = True +auto_fullscreen = True +focus_on_window_activation = "smart" +reconfigure_screens = True + +# XXX: Gasp! We're lying here. In fact, nobody really uses or cares about this +# string besides java UI toolkits; you can see several discussions on the +# mailing lists, GitHub issues, and other WM documentation that suggest setting +# this string if your java app doesn't work correctly. We may as well just lie +# and say that we're a working one by default. +# +# We choose LG3D to maximize irony: it is a 3D non-reparenting WM written in +# java that happens to be on java's whitelist. +wmname = "Qtile" diff --git a/.config/qtile/groups.py b/.config/qtile/groups.py new file mode 100644 index 0000000..3f13d52 --- /dev/null +++ b/.config/qtile/groups.py @@ -0,0 +1,58 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# Groups configuration + +from libqtile.config import Key, Group +from libqtile.command import lazy +from keys import mod, keys +from workspaces import workspaces +from screens import connected_monitors +from libqtile.config import ScratchPad, DropDown +from os import environ + +# Get terminal from environment variables +terminal = environ.get("TERMINAL") + +groups = [] +for workspace in workspaces: + matches = workspace["matches"] if "matches" in workspace else None + layouts = workspace["layout"] if "layout" in workspace else None + groups.append(Group(workspace["name"], matches=matches, layout=layouts)) + keys.append(Key([mod], workspace["key"], lazy.group[workspace["name"]].toscreen())) + keys.append(Key([mod, "shift"], workspace["key"], lazy.window.togroup(workspace["name"]))) + +for i in range(connected_monitors): + keys.extend([Key([mod, "mod1"], str(i), lazy.window.toscreen(i))]) + +# Append a scratchpad group + +conf = { + "warp_pointer": False, + "on_focus_lost_hide": False, + "opacity": 0.80, +} + +groups.append( + ScratchPad( + "scratchpad", [ + # Define a drop down terminal + # it is placed in the upper third of the screen by default + DropDown( + "term", + terminal + " -a 'Terminal'", + height=0.50, + width=0.50, + x=0.25, + y=0.2, + **conf + ), + + ] + ) +) + +# Define keys to toggle the dropdown terminals +keys.extend([ + Key([mod, "shift"], "Return", lazy.group["scratchpad"].dropdown_toggle("term")), +]) diff --git a/.config/qtile/hooks.py b/.config/qtile/hooks.py new file mode 100644 index 0000000..295c265 --- /dev/null +++ b/.config/qtile/hooks.py @@ -0,0 +1,82 @@ +# Qtile Config File +# http://www.qtile.org/ + +# Justine Smithies +# Hooks configuration + +import asyncio +import os +import subprocess +import time +from libqtile import qtile +from libqtile import hook + +from groups import groups +from libqtile.log_utils import logger + + +@hook.subscribe.startup_once +def autostart(): + home = os.path.expanduser('~') + subprocess.Popen([home + '/.config/qtile/autostart.sh']) + +# Reload config on screen changes + + +@hook.subscribe.screens_reconfigured +async def outputs_changed(): + logger.warning("Screens reconfigured") + await asyncio.sleep(1) + logger.warning("Reloading config...") + qtile.reload_config() + +# When application launched automatically focus it's group + + +@hook.subscribe.client_new +def modify_window(client): + for group in groups: # follow on auto-move + match = next((m for m in group.matches if m.compare(client)), None) + if match: + targetgroup = client.qtile.groups_map[group.name] # there can be multiple instances of a group + targetgroup.toscreen(toggle=False) + break + +# Hook to fallback to the first group with windows when last window of group is killed + + +# @hook.subscribe.client_killed +# def fallback(window): + # if window.group.windows != [window]: +# if isinstance(window, base.Static) or window.group.windows != [window]: +# return +# idx = qtile.groups.index(window.group) +# for group in qtile.groups[idx - 1::-1]: +# if group.windows: +# qtile.current_screen.toggle_group(group) +# return +# qtile.current_screen.toggle_group(qtile.groups[0]) + +# Work around for matching Spotify + + +@hook.subscribe.client_new +def slight_delay(window): + time.sleep(0.04) + +# If Spotify opens move it to group 6 + + +@hook.subscribe.client_name_updated +def spotify(window): + if window.name == 'Spotify': + window.togroup(group_name='阮 ₆') + +# If mpv opens float it at pos x, y, w, h, borderwidth, border color + + +@hook.subscribe.client_managed +def repos(window): + if window.get_wm_class() and 'mpv' in window.get_wm_class(): + window.floating = True + window.place(1200, 650, 640, 360, 2, "#ffffff") diff --git a/.config/qtile/keys.py b/.config/qtile/keys.py new file mode 100644 index 0000000..75e5bde --- /dev/null +++ b/.config/qtile/keys.py @@ -0,0 +1,277 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# Key configuration + +import os +from libqtile.config import Key +from libqtile.command import lazy + +home = os.path.expanduser('~') +terminal = os.environ.get("TERMINAL") +mod = "mod4" + +keys = [ + # Move focus to next screen + Key([mod, "control"], "period", + lazy.next_screen(), + desc="Move focus to next screen", + ), + Key([mod], "g", + lazy.screen.next_group(skip_empty=True), + desc="Move to next active group" + ), + Key([mod, "shift"], "g", + lazy.screen.prev_group(skip_empty=True), + desc="Move to previous active group" + ), + # Switch between windows in current stack pane + Key([mod], "h", + lazy.layout.left(), + desc="Move focus left in stack pane" + ), + Key([mod], "l", + lazy.layout.right(), + desc="Move focus right in stack pane" + ), + Key([mod], "k", + lazy.layout.down(), + desc="Move focus down in stack pane" + ), + Key([mod], "j", + lazy.layout.up(), + desc="Move focus up in stack pane" + ), + # Move window on the current screen + Key([mod, "shift"], "h", + lazy.layout.shuffle_left(), + desc='Shuffle left' + ), + Key([mod, "shift"], "l", + lazy.layout.shuffle_right(), + desc='Shuffle right' + ), + Key([mod, "shift"], "k", + lazy.layout.shuffle_down(), + desc='Shuffle down' + ), + Key([mod, "shift"], "j", + lazy.layout.shuffle_up(), + desc='Shuffle up' + ), + # For the BSP layout + Key([mod, "mod1"], "j", + lazy.layout.flip_down(), + desc='Flip down' + ), + Key([mod, "mod1"], "k", + lazy.layout.flip_up(), + desc='Flip up' + ), + Key([mod, "mod1"], "h", + lazy.layout.flip_left(), + desc='Flip left' + ), + Key([mod, "mod1"], "l", + lazy.layout.flip_right(), + desc='Flip right' + ), + Key([mod, "control"], "j", + lazy.layout.grow_down(), + desc='Grow down' + ), + Key([mod, "control"], "k", + lazy.layout.grow_up(), + desc='Grow up' + ), + Key([mod, "control"], "h", + lazy.layout.grow_left(), + desc='Grow left' + ), + Key([mod, "control"], "l", + lazy.layout.grow_right(), + desc='Grow right' + ), + Key([mod], "n", + lazy.layout.normalize(), + desc='normalize window size ratios' + ), + Key([mod], "m", + lazy.layout.maximize(), + desc='toggle window between minimum and maximum sizes' + ), + Key([mod], "o", + lazy.layout.grow(), + lazy.layout.increase_nmaster(), + desc='Expand window (MonadTall), increase number in master pane (Tile)' + ), + Key([mod], "i", + lazy.layout.shrink(), + lazy.layout.decrease_nmaster(), + desc='Shrink window (MonadTall), decrease number in master pane (Tile)' + ), + + # Toggle floating + Key([mod, "shift"], "f", lazy.window.toggle_floating(), + desc="Toggle floating" + ), + + # Toggle Fullscreen + Key([mod], "f", + lazy.window.toggle_fullscreen(), + lazy.hide_show_bar(position='all'), + desc='Toggle fullscreen and the bars' + ), + + # Switch window focus to other pane(s) of stack + Key([mod], "space", lazy.layout.next(), + desc="Switch window focus to other pane(s) of stack" + ), + + # Swap panes of split stack + Key([mod, "shift"], "space", + lazy.layout.rotate(), + desc="Swap panes of split stack" + ), + + # Toggle between split and unsplit sides of stack. + # Split = all windows displayed + # Unsplit = 1 window displayed, like Max layout, but still with + # multiple stack panes + Key([mod, "shift"], "s", + lazy.layout.toggle_split(), + desc="Toggle between split and unsplit sides of stack" + ), + Key([mod], "Return", + lazy.spawn(terminal), + desc="Launch terminal" + ), + + # Toggle between different layouts as defined below + Key([mod], "Tab", + lazy.next_layout(), + desc="Toggle between layouts" + ), + Key([mod], "w", + lazy.window.kill(), + desc="Kill focused window" + ), + + # Toggle bars + Key([mod], "b", + lazy.hide_show_bar(position='all'), + desc="Toggle bars" + ), + + # Qtile system keys + Key([mod, "shift", "control"], "l", + lazy.spawn("swaylock -f -i .cache/wallpaper"), + desc="Lock screen" + ), + Key([mod, "control"], "r", + lazy.reload_config(), + desc="Restart qtile" + ), + Key([mod, "control"], "q", + lazy.shutdown(), + desc="Shutdown qtile" + ), + Key([mod], "r", + lazy.spawncmd(), + desc="Spawn a command using a prompt widget" + ), + Key([mod, "control"], "p", + lazy.spawn("" + home + "/.local/bin/powermenu"), + desc="Launch Power menu" + ), + + # Rofi + Key(["control"], "space", + lazy.spawn("fuzzel"), + desc="Launch Fuzzel menu" + ), + # Window Switcher + Key([mod, "control"], "w", + lazy.spawn(home + "/.local/bin/qtile-window-switcher.py"), + desc="Launch the Window Switcher", + ), + # Install updates + Key([mod, "control"], "u", + lazy.spawn(home + "/.local/bin/statusbar/arch-updates.sh key-update"), + desc="Install updates", + ), + + # Cycle through windows in the floating layout + Key([mod, "shift"], "i", + lazy.window.toggle_minimize(), + lazy.group.next_window(), + lazy.window.bring_to_front() + ), + + # ------------ Hardware Configs ------------ + # Volume + Key([], "XF86AudioMute", + lazy.spawn(home + "/.config/qtile/statusbar/volumecontrol mute"), + desc='Mute audio' + ), + Key([], "XF86AudioLowerVolume", + lazy.spawn(home + "/.config/qtile/statusbar/volumecontrol down"), + desc='Volume down' + ), + Key([], "XF86AudioRaiseVolume", + lazy.spawn(home + "/.config/qtile/statusbar/volumecontrol up"), + desc='Volume up' + ), + + # Media keys + Key([], "XF86AudioPlay", + lazy.spawn("dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify " "/org/mpris/MediaPlayer2 " "org.mpris.MediaPlayer2.Player.PlayPause"), + desc='Audio play' + ), + Key([], "XF86AudioNext", + lazy.spawn("dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify " "/org/mpris/MediaPlayer2 " "org.mpris.MediaPlayer2.Player.Next"), + desc='Audio next' + ), + Key([], "XF86AudioPrev", + lazy.spawn("dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify " "/org/mpris/MediaPlayer2 " "org.mpris.MediaPlayer2.Player.Previous"), + desc='Audio previous' + ), + + # Brightness + Key([], "XF86MonBrightnessDown", + lazy.spawn(home + "/.config/qtile/statusbar/brightnesscontrol down"), + desc='Brightness down' + ), + Key([], "XF86MonBrightnessUp", + lazy.spawn(home + "/.config/qtile/statusbar/brightnesscontrol up"), + desc='Brightness up' + ), + + # Screenshots + # Take a screenshot of the currently focused output and save it into screenshots + Key([], "Print", + lazy.spawn(home + "/.local/bin/screenshot.sh"), + desc='Save the screens of the currently focused output to the screenshots folder' + ), + # Take a screenshot of the selected region + Key([mod], "Print", + lazy.spawn(home + "/.local/bin/screenshot.sh selected-region"), + desc='Save the selected region of the screen to the screenshots folder' + ), + # Capture region of screen to clipboard + Key([mod, "shift"], "Print", + lazy.spawn(home + "/.local/bin/screenshot.sh save-to-clipboard"), + desc='Capture a region of the screen to the clipboard' + ), + # Take a screenshot of the selected window + Key([mod, "control"], "Print", + lazy.spawn(home + "/.local/bin/screenshot.sh selected-window"), + desc='Save the selected window to the screenshots folder' + ), +] + +for i in range(1, 5): + keys.append(Key(["control", "mod1"], "F" + str(i), + lazy.core.change_vt(i), + desc='Change to virtual console ' + str(i) + ),) diff --git a/.config/qtile/layouts.py b/.config/qtile/layouts.py new file mode 100644 index 0000000..94c8b6b --- /dev/null +++ b/.config/qtile/layouts.py @@ -0,0 +1,56 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# Layout configuration + +from libqtile import layout +from libqtile.config import Match +from colors import colors + +# DEFAULT THEME SETTINGS FOR LAYOUTS # +layout_theme = {"border_width": 2, + "margin": 10, + "border_focus": '#33eeffee', + "border_normal": colors['dark0'] + } + +layouts = [ + layout.MonadTall(**layout_theme, single_border_width=2), + layout.Stack(num_stacks=2, **layout_theme), + # layout.Max(), + # Try more layouts by unleashing below layouts. + layout.Bsp(**layout_theme), + layout.Columns(**layout_theme), + +] + +floating_layout = layout.Floating( + **layout_theme, + float_rules=[ + # Run the utility of `xprop` to see the wm class and name of an X client. + # *layout.Floating.default_float_rules, + Match(title='Quit and close tabs?'), + Match(wm_type='utility'), + Match(wm_type='notification'), + Match(wm_type='toolbar'), + Match(wm_type='splash'), + Match(wm_type='dialog'), + Match(wm_class='gimp-2.99'), + Match(wm_class='Firefox'), + Match(wm_class='file_progress'), + Match(wm_class='confirm'), + Match(wm_class='dialog'), + Match(wm_class='download'), + Match(wm_class='error'), + Match(wm_class='notification'), + Match(wm_class='splash'), + Match(wm_class='toolbar'), + Match(title='About LibreOffice'), + Match(wm_class='confirmreset'), # gitk + Match(wm_class='makebranch'), # gitk + Match(wm_class='maketag'), # gitk + Match(wm_class='ssh-askpass'), # ssh-askpass + Match(title='branchdialog'), # gitk + Match(title='pinentry'), # GPG key password entry + ], +) diff --git a/.config/qtile/mouse.py b/.config/qtile/mouse.py new file mode 100644 index 0000000..6cd0e88 --- /dev/null +++ b/.config/qtile/mouse.py @@ -0,0 +1,28 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# Mouse floating layouts. + +from libqtile.config import Drag, Click +from libqtile.command import lazy +from keys import mod + +mouse = [ + Drag( + [mod], + "Button1", + lazy.window.set_position_floating(), + start=lazy.window.get_position() + ), + Drag( + [mod], + "Button3", + lazy.window.set_size_floating(), + start=lazy.window.get_size() + ), + Click( + [mod], + "Button2", + lazy.window.bring_to_front() + ) +] diff --git a/.config/qtile/ordinaldate.py b/.config/qtile/ordinaldate.py new file mode 100644 index 0000000..3376d62 --- /dev/null +++ b/.config/qtile/ordinaldate.py @@ -0,0 +1,20 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# Ordinal Date - Displays date in format Friday 11th March 2022 - 14:53 + +# Add th, nd or st to the date - use custom_date in text box to display + +from datetime import datetime as dt + + +def suffix(d): + return 'th' if 11 <= d <= 13 else {1: 'st', 2: 'nd', 3: 'rd'}.get(d % 10, 'th') + + +def custom_strftime(format, t): + return t.strftime(format).replace('{S}', str(t.day) + suffix(t.day)) + + +def custom_date(): + return custom_strftime('%A {S} %B %Y - %H:%M', dt.now()) diff --git a/.config/qtile/screens.py b/.config/qtile/screens.py new file mode 100644 index 0000000..7921302 --- /dev/null +++ b/.config/qtile/screens.py @@ -0,0 +1,24 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# Multimonitor support + +from libqtile import qtile +from libqtile.config import Screen +from libqtile import bar +from libqtile.log_utils import logger +from widgets import primary_widgets, secondary_widgets + + +def status_bar(widgets): + return bar.Bar(widgets, 20, background="#000000AA", margin=[10, 10, 0, 10]) # Margin = N E S W + + +screens = [Screen(wallpaper='.cache/wallpaper', wallpaper_mode='fill', top=status_bar(primary_widgets))] + +connected_monitors = len(qtile.core.outputs) +logger.warning(f"Found {connected_monitors} monitor(s)") + +if connected_monitors > 1: + for _ in range(1, connected_monitors): + screens.append(Screen(wallpaper='.cache/wallpaper', wallpaper_mode='fill', top=status_bar(secondary_widgets))) diff --git a/.config/qtile/statusbar/battery.py b/.config/qtile/statusbar/battery.py new file mode 100755 index 0000000..a4fa33a --- /dev/null +++ b/.config/qtile/statusbar/battery.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +import psutil +import argparse +import subprocess + + +def secs2hours(secs): + mm, ss = divmod(secs, 60) + hh, mm = divmod(mm, 60) + return "%d:%02d:%02d" % (hh, mm, ss) + + +parser = argparse.ArgumentParser() +parser.add_argument('--c', + choices=('status', 'left-click', 'middle-click', 'right-click'), + dest='command', + default='status', + help='Allowed values are status, left-click, middle-click and right-click' + ) +args = parser.parse_args() + +battery = psutil.sensors_battery() +icon = "" +percent = int(battery.percent) +time_left = battery.secsleft +isPlugged = battery.power_plugged +remaining = secs2hours(time_left) + +if args.command == "status": + if isPlugged: + if percent == 100: + icon = "󰂅" + elif percent > 89 and percent < 100: + icon = "󰂋" + elif percent > 79 and percent < 90: + icon = "󰂊" + elif percent > 69 and percent < 80: + icon = "󰢞" + elif percent > 59 and percent < 70: + icon = "󰂉" + elif percent > 49 and percent < 60: + icon = "󰢝" + elif percent > 39 and percent < 50: + icon = "󰂈" + elif percent > 29 and percent < 40: + icon = "󰂇" + elif percent > 19 and percent < 30: + icon = "󰂆" + elif percent > 9 and percent < 20: + icon = "󰢜" + elif percent > 0 and percent < 10: + icon = "󰢟" + message = str(percent) + "%" + print(icon, message, end="") + else: + if percent == 100: + icon = "󰁹" + elif percent > 89 and percent < 100: + icon = "󰂂" + elif percent > 79 and percent < 90: + icon = "󰂁" + elif percent > 69 and percent < 80: + icon = "󰂀" + elif percent > 59 and percent < 70: + icon = "󰁿" + elif percent > 49 and percent < 60: + icon = "󰁾" + elif percent > 39 and percent < 50: + icon = "󰁽" + elif percent > 29 and percent < 40: + icon = "󰁼" + elif percent > 19 and percent < 30: + icon = "󰁻" + elif percent > 9 and percent < 20: + icon = "󰁺" + elif percent > 0 and percent < 10: + icon = "󰂎" + message = str(percent) + "%" + print(icon, message, end="") +if args.command == "left-click": + if not isPlugged: + subprocess.call(["notify-send", "-r", "55555", "-u", "normal", "Est remaining time left: " + remaining]) + else: + subprocess.call(["notify-send", "-r", "55555", "-u", "normal", str(percent) + "% Charged"]) +if args.command == "middle-click": + print("Middle click") +if args.command == "right-click": + print("Right click") diff --git a/.config/qtile/statusbar/brightnesscontrol b/.config/qtile/statusbar/brightnesscontrol new file mode 100755 index 0000000..304c187 --- /dev/null +++ b/.config/qtile/statusbar/brightnesscontrol @@ -0,0 +1,44 @@ +#!/bin/bash + +# You can call this script like this: +# brightnessControl up +# brightnessControl down + +# Script inspired by these wonderful people: +# https://github.com/dastorm/volume-notification-dunst/blob/master/volume.sh +# https://gist.github.com/sebastiencs/5d7227f388d93374cebdf72e783fbd6a + +function send_notification { + icon=/usr/share/icons/Papirus-Dark/16x16/actions/brightnesssettings.svg + brightness=$(light -G) + brightness=$(echo "$brightness" | awk '{print ($0-int($0)<0.499)?int($0):int($0)+1}') + # Make the bar with the special character ─ (it's not dash -) + # https://en.wikipedia.org/wiki/Box-drawing_character + bar=$(seq -s "─" 0 $((brightness / 10 )) | sed 's/[0-9]//g') + #brightness=$((brightness *100 / 255 )) + #echo $bar + #echo $test + # Send the notification + notify-send -i "$icon" -r 5555 -u normal "$bar $brightness" +} + +case $1 in + up) + # increase the backlight by 5% + light -A 5 + send_notification + canberra-gtk-play -i audio-volume-change + ;; + down) + # decrease the backlight by 5% + light -U 5 + send_notification + canberra-gtk-play -i audio-volume-change + ;; + *) + brightness=$(light -G) + brightness=$(echo "$brightness" | awk '{print ($0-int($0)<0.499)?int($0):int($0)+1}') + icon="󰃞" + printf "%s" "$icon $brightness" "%" + ;; +esac diff --git a/.config/qtile/statusbar/calendar.sh b/.config/qtile/statusbar/calendar.sh new file mode 100755 index 0000000..71de700 --- /dev/null +++ b/.config/qtile/statusbar/calendar.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Calendar script + +function ShowCalendar() { + notify-send -i "calendar" " 📅 Calendar" "$(cal --color=always | sed "s/..7m//;s/..27m/<\/span><\/b>/")" -r 124 +} + +function EditCalendar() { + echo +} + +case "$1" in + show) + ShowCalendar + ;; + + edit) + EditCalendar + ;; + + *) + echo $"Usage: ${0##*/} {show|edit}" + exit 1 + +esac diff --git a/.config/qtile/statusbar/idleinhibit b/.config/qtile/statusbar/idleinhibit new file mode 100755 index 0000000..7ff61a6 --- /dev/null +++ b/.config/qtile/statusbar/idleinhibit @@ -0,0 +1,32 @@ +#!/bin/bash + +# Qtile swayidle toggle +function toggle { +if pgrep "swayidle" > /dev/null +then + pkill swayidle + notify-send -r 5556 -u normal " Swayidle Inactive" +else + swayidle \ + timeout 5 'qtile cmd-obj -o core -f hide_cursor' resume 'qtile cmd-obj -o core -f unhide_cursor' \ + timeout 300 'swaylock -f -i $wallpaper' \ + timeout 600 'wlopm --off \*' resume 'wlopm --on \*' & + notify-send -r 5556 -u normal " Swayidle Active" +fi +} + +case $1 in + toggle) + toggle + ;; + *) + if pgrep "swayidle" > /dev/null + then + icon="" + else + icon="" + fi + printf "%s" "$icon " + ;; +esac + diff --git a/.config/qtile/statusbar/network.sh b/.config/qtile/statusbar/network.sh new file mode 100755 index 0000000..eb98999 --- /dev/null +++ b/.config/qtile/statusbar/network.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# This script requires dnsutils aka bind to fetch the WAN IP address + +# Shows the connections names +# nmcli connection show --active | grep 'ethernet' | awk '{ print $1 }' FS=' ' +# nmcli connection show --active | grep 'wifi' | awk '{ print $1 }' FS=' ' + +# Show ethernet interface name +# nmcli connection show --active | grep 'ethernet' | awk '{ print $6 }' FS=' ' + +# Show wifi interface name +# nmcli connection show --active | grep 'wifi' | awk '{ print $4 }' FS=' ' + +function ShowInfo { + if [ "$(nmcli connection show --active | grep -oh "\w*ethernet\w*")" == "ethernet" ]; then + wan="$(dig +short myip.opendns.com @resolver1.opendns.com)" + connection="$(nmcli connection show --active | grep 'ethernet' | awk '{ print $6 }' FS=' '): $(nmcli connection show --active | grep 'ethernet' | awk '{ print $1 }' FS=' ') - $(nmcli -t -f IP4.ADDRESS dev show $(nmcli connection show --active | grep 'ethernet' | awk '{ print $6 }' FS=' ') | awk '{print $2}' FS='[:/]') +WAN IP: $wan" + elif [ "$(nmcli connection show --active | grep -oh "\w*wifi\w*")" == "wifi" ]; then + wan="$(dig +short myip.opendns.com @resolver1.opendns.com)" + connection="$(nmcli connection show --active | grep 'wifi' | awk '{ print $4 }' FS=' '): $(nmcli connection show --active | grep 'wifi' | awk '{ print $1 }' FS=' ') - $(nmcli -t -f IP4.ADDRESS dev show $(nmcli connection show --active | grep 'wifi' | awk '{ print $4 }' FS=' ') | awk '{print $2}' FS='[:/]') +WAN IP: $wan" + else + connection="No active connection." + fi + notify-send -i "network-idle" "$connection" -r 123 +} + +function IconUpdate() { + if [ "$(nmcli connection show --active | grep -oh "\w*ethernet\w*")" == "ethernet" ]; then + icon="󰈀 " + elif [ "$(nmcli connection show --active | grep -oh "\w*wifi\w*")" == "wifi" ]; then + icon=" " + else + icon="󰲜 " + fi + printf "%s" "$icon" +} + +if [ "$1" = "ShowInfo" ]; then + ShowInfo +else + IconUpdate +fi diff --git a/.config/qtile/statusbar/void-updates.sh b/.config/qtile/statusbar/void-updates.sh new file mode 100755 index 0000000..94298ae --- /dev/null +++ b/.config/qtile/statusbar/void-updates.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +case $1 in + key-update) + foot bash -c "sudo xbps-install -Suv" + qtile cmd-obj -o widget checkupdates -f force_update + ;; + *) + # Supress error codes to stop issues with CheckUpdates widget + xbps-install -Mun 2> /dev/null + exit 0 + ;; +esac diff --git a/.config/qtile/statusbar/volumecontrol b/.config/qtile/statusbar/volumecontrol new file mode 100755 index 0000000..62c4cc2 --- /dev/null +++ b/.config/qtile/statusbar/volumecontrol @@ -0,0 +1,107 @@ +#!/bin/bash + +# You can call this script like this: +# volumecontrol up +# volumecontrol down +# volumecontrol mute + +function get_volume { + amixer get Master | grep '%' | head -n 1 | cut -d '[' -f 2 | cut -d '%' -f 1 +} + +function is_mute { + amixer get Master | grep '%' | grep -oE '[^ ]+$' | grep off > /dev/null +} + +function send_notification { + volume=$(get_volume) + # Make the bar with the special character ─ (it's not dash -) + # https://en.wikipedia.org/wiki/Box-drawing_character +if [ "$volume" = "0" ]; then + icon_name="/usr/share/icons/Adwaita/16x16/legacy/audio-volume-muted.png" +notify-send -i "$icon_name" -r 5556 -u normal "$volume" + else + if [ "$volume" -lt "10" ]; then + icon_name="/usr/share/icons/Adwaita/16x16/legacy/audio-volume-low.png" +notify-send -i "$icon_name" -r 5556 -u normal "$volume" + else + if [ "$volume" -lt "30" ]; then + icon_name="/usr/share/icons/Adwaita/16x16/legacy/audio-volume-low.png" + else + if [ "$volume" -lt "70" ]; then + icon_name="/usr/share/icons/Adwaita/16x16/legacy/audio-volume-medium.png" + else + icon_name="/usr/share/icons/Adwaita/16x16/legacy/audio-volume-high.png" + fi + fi + fi +fi +bar=$(seq -s "─" $(($volume/5)) | sed 's/[0-9]//g') +# Send the notification +notify-send -i "$icon_name" -r 5556 -u normal "$bar $volume" +} + +case $1 in + up) + # Set the volume on (if it was muted) + amixer set Master on > /dev/null + # Up the volume (+ 2%) + amixer sset Master 2%+ > /dev/null + send_notification + canberra-gtk-play -i audio-volume-change + ;; + down) + amixer set Master on > /dev/null + amixer sset Master 2%- > /dev/null + send_notification + canberra-gtk-play -i audio-volume-change + ;; + mute) + # Toggle mute + amixer set Master 1+ toggle > /dev/null + if is_mute ; then + notify-send -i "/usr/share/icons/Adwaita/16x16/legacy/audio-volume-muted.png" -r 5556 -u normal "$bar Audio Muted" + else + send_notification + canberra-gtk-play -i audio-volume-change + fi + ;; + *) + volume="$(get_volume)" + + if [[ $volume == "100" ]]; then + icon="󰕾" + elif [[ $volume -ge "89" && $volume -le "100" ]]; then + icon="󰕾" + elif [[ $volume -ge "79" && $volume -le "90" ]]; then + icon="󰕾" + elif [[ $volume -ge "69" && $volume -le "80" ]]; then + icon="󰖀" + elif [[ $volume -ge "59" && $volume -le "70" ]]; then + icon="󰖀" + elif [[ $volume -ge "49" && $volume -le "60" ]]; then + icon="󰖀" + elif [[ $volume -ge "39" && $volume -le "50" ]]; then + icon="󰖀" + elif [[ $volume -ge "29" && $volume -le "40" ]]; then + icon="󰕿" + elif [[ $volume -ge "19" && $volume -le "30" ]]; then + icon="󰕿" + elif [[ $volume -ge "9" && $volume -le "20" ]]; then + icon="󰕿" + elif [[ $volume -gt "0" && $volume -le "10" ]]; then + icon="󰕿" + elif [[ $volume -eq "0" ]]; then + icon="󰝟" + volume=" M " + fi + + +if is_mute; then + icon="󰝟" + volume=" M " +fi + +printf "%s" "$icon $volume%" + ;; +esac diff --git a/.config/qtile/widgets.py b/.config/qtile/widgets.py new file mode 100644 index 0000000..1072c09 --- /dev/null +++ b/.config/qtile/widgets.py @@ -0,0 +1,106 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# Widgets setup +# Get the icons at https://www.nerdfonts.com/cheat-sheet + +import os +import subprocess +from libqtile import qtile +from libqtile import widget +from colors import colors +from ordinaldate import custom_date +from keys import terminal + + +widget_defaults = dict( + font='GoMono Nerd Font', + fontsize='12', + padding=2, + foreground=colors['light0'] +) +extension_defaults = widget_defaults.copy() + +primary_widgets = [ + widget.Spacer(length=10), + widget.GroupBox( + padding=0, + active=colors['light0'], + borderwidth=3, + inactive=colors['light4'], + this_current_screen_border=colors['neutral_green'], + this_screen_border=colors['neutral_green'], + other_screen_border='#00000000', + other_current_screen_border='#00000000', + font='GoMono Nerd Font', + fontsize=12, + highlight_method='line', + highlight_color=['00000000', '00000000'] + ), + widget.CurrentLayoutIcon(scale=0.5, **widget_defaults), + widget.CurrentLayout(**widget_defaults), + widget.Spacer(), + widget.GenPollText( + func=custom_date, + update_interval=1, + **widget_defaults, + mouse_callbacks={ + 'Button1': lambda: qtile.cmd_spawn(os.path.expanduser("~/.config/qtile/statusbar/calendar.sh show"), shell=True), + 'Button3': lambda: qtile.cmd_spawn(os.path.expanduser("~/.config/qtile/statusbar/calendar.sh edit"), shell=True) + } + ), + widget.Spacer(), + widget.CheckUpdates( + **widget_defaults, + update_interval=600, + distro='Arch_paru', + custom_command='~/.config/qtile/statusbar/void-updates.sh', + display_format=' {updates}', + colour_have_updates=colors['neutral_green'], + execute='foot bash -c "sudo xbps-install -Suv"' + ), + widget.Spacer(length=5), + widget.GenPollText(update_interval=1, **widget_defaults, func=lambda: subprocess.check_output(os.path.expanduser("~/.config/qtile/statusbar/idleinhibit")).decode(), mouse_callbacks={'Button1': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/idleinhibit toggle"), shell=True)}), + widget.Spacer(length=5), + widget.KeyboardLayout(configured_keyboards=['us', 'gb']), + widget.Spacer(length=5), + widget.GenPollText(update_interval=1, **widget_defaults, func=lambda: subprocess.check_output(os.path.expanduser("~/.config/qtile/statusbar/brightnesscontrol")).decode(), mouse_callbacks={'Button1': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/brightnesscontrol down"), shell=True), 'Button3': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/brightnesscontrol up"), shell=True)}), + widget.Spacer(length=5), + widget.GenPollText(update_interval=1, **widget_defaults, func=lambda: subprocess.check_output(os.path.expanduser("~/.config/qtile/statusbar/volumecontrol")).decode(), mouse_callbacks={'Button1': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/volumecontrol down"), shell=True), 'Button2': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/volumecontrol mute"), shell=True), 'Button3': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/volumecontrol up"), shell=True)}), + widget.Spacer(length=5), + widget.GenPollText(update_interval=1, **widget_defaults, func=lambda: subprocess.check_output(os.path.expanduser("~/.config/qtile/statusbar/battery.py")).decode(), mouse_callbacks={'Button1': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/battery.py --c left-click"), shell=True)}), + widget.Spacer(length=5), + widget.GenPollText(update_interval=1, **widget_defaults, func=lambda: subprocess.check_output(os.path.expanduser("~/.config/qtile/statusbar/network.sh")).decode(), mouse_callbacks={'Button1': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/network.sh ShowInfo"), shell=True), 'Button3': lambda: qtile.spawn(terminal + ' -e nmtui', shell=True)}), + widget.Spacer(length=10), +] + +secondary_widgets = [ + widget.Spacer(length=10), + widget.GroupBox( + padding=0, + active=colors['light0'], + borderwidth=3, + inactive=colors['light4'], + this_current_screen_border=colors['neutral_green'], + this_screen_border=colors['neutral_green'], + other_screen_border='#00000000', + other_current_screen_border='#00000000', + font='GoMono Nerd Font', + fontsize=12, + highlight_method='line', + highlight_color=['00000000', '00000000'] + ), + widget.CurrentLayoutIcon(scale=0.6, **widget_defaults), + widget.CurrentLayout(**widget_defaults), + widget.Spacer(length=440), + widget.GenPollText( + func=custom_date, + update_interval=1, + **widget_defaults, + mouse_callbacks={ + 'Button1': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/calendar.sh show"), shell=True), + 'Button3': lambda: qtile.spawn(os.path.expanduser("~/.config/qtile/statusbar/calendar.sh edit"), shell=True) + } + ), + widget.Spacer(), +] diff --git a/.config/qtile/workspaces.py b/.config/qtile/workspaces.py new file mode 100644 index 0000000..42e203f --- /dev/null +++ b/.config/qtile/workspaces.py @@ -0,0 +1,93 @@ +# Justine Smithies +# https://github.com/justinesmithies/qtile-wayland-dotfiles + +# Workspace setup +# Get the icons at https://www.nerdfonts.com/cheat-sheet + +from libqtile.config import Match + +workspaces = [ + { + "name": " ₁", + "key": "1", + "matches": [ + Match(wm_class='firefox'), + ], + "layout": "monadtall", + "spawn": [], + }, + { + "name": " ₂", + "key": "2", + "matches": [ + Match(wm_class='foot'), + Match(wm_class='ranger'), + ], + "layout": "monadtall", + "spawn": [], + }, + { + "name": " ₃", + "key": "3", + "matches": [ + Match(wm_class='nvim'), + ], + "layout": "monadtall", + "spawn": [], + }, + { + "name": " ₄", + "key": "4", + "matches": [ + Match(wm_class='telegram-desktop'), + Match(wm_class='weechat'), + ], + "layout": "monadtall", + "spawn": [], + }, + { + "name": " ₅", + "key": "5", + "matches": [ + Match(wm_class='gimp-2.99'), + ], + "layout": "monadtall", + "spawn": [], + }, + { + "name": "󰓇 ₆", + "key": "6", + "matches": [ + Match(wm_class='Spotify'), + ], + "layout": "monadtall", + "spawn": [], + }, + { + "name": " ₇", + "key": "7", + "matches": [ + Match(wm_class='soffice'), + ], + "layout": "monadtall", + "spawn": [], + }, + { + "name": "󰎕 ₈", + "key": "8", + "matches": [ + Match(wm_class='newsboat'), + ], + "layout": "monadtall", + "spawn": [], + }, + { + "name": "󰇮 ₉", + "key": "9", + "matches": [ + Match(wm_class='aerc'), + ], + "layout": "monadtall", + "spawn": [], + }, +] -- cgit v1.2.3