Some changes

main
kvj 2023-12-11 19:16:33 +01:00
parent 1b91a8df3d
commit 202a8614cd
55 changed files with 4619 additions and 3003 deletions

View File

@ -6,13 +6,13 @@ include config.mk
SRC = drw.c dwm.c util.c SRC = drw.c dwm.c util.c
OBJ = ${SRC:.c=.o} OBJ = ${SRC:.c=.o}
all: options dwm # FreeBSD users, prefix all ifdef, else and endif statements with a . for this to work (e.g. .ifdef)
options: ifdef YAJLLIBS
@echo dwm build options: all: dwm dwm-msg
@echo "CFLAGS = ${CFLAGS}" else
@echo "LDFLAGS = ${LDFLAGS}" all: dwm
@echo "CC = ${CC}" endif
.c.o: .c.o:
${CC} -c ${CFLAGS} $< ${CC} -c ${CFLAGS} $<
@ -25,8 +25,14 @@ config.h:
dwm: ${OBJ} dwm: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS} ${CC} -o $@ ${OBJ} ${LDFLAGS}
ifdef YAJLLIBS
dwm-msg:
${CC} -o $@ patch/ipc/dwm-msg.c ${LDFLAGS}
endif
clean: clean:
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
rm -f dwm-msg
dist: clean dist: clean
mkdir -p dwm-${VERSION} mkdir -p dwm-${VERSION}
@ -39,13 +45,23 @@ dist: clean
install: all install: all
mkdir -p ${DESTDIR}${PREFIX}/bin mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f dwm ${DESTDIR}${PREFIX}/bin cp -f dwm ${DESTDIR}${PREFIX}/bin
ifdef YAJLLIBS
cp -f dwm-msg ${DESTDIR}${PREFIX}/bin
endif
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
ifdef YAJLLIBS
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm-msg
endif
mkdir -p ${DESTDIR}${MANPREFIX}/man1 mkdir -p ${DESTDIR}${MANPREFIX}/man1
sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
mkdir -p ${DESTDIR}${PREFIX}/share/xsessions
test -f ${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop || cp -n dwm.desktop ${DESTDIR}${PREFIX}/share/xsessions
chmod 644 ${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop
uninstall: uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/dwm\ rm -f ${DESTDIR}${PREFIX}/bin/dwm\
${DESTDIR}${MANPREFIX}/man1/dwm.1 ${DESTDIR}${MANPREFIX}/man1/dwm.1\
${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop
.PHONY: all options clean dist install uninstall .PHONY: all clean dist install uninstall

48
README Normal file
View File

@ -0,0 +1,48 @@
dwm - dynamic window manager
============================
dwm is an extremely fast, small, and dynamic window manager for X.
Requirements
------------
In order to build dwm you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (dwm is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install dwm (if
necessary as root):
make clean install
Running dwm
-----------
Add the following line to your .xinitrc to start dwm using startx:
exec dwm
In order to connect dwm to a specific display, make sure that
the DISPLAY environment variable is set correctly, e.g.:
DISPLAY=foo.bar:1 exec dwm
(This will start dwm on display :1 of the host foo.bar.)
In order to display status info in the bar, you can do something
like this in your .xinitrc:
while xsetroot -name "`date` `uptime | sed 's/.*,//'`"
do
sleep 1
done &
exec dwm
Configuration
-------------
The configuration of dwm is done by creating a custom config.h
and (re)compiling the source code.

View File

@ -1,227 +1,314 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
/* appearance */ /* appearance */
#include <X11/XF86keysym.h>
static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int borderpx = 1; /* border pixel of windows */
static const int user_bh = 27; /* 0 means that dwm will calculate bar height, >= static const unsigned int snap = 32; /* snap pixel */
1 means dwm will user_bh as bar height */ static const unsigned int gappih = 20; /* horiz inner gap between windows */
static const int swallowfloating = static const unsigned int gappiv = 10; /* vert inner gap between windows */
0; /* 1 means swallow floating windows by default */ static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
static const unsigned int snap = 1; /* snap pixel */ static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */
static const unsigned int gappih = 6; /* horiz inner gap between windows */ static const int smartgaps_fact = 1; /* gap factor when there is only one client; 0 = no gaps, 3 = 3x outer gaps */
static const unsigned int gappiv = 6; /* vert inner gap between windows */
static const unsigned int gappoh =
6; /* horiz outer gap between windows and screen edge */
static const unsigned int gappov =
6; /* vert outer gap between windows and screen edge */
static const char buttonbar[] = "";
static int smartgaps =
0; /* 1 means no outer gap when there is only one window */
static const int showbar = 1; /* 0 means no bar */ static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */ static const int topbar = 1; /* 0 means bottom bar */
static const int horizpadbar = 3; /* horizontal padding for statusbar */ static const int bar_height = 0; /* 0 means derive from font, >= 1 explicit height */
static const int vertpadbar = 10; /* vertical padding for statusbar */ /* Status is to be shown on: -1 (all monitors), 0 (a specific monitor by index), 'A' (active monitor) */
static const int vertpad = 0; /* vertical padding of bar */ static const int statusmon = 'A';
static const int sidepad = 0; /* horizontal padding of bar */ static const unsigned int ulinepad = 5; /* horizontal padding between the underline and tag */
static const unsigned int systraypinning = static const unsigned int ulinestroke = 2; /* thickness / height of the underline */
0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor static const unsigned int ulinevoffset = 0; /* how far above the bottom of the bar the line should appear */
X */ static const int ulineall = 0; /* 1 to show underline on all tags, 0 for just the active ones */
static const unsigned int systrayonleft =
0; /* 0: systray in the right corner, >0: systray on left of status text */
static const unsigned int systrayspacing = 2; /* systray spacing */
static const int systraypinningfailfirst =
1; /* 1: if pinning fails, display systray on the first monitor, False:
display systray on the last monitor*/
static const unsigned int systrayiconsize = 20; /* systray icon size in px */
static const int showsystray = 1; /* 0 means no systray */
static const char *fonts[] = {
"Iosevka Nerd Font:size=12:style=Regular",
"Noto Color Emoji:size=12:antialias=true:autohint=true",
"Material Design Icons Desktop:size=11"};
static const char dmenufont[] = "Iosevka Nerd Font:size=12";
static const char col_back[] = "#121111";
static const char col_gray1[] = "#212126";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#dbdfdf";
static const char col_blue[] = "#808fbe";
static const char col_orange[] = "#eaac79";
static const char col_red[] = "#c15a5e";
static const char col_green[] = "#8fa176";
static const char col_cyan[] = "#8cb5af";
static const char col_yellow[] = "#d8b170";
static const char col_magenta[] = "#b183ba";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = {col_gray3, col_back, col_gray2}, /* Indicators: see patch/bar_indicators.h for options */
[SchemeBtn] = {col_blue, col_gray1, col_gray2}, static int tagindicatortype = INDICATOR_TOP_LEFT_SQUARE;
[SchemeLt] = {col_gray4, col_back, col_gray2}, static int tiledindicatortype = INDICATOR_NONE;
[SchemeSel] = {col_gray4, col_blue, col_blue}, static int floatindicatortype = INDICATOR_TOP_LEFT_SQUARE;
}; static const char *fonts[] = { "monospace:size=10" };
static const char *tagsel[][2] = { static const char dmenufont[] = "monospace:size=10";
{col_green, col_back}, {col_red, col_back}, {col_yellow, col_back},
{col_blue, col_back}, {col_magenta, col_back}, {col_cyan, col_back}, static char c000000[] = "#000000"; // placeholder value
static char normfgcolor[] = "#bbbbbb";
static char normbgcolor[] = "#222222";
static char normbordercolor[] = "#444444";
static char normfloatcolor[] = "#db8fd9";
static char selfgcolor[] = "#eeeeee";
static char selbgcolor[] = "#005577";
static char selbordercolor[] = "#005577";
static char selfloatcolor[] = "#005577";
static char titlenormfgcolor[] = "#bbbbbb";
static char titlenormbgcolor[] = "#222222";
static char titlenormbordercolor[] = "#444444";
static char titlenormfloatcolor[] = "#db8fd9";
static char titleselfgcolor[] = "#eeeeee";
static char titleselbgcolor[] = "#005577";
static char titleselbordercolor[] = "#005577";
static char titleselfloatcolor[] = "#005577";
static char tagsnormfgcolor[] = "#bbbbbb";
static char tagsnormbgcolor[] = "#222222";
static char tagsnormbordercolor[] = "#444444";
static char tagsnormfloatcolor[] = "#db8fd9";
static char tagsselfgcolor[] = "#eeeeee";
static char tagsselbgcolor[] = "#005577";
static char tagsselbordercolor[] = "#005577";
static char tagsselfloatcolor[] = "#005577";
static char hidnormfgcolor[] = "#005577";
static char hidselfgcolor[] = "#227799";
static char hidnormbgcolor[] = "#222222";
static char hidselbgcolor[] = "#222222";
static char urgfgcolor[] = "#bbbbbb";
static char urgbgcolor[] = "#222222";
static char urgbordercolor[] = "#ff0000";
static char urgfloatcolor[] = "#db8fd9";
static char *colors[][ColCount] = {
/* fg bg border float */
[SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normfloatcolor },
[SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selfloatcolor },
[SchemeTitleNorm] = { titlenormfgcolor, titlenormbgcolor, titlenormbordercolor, titlenormfloatcolor },
[SchemeTitleSel] = { titleselfgcolor, titleselbgcolor, titleselbordercolor, titleselfloatcolor },
[SchemeTagsNorm] = { tagsnormfgcolor, tagsnormbgcolor, tagsnormbordercolor, tagsnormfloatcolor },
[SchemeTagsSel] = { tagsselfgcolor, tagsselbgcolor, tagsselbordercolor, tagsselfloatcolor },
[SchemeHidNorm] = { hidnormfgcolor, hidnormbgcolor, c000000, c000000 },
[SchemeHidSel] = { hidselfgcolor, hidselbgcolor, c000000, c000000 },
[SchemeUrg] = { urgfgcolor, urgbgcolor, urgbordercolor, urgfloatcolor },
}; };
typedef struct {
const char *name;
const void *cmd;
} Sp;
const char *spcmd1[] = {"st", "-n", "spterm", "-g", "120x28", NULL}; /* Tags
const char *spcmd2[] = {"st", "-n", "spmpd", "-e", "ncmpcpp", NULL}; * In a traditional dwm the number of tags in use can be changed simply by changing the number
static Sp scratchpads[] = { * of strings in the tags array. This build does things a bit different which has some added
/* name cmd */ * benefits. If you need to change the number of tags here then change the NUMTAGS macro in dwm.c.
{"spterm", spcmd1}, *
{"spmpd", spcmd2}, * Examples:
*
* 1) static char *tagicons[][NUMTAGS*2] = {
* [DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I" },
* }
*
* 2) static char *tagicons[][1] = {
* [DEFAULT_TAGS] = { "" },
* }
*
* The first example would result in the tags on the first monitor to be 1 through 9, while the
* tags for the second monitor would be named A through I. A third monitor would start again at
* 1 through 9 while the tags on a fourth monitor would also be named A through I. Note the tags
* count of NUMTAGS*2 in the array initialiser which defines how many tag text / icon exists in
* the array. This can be changed to *3 to add separate icons for a third monitor.
*
* For the second example each tag would be represented as a bullet point. Both cases work the
* same from a technical standpoint - the icon index is derived from the tag index and the monitor
* index. If the icon index is is greater than the number of tag icons then it will wrap around
* until it an icon matches. Similarly if there are two tag icons then it would alternate between
* them. This works seamlessly with alternative tags and alttagsdecoration patches.
*/
static char *tagicons[][NUMTAGS] =
{
[DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
[ALTERNATIVE_TAGS] = { "A", "B", "C", "D", "E", "F", "G", "H", "I" },
[ALT_TAGS_DECORATION] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" },
}; };
static const StatusCmd statuscmds[] = {
{"~/.local/bin/statusbar/power", 1},
{"~/.local/bin/statusbar/wifi", 2},
{"~/.local/bin/statusbar/calendar", 3},
{"~/.local/bin/statusbar/battery", 4},
{"~/.local/bin/statusbar/sound", 5},
{"~/.local/bin/statusbar/mindash", 6},
{"~/.local/bin/statusbar/mincalendar", 7},
{"~/.local/bin/statusbar/notifications", 8},
};
static const char *statuscmd[] = {"/bin/bash", "-c", NULL, NULL};
/* tagging */
static char *tags[] = {"cmd", "www", "dev", "chat", "sys", "med"};
static char *alttags[] = {"[cmd]", "[www]", "[dev]",
"[chat]", "[sys]", "[med]"};
static const unsigned int ulinepad =
2; /* horizontal padding between the underline and tag */
static const unsigned int ulinestroke =
2; /* thickness / height of the underline */
static const unsigned int ulinevoffset =
0; /* how far above the bottom of the bar the line should appear */
static const int ulineall =
0; /* 1 to show underline on all tags, 0 for just the active ones */
/* There are two options when it comes to per-client rules:
* - a typical struct table or
* - using the RULE macro
*
* A traditional struct table looks like this:
* // class instance title wintype tags mask isfloating monitor
* { "Gimp", NULL, NULL, NULL, 1 << 4, 0, -1 },
* { "Firefox", NULL, NULL, NULL, 1 << 7, 0, -1 },
*
* The RULE macro has the default values set for each field allowing you to only
* specify the values that are relevant for your rule, e.g.
*
* RULE(.class = "Gimp", .tags = 1 << 4)
* RULE(.class = "Firefox", .tags = 1 << 7)
*
* Refer to the Rule struct definition for the list of available fields depending on
* the patches you enable.
*/
static const Rule rules[] = { static const Rule rules[] = {
/* xprop(1): /* xprop(1):
* WM_CLASS(STRING) = instance, class * WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title * WM_NAME(STRING) = title
* WM_WINDOW_ROLE(STRING) = role
* _NET_WM_WINDOW_TYPE(ATOM) = wintype
*/ */
/* class instance title tags mask isfloating isterminal RULE(.wintype = WTYPE "DIALOG", .isfloating = 1)
noswallow monitor */ RULE(.wintype = WTYPE "UTILITY", .isfloating = 1)
{"Gimp", NULL, NULL, 0, 1, 0, 0, -1}, RULE(.wintype = WTYPE "TOOLBAR", .isfloating = 1)
{"Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1}, RULE(.wintype = WTYPE "SPLASH", .isfloating = 1)
{"st-256color", NULL, NULL, 0, 0, 1, 0, -1}, RULE(.class = "Gimp", .tags = 1 << 4)
{NULL, NULL, "Event Tester", 0, 0, 0, 1, -1}, /* xev */ RULE(.class = "Firefox", .tags = 1 << 7)
{NULL, "spterm", NULL, SPTAG(0), 1, 1, 0, -1}, };
{NULL, "spmpd", NULL, SPTAG(1), 1, 1, 0, -1},
/* Bar rules allow you to configure what is shown where on the bar, as well as
* introducing your own bar modules.
*
* monitor:
* -1 show on all monitors
* 0 show on monitor 0
* 'A' show on active monitor (i.e. focused / selected) (or just -1 for active?)
* bar - bar index, 0 is default, 1 is extrabar
* alignment - how the module is aligned compared to other modules
* widthfunc, drawfunc, clickfunc - providing bar module width, draw and click functions
* name - does nothing, intended for visual clue and for logging / debugging
*/
static const BarRule barrules[] = {
/* monitor bar alignment widthfunc drawfunc clickfunc hoverfunc name */
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, hover_tags, "tags" },
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, NULL, "layout" },
{ statusmon, 0, BAR_ALIGN_RIGHT, width_status2d, draw_status2d, click_status2d, NULL, "status2d" },
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, NULL, "wintitle" },
}; };
/* layout(s) */ /* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */ static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
1; /* 1 means respect size hints in tiled resizals */ static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const int lockfullscreen =
1; /* 1 will force focus on the fullscreen window */
#define FORCE_VSPLIT \
1 /* nrowgrid layout: force two clients to always split vertically */
#include "vanitygaps.c"
static const Layout layouts[] = { static const Layout layouts[] = {
/* symbol arrange function */ /* symbol arrange function */
{"[]", tile}, /* first entry is default */ { "[]=", tile }, /* first entry is default */
{"//", NULL}, /* no layout function means floating behavior */ { "><>", NULL }, /* no layout function means floating behavior */
{"[@]", spiral}, {"[\\]", dwindle}, { "[M]", monocle },
{"[M]", monocle}, {"|M|", centeredmaster}, { ":::", gaplessgrid },
{NULL, NULL},
}; };
/* key definitions */ /* key definitions */
#define MODKEY Mod4Mask #define MODKEY Mod1Mask
#define TAGKEYS(KEY, TAG) \ #define TAGKEYS(KEY,TAG) \
{MODKEY, KEY, view, {.ui = 1 << TAG}}, \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{MODKEY | ControlMask, KEY, toggleview, {.ui = 1 << TAG}}, \ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{MODKEY | ShiftMask, KEY, tag, {.ui = 1 << TAG}}, \ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{MODKEY | ControlMask | ShiftMask, KEY, toggletag, {.ui = 1 << TAG}}, { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) \ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
{ \
.v = (const char *[]) { "/bin/sh", "-c", cmd, NULL } \
}
/* commands */ /* commands */
static const char *btncmd[] = {"rofi", "-show", "drun", NULL}; static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = {
"dmenu_run",
"-m", dmenumon,
"-fn", dmenufont,
"-nb", normbgcolor,
"-nf", normfgcolor,
"-sb", selbgcolor,
"-sf", selfgcolor,
NULL
};
static const char *termcmd[] = { "st", NULL };
static const Key keys[] = { static const Key keys[] = {
/* modifier key function argument */ /* modifier key function argument */
{MODKEY, XK_b, togglebar, {0}}, { MODKEY, XK_p, spawn, {.v = dmenucmd } },
{MODKEY, XK_j, focusstack, {.i = +1}}, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{MODKEY, XK_k, focusstack, {.i = -1}}, { MODKEY, XK_b, togglebar, {0} },
{MODKEY, XK_i, incnmaster, {.i = +1}}, { MODKEY, XK_j, focusstack, {.i = +1 } },
{MODKEY, XK_d, incnmaster, {.i = -1}}, { MODKEY, XK_k, focusstack, {.i = -1 } },
{MODKEY, XK_h, setmfact, {.f = -0.05}}, { MODKEY, XK_i, incnmaster, {.i = +1 } },
{MODKEY, XK_l, setmfact, {.f = +0.05}}, { MODKEY, XK_d, incnmaster, {.i = -1 } },
{MODKEY | ShiftMask, XK_h, setcfact, {.f = +0.25}}, { MODKEY, XK_h, setmfact, {.f = -0.05} },
{MODKEY | ShiftMask, XK_l, setcfact, {.f = -0.25}}, { MODKEY, XK_l, setmfact, {.f = +0.05} },
{MODKEY | ShiftMask, XK_o, setcfact, {.f = 0.00}}, { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } },
{MODKEY, XK_Return, zoom, {0}}, { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } },
{MODKEY | Mod4Mask, XK_u, incrgaps, {.i = +1}}, { MODKEY, XK_Return, zoom, {0} },
{MODKEY | Mod4Mask | ShiftMask, XK_u, incrgaps, {.i = -1}}, { MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } },
{MODKEY | Mod4Mask, XK_i, incrigaps, {.i = +1}}, { MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_i, incrigaps, {.i = -1}}, { MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } },
{MODKEY | Mod4Mask, XK_o, incrogaps, {.i = +1}}, { MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_o, incrogaps, {.i = -1}}, { MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } },
{MODKEY | Mod4Mask, XK_6, incrihgaps, {.i = +1}}, { MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_6, incrihgaps, {.i = -1}}, { MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } },
{MODKEY | Mod4Mask, XK_7, incrivgaps, {.i = +1}}, { MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_7, incrivgaps, {.i = -1}}, { MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } },
{MODKEY | Mod4Mask, XK_8, incrohgaps, {.i = +1}}, { MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_8, incrohgaps, {.i = -1}}, { MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } },
{MODKEY | Mod4Mask, XK_9, incrovgaps, {.i = +1}}, { MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_9, incrovgaps, {.i = -1}}, { MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } },
{MODKEY | Mod4Mask, XK_0, togglegaps, {0}}, { MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_0, defaultgaps, {0}}, { MODKEY|Mod4Mask, XK_0, togglegaps, {0} },
{MODKEY, XK_Tab, view, {0}}, { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} },
{MODKEY | ShiftMask, XK_c, killclient, {0}}, { MODKEY, XK_Tab, view, {0} },
{MODKEY, XK_t, setlayout, {.v = &layouts[0]}}, { MODKEY|ShiftMask, XK_c, killclient, {0} },
{MODKEY, XK_f, setlayout, {.v = &layouts[1]}}, { MODKEY|ShiftMask, XK_q, quit, {0} },
{MODKEY, XK_m, setlayout, {.v = &layouts[2]}}, { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} },
{MODKEY | ControlMask, XK_comma, cyclelayout, {.i = -1}}, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{MODKEY | ControlMask, XK_period, cyclelayout, {.i = +1}}, { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
{MODKEY, XK_space, setlayout, {0}}, { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
{MODKEY | ShiftMask, XK_space, togglefloating, {0}}, { MODKEY, XK_space, setlayout, {0} },
{MODKEY | ShiftMask, XK_f, togglefullscr, {0}}, { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
{MODKEY, XK_0, view, {.ui = ~0}}, { MODKEY, XK_y, togglefullscreen, {0} },
{MODKEY | ShiftMask, XK_0, tag, {.ui = ~0}}, { MODKEY|ShiftMask, XK_f, fullscreen, {0} },
{MODKEY, XK_comma, focusmon, {.i = -1}}, { MODKEY, XK_0, view, {.ui = ~0 } },
{MODKEY, XK_period, focusmon, {.i = +1}}, { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{MODKEY | ShiftMask, XK_comma, tagmon, {.i = -1}}, { MODKEY, XK_comma, focusmon, {.i = -1 } },
{MODKEY | ShiftMask, XK_period, tagmon, {.i = +1}}, { MODKEY, XK_period, focusmon, {.i = +1 } },
{MODKEY | ShiftMask, XK_b, togglescratch, {.ui = 0}}, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{MODKEY | ShiftMask, XK_v, togglescratch, {.ui = 1}}, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
TAGKEYS(XK_1, 0) TAGKEYS(XK_2, 1) TAGKEYS(XK_3, 2) TAGKEYS(XK_4, 3) TAGKEYS( XK_1, 0)
TAGKEYS(XK_5, 4) TAGKEYS(XK_6, 5) TAGKEYS( XK_2, 1)
TAGKEYS(XK_7, 6){MODKEY | ShiftMask, XK_q, quit, {0}}, TAGKEYS( XK_3, 2)
TAGKEYS( XK_4, 3)
TAGKEYS( XK_5, 4)
TAGKEYS( XK_6, 5)
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
}; };
/* button definitions */ /* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
* ClkClientWin, or ClkRootWin */
static const Button buttons[] = { static const Button buttons[] = {
/* click event mask button function argument */ /* click event mask button function argument */
{ClkButton, 0, Button1, spawn, {.v = btncmd}}, { ClkLtSymbol, 0, Button1, setlayout, {0} },
{ClkLtSymbol, 0, Button1, setlayout, {0}}, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]}}, { ClkWinTitle, 0, Button2, zoom, {0} },
{ClkStatusText, 0, Button1, spawn, {.v = statuscmd}}, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ClkStatusText, 0, Button2, spawn, {.v = statuscmd}}, /* placemouse options, choose which feels more natural:
{ClkStatusText, 0, Button3, spawn, {.v = statuscmd}}, * 0 - tiled position is relative to mouse cursor
{ClkClientWin, MODKEY, Button1, movemouse, {0}}, * 1 - tiled postiion is relative to window center
{ClkClientWin, MODKEY, Button2, togglefloating, {0}}, * 2 - mouse pointer warps to window center
{ClkClientWin, MODKEY, Button3, resizemouse, {0}}, *
{ClkTagBar, 0, Button1, view, {0}}, * The moveorplace uses movemouse or placemouse depending on the floating state
{ClkTagBar, 0, Button3, toggleview, {0}}, * of the selected client. Set up individual keybindings for the two if you want
{ClkTagBar, MODKEY, Button1, tag, {0}}, * to control these separately (i.e. to retain the feature to move a tiled window
{ClkTagBar, MODKEY, Button3, toggletag, {0}}, * into a floating position).
*/
{ ClkClientWin, MODKEY, Button1, moveorplace, {.i = 1} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
}; };

401
config.h
View File

@ -1,249 +1,238 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
/* appearance */ /* appearance */
#include <X11/XF86keysym.h>
static const unsigned int borderpx = 2; /* border pixel of windows */ static const unsigned int borderpx = 2; /* border pixel of windows */
static const int user_bh = 27; /* 0 means that dwm will calculate bar height, >= static const unsigned int snap = 32; /* snap pixel */
1 means dwm will user_bh as bar height */
static const int swallowfloating =
0; /* 1 means swallow floating windows by default */
static const unsigned int snap = 1; /* snap pixel */
static const unsigned int gappih = 7; /* horiz inner gap between windows */ static const unsigned int gappih = 7; /* horiz inner gap between windows */
static const unsigned int gappiv = 7; /* vert inner gap between windows */ static const unsigned int gappiv = 7; /* vert inner gap between windows */
static const unsigned int gappoh = static const unsigned int gappoh = 7; /* horiz outer gap between windows and screen edge */
7; /* horiz outer gap between windows and screen edge */ static const unsigned int gappov = 7; /* vert outer gap between windows and screen edge */
static const unsigned int gappov = static const int smartgaps_fact = 1; /* gap factor when there is only one client; 0 = no gaps, 3 = 3x outer gaps */
7; /* vert outer gap between windows and screen edge */
static int smartgaps =
0; /* 1 means no outer gap when there is only one window */
static const int showbar = 1; /* 0 means no bar */ static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */ static const int topbar = 1; /* 0 means bottom bar */
static const int horizpadbar = 10; /* horizontal padding for statusbar */ static const int bar_height = 37; /* 0 means derive from font, >= 1 explicit height */
static const int vertpadbar = 10; /* vertical padding for statusbar */ /* Status is to be shown on: -1 (all monitors), 0 (a specific monitor by index), 'A' (active monitor) */
static const int vertpad = 0; /* vertical padding of bar */ static const int statusmon = 'A';
static const int sidepad = 0; /* horizontal padding of bar */ static const unsigned int ulinepad = 3; /* horizontal padding between the underline and tag */
static const unsigned int systraypinning = static const unsigned int ulinestroke = 3; /* thickness / height of the underline */
0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor static const unsigned int ulinevoffset = 0; /* how far above the bottom of the bar the line should appear */
X */ static const int ulineall = 0; /* 1 to show underline on all tags, 0 for just the active ones */
static const unsigned int systrayonleft =
0; /* 0: systray in the right corner, >0: systray on left of status text */
static const unsigned int systrayspacing = 2; /* systray spacing */
static const int systraypinningfailfirst = /* Indicators: see patch/bar_indicators.h for options */
1; /* 1: if pinning fails, display systray on the first monitor, False: static int tagindicatortype = INDICATOR_NONE;
display systray on the last monitor*/ static int tiledindicatortype = INDICATOR_NONE;
static const unsigned int systrayiconsize = 20; /* systray icon size in px */ static int floatindicatortype = INDICATOR_NONE;
static const int showsystray = 1; /* 0 means no systray */
static const char *fonts[] = { static const char *fonts[] = {
"Iosevka Nerd Font:size=12:style=Regular", "Iosevka Nerd Font:size=12:style=Regular",
"Noto Color Emoji:size=12:antialias=true:autohint=true", "Noto Color Emoji:size=12:antialias=true:autohint=true",
"Material Design Icons Desktop:size=11"}; "Material Design Icons Desktop:size=11"};
static const char dmenufont[] = "Iosevka Nerd Font:size=12"; static char c000000[] = "#000000"; // placeholder value
static const char col_back[] = "#010101";
static const char col_gray1[] = "#212126";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#dbdfdf";
static const char col_blue[] = "#808fbe";
static const char col_orange[] = "#eaac79";
static const char col_red[] = "#c15a5e";
static const char col_green[] = "#8fa176";
static const char col_cyan[] = "#8cb5af";
static const char col_yellow[] = "#d8b170";
static const char col_magenta[] = "#b183ba";
static const char *colors[][3] = { static char normfgcolor[] = "#bbbbbb";
/* fg bg border */ static char normbgcolor[] = "#010101";
[SchemeNorm] = {col_gray3, col_back, col_gray1}, static char normbordercolor[] = "#212126";
[SchemeBtn] = {col_blue, col_gray1, col_gray1}, static char normfloatcolor[] = "#212126";
[SchemeLt] = {col_gray4, col_back, col_gray1},
[SchemeSel] = {col_gray4, col_blue, col_gray2}, static char selfgcolor[] = "#dbdbdf";
}; static char selbgcolor[] = "#bbbbbb";
static const char *tagsel[][2] = { static char selbordercolor[] = "#444444";
{col_green, col_back}, {col_red, col_back}, {col_yellow, col_back}, static char selfloatcolor[] = "#444444";
{col_blue, col_back}, {col_magenta, col_back}, {col_cyan, col_back},
static char titlenormfgcolor[] = "#bbbbbb";
static char titlenormbgcolor[] = "#010101";
static char titlenormbordercolor[] = "#212126";
static char titlenormfloatcolor[] = "#212126";
static char titleselfgcolor[] = "#bbbbbb";
static char titleselbgcolor[] = "#010101";
static char titleselbordercolor[] = "#212126";
static char titleselfloatcolor[] = "#212126";
static char tagsnormfgcolor[] = "#dbdbdf";
static char tagsnormbgcolor[] = "#010101";
static char tagsnormbordercolor[] = "#dbdbdf";
static char tagsnormfloatcolor[] = "#dbdbdf";
static char tagsselfgcolor[] = "#656565";
static char tagsselbgcolor[] = "#010101";
static char tagsselbordercolor[] = "#656565";
static char tagsselfloatcolor[] = "#656565";
static char hidnormfgcolor[] = "#005577";
static char hidselfgcolor[] = "#227799";
static char hidnormbgcolor[] = "#222222";
static char hidselbgcolor[] = "#222222";
static char urgfgcolor[] = "#bbbbbb";
static char urgbgcolor[] = "#222222";
static char urgbordercolor[] = "#ff0000";
static char urgfloatcolor[] = "#db8fd9";
static char *colors[][ColCount] = {
/* fg bg border float */
[SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normfloatcolor },
[SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selfloatcolor },
[SchemeTitleNorm] = { titlenormfgcolor, titlenormbgcolor, titlenormbordercolor, titlenormfloatcolor },
[SchemeTitleSel] = { titleselfgcolor, titleselbgcolor, titleselbordercolor, titleselfloatcolor },
[SchemeTagsNorm] = { tagsnormfgcolor, tagsnormbgcolor, tagsnormbordercolor, tagsnormfloatcolor },
[SchemeTagsSel] = { tagsselfgcolor, tagsselbgcolor, tagsselbordercolor, tagsselfloatcolor },
[SchemeHidNorm] = { hidnormfgcolor, hidnormbgcolor, c000000, c000000 },
[SchemeHidSel] = { hidselfgcolor, hidselbgcolor, c000000, c000000 },
[SchemeUrg] = { urgfgcolor, urgbgcolor, urgbordercolor, urgfloatcolor },
}; };
typedef struct { static char *tagicons[][NUMTAGS] =
const char *name; {
const void *cmd; [DEFAULT_TAGS] = { " cmd ", " www ", " dev ", " chat ", " sys ", " med " },
} Sp; [ALT_TAGS_DECORATION] = { "[cmd]", "[www]", "[dev]", "[chat]", "[sys]", "[med]" },
const char *terminal[] = {"st", NULL};
const char *scrot[] = {"screenshot_fullscreen", NULL};
const char *scrots[] = {"screenshot_select", NULL};
/*const char *launch[] = {"dmenu_run", "-h '37'", "-nf '#bbbbbb'", "-nb '#000000'", "-sf '#dbdfdf'", "-sb '#000000'", "-p '󱎰 |Search:'", "-fn 'Iosevka Nerd Font:size=12:style=regular," ,NULL};*/
const char *launch[] = {"run", NULL};
static Sp scratchpads[] = {
/* name cmd */
{"launch", launch},
{"terminal", terminal},
{"scrot", scrot},
{"scrots", scrots},
}; };
#include <X11/XF86keysym.h>
/* Add somewhere in your constants definition section */
static const char *upvol[] = { "pactl", "set-sink-volume", "0", "+5%", NULL };
static const char *downvol[] = { "pactl", "set-sink-volume", "0", "-5%", NULL };
static const char *mutevol[] = { "pactl", "set-sink-mute", "0", "toggle", NULL };
static const StatusCmd statuscmds[] = {
{"~/.local/bin/statusbar/power", 1},
{"~/.local/bin/statusbar/wifi", 2},
{"~/.local/bin/statusbar/calendar", 3},
{"~/.local/bin/statusbar/battery", 4},
{"~/.local/bin/statusbar/sound", 5},
{"~/.local/bin/statusbar/mindash", 6},
{"~/.local/bin/statusbar/mincalendar", 7},
{"~/.local/bin/statusbar/notifications", 8},
};
static const char *statuscmd[] = {"/bin/bash", "-c", NULL, NULL};
/* tagging */
static char *tags[] = {"cmd", "www", "dev", "chat", "sys", "med"};
static char *alttags[] = {"[cmd]", "[www]", "[dev]",
"[chat]", "[sys]", "[med]"};
static const unsigned int ulinepad =
2; /* horizontal padding between the underline and tag */
static const unsigned int ulinestroke =
2; /* thickness / height of the underline */
static const unsigned int ulinevoffset =
0; /* how far above the bottom of the bar the line should appear */
static const int ulineall =
0; /* 1 to show underline on all tags, 0 for just the active ones */
static const Rule rules[] = { static const Rule rules[] = {
/* xprop(1): RULE(.wintype = WTYPE "DIALOG", .isfloating = 1)
* WM_CLASS(STRING) = instance, class RULE(.wintype = WTYPE "UTILITY", .isfloating = 1)
* WM_NAME(STRING) = title RULE(.wintype = WTYPE "TOOLBAR", .isfloating = 1)
*/ RULE(.wintype = WTYPE "SPLASH", .isfloating = 1)
/* class instance title tags mask isfloating isterminal RULE(.class = "Gimp", .tags = 1 << 4)
noswallow monitor */ RULE(.class = "Firefox", .tags = 1 << 7)
{"Gimp", NULL, NULL, 0, 1, 0, 0, -1}, };
{"Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1},
{"st-256color", NULL, NULL, 0, 0, 1, 0, -1}, static const BarRule barrules[] = {
{NULL, NULL, "Event Tester", 0, 0, 0, 1, -1}, /* xev */ /* monitor bar alignment widthfunc drawfunc clickfunc hoverfunc name */
{NULL, "spterm", NULL, SPTAG(0), 1, 1, 0, -1}, { -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, hover_tags, "tags" },
{NULL, "spmpd", NULL, SPTAG(1), 1, 1, 0, -1}, { -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, NULL, "layout" },
{ statusmon, 0, BAR_ALIGN_RIGHT, width_status2d, draw_status2d, click_status2d, NULL, "status2d" },
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, NULL, "wintitle" },
}; };
/* layout(s) */ /* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */ static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
1; /* 1 means respect size hints in tiled resizals */ static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const int lockfullscreen =
1; /* 1 will force focus on the fullscreen window */
#define FORCE_VSPLIT \
1 /* nrowgrid layout: force two clients to always split vertically */
#include "vanitygaps.c"
/*#include "layout_grid.h"
#include "layout_grid.c"*/
static const Layout layouts[] = { static const Layout layouts[] = {
/* symbol arrange function */ /* symbol arrange function */
{"[]", tile}, /* first entry is default */ { "[]", tile }, /* first entry is default */
{"{}", spiral}, { "//", NULL }, /* no layout function means floating behavior */
{"//", NULL}, /* no layout function means floating behavior */ { "[M]", monocle },
/* {"[@]", spiral}, {"[\\]", dwindle},*/ { "#", gaplessgrid },
{"[M]", monocle}, {"|M|", centeredmaster},
{NULL, NULL},
}; };
/* key definitions */ /* key definitions */
#define MODKEY Mod4Mask #define MODKEY Mod4Mask
#define TAGKEYS(KEY, TAG) \ #define TAGKEYS(KEY,TAG) \
{MODKEY, KEY, view, {.ui = 1 << TAG}}, \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{MODKEY | ControlMask, KEY, toggleview, {.ui = 1 << TAG}}, \ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{MODKEY | ShiftMask, KEY, tag, {.ui = 1 << TAG}}, \ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{MODKEY | ControlMask | ShiftMask, KEY, toggletag, {.ui = 1 << TAG}}, { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) \ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
{ \
.v = (const char *[]) { "/bin/sh", "-c", cmd, NULL } \
}
/* commands */ /* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = {
"dmenu_run",
"-h", "37",
"-nf", "#bbbbbb",
"-nb", "#010101",
"-sf", "#dbdfdf",
"-sb", "#010101",
"-p", " | Search:",
"-fn", "Iosevka Nerd Font:size=12:style=large",
NULL
};
static const char *termcmd[] = { "st", NULL };
static const char *screenshot_selectcmd[] = { "screenshot_select", NULL };
static const char *screenshotcmd[] = { "screenshot_fullscreen", NULL };
#include <X11/XF86keysym.h>
static const Key keys[] = { static const Key keys[] = {
/* modifier key function argument */ /* modifier key function argument */
{MODKEY, XK_Print, spawn, {.v = scrot} }, { MODKEY, XK_d, spawn, {.v = dmenucmd } },
{MODKEY | ShiftMask, XK_Print, spawn, {.v = scrots } }, { MODKEY, XK_e, spawn, {.v = termcmd } },
{MODKEY, XK_e, spawn, {.v = terminal } }, { MODKEY, XK_Print, spawn, {.v = screenshotcmd} },
{MODKEY, XK_d, spawn, {.v = launch } }, { MODKEY|ShiftMask, XK_Print, spawn, {.v = screenshot_selectcmd } },
{MODKEY, XK_b, togglebar, {0}}, { MODKEY, XK_b, togglebar, {0} },
{ 0, XK_F11, spawn, {.v = downvol } }, { MODKEY, XK_j, focusstack, {.i = +1 } },
{ 0, XK_F10, spawn, {.v = mutevol } }, { MODKEY, XK_k, focusstack, {.i = -1 } },
{ 0, XK_F12, spawn, {.v = upvol } }, { MODKEY|ShiftMask, XK_i, incnmaster, {.i = +1 } },
/*boring stuff*/ { MODKEY|ShiftMask, XK_d, incnmaster, {.i = -1 } },
{MODKEY, XK_j, focusstack, {.i = +1}}, { MODKEY, XK_h, setmfact, {.f = -0.05} },
{MODKEY, XK_k, focusstack, {.i = -1}}, { MODKEY, XK_l, setmfact, {.f = +0.05} },
{MODKEY, XK_i, incnmaster, {.i = +1}}, { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } },
{MODKEY, XK_h, setmfact, {.f = -0.05}}, { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } },
{MODKEY, XK_l, setmfact, {.f = +0.05}}, { MODKEY, XK_Return, zoom, {0} },
{MODKEY | ShiftMask, XK_h, setcfact, {.f = +0.25}}, { MODKEY|Mod1Mask, XK_u, incrgaps, {.i = +1 } },
{MODKEY | ShiftMask, XK_l, setcfact, {.f = -0.25}}, { MODKEY|Mod1Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } },
{MODKEY | ShiftMask, XK_o, setcfact, {.f = 0.00}}, { MODKEY|Mod1Mask, XK_i, incrigaps, {.i = +1 } },
{MODKEY, XK_Return, zoom, {0}}, { MODKEY|Mod1Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } },
{MODKEY | Mod4Mask, XK_u, incrgaps, {.i = +1}}, { MODKEY|Mod1Mask, XK_o, incrogaps, {.i = +1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_u, incrgaps, {.i = -1}}, { MODKEY|Mod1Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } },
{MODKEY | Mod4Mask, XK_i, incrigaps, {.i = +1}}, { MODKEY|Mod1Mask, XK_6, incrihgaps, {.i = +1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_i, incrigaps, {.i = -1}}, { MODKEY|Mod1Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } },
{MODKEY | Mod4Mask, XK_o, incrogaps, {.i = +1}}, { MODKEY|Mod1Mask, XK_7, incrivgaps, {.i = +1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_o, incrogaps, {.i = -1}}, { MODKEY|Mod1Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } },
{MODKEY | Mod4Mask, XK_6, incrihgaps, {.i = +1}}, { MODKEY|Mod1Mask, XK_8, incrohgaps, {.i = +1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_6, incrihgaps, {.i = -1}}, { MODKEY|Mod1Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } },
{MODKEY | Mod4Mask, XK_7, incrivgaps, {.i = +1}}, { MODKEY|Mod1Mask, XK_9, incrovgaps, {.i = +1 } },
{MODKEY | Mod4Mask | ShiftMask, XK_7, incrivgaps, {.i = -1}}, { MODKEY|Mod1Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } },
{MODKEY | Mod4Mask, XK_8, incrohgaps, {.i = +1}}, { MODKEY|Mod1Mask, XK_0, togglegaps, {0} },
{MODKEY | Mod4Mask | ShiftMask, XK_8, incrohgaps, {.i = -1}}, { MODKEY|Mod1Mask|ShiftMask, XK_0, defaultgaps, {0} },
{MODKEY | Mod4Mask, XK_9, incrovgaps, {.i = +1}}, { MODKEY, XK_Tab, view, {0} },
{MODKEY | Mod4Mask | ShiftMask, XK_9, incrovgaps, {.i = -1}}, { MODKEY, XK_w, killclient, {0} },
{MODKEY | Mod4Mask, XK_0, togglegaps, {0}}, { MODKEY|ShiftMask, XK_q, quit, {0} },
{MODKEY | Mod4Mask | ShiftMask, XK_0, defaultgaps, {0}}, { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} },
{MODKEY, XK_Tab, view, {0}}, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{MODKEY, XK_w, killclient, {0}}, { MODKEY, XK_z, setlayout, {.v = &layouts[1]} },
{MODKEY, XK_t, setlayout, {.v = &layouts[0]}}, { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
{MODKEY | ShiftMask, XK_f, setlayout, {.v = &layouts[1]}}, { MODKEY, XK_x, setlayout, {.v = &layouts[3]} },
{MODKEY, XK_m, setlayout, {.v = &layouts[2]}}, { MODKEY, XK_space, setlayout, {0} },
{MODKEY | ControlMask, XK_comma, cyclelayout, {.i = -1}}, { MODKEY, XK_s, togglefloating, {0} },
{MODKEY | ControlMask, XK_period, cyclelayout, {.i = +1}}, { MODKEY, XK_f, togglefullscreen, {0} },
{MODKEY, XK_space, setlayout, {0}}, { MODKEY|ShiftMask, XK_f, fullscreen, {0} },
{MODKEY, XK_s, togglefloating, {0}}, { MODKEY, XK_0, view, {.ui = ~0 } },
{MODKEY, XK_f, togglefullscr, {0}}, { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{MODKEY, XK_0, view, {.ui = ~0}}, { MODKEY, XK_comma, focusmon, {.i = -1 } },
{MODKEY | ShiftMask, XK_0, tag, {.ui = ~0}}, { MODKEY, XK_period, focusmon, {.i = +1 } },
{MODKEY, XK_comma, focusmon, {.i = -1}}, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{MODKEY, XK_period, focusmon, {.i = +1}}, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
{MODKEY | ShiftMask, XK_comma, tagmon, {.i = -1}}, TAGKEYS( XK_1, 0)
{MODKEY | ShiftMask, XK_period, tagmon, {.i = +1}}, TAGKEYS( XK_2, 1)
{MODKEY | ShiftMask, XK_b, togglescratch, {.ui = 0}}, TAGKEYS( XK_3, 2)
{MODKEY | ShiftMask, XK_v, togglescratch, {.ui = 1}}, TAGKEYS( XK_4, 3)
TAGKEYS(XK_1, 0) TAGKEYS(XK_2, 1) TAGKEYS(XK_3, 2) TAGKEYS(XK_4, 3) TAGKEYS( XK_5, 4)
TAGKEYS(XK_5, 4) TAGKEYS(XK_6, 5) TAGKEYS( XK_6, 5)
TAGKEYS(XK_7, 6){MODKEY | ShiftMask, XK_q, quit, {0}},
}; };
/* button definitions */ /* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
* ClkClientWin, or ClkRootWin */
static const Button buttons[] = { static const Button buttons[] = {
/* click event mask button function argument */ /* click event mask button function argument */
{ClkButton, 0, Button1, spawn, {.v = launch}}, { ClkLtSymbol, 0, Button1, setlayout, {0} },
{ClkLtSymbol, 0, Button1, setlayout, {0}}, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]}}, { ClkWinTitle, 0, Button2, zoom, {0} },
{ClkStatusText, 0, Button1, spawn, {.v = statuscmd}}, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ClkStatusText, 0, Button2, spawn, {.v = statuscmd}}, { ClkClientWin, MODKEY, Button1, moveorplace, {.i = 1} },
{ClkStatusText, 0, Button3, spawn, {.v = statuscmd}}, { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ClkClientWin, MODKEY, Button1, movemouse, {0}}, { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ClkClientWin, MODKEY, Button2, togglefloating, {0}}, { ClkTagBar, 0, Button1, view, {0} },
{ClkClientWin, MODKEY, Button3, resizemouse, {0}}, { ClkTagBar, 0, Button3, toggleview, {0} },
{ClkTagBar, 0, Button1, view, {0}}, { ClkTagBar, MODKEY, Button1, tag, {0} },
{ClkTagBar, 0, Button3, toggleview, {0}}, { ClkTagBar, MODKEY, Button3, toggletag, {0} },
{ClkTagBar, MODKEY, Button1, tag, {0}},
{ClkTagBar, MODKEY, Button3, toggletag, {0}},
}; };

View File

@ -1,5 +1,5 @@
# dwm version # dwm version
VERSION = 6.3 VERSION = 6.4
# Customize below to fit your system # Customize below to fit your system
@ -10,6 +10,10 @@ MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib X11LIB = /usr/X11R6/lib
# FreeBSD (uncomment)
#X11INC = /usr/local/include
#X11LIB = /usr/local/lib
# Xinerama, comment if you don't want it # Xinerama, comment if you don't want it
XINERAMALIBS = -lXinerama XINERAMALIBS = -lXinerama
XINERAMAFLAGS = -DXINERAMA XINERAMAFLAGS = -DXINERAMA
@ -17,18 +21,48 @@ XINERAMAFLAGS = -DXINERAMA
# freetype # freetype
FREETYPELIBS = -lfontconfig -lXft FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2 FREETYPEINC = /usr/include/freetype2
# FreeBSD (uncomment)
#FREETYPEINC = /usr/local/include/freetype2
# OpenBSD (uncomment) # OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2 #FREETYPEINC = ${X11INC}/freetype2
#MANPREFIX = ${PREFIX}/man # OpenBSD - Uncomment this for the swallow patch / SWALLOW_PATCH
#KVMLIB = -lkvm
# Uncomment this for the alpha patch and the winicon patch (BAR_ALPHA_PATCH, BAR_WINICON_PATCH)
XRENDER = -lXrender
# Uncomment this for the mdpcontrol patch / MDPCONTROL_PATCH
#MPDCLIENT = -lmpdclient
# Uncomment for the pango patch / BAR_PANGO_PATCH
#PANGOINC = `pkg-config --cflags xft pango pangoxft`
#PANGOLIB = `pkg-config --libs xft pango pangoxft`
# Uncomment for the ipc patch / IPC_PATCH
#YAJLLIBS = -lyajl
#YAJLINC = -I/usr/include/yajl
# Uncomment this for the rounded corners patch / ROUNDED_CORNERS_PATCH
#XEXTLIB = -lXext
# Uncomment this for the swallow patch / SWALLOW_PATCH
#XCBLIBS = -lX11-xcb -lxcb -lxcb-res
# This is needed for the winicon and tagpreview patches / BAR_WINICON_PATCH / BAR_TAGPREVIEW_PATCH
#IMLIB2LIBS = -lImlib2
# Uncomment for the bidi patch
#BDINC = `pkg-config --cflags fribidi`
#BDLIBS = `pkg-config --libs fribidi`
# includes and libs # includes and libs
INCS = -I${X11INC} -I${FREETYPEINC} INCS = -I${X11INC} -I${FREETYPEINC} ${YAJLINC} ${PANGOINC} ${BDINC}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB} LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${KVMLIB} ${PANGOLIB} ${YAJLLIBS} ${IMLIB2LIBS} $(BDLIBS)
# flags # flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} CFLAGS = -std=c99 -pedantic -Wall -Wno-unused-function -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
LDFLAGS = ${LIBS} LDFLAGS = ${LIBS}
# Solaris # Solaris

108
drw.c
View File

@ -8,6 +8,7 @@
#include "drw.h" #include "drw.h"
#include "util.h" #include "util.h"
#define UTF_INVALID 0xFFFD #define UTF_INVALID 0xFFFD
#define UTF_SIZ 4 #define UTF_SIZ 4
@ -16,6 +17,7 @@ static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
static long static long
utf8decodebyte(const char c, size_t *i) utf8decodebyte(const char c, size_t *i)
{ {
@ -70,6 +72,7 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
drw->root = root; drw->root = root;
drw->w = w; drw->w = w;
drw->h = h; drw->h = h;
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
drw->gc = XCreateGC(dpy, root, 0, NULL); drw->gc = XCreateGC(dpy, root, 0, NULL);
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
@ -133,6 +136,7 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
die("no font specified."); die("no font specified.");
} }
font = ecalloc(1, sizeof(Fnt)); font = ecalloc(1, sizeof(Fnt));
font->xfont = xfont; font->xfont = xfont;
font->pattern = pattern; font->pattern = pattern;
@ -169,7 +173,6 @@ drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
} }
} }
return (drw->fonts = ret); return (drw->fonts = ret);
} }
void void
@ -182,8 +185,11 @@ drw_fontset_free(Fnt *font)
} }
void void
drw_clr_create(Drw *drw, Clr *dest, const char *clrname) drw_clr_create(
{ Drw *drw,
Clr *dest,
const char *clrname
) {
if (!drw || !dest || !clrname) if (!drw || !dest || !clrname)
return; return;
@ -198,8 +204,11 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
/* Wrapper to create color schemes. The caller has to call free(3) on the /* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */ * returned color scheme when done using it. */
Clr * Clr *
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) drw_scm_create(
{ Drw *drw,
char *clrnames[],
size_t clrcount
) {
size_t i; size_t i;
Clr *ret; Clr *ret;
@ -226,6 +235,7 @@ drw_setscheme(Drw *drw, Clr *scm)
drw->scheme = scm; drw->scheme = scm;
} }
void void
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
{ {
@ -239,12 +249,14 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
} }
int int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup)
{ {
int i, ty, ellipsis_x = 0; char buf[1024];
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; int ty;
unsigned int ew;
XftDraw *d = NULL; XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont; Fnt *usedfont, *curfont, *nextfont;
size_t i, len;
int utf8strlen, utf8charlen, render = x || y || w || h; int utf8strlen, utf8charlen, render = x || y || w || h;
long utf8codepoint = 0; long utf8codepoint = 0;
const char *utf8str; const char *utf8str;
@ -252,17 +264,13 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
FcPattern *fcpattern; FcPattern *fcpattern;
FcPattern *match; FcPattern *match;
XftResult result; XftResult result;
int charexists = 0, overflow = 0; int charexists = 0;
/* keep track of a couple codepoints for which we have no match. */
enum { nomatches_len = 64 };
static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches;
static unsigned int ellipsis_width = 0;
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
return 0; return 0;
if (!render) { if (!render) {
w = invert ? invert : ~invert; w = ~w;
} else { } else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
@ -274,10 +282,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
} }
usedfont = drw->fonts; usedfont = drw->fonts;
if (!ellipsis_width && render)
ellipsis_width = drw_fontset_getwidth(drw, "...");
while (1) { while (1) {
ew = ellipsis_len = utf8strlen = 0; utf8strlen = 0;
utf8str = text; utf8str = text;
nextfont = NULL; nextfont = NULL;
while (*text) { while (*text) {
@ -285,27 +291,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
for (curfont = drw->fonts; curfont; curfont = curfont->next) { for (curfont = drw->fonts; curfont; curfont = curfont->next) {
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) { if (charexists) {
drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); if (curfont == usedfont) {
if (ew + ellipsis_width <= w) {
/* keep track where the ellipsis still fits */
ellipsis_x = x + ew;
ellipsis_w = w - ew;
ellipsis_len = utf8strlen;
}
if (ew + tmpw > w) {
overflow = 1;
/* called from drw_fontset_getwidth_clamp():
* it wants the width AFTER the overflow
*/
if (!render)
x += tmpw;
else
utf8strlen = ellipsis_len;
} else if (curfont == usedfont) {
utf8strlen += utf8charlen; utf8strlen += utf8charlen;
text += utf8charlen; text += utf8charlen;
ew += tmpw;
} else { } else {
nextfont = curfont; nextfont = curfont;
} }
@ -313,25 +301,36 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
} }
} }
if (overflow || !charexists || nextfont) if (!charexists || nextfont)
break; break;
else else
charexists = 0; charexists = 0;
} }
if (utf8strlen) { if (utf8strlen) {
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
/* shorten text if necessary */
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; drw_font_getexts(usedfont, utf8str, len, &ew, NULL))
len--;
if (len) {
memcpy(buf, utf8str, len);
buf[len] = '\0';
if (len < utf8strlen)
for (i = len; i && i > len - 3; buf[--i] = '.')
; /* NOP */
if (render) { if (render) {
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen); usedfont->xfont, x, ty, (XftChar8 *)buf, len);
} }
x += ew; x += ew;
w -= ew; w -= ew;
} }
if (render && overflow) }
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
if (!*text || overflow) { if (!*text) {
break; break;
} else if (nextfont) { } else if (nextfont) {
charexists = 0; charexists = 0;
@ -341,12 +340,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
* character must be drawn. */ * character must be drawn. */
charexists = 1; charexists = 1;
for (i = 0; i < nomatches_len; ++i) {
/* avoid calling XftFontMatch if we know we won't find a match */
if (utf8codepoint == nomatches.codepoint[i])
goto no_match;
}
fccharset = FcCharSetCreate(); fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, utf8codepoint); FcCharSetAddChar(fccharset, utf8codepoint);
@ -358,7 +351,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
fcpattern = FcPatternDuplicate(drw->fonts->pattern); fcpattern = FcPatternDuplicate(drw->fonts->pattern);
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
FcDefaultSubstitute(fcpattern); FcDefaultSubstitute(fcpattern);
@ -375,8 +367,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
curfont->next = usedfont; curfont->next = usedfont;
} else { } else {
xfont_free(usedfont); xfont_free(usedfont);
nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
no_match:
usedfont = drw->fonts; usedfont = drw->fonts;
} }
} }
@ -388,6 +378,8 @@ no_match:
return x + (render ? w : 0); return x + (render ? w : 0);
} }
void void
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
{ {
@ -399,20 +391,11 @@ drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
} }
unsigned int unsigned int
drw_fontset_getwidth(Drw *drw, const char *text) drw_fontset_getwidth(Drw *drw, const char *text, Bool markup)
{ {
if (!drw || !drw->fonts || !text) if (!drw || !drw->fonts || !text)
return 0; return 0;
return drw_text(drw, 0, 0, 0, 0, 0, text, 0); return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup);
}
unsigned int
drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
{
unsigned int tmp = 0;
if (drw && drw->fonts && text && n)
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
return MIN(n, tmp);
} }
void void
@ -452,3 +435,4 @@ drw_cur_free(Drw *drw, Cur *cursor)
XFreeCursor(drw->dpy, cursor->cursor); XFreeCursor(drw->dpy, cursor->cursor);
free(cursor); free(cursor);
} }

23
drw.h
View File

@ -1,5 +1,6 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
typedef struct { typedef struct {
Cursor cursor; Cursor cursor;
} Cur; } Cur;
@ -12,7 +13,7 @@ typedef struct Fnt {
struct Fnt *next; struct Fnt *next;
} Fnt; } Fnt;
enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ enum { ColFg, ColBg, ColBorder, ColFloat, ColCount }; /* Clr scheme index */
typedef XftColor Clr; typedef XftColor Clr;
typedef struct { typedef struct {
@ -33,14 +34,21 @@ void drw_free(Drw *drw);
/* Fnt abstraction */ /* Fnt abstraction */
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
void drw_fontset_free(Fnt* set);
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
void drw_fontset_free(Fnt* set);
unsigned int drw_fontset_getwidth(Drw *drw, const char *text, Bool markup);
/* Colorscheme abstraction */ /* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); void drw_clr_create(
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); Drw *drw,
Clr *dest,
const char *clrname
);
Clr *drw_scm_create(
Drw *drw,
char *clrnames[],
size_t clrcount
);
/* Cursor abstraction */ /* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape); Cur *drw_cur_create(Drw *drw, int shape);
@ -52,7 +60,8 @@ void drw_setscheme(Drw *drw, Clr *scm);
/* Drawing functions */ /* Drawing functions */
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup);
/* Map functions */ /* Map functions */
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);

BIN
drw.o

Binary file not shown.

BIN
dwm

Binary file not shown.

32
dwm.1
View File

@ -30,14 +30,6 @@ top left corner. The tags which are applied to one or more windows are
indicated with an empty square in the top left corner. indicated with an empty square in the top left corner.
.P .P
dwm draws a small border around windows to indicate the focus state. dwm draws a small border around windows to indicate the focus state.
.P
On start, dwm can start additional programs that may be specified in two special
shell scripts (see the FILES section below), autostart_blocking.sh and
autostart.sh. The former is executed first and dwm will wait for its
termination before starting. The latter is executed in the background before
dwm enters its handler loop.
.P
Either of these files may be omitted.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-v .B \-v
@ -100,12 +92,6 @@ Sets monocle layout.
.B Mod1\-space .B Mod1\-space
Toggles between current and previous layout. Toggles between current and previous layout.
.TP .TP
.B Mod1\-Control\-,
Cycles backwards in layout list.
.TP
.B Mod1\-Control\-.
Cycles forwards in layout list.
.TP
.B Mod1\-j .B Mod1\-j
Focus next window. Focus next window.
.TP .TP
@ -130,9 +116,6 @@ Zooms/cycles focused window to/from master area (tiled layouts only).
.B Mod1\-Shift\-c .B Mod1\-Shift\-c
Close focused window. Close focused window.
.TP .TP
.B Mod1\-Shift\-f
Toggle fullscreen for focused window.
.TP
.B Mod1\-Shift\-space .B Mod1\-Shift\-space
Toggle focused window between tiled and floating state. Toggle focused window between tiled and floating state.
.TP .TP
@ -169,21 +152,6 @@ Toggles focused window between floating and tiled state.
.TP .TP
.B Mod1\-Button3 .B Mod1\-Button3
Resize focused window while dragging. Tiled windows will be toggled to the floating state. Resize focused window while dragging. Tiled windows will be toggled to the floating state.
.SH FILES
The files containing programs to be started along with dwm are searched for in
the following directories:
.IP "1. $XDG_DATA_HOME/dwm"
.IP "2. $HOME/.local/share/dwm"
.IP "3. $HOME/.dwm"
.P
The first existing directory is scanned for any of the autostart files below.
.TP 15
autostart.sh
This file is started as a shell background process before dwm enters its handler
loop.
.TP 15
autostart_blocking.sh
This file is started before any autostart.sh; dwm waits for its termination.
.SH CUSTOMIZATION .SH CUSTOMIZATION
dwm is customized by creating a custom config.h and (re)compiling the source dwm is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple. code. This keeps it fast, secure and simple.

2449
dwm.c

File diff suppressed because it is too large Load Diff

7
dwm.desktop Normal file
View File

@ -0,0 +1,7 @@
[Desktop Entry]
Encoding=UTF-8
Name=Dwm
Comment=Dynamic window manager
Exec=dwm
Icon=dwm
Type=XSession

BIN
dwm.o

Binary file not shown.

39
patch/bar.c Normal file
View File

@ -0,0 +1,39 @@
void
barhover(XEvent *e, Bar *bar)
{
const BarRule *br;
Monitor *m = bar->mon;
XMotionEvent *ev = &e->xmotion;
BarArg barg = { 0, 0, 0, 0 };
int r;
for (r = 0; r < LENGTH(barrules); r++) {
br = &barrules[r];
if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->hoverfunc == NULL)
continue;
if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num)
continue;
if (bar->x[r] > ev->x || ev->x > bar->x[r] + bar->w[r])
continue;
barg.x = ev->x - bar->x[r];
barg.y = ev->y - bar->borderpx;
barg.w = bar->w[r];
barg.h = bar->bh - 2 * bar->borderpx;
br->hoverfunc(bar, &barg, ev);
break;
}
}
Bar *
wintobar(Window win)
{
Monitor *m;
Bar *bar;
for (m = mons; m; m = m->next)
for (bar = m->bar; bar; bar = bar->next)
if (bar->win == win)
return bar;
return NULL;
}

2
patch/bar.h Normal file
View File

@ -0,0 +1,2 @@
static void barhover(XEvent *e, Bar *bar);
static Bar *wintobar(Window win);

104
patch/bar_indicators.c Normal file
View File

@ -0,0 +1,104 @@
/* Indicator properties, you can override these in your config.h if you want. */
#ifndef TAGSINDICATOR
#define TAGSINDICATOR 1 // 0 = off, 1 = on if >1 client/view tag, 2 = always on
#endif
#ifndef TAGSPX
#define TAGSPX 5 // # pixels for tag grid boxes
#endif
#ifndef TAGSROWS
#define TAGSROWS 3 // # rows in tag grid (9 tags, e.g. 3x3)
#endif
void
drawindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert, int type)
{
int i, boxw, boxs, indn = 0;
if (!(occ & 1 << tag) || type == INDICATOR_NONE)
return;
boxs = drw->fonts->h / 9;
boxw = drw->fonts->h / 6 + 2;
if (filled == -1)
filled = m == selmon && m->sel && m->sel->tags & 1 << tag;
switch (type) {
default:
case INDICATOR_TOP_LEFT_SQUARE:
drw_rect(drw, x + boxs, y + boxs, boxw, boxw, filled, invert);
break;
case INDICATOR_TOP_LEFT_LARGER_SQUARE:
drw_rect(drw, x + boxs + 2, y + boxs+1, boxw+1, boxw+1, filled, invert);
break;
case INDICATOR_TOP_BAR:
drw_rect(drw, x + boxw, y, w - ( 2 * boxw + 1), boxw/2, filled, invert);
break;
case INDICATOR_TOP_BAR_SLIM:
drw_rect(drw, x + boxw, y, w - ( 2 * boxw + 1), 1, 0, invert);
break;
case INDICATOR_BOTTOM_BAR:
drw_rect(drw, x + boxw, y + h - boxw/2, w - ( 2 * boxw + 1), boxw/2, filled, invert);
break;
case INDICATOR_BOTTOM_BAR_SLIM:
drw_rect(drw, x + boxw, y + h - 1, w - ( 2 * boxw + 1), 1, 0, invert);
break;
case INDICATOR_BOX:
drw_rect(drw, x + boxw, y, w - 2 * boxw, h, 0, invert);
break;
case INDICATOR_BOX_WIDER:
drw_rect(drw, x + boxw/2, y, w - boxw, h, 0, invert);
break;
case INDICATOR_BOX_FULL:
drw_rect(drw, x, y, w - 2, h, 0, invert);
break;
case INDICATOR_CLIENT_DOTS:
for (c = m->clients; c; c = c->next) {
if (c->tags & (1 << tag)) {
drw_rect(drw, x, 1 + (indn * 2), m->sel == c ? 6 : 1, 1, 1, invert);
indn++;
}
if (h <= 1 + (indn * 2)) {
indn = 0;
x += 2;
}
}
break;
case INDICATOR_RIGHT_TAGS:
if (!c)
break;
for (i = 0; i < NUMTAGS; i++) {
drw_rect(drw,
( x + w - 2 - ((NUMTAGS / TAGSROWS) * TAGSPX)
- (i % (NUMTAGS/TAGSROWS)) + ((i % (NUMTAGS / TAGSROWS)) * TAGSPX)
),
( y + 2 + ((i / (NUMTAGS/TAGSROWS)) * TAGSPX)
- ((i / (NUMTAGS/TAGSROWS)))
),
TAGSPX, TAGSPX, (c->tags >> i) & 1, 0
);
}
break;
case INDICATOR_PLUS_AND_LARGER_SQUARE:
boxs += 2;
boxw += 2;
/* falls through */
case INDICATOR_PLUS_AND_SQUARE:
drw_rect(drw, x + boxs, y + boxs, boxw % 2 ? boxw : boxw + 1, boxw % 2 ? boxw : boxw + 1, filled, invert);
/* falls through */
case INDICATOR_PLUS:
if (!(boxw % 2))
boxw += 1;
drw_rect(drw, x + boxs + boxw / 2, y + boxs, 1, boxw, filled, invert); // |
drw_rect(drw, x + boxs, y + boxs + boxw / 2, boxw + 1, 1, filled, invert); //
break;
}
}
void
drawstateindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert)
{
if (c->isfloating)
drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, floatindicatortype);
else
drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, tiledindicatortype);
}

21
patch/bar_indicators.h Normal file
View File

@ -0,0 +1,21 @@
enum {
INDICATOR_NONE,
INDICATOR_TOP_LEFT_SQUARE,
INDICATOR_TOP_LEFT_LARGER_SQUARE,
INDICATOR_TOP_BAR,
INDICATOR_TOP_BAR_SLIM,
INDICATOR_BOTTOM_BAR,
INDICATOR_BOTTOM_BAR_SLIM,
INDICATOR_BOX,
INDICATOR_BOX_WIDER,
INDICATOR_BOX_FULL,
INDICATOR_CLIENT_DOTS,
INDICATOR_RIGHT_TAGS,
INDICATOR_PLUS,
INDICATOR_PLUS_AND_SQUARE,
INDICATOR_PLUS_AND_LARGER_SQUARE,
};
static void drawindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert, int type);
static void drawstateindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert);

18
patch/bar_ltsymbol.c Normal file
View File

@ -0,0 +1,18 @@
int
width_ltsymbol(Bar *bar, BarArg *a)
{
return TEXTW(bar->mon->ltsymbol);
}
int
draw_ltsymbol(Bar *bar, BarArg *a)
{
return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, bar->mon->ltsymbol, 0, False);
}
int
click_ltsymbol(Bar *bar, Arg *arg, BarArg *a)
{
return ClkLtSymbol;
}

4
patch/bar_ltsymbol.h Normal file
View File

@ -0,0 +1,4 @@
static int width_ltsymbol(Bar *bar, BarArg *a);
static int draw_ltsymbol(Bar *bar, BarArg *a);
static int click_ltsymbol(Bar *bar, Arg *arg, BarArg *a);

20
patch/bar_status.c Normal file
View File

@ -0,0 +1,20 @@
int
width_status(Bar *bar, BarArg *a)
{
return TEXTWM(stext);
}
int
draw_status(Bar *bar, BarArg *a)
{
return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, stext, 0, True);
}
int
click_status(Bar *bar, Arg *arg, BarArg *a)
{
return ClkStatusText;
}

4
patch/bar_status.h Normal file
View File

@ -0,0 +1,4 @@
static int width_status(Bar *bar, BarArg *a);
static int draw_status(Bar *bar, BarArg *a);
static int click_status(Bar *bar, Arg *arg, BarArg *a);

172
patch/bar_status2d.c Normal file
View File

@ -0,0 +1,172 @@
int
width_status2d(Bar *bar, BarArg *a)
{
int width;
width = status2dtextlength(stext);
return width ? width + lrpad : 0;
}
int
draw_status2d(Bar *bar, BarArg *a)
{
return drawstatusbar(a, stext);
}
int
click_status2d(Bar *bar, Arg *arg, BarArg *a)
{
return ClkStatusText;
}
int
drawstatusbar(BarArg *a, char* stext)
{
int i, w, len;
int x = a->x;
int y = a->y;
short isCode = 0;
char *text;
char *p;
Clr oldbg, oldfg;
len = strlen(stext);
if (!(text = (char*) malloc(sizeof(char)*(len + 1))))
die("malloc");
p = text;
memcpy(text, stext, len);
x += lrpad / 2;
drw_setscheme(drw, scheme[LENGTH(colors)]);
drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
/* process status text */
i = -1;
while (text[++i]) {
if (text[i] == '^' && !isCode) {
isCode = 1;
text[i] = '\0';
w = TEXTWM(text) - lrpad;
drw_text(drw, x, y, w, bh, 0, text, 0, True);
x += w;
/* process code */
while (text[++i] != '^') {
if (text[i] == 'c') {
char buf[8];
if (i + 7 >= len) {
i += 7;
len = 0;
break;
}
memcpy(buf, (char*)text+i+1, 7);
buf[7] = '\0';
drw_clr_create(drw, &drw->scheme[ColFg], buf);
i += 7;
} else if (text[i] == 'b') {
char buf[8];
if (i + 7 >= len) {
i += 7;
len = 0;
break;
}
memcpy(buf, (char*)text+i+1, 7);
buf[7] = '\0';
drw_clr_create(drw, &drw->scheme[ColBg], buf);
i += 7;
} else if (text[i] == 'd') {
drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
} else if (text[i] == 'w') {
Clr swp;
swp = drw->scheme[ColFg];
drw->scheme[ColFg] = drw->scheme[ColBg];
drw->scheme[ColBg] = swp;
} else if (text[i] == 'v') {
oldfg = drw->scheme[ColFg];
oldbg = drw->scheme[ColBg];
} else if (text[i] == 't') {
drw->scheme[ColFg] = oldfg;
drw->scheme[ColBg] = oldbg;
} else if (text[i] == 'r') {
int rx = atoi(text + ++i);
while (text[++i] != ',');
int ry = atoi(text + ++i);
while (text[++i] != ',');
int rw = atoi(text + ++i);
while (text[++i] != ',');
int rh = atoi(text + ++i);
if (ry < 0)
ry = 0;
if (rx < 0)
rx = 0;
drw_rect(drw, rx + x, y + ry, rw, rh, 1, 0);
} else if (text[i] == 'f') {
x += atoi(text + ++i);
}
}
text = text + i + 1;
len -= i + 1;
i = -1;
isCode = 0;
if (len <= 0)
break;
}
}
if (!isCode && len > 0) {
w = TEXTWM(text) - lrpad;
drw_text(drw, x, y, w, bh, 0, text, 0, True);
x += w;
}
free(p);
drw_setscheme(drw, scheme[SchemeNorm]);
return 1;
}
int
status2dtextlength(char* stext)
{
int i, w, len;
short isCode = 0;
char *text;
char *p;
len = strlen(stext) + 1;
if (!(text = (char*) malloc(sizeof(char)*len)))
die("malloc");
p = text;
memcpy(text, stext, len);
/* compute width of the status text */
w = 0;
i = -1;
while (text[++i]) {
if (text[i] == '^') {
if (!isCode) {
isCode = 1;
text[i] = '\0';
w += TEXTWM(text) - lrpad;
text[i] = '^';
if (text[++i] == 'f')
w += atoi(text + ++i);
} else {
isCode = 0;
text = text + i + 1;
i = -1;
}
}
}
if (!isCode)
w += TEXTWM(text) - lrpad;
free(p);
return w;
}

6
patch/bar_status2d.h Normal file
View File

@ -0,0 +1,6 @@
static int width_status2d(Bar *bar, BarArg *a);
static int draw_status2d(Bar *bar, BarArg *a);
static int click_status2d(Bar *bar, Arg *arg, BarArg *a);
static int drawstatusbar(BarArg *a, char *text);
static int status2dtextlength(char *stext);

13
patch/bar_tagicons.c Normal file
View File

@ -0,0 +1,13 @@
char *
tagicon(Monitor *m, int tag)
{
Client *c;
int tagindex = tag + NUMTAGS * m->num;
if (tagindex >= LENGTH(tagicons[DEFAULT_TAGS]))
tagindex = tagindex % LENGTH(tagicons[DEFAULT_TAGS]);
for (c = m->clients; c && (!(c->tags & 1 << tag) || HIDDEN(c)); c = c->next);
if (c)
return tagicons[ALT_TAGS_DECORATION][tagindex];
return tagicons[DEFAULT_TAGS][tagindex];
}

8
patch/bar_tagicons.h Normal file
View File

@ -0,0 +1,8 @@
enum {
DEFAULT_TAGS,
ALTERNATIVE_TAGS,
ALT_TAGS_DECORATION,
};
static char * tagicon(Monitor *m, int tag);

68
patch/bar_tags.c Normal file
View File

@ -0,0 +1,68 @@
int
width_tags(Bar *bar, BarArg *a)
{
int w, i;
for (w = 0, i = 0; i < NUMTAGS; i++) {
w += TEXTW(tagicon(bar->mon, i));
}
return w;
}
int
draw_tags(Bar *bar, BarArg *a)
{
int invert;
int w, x = a->x;
unsigned int i, occ = 0, urg = 0;
char *icon;
Client *c;
Monitor *m = bar->mon;
for (c = m->clients; c; c = c->next) {
occ |= c->tags;
if (c->isurgent)
urg |= c->tags;
}
for (i = 0; i < NUMTAGS; i++) {
icon = tagicon(bar->mon, i);
invert = 0;
w = TEXTW(icon);
drw_setscheme(drw, scheme[
m->tagset[m->seltags] & 1 << i
? SchemeTagsSel
: urg & 1 << i
? SchemeUrg
: SchemeTagsNorm
]);
drw_text(drw, x, a->y, w, a->h, lrpad / 2, icon, invert, False);
drawindicator(m, NULL, occ, x, a->y, w, a->h, i, -1, invert, tagindicatortype);
if (ulineall || m->tagset[m->seltags] & 1 << i)
drw_rect(drw, x + ulinepad, bh - ulinestroke - ulinevoffset, w - (ulinepad * 2), ulinestroke, 1, 0);
x += w;
}
return 1;
}
int
click_tags(Bar *bar, Arg *arg, BarArg *a)
{
int i = 0, x = 0;
do {
x += TEXTW(tagicon(bar->mon, i));
} while (a->x >= x && ++i < NUMTAGS);
if (i < NUMTAGS) {
arg->ui = 1 << i;
}
return ClkTagBar;
}
int
hover_tags(Bar *bar, BarArg *a, XMotionEvent *ev)
{
return 1;
}

4
patch/bar_tags.h Normal file
View File

@ -0,0 +1,4 @@
static int width_tags(Bar *bar, BarArg *a);
static int draw_tags(Bar *bar, BarArg *a);
static int click_tags(Bar *bar, Arg *arg, BarArg *a);
static int hover_tags(Bar *bar, BarArg *a, XMotionEvent *ev);

51
patch/bar_wintitle.c Normal file
View File

@ -0,0 +1,51 @@
int
width_wintitle(Bar *bar, BarArg *a)
{
return a->w;
}
int
draw_wintitle(Bar *bar, BarArg *a)
{
int x = a->x, w = a->w;
Monitor *m = bar->mon;
Client *c = m->sel;
if (!c) {
drw_setscheme(drw, scheme[SchemeTitleNorm]);
drw_rect(drw, x, a->y, w, a->h, 1, 1);
return 0;
}
int tpad = lrpad / 2;
int tx = x;
int tw = w;
drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]);
XSetErrorHandler(xerrordummy);
if (w <= TEXTW("A") - lrpad + tpad) // reduce text padding if wintitle is too small
tpad = (w - TEXTW("A") + lrpad < 0 ? 0 : (w - TEXTW("A") + lrpad) / 2);
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, a->y, w, a->h);
tx += tpad;
tw -= lrpad;
drw_text(drw, tx, a->y, tw, a->h, 0, c->name, 0, False);
XSync(dpy, False);
XSetErrorHandler(xerror);
drawstateindicator(m, c, 1, x, a->y, w, a->h, 0, 0, c->isfixed);
return 1;
}
int
click_wintitle(Bar *bar, Arg *arg, BarArg *a)
{
return ClkWinTitle;
}

4
patch/bar_wintitle.h Normal file
View File

@ -0,0 +1,4 @@
static int width_wintitle(Bar *bar, BarArg *a);
static int draw_wintitle(Bar *bar, BarArg *a);
static int click_wintitle(Bar *bar, Arg *arg, BarArg *a);

16
patch/fullscreen.c Normal file
View File

@ -0,0 +1,16 @@
Layout *last_layout;
void
fullscreen(const Arg *arg)
{
int monocle_pos = 0;
if (selmon->showbar || last_layout == NULL) {
for (monocle_pos = 0, last_layout = (Layout *)layouts; !last_layout->arrange || last_layout->arrange != &monocle; monocle_pos++, last_layout++ );
for (last_layout = (Layout *)layouts; last_layout != selmon->lt[selmon->sellt]; last_layout++);
setlayout(&((Arg) { .v = &layouts[monocle_pos] }));
} else {
setlayout(&((Arg) { .v = last_layout }));
}
togglebar(arg);
}

2
patch/fullscreen.h Normal file
View File

@ -0,0 +1,2 @@
static void fullscreen(const Arg *arg);

24
patch/include.c Normal file
View File

@ -0,0 +1,24 @@
/* Bar functionality */
#include "bar_indicators.c"
#include "bar_tagicons.c"
#include "bar.c"
#include "bar_ltsymbol.c"
#include "bar_status.c"
#include "bar_status2d.c"
#include "bar_tags.c"
#include "bar_wintitle.c"
/* Other patches */
#include "fullscreen.c"
#include "movestack.c"
#include "placemouse.c"
#include "restartsig.c"
#include "togglefullscreen.c"
#include "vanitygaps.c"
/* Layouts */
#include "layout_facts.c"
#include "layout_gapplessgrid.c"
#include "layout_monocle.c"
#include "layout_tile.c"

23
patch/include.h Normal file
View File

@ -0,0 +1,23 @@
/* Bar functionality */
#include "bar_indicators.h"
#include "bar_tagicons.h"
#include "bar.h"
#include "bar_ltsymbol.h"
#include "bar_status.h"
#include "bar_status2d.h"
#include "bar_tags.h"
#include "bar_wintitle.h"
/* Other patches */
#include "fullscreen.h"
#include "movestack.h"
#include "placemouse.h"
#include "restartsig.h"
#include "togglefullscreen.h"
#include "vanitygaps.h"
/* Layouts */
#include "layout_gapplessgrid.h"
#include "layout_monocle.h"
#include "layout_tile.h"

62
patch/ipc/IPCClient.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef IPC_CLIENT_H_
#define IPC_CLIENT_H_
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
typedef struct IPCClient IPCClient;
/**
* This structure contains the details of an IPC Client and pointers for a
* linked list
*/
struct IPCClient {
int fd;
int subscriptions;
char *buffer;
uint32_t buffer_size;
struct epoll_event event;
IPCClient *next;
IPCClient *prev;
};
typedef IPCClient *IPCClientList;
/**
* Allocate memory for new IPCClient with the specified file descriptor and
* initialize struct.
*
* @param fd File descriptor of IPC client
*
* @return Address to allocated IPCClient struct
*/
IPCClient *ipc_client_new(int fd);
/**
* Add an IPC Client to the specified list
*
* @param list Address of the list to add the client to
* @param nc Address of the IPCClient
*/
void ipc_list_add_client(IPCClientList *list, IPCClient *nc);
/**
* Remove an IPCClient from the specified list
*
* @param list Address of the list to remove the client from
* @param c Address of the IPCClient
*/
void ipc_list_remove_client(IPCClientList *list, IPCClient *c);
/**
* Get an IPCClient from the specified IPCClient list
*
* @param list List to remove the client from
* @param fd File descriptor of the IPCClient
*/
IPCClient *ipc_list_get_client(IPCClientList list, int fd);
#endif // IPC_CLIENT_H_

549
patch/ipc/dwm-msg.c Normal file
View File

@ -0,0 +1,549 @@
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <yajl/yajl_gen.h>
#define IPC_MAGIC "DWM-IPC"
// clang-format off
#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C' }
// clang-format on
#define IPC_MAGIC_LEN 7 // Not including null char
#define IPC_EVENT_TAG_CHANGE "tag_change_event"
#define IPC_EVENT_CLIENT_FOCUS_CHANGE "client_focus_change_event"
#define IPC_EVENT_LAYOUT_CHANGE "layout_change_event"
#define IPC_EVENT_MONITOR_FOCUS_CHANGE "monitor_focus_change_event"
#define IPC_EVENT_FOCUSED_TITLE_CHANGE "focused_title_change_event"
#define IPC_EVENT_FOCUSED_STATE_CHANGE "focused_state_change_event"
#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str))
#define YINT(num) yajl_gen_integer(gen, num)
#define YDOUBLE(num) yajl_gen_double(gen, num)
#define YBOOL(v) yajl_gen_bool(gen, v)
#define YNULL() yajl_gen_null(gen)
#define YARR(body) \
{ \
yajl_gen_array_open(gen); \
body; \
yajl_gen_array_close(gen); \
}
#define YMAP(body) \
{ \
yajl_gen_map_open(gen); \
body; \
yajl_gen_map_close(gen); \
}
typedef unsigned long Window;
const char *DEFAULT_SOCKET_PATH = "/tmp/dwm.sock";
static int sock_fd = -1;
static unsigned int ignore_reply = 0;
typedef enum IPCMessageType {
IPC_TYPE_RUN_COMMAND = 0,
IPC_TYPE_GET_MONITORS = 1,
IPC_TYPE_GET_TAGS = 2,
IPC_TYPE_GET_LAYOUTS = 3,
IPC_TYPE_GET_DWM_CLIENT = 4,
IPC_TYPE_SUBSCRIBE = 5,
IPC_TYPE_EVENT = 6
} IPCMessageType;
// Every IPC message must begin with this
typedef struct dwm_ipc_header {
uint8_t magic[IPC_MAGIC_LEN];
uint32_t size;
uint8_t type;
} __attribute((packed)) dwm_ipc_header_t;
static int
recv_message(uint8_t *msg_type, uint32_t *reply_size, uint8_t **reply)
{
uint32_t read_bytes = 0;
const int32_t to_read = sizeof(dwm_ipc_header_t);
char header[to_read];
char *walk = header;
// Try to read header
while (read_bytes < to_read) {
ssize_t n = read(sock_fd, header + read_bytes, to_read - read_bytes);
if (n == 0) {
if (read_bytes == 0) {
fprintf(stderr, "Unexpectedly reached EOF while reading header.");
fprintf(stderr,
"Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n",
read_bytes, to_read);
return -2;
} else {
fprintf(stderr, "Unexpectedly reached EOF while reading header.");
fprintf(stderr,
"Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n",
read_bytes, to_read);
return -3;
}
} else if (n == -1) {
return -1;
}
read_bytes += n;
}
// Check if magic string in header matches
if (memcmp(walk, IPC_MAGIC, IPC_MAGIC_LEN) != 0) {
fprintf(stderr, "Invalid magic string. Got '%.*s', expected '%s'\n",
IPC_MAGIC_LEN, walk, IPC_MAGIC);
return -3;
}
walk += IPC_MAGIC_LEN;
// Extract reply size
memcpy(reply_size, walk, sizeof(uint32_t));
walk += sizeof(uint32_t);
// Extract message type
memcpy(msg_type, walk, sizeof(uint8_t));
walk += sizeof(uint8_t);
(*reply) = malloc(*reply_size);
// Extract payload
read_bytes = 0;
while (read_bytes < *reply_size) {
ssize_t n = read(sock_fd, *reply + read_bytes, *reply_size - read_bytes);
if (n == 0) {
fprintf(stderr, "Unexpectedly reached EOF while reading payload.");
fprintf(stderr, "Read %" PRIu32 " bytes, expected %" PRIu32 " bytes.\n",
read_bytes, *reply_size);
free(*reply);
return -2;
} else if (n == -1) {
if (errno == EINTR || errno == EAGAIN) continue;
free(*reply);
return -1;
}
read_bytes += n;
}
return 0;
}
static int
read_socket(IPCMessageType *msg_type, uint32_t *msg_size, char **msg)
{
int ret = -1;
while (ret != 0) {
ret = recv_message((uint8_t *)msg_type, msg_size, (uint8_t **)msg);
if (ret < 0) {
// Try again (non-fatal error)
if (ret == -1 && (errno == EINTR || errno == EAGAIN)) continue;
fprintf(stderr, "Error receiving response from socket. ");
fprintf(stderr, "The connection might have been lost.\n");
exit(2);
}
}
return 0;
}
static ssize_t
write_socket(const void *buf, size_t count)
{
size_t written = 0;
while (written < count) {
const ssize_t n =
write(sock_fd, ((uint8_t *)buf) + written, count - written);
if (n == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
else
return n;
}
written += n;
}
return written;
}
static void
connect_to_socket()
{
struct sockaddr_un addr;
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
// Initialize struct to 0
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, DEFAULT_SOCKET_PATH);
connect(sock, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un));
sock_fd = sock;
}
static int
send_message(IPCMessageType msg_type, uint32_t msg_size, uint8_t *msg)
{
dwm_ipc_header_t header = {
.magic = IPC_MAGIC_ARR, .size = msg_size, .type = msg_type};
size_t header_size = sizeof(dwm_ipc_header_t);
size_t total_size = header_size + msg_size;
uint8_t buffer[total_size];
// Copy header to buffer
memcpy(buffer, &header, header_size);
// Copy message to buffer
memcpy(buffer + header_size, msg, header.size);
write_socket(buffer, total_size);
return 0;
}
static int
is_float(const char *s)
{
size_t len = strlen(s);
int is_dot_used = 0;
int is_minus_used = 0;
// Floats can only have one decimal point in between or digits
// Optionally, floats can also be below zero (negative)
for (int i = 0; i < len; i++) {
if (isdigit(s[i]))
continue;
else if (!is_dot_used && s[i] == '.' && i != 0 && i != len - 1) {
is_dot_used = 1;
continue;
} else if (!is_minus_used && s[i] == '-' && i == 0) {
is_minus_used = 1;
continue;
} else
return 0;
}
return 1;
}
static int
is_unsigned_int(const char *s)
{
size_t len = strlen(s);
// Unsigned int can only have digits
for (int i = 0; i < len; i++) {
if (isdigit(s[i]))
continue;
else
return 0;
}
return 1;
}
static int
is_signed_int(const char *s)
{
size_t len = strlen(s);
// Signed int can only have digits and a negative sign at the start
for (int i = 0; i < len; i++) {
if (isdigit(s[i]))
continue;
else if (i == 0 && s[i] == '-') {
continue;
} else
return 0;
}
return 1;
}
static void
flush_socket_reply()
{
IPCMessageType reply_type;
uint32_t reply_size;
char *reply;
read_socket(&reply_type, &reply_size, &reply);
free(reply);
}
static void
print_socket_reply()
{
IPCMessageType reply_type;
uint32_t reply_size;
char *reply;
read_socket(&reply_type, &reply_size, &reply);
printf("%.*s\n", reply_size, reply);
fflush(stdout);
free(reply);
}
static int
run_command(const char *name, char *args[], int argc)
{
const unsigned char *msg;
size_t msg_size;
yajl_gen gen = yajl_gen_alloc(NULL);
// Message format:
// {
// "command": "<name>",
// "args": [ ... ]
// }
// clang-format off
YMAP(
YSTR("command"); YSTR(name);
YSTR("args"); YARR(
for (int i = 0; i < argc; i++) {
if (is_signed_int(args[i])) {
long long num = atoll(args[i]);
YINT(num);
} else if (is_float(args[i])) {
float num = atof(args[i]);
YDOUBLE(num);
} else {
YSTR(args[i]);
}
}
)
)
// clang-format on
yajl_gen_get_buf(gen, &msg, &msg_size);
send_message(IPC_TYPE_RUN_COMMAND, msg_size, (uint8_t *)msg);
if (!ignore_reply)
print_socket_reply();
else
flush_socket_reply();
yajl_gen_free(gen);
return 0;
}
static int
get_monitors()
{
send_message(IPC_TYPE_GET_MONITORS, 1, (uint8_t *)"");
print_socket_reply();
return 0;
}
static int
get_tags()
{
send_message(IPC_TYPE_GET_TAGS, 1, (uint8_t *)"");
print_socket_reply();
return 0;
}
static int
get_layouts()
{
send_message(IPC_TYPE_GET_LAYOUTS, 1, (uint8_t *)"");
print_socket_reply();
return 0;
}
static int
get_dwm_client(Window win)
{
const unsigned char *msg;
size_t msg_size;
yajl_gen gen = yajl_gen_alloc(NULL);
// Message format:
// {
// "client_window_id": "<win>"
// }
// clang-format off
YMAP(
YSTR("client_window_id"); YINT(win);
)
// clang-format on
yajl_gen_get_buf(gen, &msg, &msg_size);
send_message(IPC_TYPE_GET_DWM_CLIENT, msg_size, (uint8_t *)msg);
print_socket_reply();
yajl_gen_free(gen);
return 0;
}
static int
subscribe(const char *event)
{
const unsigned char *msg;
size_t msg_size;
yajl_gen gen = yajl_gen_alloc(NULL);
// Message format:
// {
// "event": "<event>",
// "action": "subscribe"
// }
// clang-format off
YMAP(
YSTR("event"); YSTR(event);
YSTR("action"); YSTR("subscribe");
)
// clang-format on
yajl_gen_get_buf(gen, &msg, &msg_size);
send_message(IPC_TYPE_SUBSCRIBE, msg_size, (uint8_t *)msg);
if (!ignore_reply)
print_socket_reply();
else
flush_socket_reply();
yajl_gen_free(gen);
return 0;
}
static void
usage_error(const char *prog_name, const char *format, ...)
{
va_list args;
va_start(args, format);
fprintf(stderr, "Error: ");
vfprintf(stderr, format, args);
fprintf(stderr, "\nusage: %s <command> [...]\n", prog_name);
fprintf(stderr, "Try '%s help'\n", prog_name);
va_end(args);
exit(1);
}
static void
print_usage(const char *name)
{
printf("usage: %s [options] <command> [...]\n", name);
puts("");
puts("Commands:");
puts(" run_command <name> [args...] Run an IPC command");
puts("");
puts(" get_monitors Get monitor properties");
puts("");
puts(" get_tags Get list of tags");
puts("");
puts(" get_layouts Get list of layouts");
puts("");
puts(" get_dwm_client <window_id> Get dwm client proprties");
puts("");
puts(" subscribe [events...] Subscribe to specified events");
puts(" Options: " IPC_EVENT_TAG_CHANGE ",");
puts(" " IPC_EVENT_LAYOUT_CHANGE ",");
puts(" " IPC_EVENT_CLIENT_FOCUS_CHANGE ",");
puts(" " IPC_EVENT_MONITOR_FOCUS_CHANGE ",");
puts(" " IPC_EVENT_FOCUSED_TITLE_CHANGE ",");
puts(" " IPC_EVENT_FOCUSED_STATE_CHANGE);
puts("");
puts(" help Display this message");
puts("");
puts("Options:");
puts(" --ignore-reply Don't print reply messages from");
puts(" run_command and subscribe.");
puts("");
}
int
main(int argc, char *argv[])
{
const char *prog_name = argv[0];
connect_to_socket();
if (sock_fd == -1) {
fprintf(stderr, "Failed to connect to socket\n");
return 1;
}
int i = 1;
if (i < argc && strcmp(argv[i], "--ignore-reply") == 0) {
ignore_reply = 1;
i++;
}
if (i >= argc) usage_error(prog_name, "Expected an argument, got none");
if (!argc || strcmp(argv[i], "help") == 0)
print_usage(prog_name);
else if (strcmp(argv[i], "run_command") == 0) {
if (++i >= argc) usage_error(prog_name, "No command specified");
// Command name
char *command = argv[i];
// Command arguments are everything after command name
char **command_args = argv + ++i;
// Number of command arguments
int command_argc = argc - i;
run_command(command, command_args, command_argc);
} else if (strcmp(argv[i], "get_monitors") == 0) {
get_monitors();
} else if (strcmp(argv[i], "get_tags") == 0) {
get_tags();
} else if (strcmp(argv[i], "get_layouts") == 0) {
get_layouts();
} else if (strcmp(argv[i], "get_dwm_client") == 0) {
if (++i < argc) {
if (is_unsigned_int(argv[i])) {
Window win = atol(argv[i]);
get_dwm_client(win);
} else
usage_error(prog_name, "Expected unsigned integer argument");
} else
usage_error(prog_name, "Expected the window id");
} else if (strcmp(argv[i], "subscribe") == 0) {
if (++i < argc) {
for (int j = i; j < argc; j++) subscribe(argv[j]);
} else
usage_error(prog_name, "Expected event name");
// Keep listening for events forever
while (1) {
print_socket_reply();
}
} else
usage_error(prog_name, "Invalid argument '%s'", argv[i]);
return 0;
}

66
patch/ipc/yajl_dumps.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef YAJL_DUMPS_H_
#define YAJL_DUMPS_H_
#include <string.h>
#include <yajl/yajl_gen.h>
#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str))
#define YINT(num) yajl_gen_integer(gen, num)
#define YDOUBLE(num) yajl_gen_double(gen, num)
#define YBOOL(v) yajl_gen_bool(gen, v)
#define YNULL() yajl_gen_null(gen)
#define YARR(body) \
{ \
yajl_gen_array_open(gen); \
body; \
yajl_gen_array_close(gen); \
}
#define YMAP(body) \
{ \
yajl_gen_map_open(gen); \
body; \
yajl_gen_map_close(gen); \
}
int dump_tag(yajl_gen gen, const char *name, const int tag_mask);
int dump_tags(yajl_gen gen, int tags_len);
int dump_client(yajl_gen gen, Client *c);
int dump_monitor(yajl_gen gen, Monitor *mon, int is_selected);
int dump_monitors(yajl_gen gen, Monitor *mons, Monitor *selmon);
int dump_layouts(yajl_gen gen, const Layout layouts[], const int layouts_len);
int dump_tag_state(yajl_gen gen, TagState state);
int dump_tag_event(yajl_gen gen, int mon_num, TagState old_state,
TagState new_state);
int dump_client_focus_change_event(yajl_gen gen, Client *old_client,
Client *new_client, int mon_num);
int dump_layout_change_event(yajl_gen gen, const int mon_num,
const char *old_symbol, const Layout *old_layout,
const char *new_symbol, const Layout *new_layout);
int dump_monitor_focus_change_event(yajl_gen gen, const int last_mon_num,
const int new_mon_num);
int dump_focused_title_change_event(yajl_gen gen, const int mon_num,
const Window client_id,
const char *old_name, const char *new_name);
int dump_client_state(yajl_gen gen, const ClientState *state);
int dump_focused_state_change_event(yajl_gen gen, const int mon_num,
const Window client_id,
const ClientState *old_state,
const ClientState *new_state);
int dump_error_message(yajl_gen gen, const char *reason);
#endif // YAJL_DUMPS_H_

24
patch/layout_facts.c Normal file
View File

@ -0,0 +1,24 @@
void
getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr)
{
unsigned int n;
float mfacts, sfacts;
int mtotal = 0, stotal = 0;
Client *c;
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
mfacts = MIN(n, m->nmaster);
sfacts = n - m->nmaster;
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
if (n < m->nmaster)
mtotal += msize / mfacts;
else
stotal += ssize / sfacts;
*mf = mfacts; // total factor of master area
*sf = sfacts; // total factor of stack area
*mr = msize - mtotal; // the remainder (rest) of pixels after an even master split
*sr = ssize - stotal; // the remainder (rest) of pixels after an even stack split
}

View File

@ -0,0 +1,49 @@
void
gaplessgrid(Monitor *m)
{
unsigned int i, n;
int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters
int oh, ov, ih, iv;
Client *c;
getgaps(m, &oh, &ov, &ih, &iv, &n);
if (n == 0)
return;
/* grid dimensions */
for (cols = 0; cols <= n/2; cols++)
if (cols*cols >= n)
break;
if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
cols = 2;
rows = n/cols;
cn = rn = 0; // reset column no, row no, client count
ch = (m->wh - 2*oh - ih * (rows - 1)) / rows;
cw = (m->ww - 2*ov - iv * (cols - 1)) / cols;
rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
crest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
x = m->wx + ov;
y = m->wy + oh;
for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) {
if (i/rows + 1 > cols - n%cols) {
rows = n/cols + 1;
ch = (m->wh - 2*oh - ih * (rows - 1)) / rows;
rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
}
resize(c,
x,
y + rn*(ch + ih) + MIN(rn, rrest),
cw + (cn < crest ? 1 : 0) - 2*c->bw,
ch + (rn < rrest ? 1 : 0) - 2*c->bw,
0);
rn++;
if (rn >= rows) {
rn = 0;
x += cw + ih + (cn < crest ? 1 : 0);
cn++;
}
}
}

View File

@ -0,0 +1,2 @@
static void gaplessgrid(Monitor *m);

15
patch/layout_monocle.c Normal file
View File

@ -0,0 +1,15 @@
void
monocle(Monitor *m)
{
unsigned int n = 0;
Client *c;
for (c = m->clients; c; c = c->next)
if (ISVISIBLE(c))
n++;
if (n > 0) /* override layout symbol */
snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
}

2
patch/layout_monocle.h Normal file
View File

@ -0,0 +1,2 @@
static void monocle(Monitor *m);

41
patch/layout_tile.c Normal file
View File

@ -0,0 +1,41 @@
static void
tile(Monitor *m)
{
unsigned int i, n;
int mx = 0, my = 0, mh = 0, mw = 0;
int sx = 0, sy = 0, sh = 0, sw = 0;
float mfacts, sfacts;
int mrest, srest;
Client *c;
int oh, ov, ih, iv;
getgaps(m, &oh, &ov, &ih, &iv, &n);
if (n == 0)
return;
sx = mx = m->wx + ov;
sy = my = m->wy + oh;
mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
sw = mw = m->ww - 2*ov;
if (m->nmaster && n > m->nmaster) {
sw = (mw - iv) * (1 - m->mfact);
mw = (mw - iv) * m->mfact;
sx = mx + mw + iv;
}
getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
if (i < m->nmaster) {
resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
my += HEIGHT(c) + ih;
} else {
resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
sy += HEIGHT(c) + ih;
}
}

2
patch/layout_tile.h Normal file
View File

@ -0,0 +1,2 @@
static void tile(Monitor *m);

51
patch/movestack.c Normal file
View File

@ -0,0 +1,51 @@
void
movestack(const Arg *arg)
{
Client *c = NULL, *p = NULL, *pc = NULL, *i;
if (arg->i > 0) {
if (!selmon->sel)
return;
/* find the client after selmon->sel */
for (c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
if (!c)
for (c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
}
else {
/* find the client before selmon->sel */
for (i = selmon->clients; i != selmon->sel; i = i->next)
if(ISVISIBLE(i) && !i->isfloating)
c = i;
if (!c)
for (; i; i = i->next)
if (ISVISIBLE(i) && !i->isfloating)
c = i;
}
/* find the client before selmon->sel and c */
for (i = selmon->clients; i && (!p || !pc); i = i->next) {
if (i->next == selmon->sel)
p = i;
if (i->next == c)
pc = i;
}
/* swap c and selmon->sel selmon->clients in the selmon->clients list */
if (c && c != selmon->sel) {
Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next;
selmon->sel->next = c->next==selmon->sel?c:c->next;
c->next = temp;
if (p && p != c)
p->next = c;
if (pc && pc != selmon->sel)
pc->next = selmon->sel;
if (selmon->sel == selmon->clients)
selmon->clients = c;
else if (c == selmon->clients)
selmon->clients = selmon->sel;
arrange(selmon);
}
}

2
patch/movestack.h Normal file
View File

@ -0,0 +1,2 @@
static void movestack(const Arg *arg);

155
patch/placemouse.c Normal file
View File

@ -0,0 +1,155 @@
void
moveorplace(const Arg *arg) {
if ((!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating)))
movemouse(arg);
else
placemouse(arg);
}
void
placemouse(const Arg *arg)
{
int x, y, px, py, ocx, ocy, nx = -9999, ny = -9999, freemove = 0;
Client *c, *r = NULL, *at, *prevr;
Monitor *m;
XEvent ev;
XWindowAttributes wa;
Time lasttime = 0;
int attachmode, prevattachmode;
attachmode = prevattachmode = -1;
if (!(c = selmon->sel) || !c->mon->lt[c->mon->sellt]->arrange) /* no support for placemouse when floating layout is used */
return;
if (c->isfullscreen) /* no support placing fullscreen windows by mouse */
return;
restack(selmon);
prevr = c;
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
return;
c->isfloating = 0;
c->beingmoved = 1;
XGetWindowAttributes(dpy, c->win, &wa);
ocx = wa.x;
ocy = wa.y;
if (arg->i == 2) // warp cursor to client center
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, WIDTH(c) / 2, HEIGHT(c) / 2);
if (!getrootptr(&x, &y))
return;
do {
XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
switch (ev.type) {
case ConfigureRequest:
case Expose:
case MapRequest:
handler[ev.type](&ev);
break;
case MotionNotify:
if ((ev.xmotion.time - lasttime) <= (1000 / 60))
continue;
lasttime = ev.xmotion.time;
nx = ocx + (ev.xmotion.x - x);
ny = ocy + (ev.xmotion.y - y);
if (!freemove && (abs(nx - ocx) > snap || abs(ny - ocy) > snap))
freemove = 1;
if (freemove)
XMoveWindow(dpy, c->win, nx, ny);
if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != selmon)
selmon = m;
if (arg->i == 1) { // tiled position is relative to the client window center point
px = nx + wa.width / 2;
py = ny + wa.height / 2;
} else { // tiled position is relative to the mouse cursor
px = ev.xmotion.x;
py = ev.xmotion.y;
}
r = recttoclient(px, py, 1, 1);
if (!r || r == c)
break;
if ((((float)(r->y + r->h - py) / r->h) > ((float)(r->x + r->w - px) / r->w)
&& (abs(r->y - py) < r->h / 2)) || (abs(r->x - px) < r->w / 2))
attachmode = 1; // above
else
attachmode = 0; // below
if ((r && r != prevr) || (attachmode != prevattachmode)) {
detachstack(c);
detach(c);
if (c->mon != r->mon) {
arrangemon(c->mon);
c->tags = r->mon->tagset[r->mon->seltags];
}
c->mon = r->mon;
r->mon->sel = r;
if (attachmode) {
if (r == r->mon->clients)
attach(c);
else {
for (at = r->mon->clients; at->next != r; at = at->next);
c->next = at->next;
at->next = c;
}
} else {
c->next = r->next;
r->next = c;
}
attachstack(c);
arrangemon(r->mon);
prevr = r;
prevattachmode = attachmode;
}
break;
}
} while (ev.type != ButtonRelease);
XUngrabPointer(dpy, CurrentTime);
if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != c->mon) {
detach(c);
detachstack(c);
arrangemon(c->mon);
c->mon = m;
c->tags = m->tagset[m->seltags];
attach(c);
attachstack(c);
selmon = m;
}
focus(c);
c->beingmoved = 0;
if (nx != -9999)
resize(c, nx, ny, c->w, c->h, 0);
arrangemon(c->mon);
}
Client *
recttoclient(int x, int y, int w, int h)
{
Client *c, *r = NULL;
int a, area = 0;
for (c = nexttiled(selmon->clients); c; c = nexttiled(c->next)) {
if ((a = INTERSECTC(x, y, w, h, c)) > area) {
area = a;
r = c;
}
}
return r;
}

7
patch/placemouse.h Normal file
View File

@ -0,0 +1,7 @@
#define INTERSECTC(x,y,w,h,z) (MAX(0, MIN((x)+(w),(z)->x+(z)->w) - MAX((x),(z)->x)) \
* MAX(0, MIN((y)+(h),(z)->y+(z)->h) - MAX((y),(z)->y)))
static void moveorplace(const Arg *arg);
static void placemouse(const Arg *arg);
static Client *recttoclient(int x, int y, int w, int h);

16
patch/restartsig.c Normal file
View File

@ -0,0 +1,16 @@
static int restart = 0;
void
sighup(int unused)
{
Arg a = {.i = 1};
quit(&a);
}
void
sigterm(int unused)
{
Arg a = {.i = 0};
quit(&a);
}

3
patch/restartsig.h Normal file
View File

@ -0,0 +1,3 @@
static void sighup(int unused);
static void sigterm(int unused);

10
patch/togglefullscreen.c Normal file
View File

@ -0,0 +1,10 @@
void
togglefullscreen(const Arg *arg)
{
Client *c = selmon->sel;
if (!c)
return;
setfullscreen(c, !c->isfullscreen);
}

2
patch/togglefullscreen.h Normal file
View File

@ -0,0 +1,2 @@
static void togglefullscreen(const Arg *arg);

131
patch/vanitygaps.c Normal file
View File

@ -0,0 +1,131 @@
/* Settings */
static int enablegaps = 1;
static void
setgaps(int oh, int ov, int ih, int iv)
{
if (oh < 0) oh = 0;
if (ov < 0) ov = 0;
if (ih < 0) ih = 0;
if (iv < 0) iv = 0;
selmon->gappoh = oh;
selmon->gappov = ov;
selmon->gappih = ih;
selmon->gappiv = iv;
arrange(selmon);
}
static void
togglegaps(const Arg *arg)
{
enablegaps = !enablegaps;
arrange(NULL);
}
static void
defaultgaps(const Arg *arg)
{
setgaps(gappoh, gappov, gappih, gappiv);
}
static void
incrgaps(const Arg *arg)
{
setgaps(
selmon->gappoh + arg->i,
selmon->gappov + arg->i,
selmon->gappih + arg->i,
selmon->gappiv + arg->i
);
}
static void
incrigaps(const Arg *arg)
{
setgaps(
selmon->gappoh,
selmon->gappov,
selmon->gappih + arg->i,
selmon->gappiv + arg->i
);
}
static void
incrogaps(const Arg *arg)
{
setgaps(
selmon->gappoh + arg->i,
selmon->gappov + arg->i,
selmon->gappih,
selmon->gappiv
);
}
static void
incrohgaps(const Arg *arg)
{
setgaps(
selmon->gappoh + arg->i,
selmon->gappov,
selmon->gappih,
selmon->gappiv
);
}
static void
incrovgaps(const Arg *arg)
{
setgaps(
selmon->gappoh,
selmon->gappov + arg->i,
selmon->gappih,
selmon->gappiv
);
}
static void
incrihgaps(const Arg *arg)
{
setgaps(
selmon->gappoh,
selmon->gappov,
selmon->gappih + arg->i,
selmon->gappiv
);
}
static void
incrivgaps(const Arg *arg)
{
setgaps(
selmon->gappoh,
selmon->gappov,
selmon->gappih,
selmon->gappiv + arg->i
);
}
static void
getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc)
{
unsigned int n, oe, ie;
oe = ie = enablegaps;
Client *c;
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
if (n == 1) {
oe *= smartgaps_fact; // outer gaps disabled or multiplied when only one client
}
*oh = m->gappoh*oe; // outer horizontal gap
*ov = m->gappov*oe; // outer vertical gap
*ih = m->gappih*ie; // inner horizontal gap
*iv = m->gappiv*ie; // inner vertical gap
*nc = n; // number of clients
}

15
patch/vanitygaps.h Normal file
View File

@ -0,0 +1,15 @@
/* Key binding functions */
static void defaultgaps(const Arg *arg);
static void incrgaps(const Arg *arg);
static void incrigaps(const Arg *arg);
static void incrogaps(const Arg *arg);
static void incrohgaps(const Arg *arg);
static void incrovgaps(const Arg *arg);
static void incrihgaps(const Arg *arg);
static void incrivgaps(const Arg *arg);
static void togglegaps(const Arg *arg);
/* Internals */
static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc);
static void setgaps(int oh, int ov, int ih, int iv);

View File

@ -40,3 +40,4 @@ int main(void) {
XCloseDisplay(d); XCloseDisplay(d);
exit(0); exit(0);
} }

11
util.h
View File

@ -1,8 +1,19 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
#ifndef MAX
#define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MAX(A, B) ((A) > (B) ? (A) : (B))
#endif
#ifndef MIN
#define MIN(A, B) ((A) < (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B))
#endif
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
#ifdef _DEBUG
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#else
#define DEBUG(...)
#endif
void die(const char *fmt, ...); void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size); void *ecalloc(size_t nmemb, size_t size);