Compare commits

14 Commits

Author SHA1 Message Date
explosion-mental
a07421c195 shift-tools - shifttag, moves the current selected client to the adjacent tag - shifttagclients, moves the current selected client to the adjacent tag that has at least one client else acts as shifttag - shiftview, view adjacent tag - shiftviewclients, view the closes tag that has a client. If none acts as shiftview - shiftboth, shifttag and shiftview. Basically moves the window to the next/prev tag and follows it. - shiftswaptags, its a shift implementation on the swaptags function (see 65379c6264/config.h (L48) for more details), which in short 'swaps tags' (swaps all clients with the clients on the adjacent tag). A pretty useful example of this is chosing a tag empty and sending all your clients to that tag. - swapfunction is the 'helper' function for the shiftswaptags. remember that these functions **shift**, which means you can go from tag 1 to 9 or 9 to 1. Also remember that the default argument is 1 and you can change it. 2025-10-08 23:43:48 +02:00
006706b5d0 agree: dwm-goback with dwm-warp 2025-10-08 23:09:15 +02:00
Max Schillinger
0243a59c57 add patch/function 'goback' 2025-10-08 22:57:08 +02:00
c013256eef agree: dwm-autodarkmode with dwm-awesomebar 2025-10-07 00:06:55 +02:00
dimarogiv
431135ecd9 With this patch you can focus on any of the currently open windows on the current tagset with just one key combination 2025-10-07 00:02:23 +02:00
Cyril Cressent
f2837055a1 Port the uselessgap patch to 6.2 2025-10-06 23:58:04 +02:00
Jonas Dujava
5bcc02f2a7 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
2025-10-06 23:58:04 +02:00
9e3e644c21 apply dwm-xinerama-monitors-xorder-6.4.diff 2025-10-06 23:58:04 +02:00
b6d063c786 agree: change dwm-autodarkmode signal to USR1 and leave restarsig signal to HUP 2025-10-06 23:58:04 +02:00
272db9d233 apply patch dwm-autodarkmode-20250224-6.5.diff 2025-10-06 22:33:03 +02:00
e93f93b98c apply patch dwm-awesomebar-20230431-6.4.diff 2025-10-06 22:14:07 +02:00
cc4d5e65d7 apply patch dwm-exitmenu-6.3.diff 2025-10-06 21:31:59 +02:00
Arda Atci
9b49e9ad18 preserve clients on old tags when renewing dwm
By default, when dwm is recompiled-restarted all clients will
lose it's current tag and collapse to first tag. This patch preserves
clients on old tags, however note that layout order is not preserved.
2025-10-06 21:25:59 +02:00
Christopher Drelich
cfe958510f Modifies quit to handle restarts and adds SIGHUP and SIGTERM handlers.
Modified quit() to restart if it receives arg .i = 1
MOD+CTRL+SHIFT+Q was added to confid.def.h to do just that.

Signal handlers were handled for SIGHUP and SIGTERM.
If dwm receives these signals it calls quit() with
arg .i = to 1 or 0, respectively.

To restart dwm:
MOD+CTRL+SHIFT+Q
or
kill -HUP dwmpid

To quit dwm cleanly:
MOD+SHIFT+Q
or
kill -TERM dwmpid
2025-10-06 21:23:18 +02:00
7 changed files with 280 additions and 47 deletions

View File

@@ -1,6 +1,5 @@
MIT/X Consortium License MIT/X Consortium License
© 2010-2026 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2006-2019 Anselm R Garbe <anselm@garbe.ca> © 2006-2019 Anselm R Garbe <anselm@garbe.ca>
© 2006-2009 Jukka Salmi <jukka at salmi dot ch> © 2006-2009 Jukka Salmi <jukka at salmi dot ch>
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com> © 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
@@ -12,6 +11,7 @@ MIT/X Consortium License
© 2008 Martin Hurton <martin dot hurton at gmail dot com> © 2008 Martin Hurton <martin dot hurton at gmail dot com>
© 2008 Neale Pickett <neale dot woozle dot org> © 2008 Neale Pickett <neale dot woozle dot org>
© 2009 Mate Nagy <mnagy at port70 dot net> © 2009 Mate Nagy <mnagy at port70 dot net>
© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2010-2012 Connor Lane Smith <cls@lubutu.com> © 2010-2012 Connor Lane Smith <cls@lubutu.com>
© 2011 Christoph Lohmann <20h@r-36.net> © 2011 Christoph Lohmann <20h@r-36.net>
© 2015-2016 Quentin Rameau <quinq@fifth.space> © 2015-2016 Quentin Rameau <quinq@fifth.space>

View File

@@ -2,6 +2,7 @@
/* appearance */ /* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int gappx = 6; /* gaps between windows */
static const unsigned int snap = 32; /* snap pixel */ static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */ static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */ static const int topbar = 1; /* 0 means bottom bar */
@@ -22,6 +23,7 @@ static const char *colorslight[][3] = {
/* fg bg border */ /* fg bg border */
[SchemeNorm] = { col_gray1, col_gray3, col_gray2 }, [SchemeNorm] = { col_gray1, col_gray3, col_gray2 },
[SchemeSel] = { col_cyan, col_gray4, col_cyan }, [SchemeSel] = { col_cyan, col_gray4, col_cyan },
[SchemeHid] = { col_cyan, col_gray1, col_cyan },
}; };
/* tagging */ /* tagging */
@@ -42,7 +44,6 @@ static const float mfact = 0.55; /* factor of master area size [0.05..0.95]
static const int nmaster = 1; /* number of clients in master area */ static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ 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 int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const int refreshrate = 120; /* refresh rate (per second) for client move/resize */
static const Layout layouts[] = { static const Layout layouts[] = {
/* symbol arrange function */ /* symbol arrange function */
@@ -67,11 +68,16 @@ static char dmenumon[2] = "0"; /* component of dmenu{dark,light}, manipulated in
static const char *dmenudark[] = { "dmenu_run", "-m", dmenumon, "-i", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; static const char *dmenudark[] = { "dmenu_run", "-m", dmenumon, "-i", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *dmenulight[] = { "dmenu_run", "-m", dmenumon, "-i", "-fn", dmenufont, "-nb", col_gray3, "-nf", col_gray1, "-sb", col_cyan, "-sf", col_gray4, NULL }; static const char *dmenulight[] = { "dmenu_run", "-m", dmenumon, "-i", "-fn", dmenufont, "-nb", col_gray3, "-nf", col_gray1, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL }; static const char *termcmd[] = { "st", NULL };
#include "shift-tools.c"
#include "exitdwm.c" #include "exitdwm.c"
static const Key keys[] = { static const Key keys[] = {
/* modifier key function argument */ /* modifier key function argument */
{ MODKEY, XK_p, spawndmenu, {0} }, { MODKEY, XK_p, spawndmenu, {0} },
{ MODKEY, XK_o, shiftviewclients, { .i = +1 } },
{ MODKEY|ShiftMask, XK_o, shiftview, { .i = +1 } },
{ MODKEY|ShiftMask, XK_i, shiftview, { .i = -1 } },
{ MODKEY, XK_i, shiftviewclients, { .i = -1 } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstackvis, {.i = +1 } }, { MODKEY, XK_j, focusstackvis, {.i = +1 } },
@@ -81,9 +87,14 @@ static const Key keys[] = {
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } },
{ MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY|ShiftMask, XK_h, shiftboth, { .i = -1 } },
{ MODKEY|ControlMask, XK_h, shiftswaptags, { .i = -1 } },
{ MODKEY|ControlMask, XK_l, shiftswaptags, { .i = +1 } },
{ MODKEY|ShiftMask, XK_l, shiftboth, { .i = +1 } },
{ MODKEY, XK_l, setmfact, {.f = +0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY, XK_Return, zoom, {0} }, { MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} }, { MODKEY, XK_Tab, view, {0} },
{ MODKEY, XK_g, goback, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} }, { MODKEY|ShiftMask, XK_c, killclient, {0} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
@@ -108,6 +119,14 @@ static const Key keys[] = {
TAGKEYS( XK_7, 6) TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7) TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8) TAGKEYS( XK_9, 8)
{ MODKEY|ShiftMask, XK_j, focusbynum, {.i = 0} },
{ MODKEY|ShiftMask, XK_k, focusbynum, {.i = 1} },
{ MODKEY|ShiftMask, XK_l, focusbynum, {.i = 2} },
{ MODKEY|ShiftMask, XK_colon, focusbynum, {.i = 3} },
{ MODKEY|ShiftMask, XK_f, focusbynum, {.i = 4} },
{ MODKEY|ShiftMask, XK_d, focusbynum, {.i = 5} },
{ MODKEY|ShiftMask, XK_s, focusbynum, {.i = 6} },
{ MODKEY|ShiftMask, XK_a, focusbynum, {.i = 7} },
{ MODKEY|ShiftMask, XK_q, quit, {0} }, { MODKEY|ShiftMask, XK_q, quit, {0} },
{ MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} }, { MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} },
{ MODKEY|ShiftMask, XK_e, exitdwm, {0} }, { MODKEY|ShiftMask, XK_e, exitdwm, {0} },

View File

@@ -1,5 +1,5 @@
# dwm version # dwm version
VERSION = 6.7 VERSION = 6.6
# Customize below to fit your system # Customize below to fit your system

29
drw.c
View File

@@ -178,7 +178,8 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
die("error, cannot allocate color '%s'", clrname); die("error, cannot allocate color '%s'", clrname);
} }
/* Create color schemes. */ /* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
Clr * Clr *
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
{ {
@@ -186,7 +187,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
Clr *ret; Clr *ret;
/* need at least two colors for a scheme */ /* need at least two colors for a scheme */
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(Clr)))) if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
return NULL; return NULL;
for (i = 0; i < clrcount; i++) for (i = 0; i < clrcount; i++)
@@ -194,30 +195,6 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
return ret; return ret;
} }
void
drw_clr_free(Drw *drw, Clr *c)
{
if (!drw || !c)
return;
/* c is typedef XftColor Clr */
XftColorFree(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen), c);
}
void
drw_scm_free(Drw *drw, Clr *scm, size_t clrcount)
{
size_t i;
if (!drw || !scm)
return;
for (i = 0; i < clrcount; i++)
drw_clr_free(drw, &scm[i]);
free(scm);
}
void void
drw_setfontset(Drw *drw, Fnt *set) drw_setfontset(Drw *drw, Fnt *set)
{ {

2
drw.h
View File

@@ -40,9 +40,7 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in
/* Colorscheme abstraction */ /* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
void drw_clr_free(Drw *drw, Clr *c);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
void drw_scm_free(Drw *drw, Clr *scm, size_t clrcount);
/* Cursor abstraction */ /* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape); Cur *drw_cur_create(Drw *drw, int shape);

136
dwm.c
View File

@@ -51,9 +51,10 @@
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) * 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 ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define HIDDEN(C) ((getstate(C->win) == IconicState)) #define HIDDEN(C) ((getstate(C->win) == IconicState))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw) #define WIDTH(X) ((X)->w + 2 * (X)->bw + gappx)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx)
#define TAGMASK ((1 << LENGTH(tags)) - 1) #define TAGMASK ((1 << LENGTH(tags)) - 1)
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
@@ -179,6 +180,7 @@ static Atom getatomprop(Client *c, Atom prop);
static int getrootptr(int *x, int *y); static int getrootptr(int *x, int *y);
static long getstate(Window w); static long getstate(Window w);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void goback(const Arg *arg);
static void grabbuttons(Client *c, int focused); static void grabbuttons(Client *c, int focused);
static void grabkeys(void); static void grabkeys(void);
static void hide(const Arg *arg); static void hide(const Arg *arg);
@@ -228,6 +230,7 @@ static void tagmon(const Arg *arg);
static void tile(Monitor *m); static void tile(Monitor *m);
static void togglebar(const Arg *arg); static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg); static void togglefloating(const Arg *arg);
static void focusbynum(const Arg *arg);
static void toggletag(const Arg *arg); static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg); static void toggleview(const Arg *arg);
static void togglewin(const Arg *arg); static void togglewin(const Arg *arg);
@@ -245,6 +248,7 @@ static void updatetitle(Client *c);
static void updatewindowtype(Client *c); static void updatewindowtype(Client *c);
static void updatewmhints(Client *c); static void updatewmhints(Client *c);
static void view(const Arg *arg); static void view(const Arg *arg);
static void warp(const Client *c);
static Client *wintoclient(Window w); static Client *wintoclient(Window w);
static Monitor *wintomon(Window w); static Monitor *wintomon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee); static int xerror(Display *dpy, XErrorEvent *ee);
@@ -284,7 +288,7 @@ static Cur *cursor[CurLast];
static Clr **scheme, **schemedark, **schemelight; static Clr **scheme, **schemedark, **schemelight;
static Display *dpy; static Display *dpy;
static Drw *drw; static Drw *drw;
static Monitor *mons, *selmon; static Monitor *mons, *selmon, *prevmon;
static Window root, wmcheckwin; static Window root, wmcheckwin;
static const char **dmenucmd; static const char **dmenucmd;
static int colormodechanged; static int colormodechanged;
@@ -449,6 +453,7 @@ buttonpress(XEvent *e)
/* focus monitor if necessary */ /* focus monitor if necessary */
if ((m = wintomon(ev->window)) && m != selmon) { if ((m = wintomon(ev->window)) && m != selmon) {
unfocus(selmon->sel, 1); unfocus(selmon->sel, 1);
prevmon = selmon;
selmon = m; selmon = m;
focus(NULL); focus(NULL);
} }
@@ -523,8 +528,8 @@ cleanup(void)
for (i = 0; i < CurLast; i++) for (i = 0; i < CurLast; i++)
drw_cur_free(drw, cursor[i]); drw_cur_free(drw, cursor[i]);
for (i = 0; i < LENGTH(colorsdark); i++) { for (i = 0; i < LENGTH(colorsdark); i++) {
drw_scm_free(drw, schemedark[i], 3); free(schemedark[i]);
drw_scm_free(drw, schemelight[i], 3); free(schemelight[i]);
} }
free(schemedark); free(schemedark);
free(schemelight); free(schemelight);
@@ -837,6 +842,7 @@ enternotify(XEvent *e)
m = c ? c->mon : wintomon(ev->window); m = c ? c->mon : wintomon(ev->window);
if (m != selmon) { if (m != selmon) {
unfocus(selmon->sel, 1); unfocus(selmon->sel, 1);
prevmon = selmon;
selmon = m; selmon = m;
} else if (!c || c == selmon->sel) } else if (!c || c == selmon->sel)
return; return;
@@ -869,8 +875,10 @@ focus(Client *c)
} }
} }
if (c) { if (c) {
if (c->mon != selmon) if (c->mon != selmon) {
prevmon = selmon;
selmon = c->mon; selmon = c->mon;
}
if (c->isurgent) if (c->isurgent)
seturgent(c, 0); seturgent(c, 0);
detachstack(c); detachstack(c);
@@ -906,8 +914,10 @@ focusmon(const Arg *arg)
if ((m = dirtomon(arg->i)) == selmon) if ((m = dirtomon(arg->i)) == selmon)
return; return;
unfocus(selmon->sel, 0); unfocus(selmon->sel, 0);
prevmon = selmon;
selmon = m; selmon = m;
focus(NULL); focus(NULL);
warp(selmon->sel);
} }
void void
@@ -964,14 +974,13 @@ Atom
getatomprop(Client *c, Atom prop) getatomprop(Client *c, Atom prop)
{ {
int di; int di;
unsigned long nitems, dl; unsigned long dl;
unsigned char *p = NULL; unsigned char *p = NULL;
Atom da, atom = None; Atom da, atom = None;
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
&da, &di, &nitems, &dl, &p) == Success && p) { &da, &di, &dl, &dl, &p) == Success && p) {
if (nitems > 0) atom = *(Atom *)p;
atom = *(Atom *)p;
XFree(p); XFree(p);
} }
return atom; return atom;
@@ -1028,6 +1037,22 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size)
return 1; return 1;
} }
void
goback(const Arg *arg)
{
if (prevmon == NULL) {
Arg a = {0};
view(&a);
} else if (prevmon != selmon) {
unfocus(selmon->sel, 0);
Monitor *p = selmon;
selmon = prevmon;
focus(NULL);
prevmon = p;
warp(selmon->sel);
}
}
void void
grabbuttons(Client *c, int focused) grabbuttons(Client *c, int focused)
{ {
@@ -1288,6 +1313,8 @@ motionnotify(XEvent *e)
return; return;
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
unfocus(selmon->sel, 1); unfocus(selmon->sel, 1);
if (m != selmon)
prevmon = selmon;
selmon = m; selmon = m;
focus(NULL); focus(NULL);
} }
@@ -1324,7 +1351,7 @@ movemouse(const Arg *arg)
handler[ev.type](&ev); handler[ev.type](&ev);
break; break;
case MotionNotify: case MotionNotify:
if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) if ((ev.xmotion.time - lasttime) <= (1000 / 60))
continue; continue;
lasttime = ev.xmotion.time; lasttime = ev.xmotion.time;
@@ -1349,6 +1376,7 @@ movemouse(const Arg *arg)
XUngrabPointer(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime);
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
sendmon(c, m); sendmon(c, m);
prevmon = selmon;
selmon = m; selmon = m;
focus(NULL); focus(NULL);
} }
@@ -1453,12 +1481,36 @@ void
resizeclient(Client *c, int x, int y, int w, int h) resizeclient(Client *c, int x, int y, int w, int h)
{ {
XWindowChanges wc; XWindowChanges wc;
unsigned int n;
unsigned int gapoffset;
unsigned int gapincr;
Client *nbc;
c->oldx = c->x; c->x = wc.x = x;
c->oldy = c->y; c->y = wc.y = y;
c->oldw = c->w; c->w = wc.width = w;
c->oldh = c->h; c->h = wc.height = h;
wc.border_width = c->bw; wc.border_width = c->bw;
/* Get number of clients for the selected monitor */
for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++);
/* Do nothing if layout is floating */
if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) {
gapincr = gapoffset = 0;
} else {
/* Remove border and gap if layout is monocle or only one client */
if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) {
gapoffset = 0;
gapincr = -2 * borderpx;
wc.border_width = 0;
} else {
gapoffset = gappx;
gapincr = 2 * gappx;
}
}
c->oldx = c->x; c->x = wc.x = x + gapoffset;
c->oldy = c->y; c->y = wc.y = y + gapoffset;
c->oldw = c->w; c->w = wc.width = w - gapincr;
c->oldh = c->h; c->h = wc.height = h - gapincr;
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
configure(c); configure(c);
XSync(dpy, False); XSync(dpy, False);
@@ -1493,7 +1545,7 @@ resizemouse(const Arg *arg)
handler[ev.type](&ev); handler[ev.type](&ev);
break; break;
case MotionNotify: case MotionNotify:
if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) if ((ev.xmotion.time - lasttime) <= (1000 / 60))
continue; continue;
lasttime = ev.xmotion.time; lasttime = ev.xmotion.time;
@@ -1516,6 +1568,7 @@ resizemouse(const Arg *arg)
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
sendmon(c, m); sendmon(c, m);
prevmon = selmon;
selmon = m; selmon = m;
focus(NULL); focus(NULL);
} }
@@ -1542,6 +1595,8 @@ restack(Monitor *m)
wc.sibling = c->win; 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); XSync(dpy, False);
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
} }
@@ -2017,6 +2072,19 @@ togglefloating(const Arg *arg)
arrange(selmon); arrange(selmon);
} }
void
focusbynum(const Arg *arg)
{
int i;
Client *c;
i = 0;
c = nexttiled(selmon->clients);
for (; c && i < arg->i; c = nexttiled(c->next), i++);
focus(c);
}
void void
toggletag(const Arg *arg) toggletag(const Arg *arg)
{ {
@@ -2039,6 +2107,7 @@ toggleview(const Arg *arg)
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
if (newtagset) { if (newtagset) {
prevmon = NULL;
selmon->tagset[selmon->seltags] = newtagset; selmon->tagset[selmon->seltags] = newtagset;
focus(NULL); focus(NULL);
arrange(selmon); arrange(selmon);
@@ -2164,6 +2233,16 @@ updateclientlist(void)
(unsigned char *) &(c->win), 1); (unsigned char *) &(c->win), 1);
} }
#ifdef XINERAMA
// Custom comparator: sort monitors by x_org to match physical layout left-to-right
static int
compare_xinerama_x(const void *a, const void *b) {
const XineramaScreenInfo *sa = (const XineramaScreenInfo *)a;
const XineramaScreenInfo *sb = (const XineramaScreenInfo *)b;
return sa->x_org - sb->x_org;
}
#endif /* XINERAMA */
int int
updategeom(void) updategeom(void)
{ {
@@ -2180,6 +2259,8 @@ updategeom(void)
for (n = 0, m = mons; m; m = m->next, n++); for (n = 0, m = mons; m; m = m->next, n++);
/* only consider unique geometries as separate screens */ /* only consider unique geometries as separate screens */
unique = ecalloc(nn, sizeof(XineramaScreenInfo)); unique = ecalloc(nn, sizeof(XineramaScreenInfo));
// Sort monitors by x_org so dwm handles screens in left-to-right order
qsort(info, nn, sizeof(XineramaScreenInfo), compare_xinerama_x);
for (i = 0, j = 0; i < nn; i++) for (i = 0, j = 0; i < nn; i++)
if (isuniquegeom(unique, j, &info[i])) if (isuniquegeom(unique, j, &info[i]))
memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
@@ -2355,6 +2436,7 @@ view(const Arg *arg)
{ {
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return; return;
prevmon = NULL;
selmon->seltags ^= 1; /* toggle sel tagset */ selmon->seltags ^= 1; /* toggle sel tagset */
if (arg->ui & TAGMASK) if (arg->ui & TAGMASK)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
@@ -2362,6 +2444,28 @@ view(const Arg *arg)
arrange(selmon); 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 * Client *
wintoclient(Window w) wintoclient(Window w)
{ {

135
shift-tools.c Normal file
View File

@@ -0,0 +1,135 @@
/* Sends a window to the next/prev tag */
void
shifttag(const Arg *arg)
{
Arg shifted;
shifted.ui = selmon->tagset[selmon->seltags];
if (arg->i > 0) /* left circular shift */
shifted.ui = ((shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i)));
else /* right circular shift */
shifted.ui = (shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i));
tag(&shifted);
}
/* Sends a window to the next/prev tag that has a client, else it moves it to the next/prev one. */
void
shifttagclients(const Arg *arg)
{
Arg shifted;
Client *c;
unsigned int tagmask = 0;
shifted.ui = selmon->tagset[selmon->seltags];
for (c = selmon->clients; c; c = c->next)
if (!(c->tags))
tagmask = tagmask | c->tags;
if (arg->i > 0) /* left circular shift */
do {
shifted.ui = (shifted.ui << arg->i)
| (shifted.ui >> (LENGTH(tags) - arg->i));
} while (tagmask && !(shifted.ui & tagmask));
else /* right circular shift */
do {
shifted.ui = (shifted.ui >> (- arg->i)
| shifted.ui << (LENGTH(tags) + arg->i));
} while (tagmask && !(shifted.ui & tagmask));
tag(&shifted);
}
/* Navigate to the next/prev tag */
void
shiftview(const Arg *arg)
{
Arg shifted;
shifted.ui = selmon->tagset[selmon->seltags];
if (arg->i > 0) /* left circular shift */
shifted.ui = (shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i));
else /* right circular shift */
shifted.ui = (shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i));
view(&shifted);
}
/* Navigate to the next/prev tag that has a client, else moves it to the next/prev tag */
void
shiftviewclients(const Arg *arg)
{
Arg shifted;
Client *c;
unsigned int tagmask = 0;
shifted.ui = selmon->tagset[selmon->seltags];
for (c = selmon->clients; c; c = c->next)
if (!(c->tags))
tagmask = tagmask | c->tags;
if (arg->i > 0) /* left circular shift */
do {
shifted.ui = (shifted.ui << arg->i)
| (shifted.ui >> (LENGTH(tags) - arg->i));
} while (tagmask && !(shifted.ui & tagmask));
else /* right circular shift */
do {
shifted.ui = (shifted.ui >> (- arg->i)
| shifted.ui << (LENGTH(tags) + arg->i));
} while (tagmask && !(shifted.ui & tagmask));
view(&shifted);
}
/* move the current active window to the next/prev tag and view it. More like following the window */
void
shiftboth(const Arg *arg)
{
Arg shifted;
shifted.ui = selmon->tagset[selmon->seltags];
if (arg->i > 0) /* left circular shift */
shifted.ui = ((shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i)));
else /* right circular shift */
shifted.ui = ((shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i)));
tag(&shifted);
view(&shifted);
}
//helper function for shiftswaptags.
//see: https://github.com/moizifty/DWM-Build/blob/65379c62640788881486401a0d8c79333751b02f/config.h#L48
void
swaptags(const Arg *arg)
{
Client *c;
unsigned int newtag = arg->ui & TAGMASK;
unsigned int curtag = selmon->tagset[selmon->seltags];
if (newtag == curtag || !curtag || (curtag & (curtag-1)))
return;
for (c = selmon->clients; c != NULL; c = c->next) {
if ((c->tags & newtag) || (c->tags & curtag))
c->tags ^= curtag ^ newtag;
if (!c->tags)
c->tags = newtag;
}
//move to the swaped tag
//selmon->tagset[selmon->seltags] = newtag;
focus(NULL);
arrange(selmon);
}
/* swaps "tags" (all the clients) with the next/prev tag. */
void
shiftswaptags(const Arg *arg)
{
Arg shifted;
shifted.ui = selmon->tagset[selmon->seltags];
if (arg->i > 0) /* left circular shift */
shifted.ui = ((shifted.ui << arg->i) | (shifted.ui >> (LENGTH(tags) - arg->i)));
else /* right circular shift */
shifted.ui = ((shifted.ui >> (- arg->i) | shifted.ui << (LENGTH(tags) + arg->i)));
swaptags(&shifted);
// uncomment if you also want to "go" (view) the tag where the the clients are going
//view(&shifted);
}