42 KiB
Personal dwl Configuration with Waybar
- Welcome
- dwl - dwm for Wayland
- Waybar
- Justfile
Welcome
My personal configuration of dwl, written as an Org Mode document.
Run the block below with C-c C-c
to tangle code blocks to config file.
(org-mode-restart)
(org-babel-tangle)
After making changes, run the following in a terminal to recompile.
sudo make clean install
dwl - dwm for Wayland
See Upstream README for details on project.
Patches
Always Center
Automatically center floating windows.
#define ALWAYSCENTER_PATCH 1
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.
#define ATTACHTOP_PATCH 1
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).
#define AUTOSTART_PATCH 0
Fake Fullscreen Client
Allow setting fake fullscreen per client
#define FAKE_FULLSCREEN_CLIENT_PATCH 1
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.
#define FLOAT_UNFOCUSED_BORDER_COLOR_PATCH 1
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.
#define FOREIGN_TOPLEVEL_MANAGEMENT_PATCH 1
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.
#define GAPLESSGRID_PATCH 1
IPC
Largely based on raphi's 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 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 pertag users: apply this for ipc tagsetting to work as expected
#define IPC_PATCH 1
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.
#define MENU_PATCH 1
Move Stack
Allows you to move a window up and down the stack.
#define MOVESTACK_PATCH 1
Natural Scroll Trackpad
Set natural scrolling only for trackpads.
#define NATURALSCROLLTRACKPAD_PATCH 1
Numlock Capslock
Allows activating numlock or capslock at startup.
#define NUMLOCK_CAPSLOCK_PATCH 1
Per Tag
Makes layout, mwfact and nmaster individual for every tag.
#define PERTAG_PATCH 1
Restore Monitor
Moves clients to their old output when it is reattached.
#define RESTORE_MONITOR_PATCH 1
Setup Env
Allow configuring environment variables in config.h
#define SETUPENV_PATCH 0
Unclutter
Hide the mouse cursor if it isn't being used for a certain period of time.
#define UNCLUTTER_PATCH 1
Vanity Gaps
Adds (inner) gaps between client windows and (outer) gaps between windows and the screen edge in a flexible manner.
#define VANITYGAPS_PATCH 1
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.
#define WARPCURSOR_PATCH 1
Configuration
Taken from https://github.com/djpohly/dwl/issues/466.
Appearance
#define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \
((hex >> 16) & 0xFF) / 255.0f, \
((hex >> 8) & 0xFF) / 255.0f, \
(hex & 0xFF) / 255.0f }
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 */
Tagging
/* tagging - TAGCOUNT must be no greater than 31 */
#define TAGCOUNT (9)
Logging
static int log_level = WLR_ERROR;
Menu
#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
Environment Variables
#if SETUPENV_PATCH
static const Env envs[] = {
/* variable value */
{ "XDG_CURRENT_DESKTOP", "wlroots" },
};
#endif // SETUPENV_PATCH
Autostart
#if AUTOSTART_PATCH
static const char *const autostart[] = {
"wbg", "/path/to/your/image", NULL,
NULL /* terminate */
};
#endif // AUTOSTART_PATCH
Window Rules
Use dwlmsg -w -c
to get the title and appid of focused clients.
/* 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" */ };
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" */
};
Layouts
static const Layout layouts[] = {
/* symbol arrange function */
{ "[]=", tile },
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
#if GAPLESSGRID_PATCH
{ "###", gaplessgrid },
#endif // GAPLESSGRID_PATCH
};
Monitor Rules
/* (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 },
};
Keyboard
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;
Trackpad
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;
Keybindings
/* 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 } }
Commands
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),
};
Buttons
static const Button buttons[] = {
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
};
Waybar
Launch Script
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
Start Configuration
// -*- mode: jsonc -*-
{
Bar
Configuration
"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,
},
},
Styling
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;
}
Modules
Battery
Configuration
"battery": {
"interval": 60,
"format": "{icon} {capacity}%",
"format-icons": ["", "", "", "", "", "", "", "", "", "", ""],
"tooltip": true,
"tooltip-format": "\t{timeTo}\n\t{power} W\n\t{cycles}\n\t{health}%",
},
Styling
#battery {
background: transparent;
color: #ff79c6;
}
CPU
Configuration
"cpu": {
"interval": 5,
"format": " {usage}%",
"tooltip": true,
"on-click-right": "foot btop",
},
Styling
#cpu {
background: transparent;
color: #ffb86c;
}
Clock
Configuration
"clock": {
"interval": 60,
"format": " {:%I:%M %p}",
"tooltip": true,
"tooltip-format": "<tt><small>{calendar}</small></tt>",
"calendar": {
"mode" : "month",
"mode-mon-col" : 3,
"weeks-pos" : "left",
"on-scroll" : 1,
"format": {
"months": "<span color='#50fa7b'><b>{}</b></span>",
"days": "<span color='#f8f8f2'><b>{}</b></span>",
"weeks": "<span color='#8be9fd'><b>W{}</b></span>",
"weekdays": "<span color='#f1fa8c'><b>{}</b></span>",
"today": "<span color='#bd93f9'><b><u>{}</u></b></span>"
},
},
"actions": {
"on-click": "mode",
"on-click-right": "shift_reset",
"on-scroll-up": "shift_up",
"on-scroll-down": "shift_down",
},
},
Styling
#clock {
background: transparent;
color: #bd93f9;
}
Dunst
Configuration
"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",
},
Styling
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;
}
Script
isPaused=$(dunstctl is-paused)
notificationCount=$(dunstctl count history)
if [[ "$isPaused" == "true" ]]; then
echo " $notificationCount"
else
echo " $notificationCount"
fi
DWL
Configuration
"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,
},
Styling
#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;
}
Disk
Configuration
"disk": {
"interval": 60,
"format": " {percentage_used}%",
"tooltip": true,
"tooltip-format": "Used: {used} ({percentage_used}%)\nFree: {free} ({percentage_free}%)\nTotal: {total}",
"on-click-right": "qdirstat",
},
Styling
#disk {
background: transparent;
color: #f1fa8c;
}
Idle Inhibitor
Configuration
"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,
},
Styling
#idle_inhibitor.activated {
background: transparent;
color: #f1fa8c;
}
#idle_inhibitor.deactivated {
background: transparent;
color: #44475a;
}
Memory
Configuration
"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",
},
Styling
#memory {
background: transparent;
color: #8be9fd;
}
Playerctl
Configuration
"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,
},
Styling
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;
}
Script
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
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
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
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//'"'/'\"'}'"}'
Power Menu
Configuration
"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",
},
Styling
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;
}
Pulseaudio
Configuration
"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,
},
Styling
#pulseaudio {
background: transparent;
color: #ff79c6;
}
System76 Power
Configuration
"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,
},
Styling
#custom-system76-power {
background: transparent;
color: #50fa7b;
}
Script
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'"}'
Tray
Configuration
"tray": {
"icon-size": 21,
"show-passive-items": true,
"spacing": 4,
"reverse-direction": false,
},
Styling
#tray {
background: transparent;
padding: 0px 10px;
}
End Configuration
}
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