Compare commits

..

3 Commits

Author SHA1 Message Date
f4328ead13 new config 2022-10-31 17:05:51 +01:00
e44f17bfcc config 2021-07-03 19:17:40 +02:00
67d76bdc68 Do not allow focus to drift from fullscreen client via focusstack()
It generally doesn't make much sense to allow focusstack() to navigate
away from the selected fullscreen client, as you can't even see which
client you're selecting behind it.

I have had this up for a while on the wiki as a separate patch[0], but
it seems reasonable to avoid this behaviour in dwm mainline, since I'm
struggling to think of any reason to navigate away from a fullscreen
client other than a mistake.

0: https://dwm.suckless.org/patches/alwaysfullscreen/
2021-03-29 19:16:27 +02:00
8 changed files with 58 additions and 782 deletions

1
.gitignore vendored
View File

@ -1 +0,0 @@
rebuild.sh

4
README
View File

@ -1,9 +1,5 @@
dwm - dynamic window manager
============================
version of dwm with my costum patches
description from suckless
=========================
dwm is an extremely fast, small, and dynamic window manager for X.

View File

@ -3,7 +3,6 @@
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
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" };
@ -27,11 +26,9 @@ static const Rule rules[] = {
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating isterminal noswallow monitor */
{ "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 },
{ "St", NULL, NULL, 0, 0, 1, 0, -1 },
{ NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
};
/* layout(s) */

View File

@ -1,5 +1,6 @@
/* See LICENSE file for copyright and license details. */
#include <string.h>
#include <X11/XF86keysym.h>
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
@ -20,20 +21,25 @@ static const char *colors[][3] = {
};
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "dc", "KP", "m", "g", "mail", "t"};
static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating isterminal noswallow monitor */
{ "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
//{ "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 },
{"KeePassXC",NULL, NULL, 1 << 8, 0, 0, 0, -1},
{NULL, NULL, "Discord Updater",1 << 7, 0, 0, 0, -1},
{NULL, NULL, "Discord", 1 << 7, 0, 0, 0, -1},
{ "St", NULL, NULL, 0, 0, 1, 0, -1 },
/* class instance title tags mask isfloating monitor */
{"KeePassXC",NULL, NULL, 1 << 8, 0, -1},
{NULL, NULL, "newsboat", 1 << 11, 0, -1},
{NULL, NULL, "vimpc", 1 << 9, 0, -1},
{NULL, NULL, "Discord Updater",1 << 7, 0, -1},
{NULL, NULL, "Discord", 1 << 7, 0, -1},
{"thunderbird", NULL, NULL, 1 << 11, 0, -1},
{"MultiMC5", NULL, NULL, 1 << 10, 0, -1},
{"Minecraft", "Minecraft", NULL, 1 << 10, 0, -1},
{NULL, NULL, "Steam", 1 << 10, 1, -1},
{"Steam", NULL, NULL, 1 << 10, 1, -1},
{"Microsoft Teams - Preview", NULL, NULL, 1 << 12, 0, -1},
};
/* layout(s) */
@ -65,23 +71,38 @@ static const char *dmenucmd[] = { "dmenu", "-i", "-m", dmenumon, "-fn", dmenufon
static char dmenucmdstr[256] = "--dmenu=\"";
static const char *j4_dmenu_desktopcmd[] = {"j4-dmenu-desktop", dmenucmdstr, NULL};
static const char *termcmd[] = { "st", "-f", "Liberation Mono:size=10.5", NULL };
static const char *firefoxcmd[] = {"firefox", NULL};
static const char *sleepcmd[] = {"loginctl", "suspend", NULL};
static const char *shutdowncmd[] = {"loginctl", "poweroff", NULL};
static const char *browsercmd[] = {"firefox", NULL};
static const char *shutdowncmd[] = {"systemctl", "poweroff", NULL};
static const char *lockcmd[] = {"loginctl", "lock-session", NULL};
static const char *rebootcmd[] = {"loginctl", "reboot", NULL};
static const char *screenshotcmd[] = {"/bin/bash", "-c", "import -window root ~/Bilder/screenshots/$(date +%m_%d_%y_%T).png", NULL};
static const char *rebootcmd[] = {"systemctl", "reboot", NULL};
static const char *screenshotcmd[] = {"screenshot", NULL};
static const char *mpcTogglecmd[] = {"mpc", "toggle", NULL};
static const char *mpcNextcmd[] = {"mpc", "next", NULL};
static const char *mpcPrevcmd[] = {"mpc", "prev", NULL};
static const char *mpcBegincmd[] = {"mpc", "seek", "0", NULL};
static const char *mpcLowerVolumecmd[] = {"mpc", "volume", "-5", NULL};
static const char *mpcRaiseVolumecmd[] = {"mpc", "volume", "+5", NULL};
static const char *dummycmd[] = {"echo", "-n", NULL};
static const char *mainSpeakercmd[] = {"main-speaker", NULL};
static const char *soundbarcmd[] = {"pulse-sink", "alsa_output.pci-0000_28_00.1.hdmi-stereo-extra4"};
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = j4_dmenu_desktopcmd} },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_o, spawn, {.v = firefoxcmd} },
{ MODKEY|ShiftMask, XK_s, spawn, {.v = sleepcmd}},
{ MODKEY, XK_o, spawn, {.v = browsercmd} },
{ MODKEY|ShiftMask, XK_h, spawn, {.v = shutdowncmd}},
{ MODKEY|ShiftMask, XK_l, spawn, {.v = lockcmd}},
{ MODKEY|ShiftMask, XK_r, spawn, {.v = rebootcmd}},
{ MODKEY, XK_s, spawn, {.v = screenshotcmd}},
{ 0, XF86XK_AudioPlay,spawn, {.v = mpcTogglecmd}},
{ 0, XF86XK_AudioNext,spawn, {.v = mpcNextcmd}},
{ 0, XF86XK_AudioPrev,spawn, {.v = mpcPrevcmd}},
{ 0, XF86XK_AudioStop,spawn, {.v = mpcBegincmd}},
{ 0, XF86XK_AudioLowerVolume,spawn,{.v = mpcLowerVolumecmd}},
{ 0, XF86XK_AudioRaiseVolume,spawn,{.v = mpcRaiseVolumecmd}},
{ MODKEY, XK_m, spawn, {.v = soundbarcmd}},
{ MODKEY, XK_n, spawn, {.v = mainSpeakercmd}},
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
@ -91,7 +112,7 @@ static Key keys[] = {
{ 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_c, killclient, {0} },
//{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
//{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
//{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
@ -110,8 +131,12 @@ static Key keys[] = {
TAGKEYS( XK_5, 4)
TAGKEYS( XK_6, 5)
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
TAGKEYS( XK_e, 7)
TAGKEYS( XK_w, 8)
TAGKEYS( XK_y, 9)
TAGKEYS( XK_g, 10)
TAGKEYS( XK_u, 11)
TAGKEYS( XK_z, 12)
{ MODKEY|ShiftMask, XK_q, quit, {0} },
};

View File

@ -7,23 +7,22 @@ VERSION = 6.2
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/include
X11LIB = /usr/lib64
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# Xinerama, comment if you don't want it
#XINERAMALIBS = -lXinerama
#XINERAMAFLAGS = -DXINERAMA
XINERAMALIBS = -lXinerama
XINERAMAFLAGS = -DXINERAMA
# freetype
FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
#KVMLIB = -lkvm
# includes and libs
INCS = -I${X11INC} -I${FREETYPEINC}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}

273
dwm.c
View File

@ -20,7 +20,6 @@
*
* To understand everything else, start reading main().
*/
#include <assert.h>
#include <errno.h>
#include <locale.h>
#include <signal.h>
@ -29,8 +28,6 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
@ -43,12 +40,6 @@
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
#include <X11/Xlib-xcb.h>
#include <xcb/res.h>
#ifdef __OpenBSD__
#include <sys/sysctl.h>
#include <kvm.h>
#endif /* __OpenBSD */
#include "drw.h"
#include "util.h"
@ -101,11 +92,9 @@ struct Client {
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int bw, oldbw;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
pid_t pid;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
Client *next;
Client *snext;
Client *swallowing;
Monitor *mon;
Window win;
};
@ -149,8 +138,6 @@ typedef struct {
const char *title;
unsigned int tags;
int isfloating;
int isterminal;
int noswallow;
int monitor;
} Rule;
@ -248,12 +235,6 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
static pid_t getparentprocess(pid_t p);
static int isdescprocess(pid_t p, pid_t c);
static Client *swallowingclient(Window w);
static Client *termforwin(const Client *c);
static pid_t winpid(Window w);
/* variables */
static const char broken[] = "broken";
static char stext[256];
@ -288,8 +269,6 @@ static Drw *drw;
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
static xcb_connection_t *xcon;
/* configuration, allows nested code to access above variables */
#include "config.h"
@ -319,8 +298,6 @@ applyrules(Client *c)
&& (!r->class || strstr(class, r->class))
&& (!r->instance || strstr(instance, r->instance)))
{
c->isterminal = r->isterminal;
c->noswallow = r->noswallow;
c->isfloating = r->isfloating;
c->tags |= r->tags;
for (m = mons; m && m->num != r->monitor; m = m->next);
@ -437,53 +414,6 @@ attachstack(Client *c)
c->mon->stack = c;
}
void
swallow(Client *p, Client *c)
{
if (c->noswallow || c->isterminal)
return;
if (c->noswallow && !swallowfloating && c->isfloating)
return;
detach(c);
detachstack(c);
setclientstate(c, WithdrawnState);
XUnmapWindow(dpy, p->win);
p->swallowing = c;
c->mon = p->mon;
Window w = p->win;
p->win = c->win;
c->win = w;
updatetitle(p);
XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
arrange(p->mon);
configure(p);
updateclientlist();
}
void
unswallow(Client *c)
{
c->win = c->swallowing->win;
free(c->swallowing);
c->swallowing = NULL;
/* unfullscreen the client */
setfullscreen(c, 0);
updatetitle(c);
arrange(c->mon);
XMapWindow(dpy, c->win);
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
setclientstate(c, NormalState);
focus(NULL);
arrange(c->mon);
}
void
buttonpress(XEvent *e)
{
@ -723,9 +653,6 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
else if ((c = swallowingclient(ev->window)))
unmanage(c->swallowing, 1);
}
void
@ -908,7 +835,7 @@ focusstack(const Arg *arg)
{
Client *c = NULL, *i;
if (!selmon->sel)
if (!selmon->sel || selmon->sel->isfullscreen)
return;
if (arg->i > 0) {
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
@ -1091,13 +1018,12 @@ killclient(const Arg *arg)
void
manage(Window w, XWindowAttributes *wa)
{
Client *c, *t = NULL, *term = NULL;
Client *c, *t = NULL;
Window trans = None;
XWindowChanges wc;
c = ecalloc(1, sizeof(Client));
c->win = w;
c->pid = winpid(w);
/* geometry */
c->x = c->oldx = wa->x;
c->y = c->oldy = wa->y;
@ -1112,7 +1038,6 @@ manage(Window w, XWindowAttributes *wa)
} else {
c->mon = selmon;
applyrules(c);
term = termforwin(c);
}
if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
@ -1149,8 +1074,6 @@ manage(Window w, XWindowAttributes *wa)
c->mon->sel = c;
arrange(c->mon);
XMapWindow(dpy, c->win);
if (term)
swallow(term, c);
focus(NULL);
}
@ -1714,7 +1637,6 @@ sigchld(int unused)
while (0 < waitpid(-1, NULL, WNOHANG));
}
#define SPAWN_CWD_DELIM " []{}()<>\"':"
void
spawn(const Arg *arg)
{
@ -1723,38 +1645,6 @@ spawn(const Arg *arg)
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
if(selmon->sel) {
const char* const home = getenv("HOME");
assert(home && strchr(home, '/'));
const size_t homelen = strlen(home);
char *cwd, *pathbuf = NULL;
struct stat statbuf;
cwd = strtok(selmon->sel->name, SPAWN_CWD_DELIM);
/* NOTE: strtok() alters selmon->sel->name in-place,
* but that does not matter because we are going to
* exec() below anyway; nothing else will use it */
while(cwd) {
if(*cwd == '~') { /* replace ~ with $HOME */
if(!(pathbuf = malloc(homelen + strlen(cwd)))) /* ~ counts for NULL term */
die("fatal: could not malloc() %u bytes\n", homelen + strlen(cwd));
strcpy(strcpy(pathbuf, home) + homelen, cwd + 1);
cwd = pathbuf;
}
if(strchr(cwd, '/') && !stat(cwd, &statbuf)) {
if(!S_ISDIR(statbuf.st_mode))
cwd = dirname(cwd);
if(!chdir(cwd))
break;
}
cwd = strtok(NULL, SPAWN_CWD_DELIM);
}
free(pathbuf);
}
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
@ -1878,20 +1768,6 @@ unmanage(Client *c, int destroyed)
Monitor *m = c->mon;
XWindowChanges wc;
if (c->swallowing) {
unswallow(c);
return;
}
Client *s = swallowingclient(c->win);
if (s) {
free(s->swallowing);
s->swallowing = NULL;
arrange(m);
focus(NULL);
return;
}
detach(c);
detachstack(c);
if (!destroyed) {
@ -1906,12 +1782,9 @@ unmanage(Client *c, int destroyed)
XUngrabServer(dpy);
}
free(c);
if (!s) {
arrange(m);
focus(NULL);
updateclientlist();
}
focus(NULL);
updateclientlist();
arrange(m);
}
void
@ -2174,136 +2047,6 @@ view(const Arg *arg)
arrange(selmon);
}
pid_t
winpid(Window w)
{
pid_t result = 0;
#ifdef __linux__
xcb_res_client_id_spec_t spec = {0};
spec.client = w;
spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
xcb_generic_error_t *e = NULL;
xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
if (!r)
return (pid_t)0;
xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
for (; i.rem; xcb_res_client_id_value_next(&i)) {
spec = i.data->spec;
if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
uint32_t *t = xcb_res_client_id_value_value(i.data);
result = *t;
break;
}
}
free(r);
if (result == (pid_t)-1)
result = 0;
#endif /* __linux__ */
#ifdef __OpenBSD__
Atom type;
int format;
unsigned long len, bytes;
unsigned char *prop;
pid_t ret;
if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 1), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
return 0;
ret = *(pid_t*)prop;
XFree(prop);
result = ret;
#endif /* __OpenBSD__ */
return result;
}
pid_t
getparentprocess(pid_t p)
{
unsigned int v = 0;
#ifdef __linux__
FILE *f;
char buf[256];
snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
if (!(f = fopen(buf, "r")))
return 0;
fscanf(f, "%*u %*s %*c %u", &v);
fclose(f);
#endif /* __linux__*/
#ifdef __OpenBSD__
int n;
kvm_t *kd;
struct kinfo_proc *kp;
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
if (!kd)
return 0;
kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
v = kp->p_ppid;
#endif /* __OpenBSD__ */
return (pid_t)v;
}
int
isdescprocess(pid_t p, pid_t c)
{
while (p != c && c != 0)
c = getparentprocess(c);
return (int)c;
}
Client *
termforwin(const Client *w)
{
Client *c;
Monitor *m;
if (!w->pid || w->isterminal)
return NULL;
for (m = mons; m; m = m->next) {
for (c = m->clients; c; c = c->next) {
if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
return c;
}
}
return NULL;
}
Client *
swallowingclient(Window w)
{
Client *c;
Monitor *m;
for (m = mons; m; m = m->next) {
for (c = m->clients; c; c = c->next) {
if (c->swallowing && c->swallowing->win == w)
return c;
}
}
return NULL;
}
Client *
wintoclient(Window w)
{
@ -2396,12 +2139,10 @@ main(int argc, char *argv[])
fputs("warning: no locale support\n", stderr);
if (!(dpy = XOpenDisplay(NULL)))
die("dwm: cannot open display");
if (!(xcon = XGetXCBConnection(dpy)))
die("dwm: cannot get xcb connection\n");
checkotherwm();
setup();
#ifdef __OpenBSD__
if (pledge("stdio rpath proc exec ps", NULL) == -1)
if (pledge("stdio rpath proc exec", NULL) == -1)
die("pledge");
#endif /* __OpenBSD__ */
scan();

View File

@ -1,69 +0,0 @@
https://github.com/sunaku/.dwm/compare/tip...spawn_cwd
---
diff --git a/dwm.c b/dwm.c
index 1d78655..156ee60 100644
--- a/dwm.c
+++ b/dwm.c
@@ -20,6 +20,7 @@
*
* To understand everything else, start reading main().
*/
+#include <assert.h>
#include <errno.h>
#include <locale.h>
#include <stdarg.h>
@@ -28,6 +29,8 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <libgen.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
@@ -1661,11 +1664,45 @@ sigchld(int unused) {
while(0 < waitpid(-1, NULL, WNOHANG));
}
+#define SPAWN_CWD_DELIM " []{}()<>\"':"
+
void
spawn(const Arg *arg) {
if(fork() == 0) {
if(dpy)
close(ConnectionNumber(dpy));
+ if(selmon->sel) {
+ const char* const home = getenv("HOME");
+ assert(home && strchr(home, '/'));
+ const size_t homelen = strlen(home);
+ char *cwd, *pathbuf = NULL;
+ struct stat statbuf;
+
+ cwd = strtok(selmon->sel->name, SPAWN_CWD_DELIM);
+ /* NOTE: strtok() alters selmon->sel->name in-place,
+ * but that does not matter because we are going to
+ * exec() below anyway; nothing else will use it */
+ while(cwd) {
+ if(*cwd == '~') { /* replace ~ with $HOME */
+ if(!(pathbuf = malloc(homelen + strlen(cwd)))) /* ~ counts for NULL term */
+ die("fatal: could not malloc() %u bytes\n", homelen + strlen(cwd));
+ strcpy(strcpy(pathbuf, home) + homelen, cwd + 1);
+ cwd = pathbuf;
+ }
+
+ if(strchr(cwd, '/') && !stat(cwd, &statbuf)) {
+ if(!S_ISDIR(statbuf.st_mode))
+ cwd = dirname(cwd);
+
+ if(!chdir(cwd))
+ break;
+ }
+
+ cwd = strtok(NULL, SPAWN_CWD_DELIM);
+ }
+
+ free(pathbuf);
+ }
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);

View File

@ -1,412 +0,0 @@
From b2de9b0fd7988241db516a8f032f26cb9cf32be1 Mon Sep 17 00:00:00 2001
From: Ben <ben@0x1bi.net>
Date: Fri, 7 Aug 2020 20:14:29 -0400
Subject: [PATCH] added openbsd support for swallowing
---
config.def.h | 9 +-
config.mk | 3 +-
dwm.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 237 insertions(+), 10 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1c0b587..fe51476 100644
--- a/config.def.h
+++ b/config.def.h
@@ -3,6 +3,7 @@
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
+static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
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" };
@@ -26,9 +27,11 @@ static const Rule rules[] = {
* 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 },
+ /* class instance title tags mask isfloating isterminal noswallow monitor */
+ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 },
+ { "St", NULL, NULL, 0, 0, 1, 0, -1 },
+ { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
};
/* layout(s) */
diff --git a/config.mk b/config.mk
index 7084c33..ff9e508 100644
--- a/config.mk
+++ b/config.mk
@@ -19,10 +19,11 @@ FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
+#KVMLIB = -lkvm
# includes and libs
INCS = -I${X11INC} -I${FREETYPEINC}
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB}
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
diff --git a/dwm.c b/dwm.c
index 9fd0286..e9f08f7 100644
--- a/dwm.c
+++ b/dwm.c
@@ -40,6 +40,12 @@
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
+#include <X11/Xlib-xcb.h>
+#include <xcb/res.h>
+#ifdef __OpenBSD__
+#include <sys/sysctl.h>
+#include <kvm.h>
+#endif /* __OpenBSD */
#include "drw.h"
#include "util.h"
@@ -92,9 +98,11 @@ struct Client {
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int bw, oldbw;
unsigned int tags;
- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
+ pid_t pid;
Client *next;
Client *snext;
+ Client *swallowing;
Monitor *mon;
Window win;
};
@@ -138,6 +146,8 @@ typedef struct {
const char *title;
unsigned int tags;
int isfloating;
+ int isterminal;
+ int noswallow;
int monitor;
} Rule;
@@ -235,6 +245,12 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
+static pid_t getparentprocess(pid_t p);
+static int isdescprocess(pid_t p, pid_t c);
+static Client *swallowingclient(Window w);
+static Client *termforwin(const Client *c);
+static pid_t winpid(Window w);
+
/* variables */
static const char broken[] = "broken";
static char stext[256];
@@ -269,6 +285,8 @@ static Drw *drw;
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
+static xcb_connection_t *xcon;
+
/* configuration, allows nested code to access above variables */
#include "config.h"
@@ -298,6 +316,8 @@ applyrules(Client *c)
&& (!r->class || strstr(class, r->class))
&& (!r->instance || strstr(instance, r->instance)))
{
+ c->isterminal = r->isterminal;
+ c->noswallow = r->noswallow;
c->isfloating = r->isfloating;
c->tags |= r->tags;
for (m = mons; m && m->num != r->monitor; m = m->next);
@@ -414,6 +434,53 @@ attachstack(Client *c)
c->mon->stack = c;
}
+void
+swallow(Client *p, Client *c)
+{
+
+ if (c->noswallow || c->isterminal)
+ return;
+ if (c->noswallow && !swallowfloating && c->isfloating)
+ return;
+
+ detach(c);
+ detachstack(c);
+
+ setclientstate(c, WithdrawnState);
+ XUnmapWindow(dpy, p->win);
+
+ p->swallowing = c;
+ c->mon = p->mon;
+
+ Window w = p->win;
+ p->win = c->win;
+ c->win = w;
+ updatetitle(p);
+ XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
+ arrange(p->mon);
+ configure(p);
+ updateclientlist();
+}
+
+void
+unswallow(Client *c)
+{
+ c->win = c->swallowing->win;
+
+ free(c->swallowing);
+ c->swallowing = NULL;
+
+ /* unfullscreen the client */
+ setfullscreen(c, 0);
+ updatetitle(c);
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+ setclientstate(c, NormalState);
+ focus(NULL);
+ arrange(c->mon);
+}
+
void
buttonpress(XEvent *e)
{
@@ -653,6 +720,9 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
+
+ else if ((c = swallowingclient(ev->window)))
+ unmanage(c->swallowing, 1);
}
void
@@ -1018,12 +1088,13 @@ killclient(const Arg *arg)
void
manage(Window w, XWindowAttributes *wa)
{
- Client *c, *t = NULL;
+ Client *c, *t = NULL, *term = NULL;
Window trans = None;
XWindowChanges wc;
c = ecalloc(1, sizeof(Client));
c->win = w;
+ c->pid = winpid(w);
/* geometry */
c->x = c->oldx = wa->x;
c->y = c->oldy = wa->y;
@@ -1038,6 +1109,7 @@ manage(Window w, XWindowAttributes *wa)
} else {
c->mon = selmon;
applyrules(c);
+ term = termforwin(c);
}
if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
@@ -1074,6 +1146,8 @@ manage(Window w, XWindowAttributes *wa)
c->mon->sel = c;
arrange(c->mon);
XMapWindow(dpy, c->win);
+ if (term)
+ swallow(term, c);
focus(NULL);
}
@@ -1768,6 +1842,20 @@ unmanage(Client *c, int destroyed)
Monitor *m = c->mon;
XWindowChanges wc;
+ if (c->swallowing) {
+ unswallow(c);
+ return;
+ }
+
+ Client *s = swallowingclient(c->win);
+ if (s) {
+ free(s->swallowing);
+ s->swallowing = NULL;
+ arrange(m);
+ focus(NULL);
+ return;
+ }
+
detach(c);
detachstack(c);
if (!destroyed) {
@@ -1782,9 +1870,12 @@ unmanage(Client *c, int destroyed)
XUngrabServer(dpy);
}
free(c);
- focus(NULL);
- updateclientlist();
- arrange(m);
+
+ if (!s) {
+ arrange(m);
+ focus(NULL);
+ updateclientlist();
+ }
}
void
@@ -2047,6 +2138,136 @@ view(const Arg *arg)
arrange(selmon);
}
+pid_t
+winpid(Window w)
+{
+
+ pid_t result = 0;
+
+ #ifdef __linux__
+ xcb_res_client_id_spec_t spec = {0};
+ spec.client = w;
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
+
+ xcb_generic_error_t *e = NULL;
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
+
+ if (!r)
+ return (pid_t)0;
+
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
+ spec = i.data->spec;
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
+ result = *t;
+ break;
+ }
+ }
+
+ free(r);
+
+ if (result == (pid_t)-1)
+ result = 0;
+
+ #endif /* __linux__ */
+
+ #ifdef __OpenBSD__
+ Atom type;
+ int format;
+ unsigned long len, bytes;
+ unsigned char *prop;
+ pid_t ret;
+
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 1), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
+ return 0;
+
+ ret = *(pid_t*)prop;
+ XFree(prop);
+ result = ret;
+
+ #endif /* __OpenBSD__ */
+ return result;
+}
+
+pid_t
+getparentprocess(pid_t p)
+{
+ unsigned int v = 0;
+
+#ifdef __linux__
+ FILE *f;
+ char buf[256];
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
+
+ if (!(f = fopen(buf, "r")))
+ return 0;
+
+ fscanf(f, "%*u %*s %*c %u", &v);
+ fclose(f);
+#endif /* __linux__*/
+
+#ifdef __OpenBSD__
+ int n;
+ kvm_t *kd;
+ struct kinfo_proc *kp;
+
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
+ if (!kd)
+ return 0;
+
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
+ v = kp->p_ppid;
+#endif /* __OpenBSD__ */
+
+ return (pid_t)v;
+}
+
+int
+isdescprocess(pid_t p, pid_t c)
+{
+ while (p != c && c != 0)
+ c = getparentprocess(c);
+
+ return (int)c;
+}
+
+Client *
+termforwin(const Client *w)
+{
+ Client *c;
+ Monitor *m;
+
+ if (!w->pid || w->isterminal)
+ return NULL;
+
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+Client *
+swallowingclient(Window w)
+{
+ Client *c;
+ Monitor *m;
+
+ for (m = mons; m; m = m->next) {
+ for (c = m->clients; c; c = c->next) {
+ if (c->swallowing && c->swallowing->win == w)
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
Client *
wintoclient(Window w)
{
@@ -2138,10 +2359,12 @@ main(int argc, char *argv[])
fputs("warning: no locale support\n", stderr);
if (!(dpy = XOpenDisplay(NULL)))
die("dwm: cannot open display");
+ if (!(xcon = XGetXCBConnection(dpy)))
+ die("dwm: cannot get xcb connection\n");
checkotherwm();
setup();
#ifdef __OpenBSD__
- if (pledge("stdio rpath proc exec", NULL) == -1)
+ if (pledge("stdio rpath proc exec ps", NULL) == -1)
die("pledge");
#endif /* __OpenBSD__ */
scan();
--
2.26.2