dwl/README.org
2025-01-05 22:25:31 -05:00

42 KiB

Personal dwl Configuration with Waybar

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