Merge remote-tracking branch 'upstream/master'

- Seamless restart patch
This commit is contained in:
Sravan Balaji
2022-06-17 14:07:10 -04:00
11 changed files with 674 additions and 74 deletions

View File

@ -19,6 +19,8 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
### Changelog:
2022-06-17 - Ported the seamless restart feature from dusk into dwm-flexipatch
2022-02-11 - Added the isfreesize version of the sizehints patch and the [tagsync](https://github.com/bakkeby/dwm-flexipatch/pull/219) patch (contributed by [Bagelli](https://github.com/Bagellll))
2021-11-23 - Added the taglabels and underlinetags patches
@ -602,6 +604,9 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/X9IiSSM6
- this alternative patch enables a scratchpad feature in dwm similar to the scratchpad
feature in i3wm
- seamless_restart
- allows for selected layout, assigned tags, etc. to be persisted across restarts
- [selfrestart](https://dwm.suckless.org/patches/selfrestart/)
- restart dwm without the unnecessary dependency of an external script

View File

@ -127,6 +127,7 @@
- [[#rounded-corners][Rounded Corners]]
- [[#save-floats][Save Floats]]
- [[#scratch-pads][Scratch Pads]]
- [[#seamless-restart][Seamless Restart]]
- [[#selective-fake-fullscreen][Selective Fake Fullscreen]]
- [[#self-restart][Self Restart]]
- [[#send-monitor-keep-focus][Send Monitor Keep Focus]]
@ -288,6 +289,8 @@ Browsing patches? There is a [[https://coggle.it/diagram/X9IiSSM6PTWOM9Wz][map o
** Changelog
2022-06-17 - Ported the seamless restart feature from dusk into dwm-flexipatch
2022-02-11 - Added the isfreesize version of the sizehints patch and the [[https://github.com/bakkeby/dwm-flexipatch/pull/219][tagsync]] patch (contributed by [[https://github.com/Bagellll][Bagelli]])
2021-11-23 - Added the taglabels and underlinetags patches
@ -870,6 +873,9 @@ Browsing patches? There is a [[https://coggle.it/diagram/X9IiSSM6PTWOM9Wz][map o
- this alternative patch enables a scratchpad feature in dwm similar to the scratchpad
feature in i3wm
- seamless_restart
- allows for selected layout, assigned tags, etc. to be persisted across restarts
- [[https://dwm.suckless.org/patches/selfrestart/][selfrestart]]
- restart dwm without the unnecessary dependency of an external script
@ -2588,6 +2594,21 @@ https://github.com/GasparVardanyan/dwm-scratchpad
#define SCRATCHPAD_ALT_1_PATCH 0
#+END_SRC
*** Seamless Restart
This patch persists some settings across window manager restarts. These include but are not limited to:
- client's assigned tag(s) on which monitor
- the order of clients
- nmaster
- selected layout
- plus various additions depending on what other patches are used
The above is not persisted across reboots, however.
#+BEGIN_SRC c :tangle patches.def.h
#define SEAMLESS_RESTART_PATCH 0
#+END_SRC
*** Selective Fake Fullscreen
As opposed to the original patch this only adds a rule option allowing fake fullscreen to be enabled for applications when they start. This is intended to be used in combination with the fakefullscreenclient patch and offers no practical functionality without it.

191
dwm.c
View File

@ -212,6 +212,14 @@ enum {
WMLast
}; /* default atoms */
#if SEAMLESS_RESTART_PATCH
enum {
ClientFields,
ClientTags,
ClientLast
}; /* dwm client atoms */
#endif // SEAMLESS_RESTART_PATCH
enum {
#if BAR_STATUSBUTTON_PATCH
ClkButton,
@ -335,6 +343,9 @@ struct Client {
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
#if SEAMLESS_RESTART_PATCH
unsigned int idx;
#endif // SEAMLESS_RESTART_PATCH
int oldx, oldy, oldw, oldh;
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
int bw, oldbw;
@ -620,7 +631,7 @@ static void focusmon(const Arg *arg);
#if !STACKER_PATCH
static void focusstack(const Arg *arg);
#endif // STACKER_PATCH
static Atom getatomprop(Client *c, Atom prop);
static Atom getatomprop(Client *c, Atom prop, Atom req);
static int getrootptr(int *x, int *y);
static long getstate(Window w);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
@ -782,11 +793,13 @@ static void (*handler[LASTEvent]) (XEvent *) = {
#endif // BAR_SYSTRAY_PATCH
[UnmapNotify] = unmapnotify
};
#if BAR_SYSTRAY_PATCH
static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
#else
static Atom wmatom[WMLast], netatom[NetLast];
#if BAR_SYSTRAY_PATCH
static Atom xatom[XLast];
#endif // BAR_SYSTRAY_PATCH
#if SEAMLESS_RESTART_PATCH
static Atom clientatom[ClientLast];
#endif // SEAMLESS_RESTART_PATCH
#if ON_EMPTY_KEYS_PATCH
static int isempty = 0;
#endif // ON_EMPTY_KEYS_PATCH
@ -839,7 +852,7 @@ applyrules(Client *c)
XGetClassHint(dpy, c->win, &ch);
class = ch.res_class ? ch.res_class : broken;
instance = ch.res_name ? ch.res_name : broken;
wintype = getatomprop(c, netatom[NetWMWindowType]);
wintype = getatomprop(c, netatom[NetWMWindowType], XA_ATOM);
#if WINDOWROLERULE_PATCH
gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role));
#endif // WINDOWROLERULE_PATCH
@ -1199,11 +1212,15 @@ checkotherwm(void)
void
cleanup(void)
{
#if !SEAMLESS_RESTART_PATCH
Arg a = {.ui = ~0};
#endif // SEAMLESS_RESTART_PATCH
Layout foo = { "", NULL };
Monitor *m;
size_t i;
#if !SEAMLESS_RESTART_PATCH
view(&a);
#endif // SEAMLESS_RESTART_PATCH
selmon->lt[selmon->sellt] = &foo;
for (m = mons; m; m = m->next)
while (m->stack)
@ -1690,6 +1707,11 @@ createmon(void)
#endif // PERTAG_VANITYGAPS_PATCH | VANITYGAPS_PATCH
}
#endif // PERTAG_PATCH
#if SEAMLESS_RESTART_PATCH
restoremonitorstate(m);
#endif // SEAMLESS_RESTART_PATCH
#if INSETS_PATCH
m->inset = default_inset;
#endif // INSETS_PATCH
@ -1735,9 +1757,13 @@ void
detach(Client *c)
{
Client **tc;
#if SEAMLESS_RESTART_PATCH
c->idx = 0;
#endif // SEAMLESS_RESTART_PATCH
for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
*tc = c->next;
c->next = NULL;
}
void
@ -1752,6 +1778,7 @@ detachstack(Client *c)
for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
c->mon->sel = t;
}
c->snext = NULL;
}
Monitor *
@ -2080,7 +2107,7 @@ focusstack(const Arg *arg)
#endif // STACKER_PATCH
Atom
getatomprop(Client *c, Atom prop)
getatomprop(Client *c, Atom prop, Atom req)
{
int di;
unsigned long dl;
@ -2088,26 +2115,21 @@ getatomprop(Client *c, Atom prop)
Atom da, atom = None;
#if BAR_SYSTRAY_PATCH
/* FIXME getatomprop should return the number of items and a pointer to
* the stored data instead of this workaround */
Atom req = XA_ATOM;
if (prop == xatom[XembedInfo])
req = xatom[XembedInfo];
#endif // BAR_SYSTRAY_PATCH
/* FIXME getatomprop should return the number of items and a pointer to
* the stored data instead of this workaround */
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
&da, &di, &dl, &dl, &p) == Success && p) {
atom = *(Atom *)p;
#if BAR_SYSTRAY_PATCH
if (da == xatom[XembedInfo] && dl == 2)
atom = ((Atom *)p)[1];
#endif // BAR_SYSTRAY_PATCH
XFree(p);
}
#else
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
&da, &di, &dl, &dl, &p) == Success && p) {
atom = *(Atom *)p;
XFree(p);
}
#endif // BAR_SYSTRAY_PATCH
return atom;
}
@ -2310,6 +2332,9 @@ manage(Window w, XWindowAttributes *wa)
#if SWALLOW_PATCH
Client *term = NULL;
#endif // SWALLOW_PATCH
#if SEAMLESS_RESTART_PATCH
int settings_restored;
#endif // SEAMLESS_RESTART_PATCH
Window trans = None;
XWindowChanges wc;
@ -2319,6 +2344,9 @@ manage(Window w, XWindowAttributes *wa)
c->pid = winpid(w);
#endif // SWALLOW_PATCH
/* geometry */
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
c->sfx = c->sfy = c->sfw = c->sfh = -9999;
#endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH
c->x = c->oldx = wa->x;
c->y = c->oldy = wa->y;
c->w = c->oldw = wa->width;
@ -2327,6 +2355,9 @@ manage(Window w, XWindowAttributes *wa)
#if CFACTS_PATCH
c->cfact = 1.0;
#endif // CFACTS_PATCH
#if SEAMLESS_RESTART_PATCH
settings_restored = restoreclientstate(c);
#endif // SEAMLESS_RESTART_PATCH
#if BAR_WINICON_PATCH
updateicon(c);
#endif // BAR_WINICON_PATCH
@ -2359,7 +2390,12 @@ manage(Window w, XWindowAttributes *wa)
c->iscentered = 1;
#endif // CENTER_TRANSIENT_WINDOWS_PATCH | CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH | CENTER_PATCH
} else {
#if SEAMLESS_RESTART_PATCH
if (!settings_restored)
c->mon = selmon;
#else
c->mon = selmon;
#endif // SEAMLESS_RESTART_PATCH
#if CENTER_PATCH
if (c->x == c->mon->wx && c->y == c->mon->wy)
c->iscentered = 1;
@ -2369,7 +2405,12 @@ manage(Window w, XWindowAttributes *wa)
#else
c->bw = borderpx;
#endif // SETBORDERPX_PATCH
#if SEAMLESS_RESTART_PATCH
if (!settings_restored)
applyrules(c);
#else
applyrules(c);
#endif // SEAMLESS_RESTART_PATCH
#if SWALLOW_PATCH
term = termforwin(c);
if (term)
@ -2396,7 +2437,7 @@ manage(Window w, XWindowAttributes *wa)
#endif // BAR_FLEXWINTITLE_PATCH
configure(c); /* propagates border_width, if size doesn't change */
updatesizehints(c);
if (getatomprop(c, netatom[NetWMState]) == netatom[NetWMFullscreen])
if (getatomprop(c, netatom[NetWMState], XA_ATOM) == netatom[NetWMFullscreen])
setfullscreen(c, 1);
updatewmhints(c);
#if DECORATION_HINTS_PATCH
@ -2404,8 +2445,6 @@ manage(Window w, XWindowAttributes *wa)
#endif // DECORATION_HINTS_PATCH
#if CENTER_PATCH && SAVEFLOATS_PATCH || CENTER_PATCH && EXRESIZE_PATCH
c->sfx = -9999;
c->sfy = -9999;
if (c->iscentered) {
c->sfx = c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
c->sfy = c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
@ -2421,13 +2460,12 @@ manage(Window w, XWindowAttributes *wa)
#elif ALWAYSCENTER_PATCH
c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
#elif SAVEFLOATS_PATCH || EXRESIZE_PATCH
c->sfx = -9999;
c->sfy = -9999;
#endif // CENTER_PATCH / ALWAYSCENTER_PATCH / SAVEFLOATS_PATCH
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
c->sfw = c->w;
c->sfh = c->h;
if (c->sfw == -9999) {
c->sfw = c->w;
c->sfh = c->h;
}
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
@ -2445,7 +2483,7 @@ manage(Window w, XWindowAttributes *wa)
XRaiseWindow(dpy, c->win);
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
}
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH || SEAMLESS_RESTART_PATCH
attachx(c);
#else
attach(c);
@ -2600,8 +2638,8 @@ movemouse(const Arg *arg)
#endif // FAKEFULLSCREEN_CLIENT_PATCH
#endif // FAKEFULLSCREEN_PATCH
restack(selmon);
ocx = c->x;
ocy = c->y;
nx = ocx = c->x;
ny = ocy = c->y;
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
return;
@ -2639,14 +2677,7 @@ movemouse(const Arg *arg)
togglefloating(NULL);
}
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
resize(c, nx, ny, c->w, c->h, 1);
/* save last known float coordinates */
c->sfx = nx;
c->sfy = ny;
#else
resize(c, nx, ny, c->w, c->h, 1);
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
}
#if ROUNDED_CORNERS_PATCH
drawroundedcorners(c);
@ -2654,6 +2685,7 @@ movemouse(const Arg *arg)
break;
}
} while (ev.type != ButtonRelease);
XUngrabPointer(dpy, CurrentTime);
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
#if SCRATCHPADS_PATCH
@ -2666,6 +2698,13 @@ movemouse(const Arg *arg)
selmon = m;
focus(NULL);
}
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
/* save last known float coordinates */
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
c->sfx = nx;
c->sfy = ny;
}
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
#if ROUNDED_CORNERS_PATCH
drawroundedcorners(c);
#endif // ROUNDED_CORNERS_PATCH
@ -2773,8 +2812,13 @@ quit(const Arg *arg)
#if RESTARTSIG_PATCH
restart = arg->i;
#endif // RESTARTSIG_PATCH
#if ONLYQUITONEMPTY_PATCH
#if SEAMLESS_RESTART_PATCH
Monitor *m;
#endif // SEAMLESS_RESTART_PATCH
#if ONLYQUITONEMPTY_PATCH
#if !SEAMLESS_RESTART_PATCH
Monitor *m;
#endif // SEAMLESS_RESTART_PATCH
Client *c;
unsigned int n = 0;
@ -2794,6 +2838,11 @@ quit(const Arg *arg)
running = 0;
#endif // ONLYQUITONEMPTY_PATCH
#if SEAMLESS_RESTART_PATCH
for (m = mons; m && !running; m = m->next)
persistmonitorstate(m);
#endif // SEAMLESS_RESTART_PATCH
#if COOL_AUTOSTART_PATCH
/* kill child processes */
for (i = 0; i < autostart_len && !running; i++) {
@ -2876,9 +2925,9 @@ resizeclient(Client *c, int x, int y, int w, int h)
void
resizemouse(const Arg *arg)
{
int ocx, ocy, nw, nh;
int ocx, ocy, nw, nh, nx, ny;
#if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
int opx, opy, och, ocw, nx, ny;
int opx, opy, och, ocw;
int horizcorner, vertcorner;
unsigned int dui;
Window dummy;
@ -2900,8 +2949,10 @@ resizemouse(const Arg *arg)
#endif // FAKEFULLSCREEN_CLIENT_PATCH
#endif // !FAKEFULLSCREEN_PATCH
restack(selmon);
ocx = c->x;
ocy = c->y;
nx = ocx = c->x;
ny = ocy = c->y;
nh = c->h;
nw = c->w;
#if RESIZEPOINT_PATCH
och = c->h;
ocw = c->w;
@ -2968,24 +3019,7 @@ resizemouse(const Arg *arg)
}
}
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
#if RESIZECORNERS_PATCH || RESIZEPOINT_PATCH
resizeclient(c, nx, ny, nw, nh);
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
/* save last known float dimensions */
c->sfx = nx;
c->sfy = ny;
c->sfw = nw;
c->sfh = nh;
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
#else
resize(c, c->x, c->y, nw, nh, 1);
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
c->sfx = c->x;
c->sfy = c->y;
c->sfw = nw;
c->sfh = nh;
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
#endif // RESIZECORNERS_PATCH
resize(c, nx, ny, nw, nh, 1);
#if ROUNDED_CORNERS_PATCH
drawroundedcorners(c);
#endif // ROUNDED_CORNERS_PATCH
@ -2993,6 +3027,7 @@ resizemouse(const Arg *arg)
break;
}
} while (ev.type != ButtonRelease);
#if !RESIZEPOINT_PATCH
#if RESIZECORNERS_PATCH
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
@ -3015,6 +3050,15 @@ resizemouse(const Arg *arg)
selmon = m;
focus(NULL);
}
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
/* save last known float dimensions */
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
c->sfx = nx;
c->sfy = ny;
c->sfw = nw;
c->sfh = nh;
}
#endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH
ignoreconfigurerequests = 0;
}
@ -3568,6 +3612,10 @@ setup(void)
#if WINDOWROLERULE_PATCH
wmatom[WMWindowRole] = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
#endif // WINDOWROLERULE_PATCH
#if SEAMLESS_RESTART_PATCH
clientatom[ClientFields] = XInternAtom(dpy, "_DWM_CLIENT_FIELDS", False);
clientatom[ClientTags] = XInternAtom(dpy, "_DWM_CLIENT_TAGS", False);
#endif // SEAMLESS_RESTART_PATCH
netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
#if BAR_SYSTRAY_PATCH
@ -3757,7 +3805,7 @@ showhide(Client *c)
/* show clients top down */
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
if (!c->mon->lt[c->mon->sellt]->arrange && c->sfx != -9999 && !c->isfullscreen) {
XMoveWindow(dpy, c->win, c->sfx, c->sfy);
XMoveResizeWindow(dpy, c->win, c->sfx, c->sfy, c->sfw, c->sfh);
resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0);
showhide(c->snext);
return;
@ -3935,13 +3983,26 @@ tag(const Arg *arg)
void
tagmon(const Arg *arg)
{
#if TAGMONFIXFS_PATCH
Client *c = selmon->sel;
Monitor *dest;
#if SEAMLESS_RESTART_PATCH && SAVEFLOATS_PATCH
int restored;
#endif // SEAMLESS_RESTART_PATCH | SAVEFLOATS_PATCH
if (!c || !mons->next)
return;
dest = dirtomon(arg->i);
#if SEAMLESS_RESTART_PATCH && SAVEFLOATS_PATCH
savewindowfloatposition(c, c->mon);
restored = restorewindowfloatposition(c, dest);
if (restored && (!dest->lt[dest->sellt]->arrange || c->isfloating)) {
XMoveResizeWindow(dpy, c->win, c->sfx, c->sfy, c->sfw, c->sfh);
resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 1);
}
#endif // SEAMLESS_RESTART_PATCH | SAVEFLOATS_PATCH
#if TAGMONFIXFS_PATCH
if (c->isfullscreen) {
c->isfullscreen = 0;
sendmon(c, dirtomon(arg->i));
sendmon(c, dest);
c->isfullscreen = 1;
#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
if (c->fakefullscreen != 1) {
@ -3953,11 +4014,9 @@ tagmon(const Arg *arg)
XRaiseWindow(dpy, c->win);
#endif // FAKEFULLSCREEN_CLIENT_PATCH
} else
sendmon(c, dirtomon(arg->i));
sendmon(c, dest);
#else
if (!selmon->sel || !mons->next)
return;
sendmon(selmon->sel, dirtomon(arg->i));
sendmon(c, dest);
#endif // TAGMONFIXFS_PATCH
}
@ -4991,12 +5050,12 @@ main(int argc, char *argv[])
runautostart();
#endif
run();
cleanup();
XCloseDisplay(dpy);
#if RESTARTSIG_PATCH
if (restart)
execvp(argv[0], argv);
#endif // RESTARTSIG_PATCH
cleanup();
XCloseDisplay(dpy);
return EXIT_SUCCESS;
}

View File

@ -1,8 +1,27 @@
void
attachx(Client *c)
{
#if ATTACHABOVE_PATCH
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBOTTOM_PATCH || SEAMLESS_RESTART_PATCH
Client *at;
#endif // ATTACHABOVE_PATCH | ATTACHASIDE_PATCH | ATTACHBOTTOM_PATCH | SEAMLESS_RESTART_PATCH
#if SEAMLESS_RESTART_PATCH
if (c->idx > 0) { /* then the client has a designated position in the client list */
for (at = c->mon->clients; at; at = at->next) {
if (c->idx < at->idx) {
c->next = at;
c->mon->clients = c;
return;
} else if (at->idx <= c->idx && (!at->next || c->idx <= at->next->idx)) {
c->next = at->next;
at->next = c;
return;
}
}
}
#endif // SEAMLESS_RESTART_PATCH
#if ATTACHABOVE_PATCH
if (!(c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating)) {
for (at = c->mon->clients; at->next != c->mon->sel; at = at->next);
c->next = at->next;
@ -10,9 +29,7 @@ attachx(Client *c)
return;
}
#elif ATTACHASIDE_PATCH
Client *at;
unsigned int n;
for (at = c->mon->clients, n = 0; at; at = at->next)
if (!at->isfloating && ISVISIBLEONTAG(at, c->tags))
if (++n >= c->mon->nmaster)
@ -30,7 +47,6 @@ attachx(Client *c)
return;
}
#elif ATTACHBOTTOM_PATCH
Client *at;
for (at = c->mon->clients; at && at->next; at = at->next);
if (at) {
at->next = c;

View File

@ -111,6 +111,7 @@ removesystrayicon(Client *i)
for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
if (ii)
*ii = i->next;
XReparentWindow(dpy, i->win, root, 0, 0);
free(i);
drawbarwin(systray->bar);
}
@ -163,7 +164,7 @@ updatesystrayiconstate(Client *i, XPropertyEvent *ev)
int code = 0;
if (!showsystray || !systray || !i || ev->atom != xatom[XembedInfo] ||
!(flags = getatomprop(i, xatom[XembedInfo])))
!(flags = getatomprop(i, xatom[XembedInfo], xatom[XembedInfo])))
return;
if (flags & XEMBED_MAPPED && !i->tags) {

View File

@ -97,7 +97,7 @@
#if ASPECTRESIZE_PATCH
#include "aspectresize.c"
#endif
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH || SEAMLESS_RESTART_PATCH
#include "attachx.c"
#endif
#if AUTOSTART_PATCH
@ -313,6 +313,9 @@
#if DRAGMFACT_PATCH
#include "dragmfact.c"
#endif
#if SEAMLESS_RESTART_PATCH
#include "seamless_restart.c"
#endif
/* Layouts */
#if BSTACK_LAYOUT || BSTACKHORIZ_LAYOUT || CENTEREDMASTER_LAYOUT || CENTEREDFLOATINGMASTER_LAYOUT || COLUMNS_LAYOUT || DECK_LAYOUT || TILE_LAYOUT
#include "layout_facts.c"

View File

@ -97,7 +97,7 @@
#if ASPECTRESIZE_PATCH
#include "aspectresize.h"
#endif
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH || SEAMLESS_RESTART_PATCH
#include "attachx.h"
#endif
#if AUTOSTART_PATCH
@ -223,6 +223,9 @@
#if SCRATCHPAD_ALT_1_PATCH
#include "scratchpad_alt_1.h"
#endif
#if SEAMLESS_RESTART_PATCH
#include "seamless_restart.h"
#endif
#if SELFRESTART_PATCH
#include "selfrestart.h"
#endif

471
patch/seamless_restart.c Normal file
View File

@ -0,0 +1,471 @@
void
persistmonitorstate(Monitor *m)
{
Client *c;
unsigned int i;
setmonitortags(m);
setmonitorfields(m);
/* Set client atoms */
for (i = 1, c = m->clients; c; c = c->next, ++i) {
c->idx = i;
persistclientstate(c);
#if SWALLOW_PATCH
if (c->swallowing) {
c->swallowing->idx = i;
persistclientstate(c->swallowing);
}
#endif // SWALLOW_PATCH
}
}
int
restoremonitorstate(Monitor *m)
{
return getmonitortags(m) | getmonitorfields(m);
}
void
persistclientstate(Client *c)
{
setclienttags(c);
setclientfields(c);
#if SAVEFLOATS_PATCH
savewindowfloatposition(c, c->mon);
#endif // SAVEFLOATS_PATCH
}
int
restoreclientstate(Client *c)
{
return getclienttags(c)
| getclientfields(c)
#if SAVEFLOATS_PATCH
| restorewindowfloatposition(c, c->mon ? c->mon : selmon)
#endif // SAVEFLOATS_PATCH
;
}
void setmonitorfields(Monitor *m)
{
#if PERTAG_PATCH
unsigned int i;
#endif // PERTAG_PATCH
char atom[22] = {0};
Atom monitor_fields;
#if FLEXTILE_DELUXE_LAYOUT
unsigned int flextile_deluxe_bitmask;
#endif // FLEXTILE_DELUXE_LAYOUT
sprintf(atom, "_DWM_MONITOR_FIELDS_%u", m->num);
monitor_fields = XInternAtom(dpy, atom, False);
/* Perists workspace information in 32 bits laid out like this:
*
* |0|0000|0|0000|0000|0000|0000|0000|000|000
* | | | | | | | | | |-- nmaster
* | | | | | | | | |-- nstack
* | | | | | | | |-- layout
* | | | | | | |-- flextile LAYOUT (split)
* | | | | | |-- flextile MASTER
* | | | | |-- flextile STACK1
* | | | |-- flextile STACK2
* | | |-- flextile mirror layout (indicated by negative layout)
* | |
* | |-- reserved
* |-- showbar
*/
#if PERTAG_PATCH
for (i = 0; i <= NUMTAGS; i++) {
#if FLEXTILE_DELUXE_LAYOUT
flextile_deluxe_bitmask = (m->pertag->nstacks[i] & 0x7) << 3;
if (m->pertag->ltidxs[i][m->pertag->sellts[i]]->arrange == flextile) {
flextile_deluxe_bitmask |=
(abs(m->pertag->ltaxis[i][LAYOUT]) & 0xF) << 10 |
(m->pertag->ltaxis[i][MASTER] & 0xF) << 14 |
(m->pertag->ltaxis[i][STACK] & 0xF) << 18 |
(m->pertag->ltaxis[i][STACK2] & 0xF) << 22 |
(m->pertag->ltaxis[i][LAYOUT] < 0 ? 1 : 0) << 24;
}
#endif // FLEXTILE_DELUXE_L1AYOUT
uint32_t data[] = {
#if FLEXTILE_DELUXE_LAYOUT
flextile_deluxe_bitmask |
#endif // FLEXTILE_DELUXE_LAYOUT
(m->pertag->nmasters[i] & 0x7) |
(getlayoutindex(m->pertag->ltidxs[i][m->pertag->sellts[i]]) & 0xF) << 6 |
#if PERTAGBAR_PATCH
m->pertag->showbars[i] << 31
#else
m->showbar << 31
#endif // PERTAGBAR_PATCH
};
XChangeProperty(dpy, root, monitor_fields, XA_CARDINAL, 32,
i ? PropModeAppend : PropModeReplace, (unsigned char *)data, 1);
}
#else // !PERTAG_PATCH
#if FLEXTILE_DELUXE_LAYOUT
flextile_deluxe_bitmask = (m->nstack & 0x7) << 3;
if (m->lt[m->sellt]->arrange == flextile) {
flextile_deluxe_bitmask |=
(abs(m->ltaxis[LAYOUT]) & 0xF) << 10 |
(m->ltaxis[MASTER] & 0xF) << 14 |
(m->ltaxis[STACK] & 0xF) << 18 |
(m->ltaxis[STACK2] & 0xF) << 22 |
(m->ltaxis[LAYOUT] < 0 ? 1 : 0) << 24;
}
#endif // FLEXTILE_DELUXE_L1AYOUT
uint32_t data[] = {
#if FLEXTILE_DELUXE_LAYOUT
flextile_deluxe_bitmask |
#endif // FLEXTILE_DELUXE_LAYOUT
(m->nmaster & 0x7) |
(getlayoutindex(m->lt[m->sellt]) & 0xF) << 6 |
m->showbar << 31
};
XChangeProperty(dpy, root, monitor_fields, XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)data, 1);
#endif // PERTAG_PATCH
}
int
getlayoutindex(const Layout *layout)
{
int i;
for (i = 0; i < LENGTH(layouts) && &layouts[i] != layout; i++);
if (i == LENGTH(layouts))
i = 0;
return i;
}
int
getmonitorfields(Monitor *m)
{
int di, layout_index;
#if PERTAG_PATCH
unsigned int i, restored = 0;
unsigned int tags = m->tagset[m->seltags] << 1;
#endif // PERTAG_PATCH
unsigned long dl, nitems;
unsigned char *p = NULL;
char atom[22] = {0};
Atom da, state = None;
sprintf(atom, "_DWM_MONITOR_FIELDS_%u", m->num);
Atom dwm_monitor = XInternAtom(dpy, atom, False);
if (!dwm_monitor)
return 0;
#if PERTAG_PATCH
for (i = 0; i <= NUMTAGS; i++) {
if (!(XGetWindowProperty(dpy, root, dwm_monitor, i, (NUMTAGS + 1) * sizeof dl,
False, AnyPropertyType, &da, &di, &nitems, &dl, &p) == Success && p)) {
break;
}
if (!nitems) {
XFree(p);
break;
}
/* See bit layout in the persistmonitorstate function */
state = *(Atom *)p;
m->pertag->nmasters[i] = state & 0x7;
layout_index = (state >> 6) & 0xF;
if (layout_index < LENGTH(layouts))
m->pertag->ltidxs[i][m->pertag->sellts[i]] = &layouts[layout_index];
#if FLEXTILE_DELUXE_LAYOUT
m->pertag->nstacks[i] = (state >> 3) & 0x7;
if (m->pertag->ltidxs[i][m->pertag->sellts[i]]->arrange == flextile) {
m->pertag->ltaxis[i][LAYOUT] = (state >> 10) & 0xF;
m->pertag->ltaxis[i][MASTER] = (state >> 14) & 0xF;
m->pertag->ltaxis[i][STACK] = (state >> 18) & 0xF;
m->pertag->ltaxis[i][STACK2] = (state >> 22) & 0xF;
if (state >> 24 & 0x1) {
m->pertag->ltaxis[i][LAYOUT] *= -1;
}
}
#endif // FLEXTILE_DELUXE_LAYOUT
#if PERTAGBAR_PATCH
m->pertag->showbars[i] = (state >> 31) & 0x1;
#endif // PERTAGBAR_PATCH
if (!restored && i && (tags & (1 << i))) {
m->nmaster = m->pertag->nmasters[i];
m->sellt = m->pertag->sellts[i];
m->lt[m->sellt] = m->pertag->ltidxs[i][m->sellt];
#if FLEXTILE_DELUXE_LAYOUT
m->nstack = m->pertag->nstacks[i];
if (m->lt[m->sellt]->arrange == flextile) {
m->ltaxis[LAYOUT] = m->pertag->ltaxis[i][LAYOUT];
m->ltaxis[MASTER] = m->pertag->ltaxis[i][MASTER];
m->ltaxis[STACK] = m->pertag->ltaxis[i][STACK];
m->ltaxis[STACK2] = m->pertag->ltaxis[i][STACK2];
}
#endif // FLEXTILE_DELUXE_LAYOUT
#if PERTAGBAR_PATCH
m->showbar = m->pertag->showbars[i];
#else
m->showbar = (state >> 31) & 0x1;
#endif // PERTAGBAR_PATCH
restored = 1;
}
XFree(p);
}
return restored;
#else // !PERTAG_PATCH
if (!(XGetWindowProperty(dpy, root, dwm_monitor, 0L, sizeof dl,
False, AnyPropertyType, &da, &di, &nitems, &dl, &p) == Success && p)) {
return 0;
}
if (nitems) {
state = *(Atom *)p;
/* See bit layout in the persistmonitorstate function */
m->nmaster = state & 0x7;
#if FLEXTILE_DELUXE_LAYOUT
m->nstack = (state >> 3) & 0x7;
#endif // FLEXTILE_DELUXE_LAYOUT
layout_index = (state >> 6) & 0xF;
if (layout_index < LENGTH(layouts))
m->lt[m->sellt] = &layouts[layout_index];
#if FLEXTILE_DELUXE_LAYOUT
if (m->lt[m->sellt]->arrange == flextile) {
m->ltaxis[LAYOUT] = (state >> 10) & 0xF;
m->ltaxis[MASTER] = (state >> 14) & 0xF;
m->ltaxis[STACK] = (state >> 18) & 0xF;
m->ltaxis[STACK2] = (state >> 22) & 0xF;
}
#endif // FLEXTILE_DELUXE_LAYOUT
m->showbar = (state >> 31) & 0x1;
}
XFree(p);
return 1;
#endif // PERTAG_PATCH
}
void
setmonitortags(Monitor *m)
{
char atom[22] = {0};
Atom monitor_tags;
sprintf(atom, "_DWM_MONITOR_TAGS_%u", m->num);
monitor_tags = XInternAtom(dpy, atom, False);
uint32_t data[] = { m->tagset[m->seltags] };
XChangeProperty(dpy, root, monitor_tags, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
}
int
getmonitortags(Monitor *m)
{
int di;
unsigned long dl, nitems;
unsigned char *p = NULL;
char atom[22] = {0};
Atom da, monitor_tags = None, tags;
sprintf(atom, "_DWM_MONITOR_TAGS_%u", m->num);
monitor_tags = XInternAtom(dpy, atom, False);
if (!(XGetWindowProperty(dpy, root, monitor_tags, 0L, sizeof dl,
False, AnyPropertyType, &da, &di, &nitems, &dl, &p) == Success && p)) {
return 0;
}
if (nitems) {
tags = *(Atom *)p;
m->tagset[m->seltags] = tags & TAGMASK;
}
XFree(p);
return 1;
}
void
setclientfields(Client *c)
{
/* Perists client information in 32 bits laid out like this:
*
* |00000000|00000|0|0|0|0|0|0|0|0|00000000|000
* | | | | | | | | | | | |-- monitor index
* | | | | | | | | | | |-- client index
* | | | | | | | | | |-- isfloating
* | | | | | | | | |-- ispermanent
* | | | | | | | |-- isterminal
* | | | | | | |-- noswallow
* | | | | | |-- issteam
* | | | | |-- issticky
* | | | |-- fakefullscreen
* | | |-- isfreesize
* | |
* | |-- reserved
* |-- scratchkey (for scratchpads)
*/
uint32_t data[] = {
(c->mon->num & 0x7)
| (c->idx & 0xFF) << 3
| (c->isfloating & 0x1) << 11
#if ISPERMANENT_PATCH
| (c->ispermanent & 0x1) << 12
#endif // ISPERMANENT_PATCH
#if SWALLOW_PATCH
| (c->isterminal & 0x1) << 13
| (c->noswallow & 0x1) << 14
#endif // SWALLOW_PATCH
#if STEAM_PATCH
| (c->issteam & 0x1) << 15
#endif // STEAM_PATCH
#if STICKY_PATCH
| (c->issticky & 0x1) << 16
#endif // STICKY_PATCH
#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
| (c->fakefullscreen & 0x1) << 17
#endif // FAKEFULLSCREEN_CLIENT_PATCH
#if SIZEHINTS_ISFREESIZE_PATCH
| (c->isfreesize & 0x1) << 18
#endif // SIZEHINTS_ISFREESIZE_PATCH
#if RENAMED_SCRATCHPADS_PATCH
| (c->scratchkey & 0xFF) << 24
#endif // RENAMED_SCRATCHPADS_PATCH
};
XChangeProperty(dpy, c->win, clientatom[ClientFields], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
}
int
getclientfields(Client *c)
{
Monitor *m;
Atom fields = getatomprop(c, clientatom[ClientFields], AnyPropertyType);
if (fields == None)
return 0;
/* See bit layout in the setclientfields function */
for (m = mons; m; m = m->next)
if (m->num == (fields & 0x7)) {
c->mon = m;
break;
}
c->idx = (fields >> 3) & 0xFF;
c->isfloating = (fields >> 11) & 0x1;
#if ISPERMANENT_PATCH
c->ispermanent = (fields >> 12) & 0x1;
#endif // ISPERMANENT_PATCH
#if SWALLOW_PATCH
c->isterminal = (fields >> 13) & 0x1;
c->noswallow = (fields >> 14) & 0x1;
#endif // SWALLOW_PATCH
#if STEAM_PATCH
c->issteam = (fields >> 15) & 0x1;
#endif // STEAM_PATCH
#if STICKY_PATCH
c->issticky = (fields >> 16) & 0x1;
#endif // STICKY_PATCH
#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
c->fakefullscreen = (fields >> 17) & 0x1;
#endif // FAKEFULLSCREEN_CLIENT_PATCH
#if SIZEHINTS_ISFREESIZE_PATCH
c->isfreesize = (fields >> 18) & 0x1;
#endif // SIZEHINTS_ISFREESIZE_PATCH
#if RENAMED_SCRATCHPADS_PATCH
c->scratchkey = (fields >> 24) & 0xFF;
#endif // RENAMED_SCRATCHPADS_PATCH
return 1;
}
void
setclienttags(Client *c)
{
uint32_t data[] = { c->tags };
XChangeProperty(dpy, c->win, clientatom[ClientTags], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
}
int
getclienttags(Client *c)
{
Atom tags = getatomprop(c, clientatom[ClientTags], AnyPropertyType);
if (tags == None)
return 0;
c->tags = tags & TAGMASK;
return 1;
}
#if SAVEFLOATS_PATCH
void
savewindowfloatposition(Client *c, Monitor *m)
{
char atom[22] = {0};
if (c->sfx == -9999)
return;
sprintf(atom, "_DWM_FLOATPOS_%u", m->num);
uint32_t pos[] = { (MAX(c->sfx - m->mx, 0) & 0xffff) | ((MAX(c->sfy - m->my, 0) & 0xffff) << 16) };
XChangeProperty(dpy, c->win, XInternAtom(dpy, atom, False), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pos, 1);
sprintf(atom, "_DWM_FLOATSIZE_%u", m->num);
uint32_t size[] = { (c->sfw & 0xffff) | ((c->sfh & 0xffff) << 16) };
XChangeProperty(dpy, c->win, XInternAtom(dpy, atom, False), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)size, 1);
XSync(dpy, False);
}
int
restorewindowfloatposition(Client *c, Monitor *m)
{
char atom[22] = {0};
Atom key, value;
int x, y, w, h;
if (m == NULL)
return 0;
sprintf(atom, "_DWM_FLOATPOS_%u", m->num);
key = XInternAtom(dpy, atom, False);
if (!key)
return 0;
value = getatomprop(c, key, AnyPropertyType);
if (!value)
return 0;
x = value & 0xffff;
y = value >> 16;
sprintf(atom, "_DWM_FLOATSIZE_%u", m->num);
key = XInternAtom(dpy, atom, False);
if (!key)
return 0;
value = getatomprop(c, key, AnyPropertyType);
if (!value)
return 0;
w = value & 0xffff;
h = value >> 16;
if (w <= 0 || h <= 0) {
fprintf(stderr, "restorewindowfloatposition: bad float values x = %d, y = %d, w = %d, h = %d for client = %s\n", x, y, w, h, c->name);
return 0;
}
c->sfx = m->mx + x;
c->sfy = m->my + y;
c->sfw = w;
c->sfh = h;
return 1;
}
#endif // SAVEFLOATS_PATCH

19
patch/seamless_restart.h Normal file
View File

@ -0,0 +1,19 @@
#include <stdint.h>
static void persistmonitorstate(Monitor *m);
static int restoremonitorstate(Monitor *m);
static void persistclientstate(Client *c);
static int restoreclientstate(Client *c);
static void setmonitorfields(Monitor *m);
static int getmonitorfields(Monitor *m);
static void setmonitortags(Monitor *m);
static int getmonitortags(Monitor *m);
static void setclientfields(Client *c);
static int getclientfields(Client *c);
static void setclienttags(Client *c);
static int getclienttags(Client *c);
static int getlayoutindex(const Layout *layout);
#if SAVEFLOATS_PATCH
static void savewindowfloatposition(Client *c, Monitor *m);
static int restorewindowfloatposition(Client *c, Monitor *m);
#endif // SAVEFLOATS_PATCH

View File

@ -13,7 +13,7 @@ checkfloatingrules(Client *c)
XGetClassHint(dpy, c->win, &ch);
class = ch.res_class ? ch.res_class : broken;
instance = ch.res_name ? ch.res_name : broken;
wintype = getatomprop(c, netatom[NetWMWindowType]);
wintype = getatomprop(c, netatom[NetWMWindowType], XA_ATOM);
#if WINDOWROLERULE_PATCH
gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role));
#endif // WINDOWROLERULE_PATCH

View File

@ -253,6 +253,8 @@
#define SCRATCHPAD_ALT_1_PATCH 0
#define SEAMLESS_RESTART_PATCH 0
#define SELECTIVEFAKEFULLSCREEN_PATCH 0
#define SELFRESTART_PATCH 0