#+TITLE: Personal dwl Configuration with Waybar #+AUTHOR: Sravan Balaji #+AUTO_TANGLE: t #+STARTUP: showeverything * Table of Contents :TOC_3:noexport: - [[#welcome][Welcome]] - [[#dwl---dwm-for-wayland][dwl - dwm for Wayland]] - [[#patches][Patches]] - [[#always-center][Always Center]] - [[#attach-top][Attach Top]] - [[#auto-start][Auto Start]] - [[#fake-fullscreen-client][Fake Fullscreen Client]] - [[#float-unfocused-border-color][Float Unfocused Border Color]] - [[#foreign-toplevel-management][Foreign Toplevel Management]] - [[#gapless-grid][Gapless Grid]] - [[#ipc][IPC]] - [[#menu][Menu]] - [[#move-stack][Move Stack]] - [[#natural-scroll-trackpad][Natural Scroll Trackpad]] - [[#numlock-capslock][Numlock Capslock]] - [[#per-tag][Per Tag]] - [[#restore-monitor][Restore Monitor]] - [[#setup-env][Setup Env]] - [[#unclutter][Unclutter]] - [[#vanity-gaps][Vanity Gaps]] - [[#warp-cursor][Warp Cursor]] - [[#configuration][Configuration]] - [[#appearance][Appearance]] - [[#tagging][Tagging]] - [[#logging][Logging]] - [[#menu-1][Menu]] - [[#environment-variables][Environment Variables]] - [[#autostart][Autostart]] - [[#window-rules][Window Rules]] - [[#layouts][Layouts]] - [[#monitor-rules][Monitor Rules]] - [[#keyboard][Keyboard]] - [[#trackpad][Trackpad]] - [[#keybindings][Keybindings]] - [[#commands][Commands]] - [[#buttons][Buttons]] - [[#waybar][Waybar]] - [[#launch-script][Launch Script]] - [[#start-configuration][Start Configuration]] - [[#bar][Bar]] - [[#configuration-1][Configuration]] - [[#styling][Styling]] - [[#modules][Modules]] - [[#battery][Battery]] - [[#cpu][CPU]] - [[#clock][Clock]] - [[#dunst][Dunst]] - [[#dwl][DWL]] - [[#disk][Disk]] - [[#idle-inhibitor][Idle Inhibitor]] - [[#memory][Memory]] - [[#playerctl][Playerctl]] - [[#power-menu][Power Menu]] - [[#pulseaudio][Pulseaudio]] - [[#system76-power][System76 Power]] - [[#tray][Tray]] - [[#end-configuration][End Configuration]] - [[#justfile][Justfile]] * Welcome My personal configuration of dwl, written as an [[https://orgmode.org][Org Mode]] document. Run the block below with ~C-c C-c~ to tangle code blocks to config file. #+BEGIN_SRC emacs-lisp :tangle no (org-mode-restart) (org-babel-tangle) #+END_SRC After making changes, run the following in a terminal to recompile. #+BEGIN_SRC bash :tangle no sudo make clean install #+END_SRC * dwl - dwm for Wayland See [[./README.md][Upstream README]] for details on project. ** Patches *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/alwayscenter][Always Center]] Automatically center floating windows. #+BEGIN_SRC c :tangle patches.def.h #define ALWAYSCENTER_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/attachtop][Attach Top]] This is a port of attachtop patch for dwm: https://dwm.suckless.org/patches/attachtop New client attaches below the last master/on top of the stack. Behavior feels very intuitive as it doesn't disrupt existing masters no matter the amount of them, it only pushes the clients in stack down. #+BEGIN_SRC c :tangle patches.def.h #define ATTACHTOP_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/autostart][Auto Start]] Allow dwl to execute commands from autostart array in your config.h file. And when you exit dwl all processes from autostart array will be killed. Note: Commands from array are executed using execvp(). So if you need to execute shell command you need to prefix it with "sh", "-c" (change sh to any shell you like). #+BEGIN_SRC c :tangle patches.def.h #define AUTOSTART_PATCH 0 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/fakefullscreenclient][Fake Fullscreen Client]] Allow setting fake fullscreen per client #+BEGIN_SRC c :tangle patches.def.h #define FAKE_FULLSCREEN_CLIENT_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/float-unfocused-border-color][Float Unfocused Border Color]] A revive of the floatBorderColor patch. This patch allows you to set a color for floating windows when they are unfocused. #+BEGIN_SRC c :tangle patches.def.h #define FLOAT_UNFOCUSED_BORDER_COLOR_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/foreign-toplevel-management][Foreign Toplevel Management]] Implement ~foreign-toplevel-management~, it add handlers for activate, close, fullscreen and destroy request events, it's missing minimize and maximize request handlers. #+BEGIN_SRC c :tangle patches.def.h #define FOREIGN_TOPLEVEL_MANAGEMENT_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/gaplessgrid][Gapless Grid]] Arranges windows in a grid. Except it adjusts the number of windows in the first few columns to avoid empty cells. On widescreens (w > 2*h), it splits to three columns before splitting rows. #+BEGIN_SRC c :tangle patches.def.h #define GAPLESSGRID_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc][IPC]] Largely based on [[https://sr.ht/~raphi/][raphi]]'s [[https://sr.ht/~raphi/somebar/][somebar]], this patch provides an ipc for wayland clients to get and set dwl state. The ipc is intended for status bars, but can also be scripted with tools like [[https://codeberg.org/notchoc/dwlmsg][dwlmsg]]. Status information to stdout is currently disabled as dwl tends to freeze. For now, ~dwlmsg -w~ should act as a drop-in replacement. Note to [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/pertag][pertag]] users: apply [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc/ipcpertag.patch][this]] for ipc tagsetting to work as expected #+BEGIN_SRC c :tangle patches.def.h #define IPC_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/menu][Menu]] This patch adds ~menu~ command, which allows dwl to interface with dmenu-like programs. By default, two menus are available: - focusing a window by its title by pressing ~Alt+o~ - selecting a layout from a list by pressing ~Alt+Shift+o~ Edit ~menus~ array in ~config.h~ to add/change menus and use a different dmenu program. #+BEGIN_SRC c :tangle patches.def.h #define MENU_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/movestack][Move Stack]] Allows you to move a window up and down the stack. #+BEGIN_SRC c :tangle patches.def.h #define MOVESTACK_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/naturalscrolltrackpad][Natural Scroll Trackpad]] Set natural scrolling only for trackpads. #+BEGIN_SRC c :tangle patches.def.h #define NATURALSCROLLTRACKPAD_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/numlock-capslock][Numlock Capslock]] Allows activating numlock or capslock at startup. #+BEGIN_SRC c :tangle patches.def.h #define NUMLOCK_CAPSLOCK_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/pertag][Per Tag]] Makes layout, mwfact and nmaster individual for every tag. #+BEGIN_SRC c :tangle patches.def.h #define PERTAG_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/restore-monitor][Restore Monitor]] Moves clients to their old output when it is reattached. #+BEGIN_SRC c :tangle patches.def.h #define RESTORE_MONITOR_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/setupenv][Setup Env]] Allow configuring environment variables in config.h #+BEGIN_SRC c :tangle patches.def.h #define SETUPENV_PATCH 0 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/unclutter][Unclutter]] Hide the mouse cursor if it isn't being used for a certain period of time. #+BEGIN_SRC c :tangle patches.def.h #define UNCLUTTER_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/vanitygaps][Vanity Gaps]] Adds (inner) gaps between client windows and (outer) gaps between windows and the screen edge in a flexible manner. #+BEGIN_SRC c :tangle patches.def.h #define VANITYGAPS_PATCH 1 #+END_SRC *** [[https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/warpcursor][Warp Cursor]] Warp cursor to the centre of newly focused clients. Only moves the cursor if the cursor is currently not on the new client. This is my version of the orphaned cursorwarp patch except I left out the config flag as I think it is unnecessary. #+BEGIN_SRC c :tangle patches.def.h #define WARPCURSOR_PATCH 1 #+END_SRC ** Configuration Taken from https://github.com/djpohly/dwl/issues/466. *** Appearance #+BEGIN_SRC c :tangle config.h #define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \ ((hex >> 16) & 0xFF) / 255.0f, \ ((hex >> 8) & 0xFF) / 255.0f, \ (hex & 0xFF) / 255.0f } #+END_SRC #+BEGIN_SRC c :tangle config.h static const int sloppyfocus = 1; /* focus follows mouse */ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ #if VANITYGAPS_PATCH static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ static const int monoclegaps = 0; /* 1 means outer gaps in monocle layout */ #endif // VANITYGAPS_PATCH static const unsigned int borderpx = 2; /* border pixel of windows */ #if VANITYGAPS_PATCH static const unsigned int gappih = 20; /* horiz inner gap between windows */ static const unsigned int gappiv = 20; /* vert inner gap between windows */ static const unsigned int gappoh = 30; /* horiz outer gap between windows and screen edge */ static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */ #endif // VANITYGAPS_PATCH static const float rootcolor[] = COLOR(0x282a36ff); static const float bordercolor[] = COLOR(0x4d4d4dff); static const float focuscolor[] = COLOR(0xbd93f9ff); static const float urgentcolor[] = COLOR(0xff5555ff); #if FLOAT_UNFOCUSED_BORDER_COLOR_PATCH static const float floatcolor[] = COLOR(0xff79c6ff); #endif // FLOAT_UNFOCUSED_BORDER_COLOR_PATCH /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */ #+END_SRC *** Tagging #+BEGIN_SRC c :tangle config.h /* tagging - TAGCOUNT must be no greater than 31 */ #define TAGCOUNT (9) #+END_SRC *** Logging #+BEGIN_SRC c :tangle config.h static int log_level = WLR_ERROR; #+END_SRC *** Menu #+BEGIN_SRC c :tangle config.h #if MENU_PATCH static const Menu menus[] = { /* command feed function action function */ { "rofi -dmenu -i", menuwinfeed, menuwinaction }, { "rofi -dmenu -i", menulayoutfeed, menulayoutaction }, }; #endif // MENU_PATCH #+END_SRC *** Environment Variables #+BEGIN_SRC c :tangle config.h #if SETUPENV_PATCH static const Env envs[] = { /* variable value */ { "XDG_CURRENT_DESKTOP", "wlroots" }, }; #endif // SETUPENV_PATCH #+END_SRC *** Autostart #+BEGIN_SRC c :tangle config.h #if AUTOSTART_PATCH static const char *const autostart[] = { "wbg", "/path/to/your/image", NULL, NULL /* terminate */ }; #endif // AUTOSTART_PATCH #+END_SRC *** Window Rules Use ~dwlmsg -w -c~ to get the title and appid of focused clients. #+BEGIN_EXAMPLE c /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g., leave at least one example) */ static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ /* examples: */ { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ }; #+END_EXAMPLE #+BEGIN_SRC c :tangle config.h static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ { "thunderbird-esr", NULL, 1 << 0, 0, -1 }, /* Start on ONLY tag "1" */ { "Beeper", NULL, 1 << 1, 0, -1 }, /* Start on ONLY tag "2" */ { "zoom", NULL, 1 << 1, 0, -1 }, /* Start on ONLY tag "2" */ { "Signal", NULL, 1 << 1, 0, -1 }, /* Start on ONLY tag "2" */ { "discord", NULL, 1 << 1, 0, -1 }, /* Start on ONLY tag "2" */ { "obsidian", NULL, 1 << 2, 0, -1 }, /* Start on ONLY tag "3" */ { "pocket-casts-linux", NULL, 1 << 3, 0, -1 }, /* Start on ONLY tag "4" */ { "Spotify", NULL, 1 << 3, 0, -1 }, /* Start on ONLY tag "4" */ { "Vivaldi-stable", NULL, 1 << 4, 0, -1 }, /* Start on ONLY tag "5" */ { "foot", NULL, 1 << 5, 0, -1 }, /* Start on ONLY tag "6" */ { "Emacs", NULL, 1 << 6, 0, -1 }, /* Start on ONLY tag "7" */ { "steam", NULL, 1 << 7, 0, -1 }, /* Start on ONLY tag "8" */ { "lutris", NULL, 1 << 7, 0, -1 }, /* Start on ONLY tag "8" */ { "net.davidotek.pupgui2", NULL, 1 << 7, 0, -1 }, /* Start on ONLY tag "8" */ { "gamescope", NULL, 1 << 7, 0, -1 }, /* Start on ONLY tag "8" */ { "syncthing-gtk", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ { "openrgb", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ }; #+END_SRC *** Layouts #+BEGIN_SRC c :tangle config.h static const Layout layouts[] = { /* symbol arrange function */ { "[]=", tile }, { "><>", NULL }, /* no layout function means floating behavior */ { "[M]", monocle }, #if GAPLESSGRID_PATCH { "###", gaplessgrid }, #endif // GAPLESSGRID_PATCH }; #+END_SRC *** Monitor Rules #+BEGIN_SRC c :tangle config.h /* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator ,* WARNING: negative values other than (-1, -1) cause problems with Xwayland clients ,* https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 ,*/ /* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */ static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, ,*/ /* defaults */ { NULL, 0.5f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, }; #+END_SRC *** Keyboard #+BEGIN_SRC c :tangle config.h static const struct xkb_rule_names xkb_rules = { /* can specify fields: rules, model, layout, variant, options */ /* example: .options = "ctrl:nocaps", ,*/ .options = NULL, }; #if NUMLOCK_CAPSLOCK_PATCH /* numlock and capslock */ static const int numlock = 1; static const int capslock = 0; #endif // NUMLOCK_CAPSLOCK_PATCH static const int repeat_rate = 25; static const int repeat_delay = 600; #+END_SRC *** Trackpad #+BEGIN_SRC c :tangle config.h static const int tap_to_click = 1; static const int tap_and_drag = 1; static const int drag_lock = 1; static const int natural_scrolling = 1; static const int disable_while_typing = 1; static const int left_handed = 0; static const int middle_button_emulation = 0; #if UNCLUTTER_PATCH static const int cursor_timeout = 5; #endif // UNCLUTTER_PATCH /* You can choose between: LIBINPUT_CONFIG_SCROLL_NO_SCROLL LIBINPUT_CONFIG_SCROLL_2FG LIBINPUT_CONFIG_SCROLL_EDGE LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN ,*/ static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; /* You can choose between: LIBINPUT_CONFIG_CLICK_METHOD_NONE LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER ,*/ static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; /* You can choose between: LIBINPUT_CONFIG_SEND_EVENTS_ENABLED LIBINPUT_CONFIG_SEND_EVENTS_DISABLED LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE ,*/ static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; /* You can choose between: LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE ,*/ static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; static const double accel_speed = 0.0; /* You can choose between: LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right ,*/ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; #+END_SRC *** Keybindings #+BEGIN_SRC c :tangle config.h /* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ #define MODKEY WLR_MODIFIER_LOGO #define TAGKEYS(KEY,SKEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \ { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} } /* helper for spawning shell commands in the pre dwm-5.0 fashion */ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } #+END_SRC *** Commands #+BEGIN_SRC c :tangle config.h static const char *termcmd[] = { "foot", NULL }; static const char *menucmd[] = { "rofi", "-show", "combi", NULL }; static const Key keys[] = { /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ /* modifier key function argument */ { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, #if IPC_PATCH { MODKEY, XKB_KEY_b, togglebar, {0} }, #endif // IPC_PATCH { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, #if MOVESTACK_PATCH { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_J, movestack, {.i = +1} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, movestack, {.i = -1} }, #endif // MOVESTACK_PATCH { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} }, #if VANITYGAPS_PATCH { MODKEY|WLR_MODIFIER_ALT, XKB_KEY_h, incgaps, {.i = +1 } }, { MODKEY|WLR_MODIFIER_ALT, XKB_KEY_l, incgaps, {.i = -1 } }, { MODKEY|WLR_MODIFIER_ALT|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } }, { MODKEY|WLR_MODIFIER_ALT|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } }, { MODKEY|WLR_MODIFIER_ALT|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } }, { MODKEY|WLR_MODIFIER_ALT|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } }, { MODKEY|WLR_MODIFIER_ALT, XKB_KEY_0, togglegaps, {0} }, { MODKEY|WLR_MODIFIER_ALT|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} }, { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } }, { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } }, { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } }, { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } }, { MODKEY|WLR_MODIFIER_ALT, XKB_KEY_y, incohgaps, {.i = +1 } }, { MODKEY|WLR_MODIFIER_ALT, XKB_KEY_o, incohgaps, {.i = -1 } }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } }, #endif // VANITYGAPS_PATCH { MODKEY, XKB_KEY_Return, zoom, {0} }, { MODKEY, XKB_KEY_Tab, view, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, #if GAPLESSGRID_PATCH { MODKEY, XKB_KEY_g, setlayout, {.v = &layouts[3]} }, #endif // GAPLESSGRID_PATCH { MODKEY, XKB_KEY_space, setlayout, {0} }, #if MENU_PATCH { MODKEY|WLR_MODIFIER_SHIFT|WLR_MODIFIER_CTRL, XKB_KEY_p, menu, {.v = &menus[0]} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_P, menu, {.v = &menus[1]} }, #endif // MENU_PATCH { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, #if FAKE_FULLSCREEN_CLIENT_PATCH { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_E, togglefakefullscreen, {0} }, #endif // FAKE_FULLSCREEN_CLIENT_PATCH { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} }, TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0), TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3), TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4), TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5), TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6), TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7), TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8), { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} }, /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} }, /* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is ,* do not remove them. ,*/ #define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} } CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6), CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12), }; #+END_SRC *** Buttons #+BEGIN_SRC c :tangle config.h static const Button buttons[] = { { MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} }, { MODKEY, BTN_MIDDLE, togglefloating, {0} }, { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} }, }; #+END_SRC * Waybar ** Launch Script #+BEGIN_SRC shell :shebang #!/usr/bin/env bash :tangle waybar/launch.sh killall waybar || true until /usr/bin/waybar \ --config $HOME/.config/dwl/waybar/config.jsonc \ --style $HOME/.config/dwl/waybar/style.css; do if [ $? -ne 143 ]; then echo "Dwl Waybar stopped with exit code $?. Respawning..." >&2; sleep 1; else echo "Dwl Waybar manually killed with SIGTERM"; break; fi done #+END_SRC ** Start Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc // -*- mode: jsonc -*- { #+END_SRC ** Bar *** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "layer": "top", // Waybar at top layer // "output": "", "position": "top", // Waybar position (top|bottom|left|right) // "height": 25, // Waybar height (to be removed for auto height) // "width": 1280, // Waybar width "spacing": 4, // Gaps between modules (4px) "mode": "dock", "start_hidden": false, "fixed-center": true, "reload_style_on_change": true, "modules-left": [ "group/power-menu", "dwl/tags", "dwl/window#title", "dwl/window#layout", ], "modules-center": [ "tray", ], "modules-right": [ "group/media-playing", "pulseaudio", "idle_inhibitor", "custom/system76-power", "cpu", "memory", "disk", "battery", "clock", "group/dunst", ], "group/power-menu": { "orientation": "inherit", "modules": [ "custom/power-menu-launcher", "custom/power-menu-shutdown", "custom/power-menu-reboot", "custom/power-menu-sleep", "custom/power-menu-lock", "custom/power-menu-logout", ], "drawer": { "transition-duration": 500, "transition-left-to-right": true, "click-to-reveal": false, }, }, "group/media-playing": { "orientation": "inherit", "modules": [ "custom/media-playing-source", "custom/media-playing-prev", "custom/media-playing-play-pause", "custom/media-playing-next", ], }, "group/dunst": { "orientation": "inherit", "modules": [ "custom/dunst-status", "custom/dunst-history-view", "custom/dunst-clear", "custom/dunst-history-clear", ], "drawer": { "transition-duration": 500, "transition-left-to-right": true, "click-to-reveal": false, }, }, #+END_SRC *** Styling #+BEGIN_SRC css :tangle waybar/style.css window#waybar { background: transparent; } #window { padding: 0px 0px; color: transparent; background: transparent; } widget { background: #282a36; border-radius: 25px; } label.module { padding: 0px 10px; } button { border-radius: 0px; padding: 0px 0px; } .module,button { font-size: 15px; font-family: Ubuntu Nerd Font; } #+END_SRC ** Modules *** Battery **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "battery": { "interval": 60, "format": "{icon} {capacity}%", "format-icons": ["󰂎", "󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"], "tooltip": true, "tooltip-format": "󱧥\t{timeTo}\n󱐋\t{power} W\n󱠴\t{cycles}\n󱈏\t{health}%", }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #battery { background: transparent; color: #ff79c6; } #+END_SRC *** CPU **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "cpu": { "interval": 5, "format": " {usage}%", "tooltip": true, "on-click-right": "foot btop", }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #cpu { background: transparent; color: #ffb86c; } #+END_SRC *** Clock **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "clock": { "interval": 60, "format": "󰥔 {:%I:%M %p}", "tooltip": true, "tooltip-format": "{calendar}", "calendar": { "mode" : "month", "mode-mon-col" : 3, "weeks-pos" : "left", "on-scroll" : 1, "format": { "months": "{}", "days": "{}", "weeks": "W{}", "weekdays": "{}", "today": "{}" }, }, "actions": { "on-click": "mode", "on-click-right": "shift_reset", "on-scroll-up": "shift_up", "on-scroll-down": "shift_down", }, }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #clock { background: transparent; color: #bd93f9; } #+END_SRC *** Dunst **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "custom/dunst-status": { "exec": "~/.config/dwl/waybar/scripts/dunst.sh", "restart-interval": 1, "on-click": "~/.scripts/dunst.sh --dnd", "on-click-right": "~/.scripts/dunst.sh --rofi", "tooltip": true, "tooltip-format": "Toggle Do Not Disturb", }, "custom/dunst-clear": { "format": "", "on-click": "~/.scripts/dunst.sh --close-all", "tooltip": true, "tooltip-format": "Close Open Notifications", }, "custom/dunst-history-view": { "format": "󰋚", "on-click": "~/.scripts/dunst.sh --history", "tooltip": true, "tooltip-format": "View Notification History", }, "custom/dunst-history-clear": { "format": "󰎟", "on-click": "~/.scripts/dunst.sh --history-clear", "tooltip": true, "tooltip-format": "Clear Notification History", }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css box#dunst { padding: 0px 10px; } #custom-dunst-status { background: transparent; color: #50fa7b; padding: 0px 5px; } #custom-dunst-clear { background: transparent; color: #50fa7b; padding: 0px 5px; } #custom-dunst-history-view { background: transparent; color: #50fa7b; padding: 0px 5px; } #custom-dunst-history-clear { background: transparent; color: #50fa7b; padding: 0px 5px; } #+END_SRC **** Script #+BEGIN_SRC shell :shebang #!/usr/bin/env bash :tangle waybar/scripts/dunst.sh isPaused=$(dunstctl is-paused) notificationCount=$(dunstctl count history) if [[ "$isPaused" == "true" ]]; then echo "󰂛 $notificationCount" else echo "󰂚 $notificationCount" fi #+END_SRC *** DWL **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "dwl/tags": { "num-tags": 9, "tag-labels": [ "󰻧 ₁", "󰍩 ₂", "󰠮 ₃", " ₄", "󰖟 ₅", " ₆", "󰊢 ₇", "󰊖 ₈", " ₉" ], "disable-click": false }, "dwl/window#title": { "format": "{title}", "all-outputs": false, "icon": true, "icon-size": 21, "tooltip": true, "max-length": 30, }, "dwl/window#layout": { "format": "{layout}", "tooltip": false, "all-outputs": false, "icon": false, }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #tags { padding: 0px 10px; } #tags button { background: transparent; color: #44475a; padding: 0px 5px; } #tags button.occupied { background: transparent; color: #f1fa8c; } #tags button.focused { background: transparent; box-shadow: inset 0 -3px #bd93f9; } #tags button.urgent { background: transparent; color: #ff5555; } #window.title { background: transparent; color: #f8f8f2; padding: 0px 10px; } #window.layout { background: transparent; color: #50fa7b; padding: 0px 10px; } #+END_SRC *** Disk **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "disk": { "interval": 60, "format": "󰋊 {percentage_used}%", "tooltip": true, "tooltip-format": "Used: {used} ({percentage_used}%)\nFree: {free} ({percentage_free}%)\nTotal: {total}", "on-click-right": "qdirstat", }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #disk { background: transparent; color: #f1fa8c; } #+END_SRC *** Idle Inhibitor **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "idle_inhibitor": { "format": "{icon}", "format-icons": { "activated": "󱄄 on", "deactivated": "󰶐 off", }, "tooltip": true, "tooltip-format-activated": "Idle Inhibitor: {status}", "tooltip-format-deactivated": "Idle Inhibitor: {status}", "start-activated": true, }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #idle_inhibitor.activated { background: transparent; color: #f1fa8c; } #idle_inhibitor.deactivated { background: transparent; color: #44475a; } #+END_SRC *** Memory **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "memory": { "interval": 5, "format": " {percentage}%", "tooltip": true, "tooltip-format": "RAM:\n\tUsed: {used} GiB ({percentage}%)\n\tFree: {avail} GiB\n\tTotal: {total} GiB\nSwap:\n\tUsed: {swapUsed} GiB ({swapPercentage}%)\n\tFree: {swapAvail} GiB\n\tTotal: {swapTotal} GiB", "on-click-right": "foot btop", }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #memory { background: transparent; color: #8be9fd; } #+END_SRC *** Playerctl **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "custom/media-playing-source": { "exec": "~/.config/dwl/waybar/scripts/get-media-playing.sh", "return-type": "json", "restart-interval": 1, "on-click": "~/.scripts/playerctl.sh --change", "tooltip": true, }, "custom/media-playing-prev": { "format": "󰒮", "on-click": "~/.scripts/playerctl.sh --prev", "tooltip": false, }, "custom/media-playing-play-pause": { "exec": "~/.config/dwl/waybar/scripts/get-media-status-icon.sh", "restart-interval": 1, "on-click": "~/.scripts/playerctl.sh --play-pause", "tooltip": false, }, "custom/media-playing-next": { "format": "󰒭", "on-click": "~/.scripts/playerctl.sh --next", "tooltip": false, }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css box#media-playing { padding: 0px 10px; } #custom-media-playing-source { background: transparent; color: #ff5555; padding: 0px 5px; } #custom-media-playing-prev { background: transparent; color: #ff5555; padding: 0px 5px; } #custom-media-playing-play-pause { background: transparent; color: #ff5555; padding: 0px 5px; } #custom-media-playing-next { background: transparent; color: #ff5555; padding: 0px 5px; } #+END_SRC **** Script #+BEGIN_SRC shell :shebang #!/usr/bin/env bash :tangle waybar/scripts/get-media-source-icon.sh mediaStatus=$(playerctl --player=playerctld metadata 2>&1) if [[ "$mediaStatus" == "No player could handle this command" ]]; then echo "󰡀" else trackid=$(playerctl --player=playerctld metadata --format '{{ mpris:trackid }}') title=$(playerctl --player=playerctld metadata --format '{{ xesam:title }}') if grep -q -i "netflix" <<< "$title"; then echo "󰝆" elif grep -q -i "hulu" <<< "$title"; then echo "󰠩" elif grep -q -i "prime video" <<< "$title"; then echo "" elif grep -q -i "youtube tv" <<< "$title"; then echo "󰑈" elif grep -q -i "chromium" <<< "$trackid"; then echo "" elif grep -q -i "vlc" <<< "$trackid"; then echo "󰕼" elif grep -q -i "spotify" <<< "$trackid"; then echo "" else echo "󰡀" fi fi #+END_SRC #+BEGIN_SRC shell :shebang #!/usr/bin/env bash :tangle waybar/scripts/get-media-status-icon.sh mediaStatus=$(`dirname $0`/get-media-status.sh) if [[ "$mediaStatus" == "N/A" ]]; then echo "󰐎" else if [[ "$mediaStatus" == "Playing" ]]; then echo "󰏤" elif [[ "$mediaStatus" == "Paused" ]]; then echo "󰐊" fi fi #+END_SRC #+BEGIN_SRC shell :shebang #!/usr/bin/env bash :tangle waybar/scripts/get-media-status.sh mediaStatus=$(playerctl --player=playerctld metadata 2>&1) if [[ "$mediaStatus" == "No player could handle this command" ]]; then echo "N/A" else status=$(playerctl --player=playerctld metadata --format '{{ status }}') echo $status fi #+END_SRC #+BEGIN_SRC shell :shebang #!/usr/bin/env bash :tangle waybar/scripts/get-media-playing.sh mediaSourceIcon=$(`dirname $0`/get-media-source-icon.sh) mediaStatus=$(playerctl --player=playerctld metadata 2>&1) if [[ "$mediaStatus" == "No player could handle this command" ]]; then artist="N/A" title="N/A" album="N/A" status="N/A" else artist=$(playerctl --player=playerctld metadata --format '{{ xesam:artist }}') title=$(playerctl --player=playerctld metadata --format '{{ xesam:title }}') album=$(playerctl --player=playerctld metadata --format '{{ xesam:album }}') status=$(playerctl --player=playerctld metadata --format '{{ status }}') if [[ $artist == "" ]]; then artist="N/A" fi if [[ $title == "" ]]; then title="N/A" fi if [[ $album == "" ]]; then album="N/A" fi if [[ $status == "" ]]; then status="N/A" fi fi echo '{"text":"'$mediaSourceIcon'","tooltip":"󰝚\t'${title//'"'/'\"'}'\r󰠃\t'${artist//'"'/'\"'}'\r󰀥\t'${album//'"'/'\"'}'\r󰐎\t'${status//'"'/'\"'}'"}' #+END_SRC *** Power Menu **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "custom/power-menu-launcher": { "format": "", "on-click": "rofi -show combi", "on-click-right": "~/.scripts/control-center.sh --rofi", "tooltip": true, "tooltip-format": "Application Launcher", }, "custom/power-menu-shutdown": { "format": "", "on-click": "~/.scripts/session.sh --shutdown", "tooltip": true, "tooltip-format": "Shutdown", }, "custom/power-menu-reboot": { "format": "", "on-click": "~/.scripts/session.sh --reboot", "tooltip": true, "tooltip-format": "Reboot", }, "custom/power-menu-sleep": { "format": "⏾", "on-click": "~/.scripts/session.sh --sleep", "tooltip": true, "tooltip-format": "Sleep", }, "custom/power-menu-lock": { "format": "", "on-click": "~/.scripts/session.sh --lock", "tooltip": true, "tooltip-format": "Lock", }, "custom/power-menu-logout": { "format": "", "on-click": "~/.scripts/session.sh --logout", "tooltip": true, "tooltip-format": "Logout", }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css box#power-menu { padding: 0px 10px; } #custom-power-menu-launcher { background: transparent; color: #8be9fd; padding: 0px 5px; } #custom-power-menu-shutdown { background: transparent; color: #ff5555; padding: 0px 5px; } #custom-power-menu-reboot { background: transparent; color: #50fa7b; padding: 0px 5px; } #custom-power-menu-sleep { background: transparent; color: #f1fa8c; padding: 0px 5px; } #custom-power-menu-lock { background: transparent; color: #ff79c6; padding: 0px 5px; } #custom-power-menu-logout { background: transparent; color: #ffb86c; padding: 0px 5px; } #+END_SRC *** Pulseaudio **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "pulseaudio": { "interval": 5, "format": "{icon} {volume}%", "format-bluetooth": "{icon} 󰂯 {volume}%", "format-muted": "󰝟 muted", "format-icons": { "hdmi": "󰡁", "headset": "󰋎", "speaker": "󰓃", "headphone": "󰋋", "car": "", "hifi": "󰤽", "default": "", }, "scroll-step": 5, "on-click": "~/.scripts/pactl.sh --mute", "on-click-right": "~/.scripts/pactl.sh --mixer", "tooltip": true, "tooltip-format": "{desc}", "scroll-step": 0.25, }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #pulseaudio { background: transparent; color: #ff79c6; } #+END_SRC *** System76 Power **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "custom/system76-power": { "exec": "~/.config/dwl/waybar/scripts/system76-power.sh", "return-type": "json", "restart-interval": 60, "on-click-right": "~/.scripts/cpu-gpu.sh --rofi", "tooltip": true, }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #custom-system76-power { background: transparent; color: #50fa7b; } #+END_SRC **** Script #+BEGIN_SRC shell :shebang #!/usr/bin/env bash :tangle waybar/scripts/system76-power.sh profile="$(sudo system76-power profile | sed -z '$ s/\n$//' | tr '\n' '\r')" graphics="$(sudo system76-power graphics)" graphicsPower="$(sudo system76-power graphics power)" chargeThresholds="$(sudo system76-power charge-thresholds | sed -z '$ s/\n$//' | tr '\n' '\r')" echo '{"text":"󰢮 '$graphics'","tooltip":"󰢮\t'$graphics'\r󰐥\t'$graphicsPower'\r\r Profile\r'$profile'\r\r󰚥 Charge Thresholds\r'$chargeThresholds'"}' #+END_SRC *** Tray **** Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc "tray": { "icon-size": 21, "show-passive-items": true, "spacing": 4, "reverse-direction": false, }, #+END_SRC **** Styling #+BEGIN_SRC css :tangle waybar/style.css #tray { background: transparent; padding: 0px 10px; } #+END_SRC ** End Configuration #+BEGIN_SRC jsonc :tangle waybar/config.jsonc } #+END_SRC * Justfile #+BEGIN_SRC just :tangle justfile set shell := ["bash", "-c"] # List just commands by default default: @just --list # Rebuild project dwl-rebuild: sudo make clean all # Run waybar with dwl configuration dwl-launch-waybar: ./waybar/launch.sh #+END_SRC