Compare commits

...

9 Commits
6.4 ... master

Author SHA1 Message Date
37d3482e82
New theme + kb 2024-08-09 00:34:34 +03:00
9d72348d46
Mostly working for me 2024-05-30 22:39:43 +03:00
Hiltjo Posthuma
061e9fe9a7 bump version to 6.5 2024-03-19 12:13:16 +01:00
Hiltjo Posthuma
9f8855343c Makefile: remove the options target
The Makefile used to suppress output (by using @), so this target made sense at
the time.

But the Makefile should be simple and make debugging with less abstractions or
fancy printing.  The Makefile was made verbose and doesn't hide the build
output, so remove this target.

Prompted by a question on the mailing list about the options target.
2023-09-22 15:13:29 +02:00
Hiltjo Posthuma
e81f17d4c1 restore SIGCHLD sighandler to default before spawning a program
From sigaction(2):
A child created via fork(2) inherits a copy of its parent's signal dispositions.
During an execve(2), the dispositions of handled signals are reset to the default;
the dispositions of ignored signals are left unchanged.

This refused to start directly some programs from configuring in config.h:

static Key keys[] = {
	MODKEY,                       XK_o,      spawn,          {.v = cmd } },
};

Some reported programs that didn't start were: mpv, anki, dmenu_extended.

Reported by pfx.
Initial patch suggestion by Storkman.
2023-04-09 12:37:14 +02:00
NRK
348f6559ab config.mk: update to _XOPEN_SOURCE=700L
SA_NOCLDWAIT is marked as XSI in the posix spec [0] and FreeBSD and NetBSD
seems to more be strict about the feature test macro [1].

so update the macro to use _XOPEN_SOURCE=700L instead, which is equivalent to
_POSIX_C_SOURCE=200809L except that it also unlocks the X/Open System
Interfaces.

[0]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html#tag_13_42
[1]: https://lists.suckless.org/dev/2302/35111.html

Tested on:
* NetBSD 9.3 (fixed).
* FreeBSD 13 (fixed).
* Void Linux musl.
* Void Linux glibc.
* OpenBSD 7.2 (stable).
* Slackware 11.

Reported-by: beastie <pufferfish@riseup.net>
2023-02-17 15:27:34 +01:00
Chris Down
712d6639ff Use sigaction(SA_NOCLDWAIT) for SIGCHLD handling
signal() semantics are pretty unclearly specified. For example, depending on OS
kernel and libc, the handler may be returned to SIG_DFL (hence the inner call
to read the signal handler). Moving to sigaction() means the behaviour is
consistently defined.

Using SA_NOCLDWAIT also allows us to avoid calling the non-reentrant function
die() in the handler.

Some addditional notes for archival purposes:

* NRK pointed out errno of waitpid could also theoretically get clobbered.
* The original patch was iterated on and modified by NRK and Hiltjo:
  * SIG_DFL was changed to SIG_IGN, this is required, atleast on older systems
    such as tested on Slackware 11.
  * signals are not blocked using sigprocmask, because in theory it would
    briefly for example also ignore a SIGTERM signal. It is OK if waitpid() is (in
    theory interrupted).

POSIX reference:
"Consequences of Process Termination":
https://pubs.opengroup.org/onlinepubs/9699919799/functions/_Exit.html#tag_16_01_03_01
2023-01-28 13:34:43 +01:00
Chris Down
89f9905714 grabkeys: Avoid missing events when a keysym maps to multiple keycodes
It's not uncommon for one keysym to map to multiple keycodes. For
example, the "play" button on my keyboard sends keycode 172, but my
bluetooth headphones send keycode 208, both of which map back to
XF86AudioPlay:

    % xmodmap -pke | grep XF86AudioPlay
    keycode 172 = XF86AudioPlay XF86AudioPause XF86AudioPlay XF86AudioPause
    keycode 208 = XF86AudioPlay NoSymbol XF86AudioPlay
    keycode 215 = XF86AudioPlay NoSymbol XF86AudioPlay

This is a problem because the current code only grabs a single one of
these keycodes, which means that events for any other keycode also
mapping to the bound keysym will not be handled by dwm. In my case, this
means that binding XF86AudioPlay does the right thing and correctly
handles my keyboard's keys, but does nothing on my headphones. I'm not
the only person affected by this, there are other reports[0].

In order to fix this, we look at the mappings between keycodes and
keysyms at grabkeys() time and pick out all matching keycodes rather
than just the first one. The keypress() side of this doesn't need any
changes because the keycode gets converted back to a canonical keysym
before any action is taken.

0: https://github.com/cdown/dwm/issues/11
2022-12-07 23:06:26 +01:00
Hiltjo Posthuma
ba56fe9fea Revert "Remove dmenumon variable"
This reverts commit c2b748e793.

Revert back this change. It seems to not be an edge-case anymore since
multiple users have asked about this new behaviour now.
2022-10-28 16:37:56 +02:00
14 changed files with 1404 additions and 419 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/compile_commands.json
/build
/.cache

View File

@ -4,48 +4,35 @@
include config.mk
SRC = drw.c dwm.c util.c
OBJ = ${SRC:.c=.o}
OBJ = $(patsubst %.c,build/obj/%.c.o,$(SRC))
all: options dwm
all: build/dwm compile_commands.json
options:
@echo dwm build options:
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
build/obj/%.c.o: %.c
mkdir -p $(dir $@)
${CC} -c ${CFLAGS} -o $@ $<
.c.o:
${CC} -c ${CFLAGS} $<
${OBJ}: config.h config.mk
config.h:
cp config.def.h $@
dwm: ${OBJ}
build/dwm: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
dist: clean
mkdir -p dwm-${VERSION}
cp -R LICENSE Makefile README config.def.h config.mk\
dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION}
tar -cf dwm-${VERSION}.tar dwm-${VERSION}
gzip dwm-${VERSION}.tar
rm -rf dwm-${VERSION}
install: all
mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f dwm ${DESTDIR}${PREFIX}/bin
cp -f build/dwm ${DESTDIR}${PREFIX}/bin
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
mkdir -p ${DESTDIR}${MANPREFIX}/man1
sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
cp dwm.desktop /usr/share/xsessions/dwm.desktop
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
${DESTDIR}${MANPREFIX}/man1/dwm.1
rm -f ${DESTDIR}${PREFIX}/bin/dwm \
${DESTDIR}${MANPREFIX}/man1/dwm.1 \
/usr/share/xsessions/dwm.desktop
.PHONY: all options clean dist install uninstall
compile_commands.json:
compiledb -n make
.PHONY: all clean dist install uninstall

View File

@ -1,115 +0,0 @@
/* See LICENSE file for copyright and license details. */
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#eeeeee";
static const char col_cyan[] = "#005577";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
};
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
};
/* layout(s) */
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 resizehints = 1; /* 1 means respect size hints in tiled resizals */
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const Layout layouts[] = {
/* symbol arrange function */
{ "[]=", tile }, /* first entry is default */
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
};
/* key definitions */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
static const Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -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_5, 4)
TAGKEYS( XK_6, 5)
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
{ MODKEY|ShiftMask, XK_q, quit, {0} },
};
/* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static const Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ 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} },
};

162
config.h Normal file
View File

@ -0,0 +1,162 @@
/* See LICENSE file for copyright and license details. */
#ifndef _H_DWM_CONF
#define _H_DWM_CONF
#include "dwm.h"
/* appearance */
const unsigned int borderpx = 1; /* border pixel of windows */
const int startwithgaps[] = { 1 }; /* 1 means gaps are used by default, this can be customized for each tag */
const unsigned int gappx[] = { 10 }; /* default gap between windows in pixels, this can be customized for each tag */
const unsigned int snap = 32; /* snap pixel */
const int showbar = 1; /* 0 means no bar */
const int topbar = 0; /* 0 means bottom bar */
const char *fonts[] = { "monospace:size=10" };
const char dmenufont[] = "monospace:size=10";
const char* THEME_BW[][3] = {
[SchemeNorm] = {"#aaaaaa", "#181818", "#181818"},
[SchemeSel] = {"#aaaaaa", "#3f3f3f", "#3f3f3f"},
};
const char* THEME_DEFAULT[][3] = {
/* text inactive tag/status bar border */
[SchemeNorm] = { "#bbbbbb", "#222222", "#444444" },
/* text active tag/middle bar border*/
[SchemeSel] = { "#eeeeee", "#005577", "#005577" },
};
#define colors THEME_BW
/* tagging */
const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 2, 0, -1 },
};
/* layout(s) */
const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
const int nmaster = 1; /* number of clients in master area */
const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
const Layout layouts[] = {
/* symbol arrange function */
{ "[T]", tile }, /* first entry is default */
{ "[F]", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
};
/* key definitions */
#define MODKEY Mod4Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/bash", "-c", cmd, NULL } }
const char* upvol[] = { "/usr/bin/pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%", NULL };
const char* downvol[] = { "/usr/bin/pactl", "set-sink-volume", "@DEFAULT_SINK@", "-5%", NULL };
const char* mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "@DEFAULT_SINK@", "toggle", NULL };
const char* light_up[] = { "/usr/bin/light", "-A", "5", NULL };
const char* light_down[] = { "/usr/bin/light", "-U", "5", NULL };
const char* rofi[] = { "rofi", "-modi", "drun", "-show", "drun", "-config", "~/.config/rofi/rofidmenu.rasi", NULL };
/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */
const StatusCmd statuscmds[] = {
{ "notify-send Mouse$BUTTON", 1 },
};
const char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL };
const Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_w, spawn, { .v = (const char*[]){"firefox", NULL} } },
{ MODKEY, XK_n, spawn, { .v = (const char*[]){"thunar", NULL} } },
{ MODKEY, XK_Return, spawn, { .v = (const char*[]){"alacritty", NULL} } },
{ 0, XF86XK_AudioPlay, spawn, { .v = (const char*[]){"firefox", NULL} } },
{ 0, XK_Print, spawn, { .v = (const char*[]){"flameshot", "gui", NULL} } },
{ 0, XF86XK_AudioStop, spawn, { .v = (const char*[]){"playerctl", "play-pause", NULL} } },
{ 0, XF86XK_AudioNext, spawn, { .v = (const char*[]){"playerctl", "next", NULL} } },
{ 0, XF86XK_AudioPrev, spawn, { .v = (const char*[]){"playerctl", "previous", NULL} } },
{ MODKEY, XK_d, spawn, { .v = rofi } },
{ 0, XF86XK_AudioRaiseVolume, spawn, { .v = upvol } },
{ 0, XF86XK_AudioLowerVolume, spawn, { .v = downvol } },
{ 0, XF86XK_AudioMute, spawn, { .v = mutevol } },
{ 0, XF86XK_MonBrightnessUp, spawn, { .v = light_up } },
{ 0, XF86XK_MonBrightnessDown, spawn, { .v = light_down} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY, XK_f, togglefullscr, {0} },
{ MODKEY, XK_Tab, view, {0} }, // Switch windows
{ MODKEY, XK_q, killclient, {0} }, // Kill prog
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XK_s, setlayout, {.v = &layouts[2]} },
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_e, quit, {0}},
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
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)
// { MODKEY, XK_minus, setgaps, {.i = -5 } },
// { MODKEY, XK_equal, setgaps, {.i = +5 } },
// { MODKEY|ShiftMask, XK_minus, setgaps, {.i = GAP_RESET } },
// { MODKEY|ShiftMask, XK_equal, setgaps, {.i = GAP_TOGGLE} },
// ????????????????????????????//
// { MODKEY, XK_comma, focusmon, {.i = -1 } },
// { MODKEY, XK_period, focusmon, {.i = +1 } },
// { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
// { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
// { MODKEY, XK_b, togglebar, {0} }, // stupid
// { MODKEY, XK_Return, zoom, {0} },
// { MODKEY, XK_d, incnmaster, {.i = -1 } },
};
/* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
const Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button1, spawn, {.v = statuscmd } },
{ ClkStatusText, 0, Button2, spawn, {.v = statuscmd } },
{ ClkStatusText, 0, Button3, spawn, {.v = statuscmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ 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} },
};
#endif

View File

@ -1,5 +1,5 @@
# dwm version
VERSION = 6.4
VERSION = 6.5
# Customize below to fit your system
@ -26,7 +26,7 @@ INCS = -I${X11INC} -I${FREETYPEINC}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
# 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 = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
LDFLAGS = ${LIBS}

22
drw.h
View File

@ -1,5 +1,25 @@
/* See LICENSE file for copyright and license details. */
#ifndef _H_DRW
#define _H_DRW
#include <signal.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
typedef struct {
Cursor cursor;
} Cur;
@ -56,3 +76,5 @@ int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned in
/* Map functions */
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
#endif

3
dwm.1
View File

@ -116,6 +116,9 @@ Zooms/cycles focused window to/from master area (tiled layouts only).
.B Mod1\-Shift\-c
Close focused window.
.TP
.B Mod1\-Shift\-f
Toggle fullscreen for focused window.
.TP
.B Mod1\-Shift\-space
Toggle focused window between tiled and floating state.
.TP

544
dwm.c
View File

@ -43,238 +43,10 @@
#include "drw.h"
#include "util.h"
#include "dwm.h"
/* macros */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
#define TAGMASK ((1 << LENGTH(tags)) - 1)
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { SchemeNorm, SchemeSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
typedef union {
int i;
unsigned int ui;
float f;
const void *v;
} Arg;
typedef struct {
unsigned int click;
unsigned int mask;
unsigned int button;
void (*func)(const Arg *arg);
const Arg arg;
} Button;
typedef struct Monitor Monitor;
typedef struct Client Client;
struct Client {
char name[256];
float mina, maxa;
int x, y, w, h;
int oldx, oldy, oldw, oldh;
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
int bw, oldbw;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
Client *next;
Client *snext;
Monitor *mon;
Window win;
};
typedef struct {
unsigned int mod;
KeySym keysym;
void (*func)(const Arg *);
const Arg arg;
} Key;
typedef struct {
const char *symbol;
void (*arrange)(Monitor *);
} Layout;
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
int showbar;
int topbar;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
const Layout *lt[2];
};
typedef struct {
const char *class;
const char *instance;
const char *title;
unsigned int tags;
int isfloating;
int monitor;
} Rule;
/* function declarations */
static void applyrules(Client *c);
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
static void arrange(Monitor *m);
static void arrangemon(Monitor *m);
static void attach(Client *c);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
static void checkotherwm(void);
static void cleanup(void);
static void cleanupmon(Monitor *mon);
static void clientmessage(XEvent *e);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
static Monitor *createmon(void);
static void destroynotify(XEvent *e);
static void detach(Client *c);
static void detachstack(Client *c);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
static Atom getatomprop(Client *c, Atom prop);
static int getrootptr(int *x, int *y);
static long getstate(Window w);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, int focused);
static void grabkeys(void);
static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
static void motionnotify(XEvent *e);
static void movemouse(const Arg *arg);
static Client *nexttiled(Client *c);
static void pop(Client *c);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
static Monitor *recttomon(int x, int y, int w, int h);
static void resize(Client *c, int x, int y, int w, int h, int interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void scan(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
static void setfocus(Client *c);
static void setfullscreen(Client *c, int fullscreen);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
static void unmapnotify(XEvent *e);
static void updatebarpos(Monitor *m);
static void updatebars(void);
static void updateclientlist(void);
static int updategeom(void);
static void updatenumlockmask(void);
static void updatesizehints(Client *c);
static void updatestatus(void);
static void updatetitle(Client *c);
static void updatewindowtype(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
/* variables */
static const char broken[] = "broken";
static char stext[256];
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh; /* bar height */
static int lrpad; /* sum of left and right padding for text */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ClientMessage] = clientmessage,
[ConfigureRequest] = configurerequest,
[ConfigureNotify] = configurenotify,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[Expose] = expose,
[FocusIn] = focusin,
[KeyPress] = keypress,
[MappingNotify] = mappingnotify,
[MapRequest] = maprequest,
[MotionNotify] = motionnotify,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
};
static Atom wmatom[WMLast], netatom[NetLast];
static int running = 1;
static Cur *cursor[CurLast];
static Clr **scheme;
static Display *dpy;
static Drw *drw;
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
/* configuration, allows nested code to access above variables */
#include "config.h"
/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
/* function implementations */
void
applyrules(Client *c)
@ -442,8 +214,27 @@ buttonpress(XEvent *e)
arg.ui = 1 << i;
} else if (ev->x < x + TEXTW(selmon->ltsymbol))
click = ClkLtSymbol;
else if (ev->x > selmon->ww - (int)TEXTW(stext))
else if (ev->x > selmon->ww - statusw) {
char *text, *s, ch;
*lastbutton = '0' + ev->button;
x = selmon->ww - statusw;
click = ClkStatusText;
statuscmdn = 0;
for (text = s = stext; *s && x <= ev->x; s++) {
if ((unsigned char)(*s) < ' ') {
ch = *s;
*s = '\0';
x += TEXTW(text) - lrpad;
*s = ch;
text = s + 1;
if (x >= ev->x)
break;
statuscmdn = ch;
}
}
}
else
click = ClkWinTitle;
} else if ((c = wintoclient(ev->window))) {
@ -635,6 +426,7 @@ Monitor *
createmon(void)
{
Monitor *m;
unsigned int i;
m = ecalloc(1, sizeof(Monitor));
m->tagset[0] = m->tagset[1] = 1;
@ -645,6 +437,26 @@ createmon(void)
m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
m->pertag = ecalloc(1, sizeof(Pertag));
m->pertag->curtag = m->pertag->prevtag = 1;
for (i = 0; i <= LENGTH(tags); i++) {
m->pertag->nmasters[i] = m->nmaster;
m->pertag->mfacts[i] = m->mfact;
m->pertag->ltidxs[i][0] = m->lt[0];
m->pertag->ltidxs[i][1] = m->lt[1];
m->pertag->sellts[i] = m->sellt;
m->pertag->showbars[i] = m->showbar;
if (i > 0) {
m->pertag->drawwithgaps[i] = startwithgaps[(i - 1) % LENGTH(gappx)];
m->pertag->gappx[i] = gappx[(i - 1) % LENGTH(gappx)];
}
}
m->pertag->drawwithgaps[0] = startwithgaps[0];
m->pertag->gappx[0] = gappx[0];
return m;
}
@ -710,9 +522,24 @@ drawbar(Monitor *m)
/* draw status first so it can be overdrawn by tags later */
if (m == selmon) { /* status is only drawn on selected monitor */
char *text, *s, ch;
drw_setscheme(drw, scheme[SchemeNorm]);
tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
x = 0;
for (text = s = stext; *s; s++) {
if ((unsigned char)(*s) < ' ') {
ch = *s;
*s = '\0';
tw = TEXTW(text) - lrpad;
drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
x += tw;
*s = ch;
text = s + 1;
}
}
tw = TEXTW(text) - lrpad + 2;
drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
tw = statusw;
}
for (c = m->clients; c; c = c->next) {
@ -803,6 +630,12 @@ focus(Client *c)
attachstack(c);
grabbuttons(c, 1);
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
if (!selmon->pertag->drawwithgaps[selmon->pertag->curtag] && !c->isfloating) {
XWindowChanges wc;
wc.sibling = selmon->barwin;
wc.stack_mode = Below;
XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
}
setfocus(c);
} else {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
@ -955,23 +788,33 @@ grabkeys(void)
{
updatenumlockmask();
{
unsigned int i, j;
unsigned int i, j, k;
unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
KeyCode code;
int start, end, skip;
KeySym *syms;
XUngrabKey(dpy, AnyKey, AnyModifier, root);
for (i = 0; i < LENGTH(keys); i++)
if ((code = XKeysymToKeycode(dpy, keys[i].keysym)))
for (j = 0; j < LENGTH(modifiers); j++)
XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
True, GrabModeAsync, GrabModeAsync);
XDisplayKeycodes(dpy, &start, &end);
syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
if (!syms)
return;
for (k = start; k <= end; k++)
for (i = 0; i < LENGTH(keys); i++)
/* skip modifier codes, we do that ourselves */
if (keys[i].keysym == syms[(k - start) * skip])
for (j = 0; j < LENGTH(modifiers); j++)
XGrabKey(dpy, k,
keys[i].mod | modifiers[j],
root, True,
GrabModeAsync, GrabModeAsync);
XFree(syms);
}
}
void
incnmaster(const Arg *arg)
{
selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
arrange(selmon);
}
@ -1113,7 +956,10 @@ monocle(Monitor *m)
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);
if (selmon->pertag->drawwithgaps[selmon->pertag->curtag])
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
else
resize(c, m->wx - c->bw, m->wy, m->ww, m->wh, False);
}
void
@ -1283,6 +1129,15 @@ resizeclient(Client *c, int x, int y, int w, int h)
c->oldw = c->w; c->w = wc.width = w;
c->oldh = c->h; c->h = wc.height = h;
wc.border_width = c->bw;
if (!selmon->pertag->drawwithgaps[selmon->pertag->curtag] && /* this is the noborderfloatingfix patch, slightly modified so that it will work if, and only if, gaps are disabled. */
(((nexttiled(c->mon->clients) == c && !nexttiled(c->next)) /* these two first lines are the only ones changed. if you are manually patching and have noborder installed already, just change these lines; or conversely, just remove this section if the noborder patch is not desired;) */
|| &monocle == c->mon->lt[c->mon->sellt]->arrange))
&& !c->isfullscreen && !c->isfloating
&& NULL != c->mon->lt[c->mon->sellt]->arrange) {
c->w = wc.width += c->bw * 2;
c->h = wc.height += c->bw * 2;
wc.border_width = 0;
}
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
configure(c);
XSync(dpy, False);
@ -1381,6 +1236,12 @@ run(void)
handler[ev.type](&ev); /* call handler */
}
void
runAutostart(void) {
system("cd ~/.dwm; ./autostart_blocking.sh");
system("cd ~/.dwm; ./autostart.sh &");
}
void
scan(void)
{
@ -1498,13 +1359,36 @@ setfullscreen(Client *c, int fullscreen)
}
}
void
setgaps(const Arg *arg)
{
switch(arg->i)
{
case GAP_TOGGLE:
selmon->pertag->drawwithgaps[selmon->pertag->curtag] = !selmon->pertag->drawwithgaps[selmon->pertag->curtag];
break;
case GAP_RESET:
if (selmon->pertag->curtag > 0)
selmon->pertag->gappx[selmon->pertag->curtag] = gappx[selmon->pertag->curtag - 1 % LENGTH(gappx)];
else
selmon->pertag->gappx[0] = gappx[0];
break;
default:
if (selmon->pertag->gappx[selmon->pertag->curtag] + arg->i < 0)
selmon->pertag->gappx[selmon->pertag->curtag] = 0;
else
selmon->pertag->gappx[selmon->pertag->curtag] += arg->i;
}
arrange(selmon);
}
void
setlayout(const Arg *arg)
{
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
selmon->sellt ^= 1;
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
if (arg && arg->v)
selmon->lt[selmon->sellt] = (Layout *)arg->v;
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
if (selmon->sel)
arrange(selmon);
@ -1523,7 +1407,7 @@ setmfact(const Arg *arg)
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
if (f < 0.05 || f > 0.95)
return;
selmon->mfact = f;
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
arrange(selmon);
}
@ -1533,9 +1417,16 @@ setup(void)
int i;
XSetWindowAttributes wa;
Atom utf8string;
struct sigaction sa;
/* clean up any zombies immediately */
sigchld(0);
/* do not transform children into zombies when they terminate */
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
sa.sa_handler = SIG_IGN;
sigaction(SIGCHLD, &sa, NULL);
/* clean up any zombies (inherited from .xinitrc etc) immediately */
while (waitpid(-1, NULL, WNOHANG) > 0);
/* init screen */
screen = DefaultScreen(dpy);
@ -1628,21 +1519,34 @@ showhide(Client *c)
}
}
void
sigchld(int unused)
{
if (signal(SIGCHLD, sigchld) == SIG_ERR)
die("can't install SIGCHLD handler:");
while (0 < waitpid(-1, NULL, WNOHANG));
}
void
spawn(const Arg *arg)
{
struct sigaction sa;
// if (arg->v == dmenucmd)
// dmenumon[0] = '0' + selmon->num;
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
if (arg->v == statuscmd) {
for (int i = 0; i < LENGTH(statuscmds); i++) {
if (statuscmdn == statuscmds[i].id) {
statuscmd[2] = statuscmds[i].cmd;
setenv("BUTTON", lastbutton, 1);
break;
}
}
if (!statuscmd[2])
exit(EXIT_SUCCESS);
}
setsid();
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &sa, NULL);
execvp(((char **)arg->v)[0], (char **)arg->v);
die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
}
@ -1675,29 +1579,48 @@ tile(Monitor *m)
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
if (n == 0)
return;
if (n > m->nmaster)
mw = m->nmaster ? m->ww * m->mfact : 0;
else
mw = m->ww;
for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
if (i < m->nmaster) {
h = (m->wh - my) / (MIN(n, m->nmaster) - i);
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
if (my + HEIGHT(c) < m->wh)
my += HEIGHT(c);
} else {
h = (m->wh - ty) / (n - i);
resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
if (ty + HEIGHT(c) < m->wh)
ty += HEIGHT(c);
}
if (m->pertag->drawwithgaps[m->pertag->curtag]) { /* draw with fullgaps logic */
if (n > m->nmaster)
mw = m->nmaster ? m->ww * m->mfact : 0;
else
mw = m->ww - m->pertag->gappx[m->pertag->curtag];
for (i = 0, my = ty = m->pertag->gappx[m->pertag->curtag], c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
if (i < m->nmaster) {
h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->pertag->gappx[m->pertag->curtag];
resize(c, m->wx + m->pertag->gappx[m->pertag->curtag], m->wy + my, mw - (2*c->bw) - m->pertag->gappx[m->pertag->curtag], h - (2*c->bw), 0);
if (my + HEIGHT(c) + m->pertag->gappx[m->pertag->curtag] < m->wh)
my += HEIGHT(c) + m->pertag->gappx[m->pertag->curtag];
} else {
h = (m->wh - ty) / (n - i) - m->pertag->gappx[m->pertag->curtag];
resize(c, m->wx + mw + m->pertag->gappx[m->pertag->curtag], m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->pertag->gappx[m->pertag->curtag], h - (2*c->bw), 0);
if (ty + HEIGHT(c) + m->pertag->gappx[m->pertag->curtag] < m->wh)
ty += HEIGHT(c) + m->pertag->gappx[m->pertag->curtag];
}
} else { /* draw with singularborders logic */
if (n > m->nmaster)
mw = m->nmaster ? m->ww * m->mfact : 0;
else
mw = m->ww;
for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
if (i < m->nmaster) {
h = (m->wh - my) / (MIN(n, m->nmaster) - i);
if (n == 1)
resize(c, m->wx - c->bw, m->wy, m->ww, m->wh, False);
else
resize(c, m->wx - c->bw, m->wy + my, mw - c->bw, h - c->bw, False);
my += HEIGHT(c) - c->bw;
} else {
h = (m->wh - ty) / (n - i);
resize(c, m->wx + mw - c->bw, m->wy + ty, m->ww - mw, h - c->bw, False);
ty += HEIGHT(c) - c->bw;
}
}
}
void
togglebar(const Arg *arg)
{
selmon->showbar = !selmon->showbar;
selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
updatebarpos(selmon);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
arrange(selmon);
@ -1717,6 +1640,13 @@ togglefloating(const Arg *arg)
arrange(selmon);
}
void
togglefullscr(const Arg *arg)
{
if(selmon->sel)
setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
}
void
toggletag(const Arg *arg)
{
@ -1736,9 +1666,33 @@ void
toggleview(const Arg *arg)
{
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
int i;
if (newtagset) {
selmon->tagset[selmon->seltags] = newtagset;
if (newtagset == ~0) {
selmon->pertag->prevtag = selmon->pertag->curtag;
selmon->pertag->curtag = 0;
}
/* test if the user did not select the same tag */
if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
selmon->pertag->prevtag = selmon->pertag->curtag;
for (i = 0; !(newtagset & 1 << i); i++) ;
selmon->pertag->curtag = i + 1;
}
/* apply settings for this view */
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
togglebar(NULL);
focus(NULL);
arrange(selmon);
}
@ -1987,8 +1941,23 @@ updatesizehints(Client *c)
void
updatestatus(void)
{
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) {
strcpy(stext, "dwm-"VERSION);
statusw = TEXTW(stext) - lrpad + 2;
} else {
char *text, *s, ch;
statusw = 0;
for (text = s = stext; *s; s++) {
if ((unsigned char)(*s) < ' ') {
ch = *s;
*s = '\0';
statusw += TEXTW(text) - lrpad;
*s = ch;
text = s + 1;
}
}
statusw += TEXTW(text) - lrpad + 2;
}
drawbar(selmon);
}
@ -2035,11 +2004,37 @@ updatewmhints(Client *c)
void
view(const Arg *arg)
{
int i;
unsigned int tmptag;
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return;
selmon->seltags ^= 1; /* toggle sel tagset */
if (arg->ui & TAGMASK)
if (arg->ui & TAGMASK) {
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
selmon->pertag->prevtag = selmon->pertag->curtag;
if (arg->ui == ~0)
selmon->pertag->curtag = 0;
else {
for (i = 0; !(arg->ui & 1 << i); i++) ;
selmon->pertag->curtag = i + 1;
}
} else {
tmptag = selmon->pertag->prevtag;
selmon->pertag->prevtag = selmon->pertag->curtag;
selmon->pertag->curtag = tmptag;
}
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
togglebar(NULL);
focus(NULL);
arrange(selmon);
}
@ -2140,6 +2135,7 @@ main(int argc, char *argv[])
die("pledge");
#endif /* __OpenBSD__ */
scan();
runAutostart();
run();
cleanup();
XCloseDisplay(dpy);

9
dwm.desktop Normal file
View File

@ -0,0 +1,9 @@
# copy to /usr/share/xsessions/dwm.desktop
[Desktop Entry]
Encoding=UTF-8
Name=dwm
Comment=Dynamic window manager
Exec=dwm
Icon=dwm
Type=XSession

292
dwm.h Normal file
View File

@ -0,0 +1,292 @@
#ifndef _H_DWM
#define _H_DWM
#include <errno.h>
#include <locale.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
#include "drw.h"
#include "util.h"
/* macros */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
#define TAGMASK ((1 << LENGTH(tags)) - 1)
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
#define GAP_TOGGLE 100
#define GAP_RESET 0
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { SchemeNorm, SchemeSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
typedef union {
int i;
unsigned int ui;
float f;
const void *v;
} Arg;
typedef struct {
unsigned int click;
unsigned int mask;
unsigned int button;
void (*func)(const Arg *arg);
const Arg arg;
} Button;
typedef struct Monitor Monitor;
typedef struct Client Client;
struct Client {
char name[256];
float mina, maxa;
int x, y, w, h;
int oldx, oldy, oldw, oldh;
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
int bw, oldbw;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
Client *next;
Client *snext;
Monitor *mon;
Window win;
};
typedef struct {
unsigned int mod;
KeySym keysym;
void (*func)(const Arg *);
const Arg arg;
} Key;
typedef struct {
const char *symbol;
void (*arrange)(Monitor *);
} Layout;
typedef struct Pertag Pertag;
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
int showbar;
int topbar;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
const Layout *lt[2];
Pertag *pertag;
};
typedef struct {
const char *class;
const char *instance;
const char *title;
unsigned int tags;
int isfloating;
int monitor;
} Rule;
typedef struct {
const char *cmd;
int id;
} StatusCmd;
/* function declarations */
void applyrules(Client *c);
int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
void arrange(Monitor *m);
void arrangemon(Monitor *m);
void attach(Client *c);
void attachstack(Client *c);
void buttonpress(XEvent *e);
void checkotherwm(void);
void cleanup(void);
void cleanupmon(Monitor *mon);
void clientmessage(XEvent *e);
void configure(Client *c);
void configurenotify(XEvent *e);
void configurerequest(XEvent *e);
Monitor *createmon(void);
void destroynotify(XEvent *e);
void detach(Client *c);
void detachstack(Client *c);
Monitor *dirtomon(int dir);
void drawbar(Monitor *m);
void drawbars(void);
void enternotify(XEvent *e);
void expose(XEvent *e);
void focus(Client *c);
void focusin(XEvent *e);
void focusmon(const Arg *arg);
void focusstack(const Arg *arg);
Atom getatomprop(Client *c, Atom prop);
int getrootptr(int *x, int *y);
long getstate(Window w);
int gettextprop(Window w, Atom atom, char *text, unsigned int size);
void grabbuttons(Client *c, int focused);
void grabkeys(void);
void incnmaster(const Arg *arg);
void keypress(XEvent *e);
void killclient(const Arg *arg);
void manage(Window w, XWindowAttributes *wa);
void mappingnotify(XEvent *e);
void maprequest(XEvent *e);
void monocle(Monitor *m);
void motionnotify(XEvent *e);
void movemouse(const Arg *arg);
Client *nexttiled(Client *c);
void pop(Client *c);
void propertynotify(XEvent *e);
void quit(const Arg *arg);
Monitor *recttomon(int x, int y, int w, int h);
void resize(Client *c, int x, int y, int w, int h, int interact);
void resizeclient(Client *c, int x, int y, int w, int h);
void resizemouse(const Arg *arg);
void restack(Monitor *m);
void run(void);
void runAutostart(void);
void scan(void);
int sendevent(Client *c, Atom proto);
void sendmon(Client *c, Monitor *m);
void setclientstate(Client *c, long state);
void setfocus(Client *c);
void setfullscreen(Client *c, int fullscreen);
void setgaps(const Arg *arg);
void setlayout(const Arg *arg);
void setmfact(const Arg *arg);
void setup(void);
void seturgent(Client *c, int urg);
void showhide(Client *c);
void spawn(const Arg *arg);
void tag(const Arg *arg);
void tagmon(const Arg *arg);
void tile(Monitor *m);
void togglebar(const Arg *arg);
void togglefloating(const Arg *arg);
void togglefullscr(const Arg *arg);
void toggletag(const Arg *arg);
void toggleview(const Arg *arg);
void unfocus(Client *c, int setfocus);
void unmanage(Client *c, int destroyed);
void unmapnotify(XEvent *e);
void updatebarpos(Monitor *m);
void updatebars(void);
void updateclientlist(void);
int updategeom(void);
void updatenumlockmask(void);
void updatesizehints(Client *c);
void updatestatus(void);
void updatetitle(Client *c);
void updatewindowtype(Client *c);
void updatewmhints(Client *c);
void view(const Arg *arg);
Client *wintoclient(Window w);
Monitor *wintomon(Window w);
int xerror(Display *dpy, XErrorEvent *ee);
int xerrordummy(Display *dpy, XErrorEvent *ee);
int xerrorstart(Display *dpy, XErrorEvent *ee);
void zoom(const Arg *arg);
/* variables */
const char broken[] = "broken";
char stext[256];
int screen;
int sw, sh; /* X display screen geometry width, height */
int bh; /* bar height */
int lrpad; /* sum of left and right padding for text */
int (*xerrorxlib)(Display *, XErrorEvent *);
unsigned int numlockmask = 0;
void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ClientMessage] = clientmessage,
[ConfigureRequest] = configurerequest,
[ConfigureNotify] = configurenotify,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[Expose] = expose,
[FocusIn] = focusin,
[KeyPress] = keypress,
[MappingNotify] = mappingnotify,
[MapRequest] = maprequest,
[MotionNotify] = motionnotify,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
};
Atom wmatom[WMLast], netatom[NetLast];
int running = 1;
Cur *cursor[CurLast];
Clr **scheme;
Display *dpy;
Drw *drw;
Monitor *mons, *selmon;
Window root, wmcheckwin;
int statusw;
int statuscmdn;
char lastbutton[] = "-";
/* configuration, allows nested code to access above variables */
struct Pertag {
unsigned int curtag, prevtag; /* current and previous tag */
int nmasters[10]; /* number of windows in master area */
float mfacts[10]; /* mfacts per tag */
unsigned int sellts[10]; /* selected layouts */
const Layout *ltidxs[10][2]; /* matrix of tags and layouts indexes */
int showbars[10]; /* display bar for the current tag */
int drawwithgaps[10]; /* gaps toggle for each tag */
int gappx[10]; /* gaps for each tag */
};
/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[10 > 31 ? -1 : 1]; };
#endif

View File

@ -0,0 +1,68 @@
From eea13010ffc3983392857ee1e3804e3aa1064d7a Mon Sep 17 00:00:00 2001
From: Soenke Lambert <s.lambert@mittwald.de>
Date: Wed, 13 Oct 2021 18:21:09 +0200
Subject: [PATCH] Fullscreen current window with [Alt]+[Shift]+[f]
This actually fullscreens a window, instead of just hiding the statusbar
and applying the monocle layout.
---
config.def.h | 1 +
dwm.1 | 3 +++
dwm.c | 8 ++++++++
3 files changed, 12 insertions(+)
diff --git a/config.def.h b/config.def.h
index 1c0b587..8cd3204 100644
--- a/config.def.h
+++ b/config.def.h
@@ -78,6 +78,7 @@ static Key keys[] = {
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
+ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} },
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
diff --git a/dwm.1 b/dwm.1
index 13b3729..a368d05 100644
--- a/dwm.1
+++ b/dwm.1
@@ -116,6 +116,9 @@ Zooms/cycles focused window to/from master area (tiled layouts only).
.B Mod1\-Shift\-c
Close focused window.
.TP
+.B Mod1\-Shift\-f
+Toggle fullscreen for focused window.
+.TP
.B Mod1\-Shift\-space
Toggle focused window between tiled and floating state.
.TP
diff --git a/dwm.c b/dwm.c
index 4465af1..c1b899a 100644
--- a/dwm.c
+++ b/dwm.c
@@ -211,6 +211,7 @@ static void tagmon(const Arg *arg);
static void tile(Monitor *);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
+static void togglefullscr(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
@@ -1719,6 +1720,13 @@ togglefloating(const Arg *arg)
arrange(selmon);
}
+void
+togglefullscr(const Arg *arg)
+{
+ if(selmon->sel)
+ setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
+}
+
void
toggletag(const Arg *arg)
{
--
2.30.2

View File

@ -0,0 +1,39 @@
commit 5918623c5bd7fda155bf9dc3d33890c4ae1722d0
Author: Simon Bremer <simon.bremer@tum.de>
Date: Thu Dec 22 17:31:07 2016 +0100
Applied and fixed autostart patch for previous version;
diff --git a/dwm.c b/dwm.c
index d27cb67..066ed71 100644
--- a/dwm.c
+++ b/dwm.c
@@ -194,6 +194,7 @@ static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
+static void runAutostart(void);
static void scan(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
@@ -1386,6 +1387,12 @@ run(void)
}
void
+runAutostart(void) {
+ system("cd ~/.dwm; ./autostart_blocking.sh");
+ system("cd ~/.dwm; ./autostart.sh &");
+}
+
+void
scan(void)
{
unsigned int i, num;
@@ -2145,6 +2152,7 @@ main(int argc, char *argv[])
checkotherwm();
setup();
scan();
+ runAutostart();
run();
cleanup();
XCloseDisplay(dpy);

View File

@ -0,0 +1,352 @@
diff -pu dwm.git/config.def.h dwm.functionalgapspertag/config.def.h
--- dwm.git/config.def.h 2021-02-27 21:17:53.862314811 -0600
+++ dwm.functionalgapspertag/config.def.h 2021-03-01 15:40:07.312696974 -0600
@@ -2,6 +2,8 @@
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
+static const int startwithgaps[] = { 0 }; /* 1 means gaps are used by default, this can be customized for each tag */
+static const unsigned int gappx[] = { 10 }; /* default gap between windows in pixels, this can be customized for each tag */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
@@ -84,6 +86,10 @@ static Key keys[] = {
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
+ { MODKEY, XK_minus, setgaps, {.i = -5 } },
+ { MODKEY, XK_equal, setgaps, {.i = +5 } },
+ { MODKEY|ShiftMask, XK_minus, setgaps, {.i = GAP_RESET } },
+ { MODKEY|ShiftMask, XK_equal, setgaps, {.i = GAP_TOGGLE} },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
diff -pu dwm.git/dwm.c dwm.functionalgapspertag/dwm.c
--- dwm.git/dwm.c 2021-02-27 21:17:53.862314811 -0600
+++ dwm.functionalgapspertag/dwm.c 2021-03-01 17:10:10.402964866 -0600
@@ -57,6 +57,9 @@
#define TAGMASK ((1 << LENGTH(tags)) - 1)
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
+#define GAP_TOGGLE 100
+#define GAP_RESET 0
+
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { SchemeNorm, SchemeSel }; /* color schemes */
@@ -111,6 +114,8 @@ typedef struct {
void (*arrange)(Monitor *);
} Layout;
+typedef struct Pertag Pertag;
+
struct Monitor {
char ltsymbol[16];
float mfact;
@@ -130,6 +135,7 @@ struct Monitor {
Monitor *next;
Window barwin;
const Layout *lt[2];
+ Pertag *pertag;
};
typedef struct {
@@ -200,6 +206,7 @@ static void sendmon(Client *c, Monitor *
static void setclientstate(Client *c, long state);
static void setfocus(Client *c);
static void setfullscreen(Client *c, int fullscreen);
+static void setgaps(const Arg *arg);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
@@ -272,6 +279,18 @@ static Window root, wmcheckwin;
/* configuration, allows nested code to access above variables */
#include "config.h"
+struct Pertag {
+ unsigned int curtag, prevtag; /* current and previous tag */
+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
+ int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
+
+ int drawwithgaps[LENGTH(tags) + 1]; /* gaps toggle for each tag */
+ int gappx[LENGTH(tags) + 1]; /* gaps for each tag */
+};
+
/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
@@ -632,6 +651,7 @@ Monitor *
createmon(void)
{
Monitor *m;
+ unsigned int i;
m = ecalloc(1, sizeof(Monitor));
m->tagset[0] = m->tagset[1] = 1;
@@ -642,6 +662,26 @@ createmon(void)
m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+ m->pertag = ecalloc(1, sizeof(Pertag));
+ m->pertag->curtag = m->pertag->prevtag = 1;
+
+ for (i = 0; i <= LENGTH(tags); i++) {
+ m->pertag->nmasters[i] = m->nmaster;
+ m->pertag->mfacts[i] = m->mfact;
+
+ m->pertag->ltidxs[i][0] = m->lt[0];
+ m->pertag->ltidxs[i][1] = m->lt[1];
+ m->pertag->sellts[i] = m->sellt;
+
+ m->pertag->showbars[i] = m->showbar;
+ if (i > 0) {
+ m->pertag->drawwithgaps[i] = startwithgaps[(i - 1) % LENGTH(gappx)];
+ m->pertag->gappx[i] = gappx[(i - 1) % LENGTH(gappx)];
+ }
+ }
+ m->pertag->drawwithgaps[0] = startwithgaps[0];
+ m->pertag->gappx[0] = gappx[0];
+
return m;
}
@@ -797,6 +837,12 @@ focus(Client *c)
attachstack(c);
grabbuttons(c, 1);
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+ if (!selmon->pertag->drawwithgaps[selmon->pertag->curtag] && !c->isfloating) {
+ XWindowChanges wc;
+ wc.sibling = selmon->barwin;
+ wc.stack_mode = Below;
+ XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
+ }
setfocus(c);
} else {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
@@ -967,7 +1013,7 @@ grabkeys(void)
void
incnmaster(const Arg *arg)
{
- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
arrange(selmon);
}
@@ -1113,7 +1159,10 @@ monocle(Monitor *m)
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);
+ if (selmon->pertag->drawwithgaps[selmon->pertag->curtag])
+ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
+ else
+ resize(c, m->wx - c->bw, m->wy, m->ww, m->wh, False);
}
void
@@ -1283,6 +1332,15 @@ resizeclient(Client *c, int x, int y, in
c->oldw = c->w; c->w = wc.width = w;
c->oldh = c->h; c->h = wc.height = h;
wc.border_width = c->bw;
+ if (!selmon->pertag->drawwithgaps[selmon->pertag->curtag] && /* this is the noborderfloatingfix patch, slightly modified so that it will work if, and only if, gaps are disabled. */
+ (((nexttiled(c->mon->clients) == c && !nexttiled(c->next)) /* these two first lines are the only ones changed. if you are manually patching and have noborder installed already, just change these lines; or conversely, just remove this section if the noborder patch is not desired;) */
+ || &monocle == c->mon->lt[c->mon->sellt]->arrange))
+ && !c->isfullscreen && !c->isfloating
+ && NULL != c->mon->lt[c->mon->sellt]->arrange) {
+ c->w = wc.width += c->bw * 2;
+ c->h = wc.height += c->bw * 2;
+ wc.border_width = 0;
+ }
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
configure(c);
XSync(dpy, False);
@@ -1499,12 +1557,35 @@ setfullscreen(Client *c, int fullscreen)
}
void
+setgaps(const Arg *arg)
+{
+ switch(arg->i)
+ {
+ case GAP_TOGGLE:
+ selmon->pertag->drawwithgaps[selmon->pertag->curtag] = !selmon->pertag->drawwithgaps[selmon->pertag->curtag];
+ break;
+ case GAP_RESET:
+ if (selmon->pertag->curtag > 0)
+ selmon->pertag->gappx[selmon->pertag->curtag] = gappx[selmon->pertag->curtag - 1 % LENGTH(gappx)];
+ else
+ selmon->pertag->gappx[0] = gappx[0];
+ break;
+ default:
+ if (selmon->pertag->gappx[selmon->pertag->curtag] + arg->i < 0)
+ selmon->pertag->gappx[selmon->pertag->curtag] = 0;
+ else
+ selmon->pertag->gappx[selmon->pertag->curtag] += arg->i;
+ }
+ arrange(selmon);
+}
+
+void
setlayout(const Arg *arg)
{
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
- selmon->sellt ^= 1;
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
if (arg && arg->v)
- selmon->lt[selmon->sellt] = (Layout *)arg->v;
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
if (selmon->sel)
arrange(selmon);
@@ -1523,7 +1604,7 @@ setmfact(const Arg *arg)
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
if (f < 0.05 || f > 0.95)
return;
- selmon->mfact = f;
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
arrange(selmon);
}
@@ -1680,29 +1761,48 @@ tile(Monitor *m)
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
if (n == 0)
return;
-
- if (n > m->nmaster)
- mw = m->nmaster ? m->ww * m->mfact : 0;
- else
- mw = m->ww;
- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < m->nmaster) {
- h = (m->wh - my) / (MIN(n, m->nmaster) - i);
- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
- if (my + HEIGHT(c) < m->wh)
- my += HEIGHT(c);
- } else {
- h = (m->wh - ty) / (n - i);
- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
- if (ty + HEIGHT(c) < m->wh)
- ty += HEIGHT(c);
- }
+ if (m->pertag->drawwithgaps[m->pertag->curtag]) { /* draw with fullgaps logic */
+ if (n > m->nmaster)
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ else
+ mw = m->ww - m->pertag->gappx[m->pertag->curtag];
+ for (i = 0, my = ty = m->pertag->gappx[m->pertag->curtag], c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->pertag->gappx[m->pertag->curtag];
+ resize(c, m->wx + m->pertag->gappx[m->pertag->curtag], m->wy + my, mw - (2*c->bw) - m->pertag->gappx[m->pertag->curtag], h - (2*c->bw), 0);
+ if (my + HEIGHT(c) + m->pertag->gappx[m->pertag->curtag] < m->wh)
+ my += HEIGHT(c) + m->pertag->gappx[m->pertag->curtag];
+ } else {
+ h = (m->wh - ty) / (n - i) - m->pertag->gappx[m->pertag->curtag];
+ resize(c, m->wx + mw + m->pertag->gappx[m->pertag->curtag], m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->pertag->gappx[m->pertag->curtag], h - (2*c->bw), 0);
+ if (ty + HEIGHT(c) + m->pertag->gappx[m->pertag->curtag] < m->wh)
+ ty += HEIGHT(c) + m->pertag->gappx[m->pertag->curtag];
+ }
+ } else { /* draw with singularborders logic */
+ if (n > m->nmaster)
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ else
+ mw = m->ww;
+ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if (i < m->nmaster) {
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i);
+ if (n == 1)
+ resize(c, m->wx - c->bw, m->wy, m->ww, m->wh, False);
+ else
+ resize(c, m->wx - c->bw, m->wy + my, mw - c->bw, h - c->bw, False);
+ my += HEIGHT(c) - c->bw;
+ } else {
+ h = (m->wh - ty) / (n - i);
+ resize(c, m->wx + mw - c->bw, m->wy + ty, m->ww - mw, h - c->bw, False);
+ ty += HEIGHT(c) - c->bw;
+ }
+ }
}
void
togglebar(const Arg *arg)
{
- selmon->showbar = !selmon->showbar;
+ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
updatebarpos(selmon);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
arrange(selmon);
@@ -1741,9 +1841,33 @@ void
toggleview(const Arg *arg)
{
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+ int i;
if (newtagset) {
selmon->tagset[selmon->seltags] = newtagset;
+
+ if (newtagset == ~0) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->pertag->curtag = 0;
+ }
+
+ /* test if the user did not select the same tag */
+ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ for (i = 0; !(newtagset & 1 << i); i++) ;
+ selmon->pertag->curtag = i + 1;
+ }
+
+ /* apply settings for this view */
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
+
focus(NULL);
arrange(selmon);
}
@@ -2038,11 +2162,37 @@ updatewmhints(Client *c)
void
view(const Arg *arg)
{
+ int i;
+ unsigned int tmptag;
+
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return;
selmon->seltags ^= 1; /* toggle sel tagset */
- if (arg->ui & TAGMASK)
+ if (arg->ui & TAGMASK) {
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+
+ if (arg->ui == ~0)
+ selmon->pertag->curtag = 0;
+ else {
+ for (i = 0; !(arg->ui & 1 << i); i++) ;
+ selmon->pertag->curtag = i + 1;
+ }
+ } else {
+ tmptag = selmon->pertag->prevtag;
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->pertag->curtag = tmptag;
+ }
+
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
+
focus(NULL);
arrange(selmon);
}

View File

@ -0,0 +1,167 @@
From 02c4a28dd7f3a88eef3a4e533ace35f79cf09d57 Mon Sep 17 00:00:00 2001
From: Daniel Bylinka <daniel.bylinka@gmail.com>
Date: Fri, 2 Apr 2021 19:34:38 +0200
Subject: [PATCH] [statuscmd] Run shell commands based on mouse location and
button
---
config.def.h | 10 ++++++-
dwm.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 81 insertions(+), 5 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1c0b587..8f88366 100644
--- a/config.def.h
+++ b/config.def.h
@@ -59,6 +59,12 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
+/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */
+static const StatusCmd statuscmds[] = {
+ { "notify-send Mouse$BUTTON", 1 },
+};
+static const char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL };
+
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
@@ -103,7 +109,9 @@ static Button buttons[] = {
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkStatusText, 0, Button1, spawn, {.v = statuscmd } },
+ { ClkStatusText, 0, Button2, spawn, {.v = statuscmd } },
+ { ClkStatusText, 0, Button3, spawn, {.v = statuscmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
diff --git a/dwm.c b/dwm.c
index b0b3466..eb478a5 100644
--- a/dwm.c
+++ b/dwm.c
@@ -141,6 +141,11 @@ typedef struct {
int monitor;
} Rule;
+typedef struct {
+ const char *cmd;
+ int id;
+} StatusCmd;
+
/* function declarations */
static void applyrules(Client *c);
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
@@ -238,6 +243,9 @@ static void zoom(const Arg *arg);
/* variables */
static const char broken[] = "broken";
static char stext[256];
+static int statusw;
+static int statuscmdn;
+static char lastbutton[] = "-";
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh, blw = 0; /* bar geometry */
@@ -440,8 +448,27 @@ buttonpress(XEvent *e)
arg.ui = 1 << i;
} else if (ev->x < x + blw)
click = ClkLtSymbol;
- else if (ev->x > selmon->ww - (int)TEXTW(stext))
+ else if (ev->x > selmon->ww - statusw) {
+ char *text, *s, ch;
+ *lastbutton = '0' + ev->button;
+
+ x = selmon->ww - statusw;
click = ClkStatusText;
+
+ statuscmdn = 0;
+ for (text = s = stext; *s && x <= ev->x; s++) {
+ if ((unsigned char)(*s) < ' ') {
+ ch = *s;
+ *s = '\0';
+ x += TEXTW(text) - lrpad;
+ *s = ch;
+ text = s + 1;
+ if (x >= ev->x)
+ break;
+ statuscmdn = ch;
+ }
+ }
+ }
else
click = ClkWinTitle;
} else if ((c = wintoclient(ev->window))) {
@@ -704,9 +731,24 @@ drawbar(Monitor *m)
/* draw status first so it can be overdrawn by tags later */
if (m == selmon) { /* status is only drawn on selected monitor */
+ char *text, *s, ch;
drw_setscheme(drw, scheme[SchemeNorm]);
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+
+ x = 0;
+ for (text = s = stext; *s; s++) {
+ if ((unsigned char)(*s) < ' ') {
+ ch = *s;
+ *s = '\0';
+ tw = TEXTW(text) - lrpad;
+ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
+ x += tw;
+ *s = ch;
+ text = s + 1;
+ }
+ }
+ tw = TEXTW(text) - lrpad + 2;
+ drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0);
+ tw = statusw;
}
for (c = m->clients; c; c = c->next) {
@@ -1645,6 +1687,17 @@ spawn(const Arg *arg)
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
+ if (arg->v == statuscmd) {
+ for (int i = 0; i < LENGTH(statuscmds); i++) {
+ if (statuscmdn == statuscmds[i].id) {
+ statuscmd[2] = statuscmds[i].cmd;
+ setenv("BUTTON", lastbutton, 1);
+ break;
+ }
+ }
+ if (!statuscmd[2])
+ exit(EXIT_SUCCESS);
+ }
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
@@ -1990,8 +2043,23 @@ updatesizehints(Client *c)
void
updatestatus(void)
{
- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
+ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) {
strcpy(stext, "dwm-"VERSION);
+ statusw = TEXTW(stext) - lrpad + 2;
+ } else {
+ char *text, *s, ch;
+ statusw = 0;
+ for (text = s = stext; *s; s++) {
+ if ((unsigned char)(*s) < ' ') {
+ ch = *s;
+ *s = '\0';
+ statusw += TEXTW(text) - lrpad;
+ *s = ch;
+ text = s + 1;
+ }
+ }
+ statusw += TEXTW(text) - lrpad + 2;
+ }
drawbar(selmon);
}
--
2.31.0