Compare commits

..

No commits in common. "cace4126affb059eba8f983950a8ba7863b73959" and "a38e1a252f09dc880f6bbd611e440f55d38460ae" have entirely different histories.

14 changed files with 59 additions and 1998 deletions

View File

@ -20,7 +20,7 @@ dwm: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz config.h
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
dist: clean
mkdir -p dwm-${VERSION}

View File

@ -3,12 +3,10 @@
/* 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 standard bar */
static const int topbar = 1; /* 0 means standard bar at bottom */
static const int extrabar = 1; /* 0 means no extra bar */
static const char statussep = ';'; /* separator between statuses */
static const int user_bh = 2; /* 2 is the default spacing around the bar's font */
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
@ -22,7 +20,6 @@ static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
[SchemeHid] = { col_cyan, col_gray1, col_cyan },
};
static const unsigned int alphas[][3] = {
/* fg bg border*/
@ -38,18 +35,11 @@ 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 },
};
/* window following */
#define WFACTIVE '>'
#define WFINACTIVE 'v'
#define WFDEFAULT WFINACTIVE
/* 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 */
@ -85,11 +75,8 @@ static const Key keys[] = {
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY|ShiftMask, XK_b, toggleextrabar, {0} },
{ MODKEY, XK_n, togglefollow, {0} },
{ MODKEY, XK_j, focusstackvis, {.i = +1 } },
{ MODKEY, XK_k, focusstackvis, {.i = -1 } },
{ MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } },
{ MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } },
{ 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} },
@ -108,9 +95,6 @@ static const Key keys[] = {
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
{ MODKEY, XK_s, show, {0} },
{ MODKEY|ShiftMask, XK_s, showall, {0} },
{ MODKEY, XK_h, hide, {0} },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
@ -130,8 +114,6 @@ static const Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkFollowSymbol, 0, Button1, togglefollow, {0} },
{ ClkWinTitle, 0, Button1, togglewin, {0} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkExBarLeftStatus, 0, Button2, spawn, {.v = termcmd } },

View File

@ -20,11 +20,10 @@ FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
#MANPREFIX = ${PREFIX}/man
#KVMLIB = -lkvm
# includes and libs
INCS = -I${X11INC} -I${FREETYPEINC}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender -lX11-xcb -lxcb -lxcb-res ${KVMLIB}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}

0
dmc.c
View File

6
dwm.1
View File

@ -44,8 +44,7 @@ command.
.TP
.B Button1
click on a tag label to display all windows with that tag, click on the layout
label toggles between tiled and floating layout, click on the window follow
icon toggles it on and off.
label toggles between tiled and floating layout.
.TP
.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
@ -81,9 +80,6 @@ Send focused window to next screen, if any.
.B Mod1\-b
Toggles bar on and off.
.TP
.B Mod1\-n
Toggles window following on and off.
.TP
.B Mod1\-t
Sets tiled layout.
.TP

626
dwm.c
View File

@ -40,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"
@ -56,7 +50,6 @@
#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 HIDDEN(C) ((getstate(C->win) == IconicState))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
@ -67,14 +60,14 @@
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */
enum { SchemeNorm, SchemeSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkExBarLeftStatus, ClkExBarMiddle, ClkExBarRightStatus,
ClkClientWin, ClkRootWin, ClkFollowSymbol, ClkLast }; /* clicks */
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
typedef union {
int i;
@ -102,11 +95,9 @@ struct Client {
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
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;
};
@ -126,14 +117,11 @@ typedef struct {
typedef struct Pertag Pertag;
struct Monitor {
char ltsymbol[16];
char wfsymbol[2];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
int eby; /* extra bar geometry */
int btw; /* width of tasks portion of bar */
int bt; /* number of tasks */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
@ -141,7 +129,6 @@ struct Monitor {
unsigned int tagset[2];
int showbar;
int topbar;
int hidsel;
int extrabar;
Client *clients;
Client *sel;
@ -159,8 +146,6 @@ typedef struct {
const char *title;
unsigned int tags;
int isfloating;
int isterminal;
int noswallow;
int monitor;
} Rule;
@ -189,21 +174,16 @@ static void drawbar(Monitor *m);
static void drawbars(void);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static Client *findbefore(Client *c);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
static void focusstackvis(const Arg *arg);
static void focusstackhid(const Arg *arg);
static void focusstack(int inc, int vis);
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 hide(const Arg *arg);
static void hidewin(Client *c);
static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
@ -234,9 +214,6 @@ 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 show(const Arg *arg);
static void showall(const Arg *arg);
static void showwin(Client *c);
static void showhide(Client *c);
static void sighup(int unused);
static void sigterm(int unused);
@ -247,10 +224,8 @@ static void tile(Monitor *m);
static void togglebar(const Arg *arg);
static void toggleextrabar(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefollow(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void togglewin(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
static void unmapnotify(XEvent *e);
@ -265,7 +240,6 @@ static void updatetitle(Client *c);
static void updatewindowtype(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
static void warp(const Client *c);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee);
@ -274,14 +248,7 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void xinitvisual();
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 Client *prevzoom = NULL;
static const char broken[] = "broken";
static char stext[256];
static char estextl[256];
@ -323,8 +290,6 @@ static Visual *visual;
static int depth;
static Colormap cmap;
static xcb_connection_t *xcon;
/* configuration, allows nested code to access above variables */
#include "config.h"
@ -363,8 +328,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);
@ -492,53 +455,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)
{
@ -563,29 +479,12 @@ buttonpress(XEvent *e)
if (i < LENGTH(tags)) {
click = ClkTagBar;
arg.ui = 1 << i;
} else if (ev->x < (x = (x + TEXTW(selmon->ltsymbol))))
} else if (ev->x < x + TEXTW(selmon->ltsymbol))
click = ClkLtSymbol;
else if (ev->x < x + TEXTW(selmon->wfsymbol))
click = ClkFollowSymbol;
/* 2px right padding */
else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2)
else if (ev->x > selmon->ww - (int)TEXTW(stext))
click = ClkStatusText;
else {
x += TEXTW(selmon->ltsymbol);
c = m->clients;
if (c) {
do {
if (!ISVISIBLE(c))
continue;
else
x +=(1.0 / (double)m->bt) * m->btw;
} while (ev->x > x && (c = c->next));
click = ClkWinTitle;
arg.v = c;
}
}
} else if ((c = wintoclient(ev->window))) {
focus(c);
restack(selmon);
@ -595,7 +494,7 @@ buttonpress(XEvent *e)
for (i = 0; i < LENGTH(buttons); i++)
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
}
void
@ -804,8 +703,6 @@ createmon(void)
m->pertag->showbars[i] = m->showbar;
}
m->wfsymbol[0] = WFDEFAULT;
m->wfsymbol[1] = '\0';
return m;
}
@ -817,9 +714,6 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
else if ((c = swallowingclient(ev->window)))
unmanage(c->swallowing, 1);
}
void
@ -863,7 +757,7 @@ dirtomon(int dir)
void
drawbar(Monitor *m)
{
int x, w, tw = 0, etwl = 0, etwr = 0, n = 0, scm;
int x, w, tw = 0, etwl = 0, etwr = 0;
int boxs = drw->fonts->h / 9;
int boxw = drw->fonts->h / 6 + 2;
unsigned int i, occ = 0, urg = 0;
@ -878,8 +772,6 @@ drawbar(Monitor *m)
drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
for (c = m->clients; c; c = c->next) {
if (ISVISIBLE(c))
n++;
occ |= c->tags;
if (c->isurgent)
urg |= c->tags;
@ -899,40 +791,17 @@ drawbar(Monitor *m)
drw_setscheme(drw, scheme[SchemeNorm]);
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
w = TEXTW(m->wfsymbol);
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->wfsymbol, 0);
if ((w = m->ww - tw - x) > bh) {
if (n > 0) {
int remainder = w % n;
int tabw = (1.0 / (double)n) * w + 1;
for (c = m->clients; c; c = c->next) {
if (!ISVISIBLE(c))
continue;
if (m->sel == c && m == selmon)
scm = SchemeSel;
else if (HIDDEN(c))
scm = SchemeHid;
else
scm = SchemeNorm;
drw_setscheme(drw, scheme[scm]);
if (remainder >= 0) {
if (remainder == 0) {
tabw--;
}
remainder--;
}
drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0);
x += tabw;
}
if (m->sel) {
drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
if (m->sel->isfloating)
drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
} else {
drw_setscheme(drw, scheme[SchemeNorm]);
drw_rect(drw, x, 0, w, bh, 1, 1);
}
}
m->bt = n;
m->btw = w;
drw_map(drw, m->barwin, 0, 0, m->ww, bh);
drw_setscheme(drw, scheme[SchemeNorm]);
@ -983,31 +852,13 @@ expose(XEvent *e)
drawbar(m);
}
Client *
findbefore(Client *c)
{
Client *tmp;
if (c == selmon->clients)
return NULL;
for (tmp = selmon->clients; tmp && tmp->next != c; tmp = tmp->next);
return tmp;
}
void
focus(Client *c)
{
if (!c || !ISVISIBLE(c))
for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext);
if (selmon->sel && selmon->sel != c) {
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
if (selmon->sel && selmon->sel != c)
unfocus(selmon->sel, 0);
if (selmon->hidsel) {
hidewin(selmon->sel);
if (c)
arrange(c->mon);
selmon->hidsel = 0;
}
}
if (c) {
if (c->mon != selmon)
selmon = c->mon;
@ -1048,56 +899,31 @@ focusmon(const Arg *arg)
unfocus(selmon->sel, 0);
selmon = m;
focus(NULL);
warp(selmon->sel);
}
void
focusstackvis(const Arg *arg) {
focusstack(arg->i, 0);
}
void
focusstackhid(const Arg *arg) {
focusstack(arg->i, 1);
}
void
focusstack(int inc, int hid)
focusstack(const Arg *arg)
{
Client *c = NULL, *i;
// if no client selected AND exclude hidden client; if client selected but fullscreened
if ((!selmon->sel && !hid) || (selmon->sel && selmon->sel->isfullscreen && lockfullscreen))
if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
return;
if (!selmon->clients)
return;
if (inc > 0) {
if (selmon->sel)
for (c = selmon->sel->next;
c && (!ISVISIBLE(c) || (!hid && HIDDEN(c)));
c = c->next);
if (arg->i > 0) {
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
if (!c)
for (c = selmon->clients;
c && (!ISVISIBLE(c) || (!hid && HIDDEN(c)));
c = c->next);
for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
} else {
if (selmon->sel) {
for (i = selmon->clients; i != selmon->sel; i = i->next)
if (ISVISIBLE(i) && !(!hid && HIDDEN(i)))
if (ISVISIBLE(i))
c = i;
} else
c = selmon->clients;
if (!c)
for (; i; i = i->next)
if (ISVISIBLE(i) && !(!hid && HIDDEN(i)))
if (ISVISIBLE(i))
c = i;
}
if (c) {
focus(c);
restack(selmon);
if (HIDDEN(c)) {
showwin(c);
c->mon->hidsel = 1;
}
}
}
@ -1217,36 +1043,6 @@ grabkeys(void)
}
}
void
hide(const Arg *arg)
{
hidewin(selmon->sel);
focus(NULL);
arrange(selmon);
}
void
hidewin(Client *c) {
if (!c || HIDDEN(c))
return;
Window w = c->win;
static XWindowAttributes ra, ca;
// more or less taken directly from blackbox's hide() function
XGrabServer(dpy);
XGetWindowAttributes(dpy, root, &ra);
XGetWindowAttributes(dpy, w, &ca);
// prevent UnmapNotify events
XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask);
XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask);
XUnmapWindow(dpy, w);
setclientstate(c, IconicState);
XSelectInput(dpy, root, ra.your_event_mask);
XSelectInput(dpy, w, ca.your_event_mask);
XUngrabServer(dpy);
}
void
incnmaster(const Arg *arg)
{
@ -1310,13 +1106,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;
@ -1331,7 +1126,6 @@ manage(Window w, XWindowAttributes *wa)
} else {
c->mon = selmon;
applyrules(c);
term = termforwin(c);
}
if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
@ -1384,16 +1178,12 @@ manage(Window w, XWindowAttributes *wa)
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
(unsigned char *) &(c->win), 1);
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
if (!HIDDEN(c))
setclientstate(c, NormalState);
if (c->mon == selmon)
unfocus(selmon->sel, 0);
c->mon->sel = c;
arrange(c->mon);
if (!HIDDEN(c))
XMapWindow(dpy, c->win);
if (term)
swallow(term, c);
focus(NULL);
}
@ -1495,60 +1285,11 @@ movemouse(const Arg *arg)
ny = selmon->wy;
else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
ny = selmon->wy + selmon->wh - HEIGHT(c);
if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
&& (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
togglefloating(NULL);
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
resize(c, nx, ny, c->w, c->h, 1);
else if (selmon->lt[selmon->sellt]->arrange || !c->isfloating) {
if ((m = recttomon(ev.xmotion.x_root, ev.xmotion.y_root, 1, 1)) != selmon) {
sendmon(c, m);
selmon = m;
focus(NULL);
}
Client *cc = c->mon->clients;
while (1) {
if (cc == 0) break;
if(
cc != c && !cc->isfloating && ISVISIBLE(cc) &&
ev.xmotion.x_root > cc->x &&
ev.xmotion.x_root < cc->x + cc->w &&
ev.xmotion.y_root > cc->y &&
ev.xmotion.y_root < cc->y + cc->h ) {
break;
}
cc = cc->next;
}
if (cc) {
Client *cl1, *cl2, ocl1;
if (!selmon->lt[selmon->sellt]->arrange) return;
cl1 = c;
cl2 = cc;
ocl1 = *cl1;
strcpy(cl1->name, cl2->name);
cl1->win = cl2->win;
cl1->x = cl2->x;
cl1->y = cl2->y;
cl1->w = cl2->w;
cl1->h = cl2->h;
cl2->win = ocl1.win;
strcpy(cl2->name, ocl1.name);
cl2->x = ocl1.x;
cl2->y = ocl1.y;
cl2->w = ocl1.w;
cl2->h = ocl1.h;
selmon->sel = cl2;
c = cc;
focus(c);
arrange(cl1->mon);
}
}
break;
}
} while (ev.type != ButtonRelease);
@ -1563,7 +1304,7 @@ movemouse(const Arg *arg)
Client *
nexttiled(Client *c)
{
for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next);
for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
return c;
}
@ -1616,16 +1357,6 @@ propertynotify(XEvent *e)
void
quit(const Arg *arg)
{
// fix: reloading dwm keeps all the hidden clients hidden
Monitor *m;
Client *c;
for (m = mons; m; m = m->next) {
if (m) {
for (c = m->stack; c; c = c->next)
if (c && HIDDEN(c)) showwin(c);
}
}
if(arg->i) restart = 1;
running = 0;
}
@ -1685,16 +1416,7 @@ resizemouse(const Arg *arg)
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
return;
if (c->isfloating || NULL == c->mon->lt[c->mon->sellt]->arrange) {
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
} else {
XWarpPointer(dpy, None, root, 0, 0, 0, 0,
selmon->mx + (selmon->ww * selmon->mfact),
selmon->my + (selmon->wh / 2)
);
}
do {
XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
switch(ev.type) {
@ -1710,24 +1432,19 @@ resizemouse(const Arg *arg)
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
{
if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
togglefloating(NULL);
}
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
resize(c, c->x, c->y, nw, nh, 1);
break;
}
} while (ev.type != ButtonRelease);
if (c->isfloating || NULL == c->mon->lt[c->mon->sellt]->arrange) {
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
} else {
selmon->mfact = (double) (ev.xmotion.x_root - selmon->mx) / (double) selmon->ww;
arrange(selmon);
XWarpPointer(dpy, None, root, 0, 0, 0, 0,
selmon->mx + (selmon->ww * selmon->mfact),
selmon->my + (selmon->wh / 2)
);
}
XUngrabPointer(dpy, CurrentTime);
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
@ -1758,8 +1475,6 @@ restack(Monitor *m)
wc.sibling = c->win;
}
}
if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && m->lt[m->sellt]->arrange != &monocle)
warp(m->sel);
XSync(dpy, False);
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
@ -1978,7 +1693,7 @@ setup(void)
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded.");
lrpad = drw->fonts->h;
bh = drw->fonts->h + user_bh;
bh = drw->fonts->h + 2;
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
@ -2044,42 +1759,6 @@ seturgent(Client *c, int urg)
XFree(wmh);
}
void
show(const Arg *arg)
{
if (selmon->hidsel)
selmon->hidsel = 0;
showwin(selmon->sel);
}
void
showall(const Arg *arg)
{
Client *c = NULL;
selmon->hidsel = 0;
for (c = selmon->clients; c; c = c->next) {
if (ISVISIBLE(c))
showwin(c);
}
if (!selmon->sel) {
for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
if (c)
focus(c);
}
restack(selmon);
}
void
showwin(Client *c)
{
if (!c || !HIDDEN(c))
return;
XMapWindow(dpy, c->win);
setclientstate(c, NormalState);
arrange(c->mon);
}
void
showhide(Client *c)
{
@ -2153,8 +1832,6 @@ tag(const Arg *arg)
focus(NULL);
arrange(selmon);
}
if (selmon->wfsymbol[0] == WFACTIVE)
view(arg);
}
void
@ -2163,8 +1840,6 @@ tagmon(const Arg *arg)
if (!selmon->sel || !mons->next)
return;
sendmon(selmon->sel, dirtomon(arg->i));
if (selmon->wfsymbol[0] == WFACTIVE)
focusmon(arg);
}
void
@ -2222,13 +1897,6 @@ toggleextrabar(const Arg *arg)
arrange(selmon);
}
void
togglefollow(const Arg *arg)
{
selmon->wfsymbol[0] = (selmon->wfsymbol[0] == WFACTIVE) ? WFINACTIVE : WFACTIVE;
drawbars();
}
void
togglefloating(const Arg *arg)
{
@ -2307,23 +1975,6 @@ toggleview(const Arg *arg)
}
}
void
togglewin(const Arg *arg)
{
Client *c = (Client*)arg->v;
if (c == selmon->sel) {
hidewin(c);
focus(NULL);
arrange(c->mon);
} else {
if (HIDDEN(c))
showwin(c);
focus(c);
restack(selmon);
}
}
void
unfocus(Client *c, int setfocus)
{
@ -2343,20 +1994,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) {
@ -2372,12 +2009,9 @@ unmanage(Client *c, int destroyed)
XUngrabServer(dpy);
}
free(c);
if (!s) {
arrange(m);
focus(NULL);
updateclientlist();
}
arrange(m);
}
void
@ -2703,158 +2337,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", 0), 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;
}
void
warp(const Client *c)
{
int x, y;
if (!c) {
XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww / 2, selmon->wy + selmon->wh / 2);
return;
}
if (!getrootptr(&x, &y) ||
(x > c->x - c->bw &&
y > c->y - c->bw &&
x < c->x + c->w + c->bw*2 &&
y < c->y + c->h + c->bw*2) ||
(y > c->mon->by && y < c->mon->by + bh) ||
(c->mon->topbar && !y))
return;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2);
}
Client *
wintoclient(Window w)
{
@ -2962,38 +2444,12 @@ void
zoom(const Arg *arg)
{
Client *c = selmon->sel;
Client *at = NULL, *cold, *cprevious = NULL;
if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
return;
if (c == nexttiled(selmon->clients)) {
at = findbefore(prevzoom);
if (at)
cprevious = nexttiled(at->next);
if (!cprevious || cprevious != prevzoom) {
prevzoom = NULL;
if (!c || !(c = nexttiled(c->next)))
if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
return;
} else
c = cprevious;
}
cold = nexttiled(selmon->clients);
if (c != cold && !at)
at = findbefore(c);
detach(c);
attach(c);
/* swap windows instead of pushing the previous one down */
if (c != cold && at) {
prevzoom = cold;
if (cold && at != cold) {
detach(cold);
cold->next = at->next;
at->next = cold;
}
}
focus(c);
arrange(c->mon);
pop(c);
}
int
@ -3007,12 +2463,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,25 +0,0 @@
diff --git a/config.def.h b/config.def.h
index 1c0b587..9814500 100644
--- a/config.def.h
+++ b/config.def.h
@@ -5,6 +5,7 @@ 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 int user_bh = 2; /* 2 is the default spacing around the bar's font */
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
diff --git a/dwm.c b/dwm.c
index 4465af1..2c27cb3 100644
--- a/dwm.c
+++ b/dwm.c
@@ -1545,7 +1545,7 @@ setup(void)
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded.");
lrpad = drw->fonts->h;
- bh = drw->fonts->h + 2;
+ bh = drw->fonts->h + user_bh;
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);

View File

@ -1,446 +0,0 @@
diff --git a/config.def.h b/config.def.h
index 061ad66..05f18e5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -16,6 +16,7 @@ static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
+ [SchemeHid] = { col_cyan, col_gray1, col_cyan },
};
/* tagging */
@@ -64,8 +65,10 @@ static const Key keys[] = {
{ 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_j, focusstackvis, {.i = +1 } },
+ { MODKEY, XK_k, focusstackvis, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
@@ -84,6 +87,9 @@ static const Key keys[] = {
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
+ { MODKEY, XK_s, show, {0} },
+ { MODKEY|ShiftMask, XK_s, showall, {0} },
+ { MODKEY, XK_h, hide, {0} },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
@@ -102,6 +108,7 @@ static const Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
+ { ClkWinTitle, 0, Button1, togglewin, {0} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
diff --git a/dwm.c b/dwm.c
index e5efb6a..0d18e1b 100644
--- a/dwm.c
+++ b/dwm.c
@@ -50,6 +50,7 @@
#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 HIDDEN(C) ((getstate(C->win) == IconicState))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
@@ -59,7 +60,7 @@
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
-enum { SchemeNorm, SchemeSel }; /* color schemes */
+enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
@@ -117,6 +118,8 @@ struct Monitor {
int nmaster;
int num;
int by; /* bar geometry */
+ int btw; /* width of tasks portion of bar */
+ int bt; /* number of tasks */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
@@ -124,6 +127,7 @@ struct Monitor {
unsigned int tagset[2];
int showbar;
int topbar;
+ int hidsel;
Client *clients;
Client *sel;
Client *stack;
@@ -168,13 +172,17 @@ 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 void focusstackvis(const Arg *arg);
+static void focusstackhid(const Arg *arg);
+static void focusstack(int inc, int vis);
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 hide(const Arg *arg);
+static void hidewin(Client *c);
static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
@@ -204,6 +212,9 @@ 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 show(const Arg *arg);
+static void showall(const Arg *arg);
+static void showwin(Client *c);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
@@ -214,6 +225,7 @@ 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 togglewin(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
static void unmapnotify(XEvent *e);
@@ -442,10 +454,25 @@ 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))
+ /* 2px right padding */
+ else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2)
click = ClkStatusText;
- else
- click = ClkWinTitle;
+ else {
+ x += TEXTW(selmon->ltsymbol);
+ c = m->clients;
+
+ if (c) {
+ do {
+ if (!ISVISIBLE(c))
+ continue;
+ else
+ x +=(1.0 / (double)m->bt) * m->btw;
+ } while (ev->x > x && (c = c->next));
+
+ click = ClkWinTitle;
+ arg.v = c;
+ }
+ }
} else if ((c = wintoclient(ev->window))) {
focus(c);
restack(selmon);
@@ -455,7 +482,7 @@ buttonpress(XEvent *e)
for (i = 0; i < LENGTH(buttons); i++)
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
+ buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
}
void
@@ -699,7 +726,7 @@ dirtomon(int dir)
void
drawbar(Monitor *m)
{
- int x, w, tw = 0;
+ int x, w, tw = 0, n = 0, scm;
int boxs = drw->fonts->h / 9;
int boxw = drw->fonts->h / 6 + 2;
unsigned int i, occ = 0, urg = 0;
@@ -716,6 +743,8 @@ drawbar(Monitor *m)
}
for (c = m->clients; c; c = c->next) {
+ if (ISVISIBLE(c))
+ n++;
occ |= c->tags;
if (c->isurgent)
urg |= c->tags;
@@ -736,16 +765,36 @@ drawbar(Monitor *m)
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
if ((w = m->ww - tw - x) > bh) {
- if (m->sel) {
- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
- if (m->sel->isfloating)
- drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+ if (n > 0) {
+ int remainder = w % n;
+ int tabw = (1.0 / (double)n) * w + 1;
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c))
+ continue;
+ if (m->sel == c)
+ scm = SchemeSel;
+ else if (HIDDEN(c))
+ scm = SchemeHid;
+ else
+ scm = SchemeNorm;
+ drw_setscheme(drw, scheme[scm]);
+
+ if (remainder >= 0) {
+ if (remainder == 0) {
+ tabw--;
+ }
+ remainder--;
+ }
+ drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0);
+ x += tabw;
+ }
} else {
drw_setscheme(drw, scheme[SchemeNorm]);
drw_rect(drw, x, 0, w, bh, 1, 1);
}
}
+ m->bt = n;
+ m->btw = w;
drw_map(drw, m->barwin, 0, 0, m->ww, bh);
}
@@ -791,9 +840,17 @@ void
focus(Client *c)
{
if (!c || !ISVISIBLE(c))
- for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
- if (selmon->sel && selmon->sel != c)
+ for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext);
+ if (selmon->sel && selmon->sel != c) {
unfocus(selmon->sel, 0);
+
+ if (selmon->hidsel) {
+ hidewin(selmon->sel);
+ if (c)
+ arrange(c->mon);
+ selmon->hidsel = 0;
+ }
+ }
if (c) {
if (c->mon != selmon)
selmon = c->mon;
@@ -837,28 +894,52 @@ focusmon(const Arg *arg)
}
void
-focusstack(const Arg *arg)
+focusstackvis(const Arg *arg) {
+ focusstack(arg->i, 0);
+}
+
+void
+focusstackhid(const Arg *arg) {
+ focusstack(arg->i, 1);
+}
+
+void
+focusstack(int inc, int hid)
{
Client *c = NULL, *i;
-
- if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
+ // if no client selected AND exclude hidden client; if client selected but fullscreened
+ if ((!selmon->sel && !hid) || (selmon->sel && selmon->sel->isfullscreen && lockfullscreen))
return;
- if (arg->i > 0) {
- for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
+ if (!selmon->clients)
+ return;
+ if (inc > 0) {
+ if (selmon->sel)
+ for (c = selmon->sel->next;
+ c && (!ISVISIBLE(c) || (!hid && HIDDEN(c)));
+ c = c->next);
if (!c)
- for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
+ for (c = selmon->clients;
+ c && (!ISVISIBLE(c) || (!hid && HIDDEN(c)));
+ c = c->next);
} else {
- for (i = selmon->clients; i != selmon->sel; i = i->next)
- if (ISVISIBLE(i))
- c = i;
+ if (selmon->sel) {
+ for (i = selmon->clients; i != selmon->sel; i = i->next)
+ if (ISVISIBLE(i) && !(!hid && HIDDEN(i)))
+ c = i;
+ } else
+ c = selmon->clients;
if (!c)
for (; i; i = i->next)
- if (ISVISIBLE(i))
+ if (ISVISIBLE(i) && !(!hid && HIDDEN(i)))
c = i;
}
if (c) {
focus(c);
restack(selmon);
+ if (HIDDEN(c)) {
+ showwin(c);
+ c->mon->hidsel = 1;
+ }
}
}
@@ -968,6 +1049,36 @@ grabkeys(void)
}
}
+void
+hide(const Arg *arg)
+{
+ hidewin(selmon->sel);
+ focus(NULL);
+ arrange(selmon);
+}
+
+void
+hidewin(Client *c) {
+ if (!c || HIDDEN(c))
+ return;
+
+ Window w = c->win;
+ static XWindowAttributes ra, ca;
+
+ // more or less taken directly from blackbox's hide() function
+ XGrabServer(dpy);
+ XGetWindowAttributes(dpy, root, &ra);
+ XGetWindowAttributes(dpy, w, &ca);
+ // prevent UnmapNotify events
+ XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask);
+ XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask);
+ XUnmapWindow(dpy, w);
+ setclientstate(c, IconicState);
+ XSelectInput(dpy, root, ra.your_event_mask);
+ XSelectInput(dpy, w, ca.your_event_mask);
+ XUngrabServer(dpy);
+}
+
void
incnmaster(const Arg *arg)
{
@@ -1070,12 +1181,14 @@ manage(Window w, XWindowAttributes *wa)
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
(unsigned char *) &(c->win), 1);
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
- setclientstate(c, NormalState);
+ if (!HIDDEN(c))
+ setclientstate(c, NormalState);
if (c->mon == selmon)
unfocus(selmon->sel, 0);
c->mon->sel = c;
arrange(c->mon);
- XMapWindow(dpy, c->win);
+ if (!HIDDEN(c))
+ XMapWindow(dpy, c->win);
focus(NULL);
}
@@ -1196,7 +1309,7 @@ movemouse(const Arg *arg)
Client *
nexttiled(Client *c)
{
- for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
+ for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next);
return c;
}
@@ -1249,6 +1362,16 @@ propertynotify(XEvent *e)
void
quit(const Arg *arg)
{
+ // fix: reloading dwm keeps all the hidden clients hidden
+ Monitor *m;
+ Client *c;
+ for (m = mons; m; m = m->next) {
+ if (m) {
+ for (c = m->stack; c; c = c->next)
+ if (c && HIDDEN(c)) showwin(c);
+ }
+ }
+
running = 0;
}
@@ -1610,6 +1733,42 @@ seturgent(Client *c, int urg)
XFree(wmh);
}
+void
+show(const Arg *arg)
+{
+ if (selmon->hidsel)
+ selmon->hidsel = 0;
+ showwin(selmon->sel);
+}
+
+void
+showall(const Arg *arg)
+{
+ Client *c = NULL;
+ selmon->hidsel = 0;
+ for (c = selmon->clients; c; c = c->next) {
+ if (ISVISIBLE(c))
+ showwin(c);
+ }
+ if (!selmon->sel) {
+ for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
+ if (c)
+ focus(c);
+ }
+ restack(selmon);
+}
+
+void
+showwin(Client *c)
+{
+ if (!c || !HIDDEN(c))
+ return;
+
+ XMapWindow(dpy, c->win);
+ setclientstate(c, NormalState);
+ arrange(c->mon);
+}
+
void
showhide(Client *c)
{
@@ -1744,6 +1903,23 @@ toggleview(const Arg *arg)
}
}
+void
+togglewin(const Arg *arg)
+{
+ Client *c = (Client*)arg->v;
+
+ if (c == selmon->sel) {
+ hidewin(c);
+ focus(NULL);
+ arrange(c->mon);
+ } else {
+ if (HIDDEN(c))
+ showwin(c);
+ focus(c);
+ restack(selmon);
+ }
+}
+
void
unfocus(Client *c, int setfocus)
{

View File

@ -1,412 +0,0 @@
From 0cf9a007511f7dfd7dd94171b172562ebac9b6d5 Mon Sep 17 00:00:00 2001
From: Tom Schwindl <schwindl@posteo.de>
Date: Sat, 10 Sep 2022 12:51:09 +0200
Subject: [PATCH] 6.3 swallow patch
---
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 061ad662f82a..0b2b8ffd30d5 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 81c493ef4aff..52d1ebf30bec 100644
--- a/config.mk
+++ b/config.mk
@@ -20,10 +20,11 @@ FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
#MANPREFIX = ${PREFIX}/man
+#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 e5efb6a22806..e68294b6b679 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, hintsvalid;
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);
@@ -416,6 +436,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)
{
@@ -656,6 +723,9 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
+
+ else if ((c = swallowingclient(ev->window)))
+ unmanage(c->swallowing, 1);
}
void
@@ -1022,12 +1092,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;
@@ -1042,6 +1113,7 @@ manage(Window w, XWindowAttributes *wa)
} else {
c->mon = selmon;
applyrules(c);
+ term = termforwin(c);
}
if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
@@ -1076,6 +1148,8 @@ manage(Window w, XWindowAttributes *wa)
c->mon->sel = c;
arrange(c->mon);
XMapWindow(dpy, c->win);
+ if (term)
+ swallow(term, c);
focus(NULL);
}
@@ -1763,6 +1837,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) {
@@ -1778,9 +1866,12 @@ unmanage(Client *c, int destroyed)
XUngrabServer(dpy);
}
free(c);
- focus(NULL);
- updateclientlist();
- arrange(m);
+
+ if (!s) {
+ arrange(m);
+ focus(NULL);
+ updateclientlist();
+ }
}
void
@@ -2044,6 +2135,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", 0), 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)
{
@@ -2133,10 +2354,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.37.2

View File

@ -1,79 +0,0 @@
From a229c36f51ad6f8b40109ed53c643f242351962a Mon Sep 17 00:00:00 2001
From: Jonas Dujava <jonas.dujava@gmail.com>
Date: Fri, 26 May 2023 22:14:48 +0200
Subject: [PATCH] Warp patch
Warps the mouse cursor to the center of the currently focused
window or screen when the mouse cursor is
(a) on a different screen, or
(b) on top of a different window.
This version properly handles warping to windows that have not been
mapped yet (before it resulted in a change of the stack order).
See the discussion in (thanks goes to Bakkeby):
https://github.com/bakkeby/patches/issues/60
---
dwm.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/dwm.c b/dwm.c
index e5efb6a..7ea6c14 100644
--- a/dwm.c
+++ b/dwm.c
@@ -228,6 +228,7 @@ static void updatetitle(Client *c);
static void updatewindowtype(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
+static void warp(const Client *c);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee);
@@ -834,6 +835,7 @@ focusmon(const Arg *arg)
unfocus(selmon->sel, 0);
selmon = m;
focus(NULL);
+ warp(selmon->sel);
}
void
@@ -1366,6 +1368,8 @@ restack(Monitor *m)
wc.sibling = c->win;
}
}
+ if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && m->lt[m->sellt]->arrange != &monocle)
+ warp(m->sel);
XSync(dpy, False);
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
@@ -2044,6 +2048,28 @@ view(const Arg *arg)
arrange(selmon);
}
+void
+warp(const Client *c)
+{
+ int x, y;
+
+ if (!c) {
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww / 2, selmon->wy + selmon->wh / 2);
+ return;
+ }
+
+ if (!getrootptr(&x, &y) ||
+ (x > c->x - c->bw &&
+ y > c->y - c->bw &&
+ x < c->x + c->w + c->bw*2 &&
+ y < c->y + c->h + c->bw*2) ||
+ (y > c->mon->by && y < c->mon->by + bh) ||
+ (c->mon->topbar && !y))
+ return;
+
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2);
+}
+
Client *
wintoclient(Window w)
{
--
2.40.1

View File

@ -1,95 +0,0 @@
From 3867ef5a68e15a4faff377ddbc8371853de4a800 Mon Sep 17 00:00:00 2001
From: aleks <aleks.stier@icloud.com>
Date: Sat, 19 Oct 2019 00:56:21 +0200
Subject: [PATCH] Put master to exact position of zoomed client
The default behaviour when zooming a client is to put the previous
master on top of the client-stack. This patch puts the master to the
exact position of the zoomed client in the stack.
---
dwm.c | 44 ++++++++++++++++++++++++++++++++++++++++----
1 file changed, 40 insertions(+), 4 deletions(-)
diff --git a/dwm.c b/dwm.c
index 4465af1..1719b36 100644
--- a/dwm.c
+++ b/dwm.c
@@ -165,6 +165,7 @@ static void drawbar(Monitor *m);
static void drawbars(void);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
+static Client *findbefore(Client *c);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
@@ -235,6 +236,7 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
/* variables */
+static Client *prevzoom = NULL;
static const char broken[] = "broken";
static char stext[256];
static int screen;
@@ -780,6 +782,16 @@ expose(XEvent *e)
drawbar(m);
}
+Client *
+findbefore(Client *c)
+{
+ Client *tmp;
+ if (c == selmon->clients)
+ return NULL;
+ for (tmp = selmon->clients; tmp && tmp->next != c; tmp = tmp->next);
+ return tmp;
+}
+
void
focus(Client *c)
{
@@ -2114,14 +2126,38 @@ void
zoom(const Arg *arg)
{
Client *c = selmon->sel;
+ Client *at = NULL, *cold, *cprevious = NULL;
if (!selmon->lt[selmon->sellt]->arrange
|| (selmon->sel && selmon->sel->isfloating))
return;
- if (c == nexttiled(selmon->clients))
- if (!c || !(c = nexttiled(c->next)))
- return;
- pop(c);
+ if (c == nexttiled(selmon->clients)) {
+ at = findbefore(prevzoom);
+ if (at)
+ cprevious = nexttiled(at->next);
+ if (!cprevious || cprevious != prevzoom) {
+ prevzoom = NULL;
+ if (!c || !(c = nexttiled(c->next)))
+ return;
+ } else
+ c = cprevious;
+ }
+ cold = nexttiled(selmon->clients);
+ if (c != cold && !at)
+ at = findbefore(c);
+ detach(c);
+ attach(c);
+ /* swap windows instead of pushing the previous one down */
+ if (c != cold && at) {
+ prevzoom = cold;
+ if (cold && at != cold) {
+ detach(cold);
+ cold->next = at->next;
+ at->next = cold;
+ }
+ }
+ focus(c);
+ arrange(c->mon);
}
int
--
2.23.0

View File

@ -1,68 +0,0 @@
From 17df87822b379ce47d0aba3c36c5ef0adf4a7c3e Mon Sep 17 00:00:00 2001
From: Miles Alan <m@milesalan.com>
Date: Sun, 8 Dec 2019 18:15:13 -0600
Subject: [PATCH] Mod + Right click / drag in tiling mode to resize mfact.
Works with multiple monitors.
---
dwm.c | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/dwm.c b/dwm.c
index c15f679..e273803 100644
--- a/dwm.c
+++ b/dwm.c
@@ -1911,7 +1911,16 @@ resizemouse(const Arg *arg)
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
return;
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+
+ if (c->isfloating || NULL == c->mon->lt[c->mon->sellt]->arrange) {
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+ } else {
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0,
+ selmon->mx + (selmon->ww * selmon->mfact),
+ selmon->my + (selmon->wh / 2)
+ );
+ }
+
do {
XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
switch(ev.type) {
@@ -1927,19 +1936,24 @@ resizemouse(const Arg *arg)
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
- if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
- && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
- {
- if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
- && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
- togglefloating(NULL);
- }
+
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
resize(c, c->x, c->y, nw, nh, 1);
break;
}
} while (ev.type != ButtonRelease);
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+
+ if (c->isfloating || NULL == c->mon->lt[c->mon->sellt]->arrange) {
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
+ } else {
+ selmon->mfact = (double) (ev.xmotion.x_root - selmon->mx) / (double) selmon->ww;
+ arrange(selmon);
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0,
+ selmon->mx + (selmon->ww * selmon->mfact),
+ selmon->my + (selmon->wh / 2)
+ );
+ }
+
XUngrabPointer(dpy, CurrentTime);
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
--
2.23.0

View File

@ -1,83 +0,0 @@
From 427c5fef13676179621949f0a8a4036e49d4b74e Mon Sep 17 00:00:00 2001
From: Niki <>
Date: Sun, 10 Dec 2023 00:29:59 +0000
Subject: [PATCH] The function `movemouse` now doesn't force clients to be
floating.
Tiling clients when moved will swap with any existing clients that
overlap with the cursor, and snap to other monitors.
---
dwm.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 53 insertions(+), 3 deletions(-)
diff --git a/dwm.c b/dwm.c
index d12be2d..b1023e0 100644
--- a/dwm.c
+++ b/dwm.c
@@ -1189,11 +1189,60 @@ movemouse(const Arg *arg)
ny = selmon->wy;
else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
ny = selmon->wy + selmon->wh - HEIGHT(c);
- if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
- && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
- togglefloating(NULL);
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
resize(c, nx, ny, c->w, c->h, 1);
+ else if (selmon->lt[selmon->sellt]->arrange || !c->isfloating) {
+ if ((m = recttomon(ev.xmotion.x_root, ev.xmotion.y_root, 1, 1)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
+
+ Client *cc = c->mon->clients;
+ while (1) {
+ if (cc == 0) break;
+ if(
+ cc != c && !cc->isfloating && ISVISIBLE(cc) &&
+ ev.xmotion.x_root > cc->x &&
+ ev.xmotion.x_root < cc->x + cc->w &&
+ ev.xmotion.y_root > cc->y &&
+ ev.xmotion.y_root < cc->y + cc->h ) {
+ break;
+ }
+
+ cc = cc->next;
+ }
+
+ if (cc) {
+ Client *cl1, *cl2, ocl1;
+
+ if (!selmon->lt[selmon->sellt]->arrange) return;
+
+ cl1 = c;
+ cl2 = cc;
+ ocl1 = *cl1;
+ strcpy(cl1->name, cl2->name);
+ cl1->win = cl2->win;
+ cl1->x = cl2->x;
+ cl1->y = cl2->y;
+ cl1->w = cl2->w;
+ cl1->h = cl2->h;
+
+ cl2->win = ocl1.win;
+ strcpy(cl2->name, ocl1.name);
+ cl2->x = ocl1.x;
+ cl2->y = ocl1.y;
+ cl2->w = ocl1.w;
+ cl2->h = ocl1.h;
+
+ selmon->sel = cl2;
+
+ c = cc;
+ focus(c);
+
+ arrange(cl1->mon);
+ }
+ }
break;
}
} while (ev.type != ButtonRelease);
--
2.43.0

View File

@ -1,162 +0,0 @@
From 0d52397649099000d154b65c077fe927608d8d0b Mon Sep 17 00:00:00 2001
From: Aidan Hall <aidan.hall202@gmail.com>
Date: Sun, 2 Oct 2022 18:13:36 +0100
Subject: [PATCH] window following for latest git version
---
config.def.h | 7 +++++++
dwm.1 | 6 +++++-
dwm.c | 24 ++++++++++++++++++++++--
3 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/config.def.h b/config.def.h
index 061ad66..5eb37ed 100644
--- a/config.def.h
+++ b/config.def.h
@@ -31,6 +31,11 @@ static const Rule rules[] = {
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
};
+/* window following */
+#define WFACTIVE '>'
+#define WFINACTIVE 'v'
+#define WFDEFAULT WFINACTIVE
+
/* 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 */
@@ -64,6 +69,7 @@ static const Key keys[] = {
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
+ { MODKEY, XK_n, togglefollow, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
@@ -102,6 +108,7 @@ static const Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
+ { ClkFollowSymbol, 0, Button1, togglefollow, {0} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
diff --git a/dwm.1 b/dwm.1
index ddc8321..67dfbc0 100644
--- a/dwm.1
+++ b/dwm.1
@@ -44,7 +44,8 @@ command.
.TP
.B Button1
click on a tag label to display all windows with that tag, click on the layout
-label toggles between tiled and floating layout.
+label toggles between tiled and floating layout, click on the window follow
+icon toggles it on and off.
.TP
.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
@@ -80,6 +81,9 @@ Send focused window to next screen, if any.
.B Mod1\-b
Toggles bar on and off.
.TP
+.B Mod1\-n
+Toggles window following on and off.
+.TP
.B Mod1\-t
Sets tiled layout.
.TP
diff --git a/dwm.c b/dwm.c
index e5efb6a..6d86a9c 100644
--- a/dwm.c
+++ b/dwm.c
@@ -65,7 +65,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
- ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+ ClkClientWin, ClkRootWin, ClkFollowSymbol, ClkLast }; /* clicks */
typedef union {
int i;
@@ -113,6 +113,7 @@ typedef struct {
struct Monitor {
char ltsymbol[16];
+ char wfsymbol[2];
float mfact;
int nmaster;
int num;
@@ -212,6 +213,7 @@ 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 togglefollow(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
@@ -440,8 +442,10 @@ buttonpress(XEvent *e)
if (i < LENGTH(tags)) {
click = ClkTagBar;
arg.ui = 1 << i;
- } else if (ev->x < x + TEXTW(selmon->ltsymbol))
+ } else if (ev->x < (x = (x + TEXTW(selmon->ltsymbol))))
click = ClkLtSymbol;
+ else if (ev->x < x + TEXTW(selmon->wfsymbol))
+ click = ClkFollowSymbol;
else if (ev->x > selmon->ww - (int)TEXTW(stext))
click = ClkStatusText;
else
@@ -645,6 +649,8 @@ createmon(void)
m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+ m->wfsymbol[0] = WFDEFAULT;
+ m->wfsymbol[1] = '\0';
return m;
}
@@ -735,6 +741,9 @@ drawbar(Monitor *m)
drw_setscheme(drw, scheme[SchemeNorm]);
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
+ w = TEXTW(m->wfsymbol);
+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->wfsymbol, 0);
+
if ((w = m->ww - tw - x) > bh) {
if (m->sel) {
drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
@@ -1656,6 +1665,8 @@ tag(const Arg *arg)
focus(NULL);
arrange(selmon);
}
+ if (selmon->wfsymbol[0] == WFACTIVE)
+ view(arg);
}
void
@@ -1664,6 +1675,8 @@ tagmon(const Arg *arg)
if (!selmon->sel || !mons->next)
return;
sendmon(selmon->sel, dirtomon(arg->i));
+ if (selmon->wfsymbol[0] == WFACTIVE)
+ focusmon(arg);
}
void
@@ -1703,6 +1716,13 @@ togglebar(const Arg *arg)
arrange(selmon);
}
+void
+togglefollow(const Arg *arg)
+{
+ selmon->wfsymbol[0] = (selmon->wfsymbol[0] == WFACTIVE) ? WFINACTIVE : WFACTIVE;
+ drawbars();
+}
+
void
togglefloating(const Arg *arg)
{
--
2.37.3