commit c2c4fca49a16ab20986e905d793aa484ca662abf
parent d7f33aef63cf88d367107f4aa49bde8606507c7d
Author: Lucas de Sena <lucas@seninha.org>
Date: Fri, 7 Apr 2023 18:35:18 -0300
implement shodc exit; fix #38
Diffstat:
8 files changed, 72 insertions(+), 68 deletions(-)
diff --git a/shod.1 b/shod.1
@@ -19,6 +19,8 @@
.Nm shodc
.Cm desk
.Nm shodc
+.Cm exit
+.Nm shodc
.Cm focus
.Op Fl clrtbpnLRTBPN
.Op Ar win_id
@@ -167,6 +169,12 @@ operation lists the desktops, one per line.
If the line begins with an asterisk, the desktop is the focused one;
If the line begins with an hyphen, the desktop has an urgent window in it.
The number is the number of windows in the desktop.
+.Ss Exit shod
+The
+.Cm exit
+operation exits the
+.Nm shod
+window manager.
.Ss Focus window
The
.Cm focus
diff --git a/shod.c b/shod.c
@@ -19,7 +19,6 @@
| PropertyChangeMask)
static int (*xerrorxlib)(Display *, XErrorEvent *);
-volatile sig_atomic_t running = 1;
/* shared variables */
unsigned long clientmask = CWEventMask | CWColormap | CWBackPixel | CWBorderPixel;
@@ -28,7 +27,7 @@ XSetWindowAttributes clientswa = {
| SubstructureRedirectMask | ButtonPressMask | FocusChangeMask
| Button1MotionMask
};
-struct WM wm = {};
+struct WM wm = { .running = 1 };
struct Dock dock;
/* show usage and exit */
@@ -96,7 +95,7 @@ xerror(Display *dpy, XErrorEvent *e)
exit(1); /* unreached */
}
-/* startup error handler to check if another window manager is already running. */
+/* startup error handler to check if another window manager is already running */
static int
xerrorstart(Display *dpy, XErrorEvent *e)
{
@@ -105,14 +104,6 @@ xerrorstart(Display *dpy, XErrorEvent *e)
errx(1, "another window manager is already running");
}
-/* stop running */
-static void
-siginthandler(int signo)
-{
- (void)signo;
- running = 0;
-}
-
/* read command-line options */
static char *
getoptions(int argc, char *argv[])
@@ -170,13 +161,6 @@ initsignal(void)
err(1, "sigaction");
while (waitpid(-1, NULL, WNOHANG) != -1)
;
-
- /* set running to 0 */
- sa.sa_handler = siginthandler;
- sa.sa_flags = 0;
- sigemptyset(&sa.sa_mask);
- if (sigaction(SIGINT, &sa, NULL) == -1)
- err(1, "sigaction");
}
/* initialize cursors */
@@ -241,7 +225,7 @@ initdummywindows(void)
}
swa = clientswa;
swa.event_mask |= KeyPressMask;
- wm.wmcheckwin = XCreateWindow(
+ wm.checkwin = wm.focuswin = wm.dragwin = wm.restackwin = XCreateWindow(
dpy, root,
- (2 * config.borderwidth + config.titlewidth),
- (2 * config.borderwidth + config.titlewidth),
@@ -251,20 +235,14 @@ initdummywindows(void)
clientmask,
&swa
);
- wm.wmcheckpix = XCreatePixmap(
- dpy, wm.wmcheckwin,
- 2 * config.borderwidth + config.titlewidth,
- 2 * config.borderwidth + config.titlewidth,
- depth
- );
}
/* map and hide dummy windows */
static void
mapdummywins(void)
{
- XMapWindow(dpy, wm.wmcheckwin);
- XSetInputFocus(dpy, wm.wmcheckwin, RevertToParent, CurrentTime);
+ XMapWindow(dpy, wm.focuswin);
+ XSetInputFocus(dpy, wm.focuswin, RevertToParent, CurrentTime);
}
/* run stdin on sh */
@@ -299,8 +277,7 @@ cleandummywindows(void)
{
int i;
- XFreePixmap(dpy, wm.wmcheckpix);
- XDestroyWindow(dpy, wm.wmcheckwin);
+ XDestroyWindow(dpy, wm.checkwin);
for (i = 0; i < LAYER_LAST; i++) {
XDestroyWindow(dpy, wm.layers[i].frame);
}
@@ -389,8 +366,8 @@ main(int argc, char *argv[])
initatoms();
initroot();
initdummywindows();
- inittheme();
initdock();
+ inittheme();
/* set up list of monitors */
monupdate();
@@ -414,12 +391,14 @@ main(int argc, char *argv[])
setmod();
/* run main event loop */
- while (running && !XNextEvent(dpy, &ev)) {
+ while (!XNextEvent(dpy, &ev)) {
wm.setclientlist = 0;
if (wm.xrandr && ev.type - wm.xrandrev == RRScreenChangeNotify)
monevent(&ev);
else if (ev.type < LASTEvent && xevents[ev.type] != NULL)
(*xevents[ev.type])(&ev);
+ if (!wm.running)
+ break;
if (wm.setclientlist) {
ewmhsetclients();
}
@@ -428,8 +407,8 @@ main(int argc, char *argv[])
/* clean up */
cleandummywindows();
cleancursors();
- cleantheme();
cleanwm();
+ cleantheme();
/* clear ewmh hints */
ewmhsetclients();
diff --git a/shod.h b/shod.h
@@ -526,6 +526,8 @@ struct Notification {
};
struct WM {
+ int running;
+
/*
* The window manager maintains a list of monitors and several
* window-holding entities such as containers and bars.
@@ -570,20 +572,12 @@ struct WM {
struct Monitor *selmon; /* pointer to selected monitor */
/*
- * Shod uses a dummy window called wmcheckwin for multiple
- * purposes:
- * - It is necessary to implement EWMH's _NET_SUPPORTING_WM_CHECK property.
- * - It is hidden out of the screen and gets the focus when no
- * window has the keyboard focus.
- * - When the user reorder the tiles in a container by dragging a
- * title bar with the right mouse button, this window follows
- * the mouse pointer to indicate that dragging is in action.
- *
- * We first draw into the `wmcheckpix` pixmap and then copy its
- * contents into the `wmcheckwin` when the window is damaged.
+ * Dummy windows
*/
- Window wmcheckwin; /* dummy window required by EWMH */
- Pixmap wmcheckpix;
+ Window checkwin; /* carries _NET_SUPPORTING_WM_CHECK */
+ Window focuswin; /* gets focus when no container is visible */
+ Window dragwin; /* follows mouse while dragging */
+ Window restackwin; /* reordered in Z axis to save a position */
Cursor cursors[CURSOR_LAST]; /* cursors for the mouse pointer */
int showingdesk; /* whether the desktop is being shown */
diff --git a/shodc.c b/shodc.c
@@ -55,6 +55,7 @@ usage(void)
(void)fprintf(stderr, "usage: shodc close [WIN_ID]\n");
(void)fprintf(stderr, " shodc cycle [-s]\n");
(void)fprintf(stderr, " shodc desks\n");
+ (void)fprintf(stderr, " shodc exit\n");
(void)fprintf(stderr, " shodc focus [-clrtbpnLRTBPN] [WIN_ID]\n");
(void)fprintf(stderr, " shodc geom [-X|-x N] [-Y|-y N] [-W|-w N] [-H|-h N] [WIN_ID]\n");
(void)fprintf(stderr, " shodc goto [-m MON_ID] DESK_ID\n");
@@ -610,6 +611,20 @@ cycle(int argc, char *argv[])
clientmsg(None, atoms[_SHOD_CYCLE], shift, 0, 0, 0, 0);
}
+/* exit shod */
+static void
+exitshod(int argc, char *argv[])
+{
+ Window checkwin;
+
+ (void)argc;
+ (void)argv;
+ checkwin = getwinprop(root, atoms[_NET_SUPPORTING_WM_CHECK]);
+ if (checkwin != None) {
+ XDestroyWindow(dpy, checkwin);
+ }
+}
+
/* shodc: remote controller for shod */
int
main(int argc, char *argv[])
@@ -638,9 +653,10 @@ main(int argc, char *argv[])
state(argc - 1, argv + 1);
else if (strcmp(argv[1], "cycle") == 0)
cycle(argc - 1, argv + 1);
+ else if (strcmp(argv[1], "exit") == 0)
+ exitshod(argc - 1, argv + 1);
else
usage();
-
XCloseDisplay(dpy);
return 0;
}
diff --git a/xcontainer.c b/xcontainer.c
@@ -1611,9 +1611,9 @@ containerraisetemp(struct Container *prevc, int backward)
newc = prevc;
if (newc->ishidden)
XMapWindow(dpy, newc->frame);
- /* we save the Z-axis position of the container with wm.wmcheckwin */
+ /* we save the Z-axis position of the container with wm.restackwin */
wins[0] = newc->frame;
- wins[1] = wm.wmcheckwin;
+ wins[1] = wm.restackwin;
XRestackWindows(dpy, wins, 2);
XRaiseWindow(dpy, newc->frame);
wm.focused = newc;
@@ -1633,7 +1633,7 @@ containerbacktoplace(struct Container *c, int restack)
wm.focused = NULL;
containerdecorate(c, NULL, NULL, 1, 0);
if (restack) {
- wins[0] = wm.wmcheckwin;
+ wins[0] = wm.restackwin;
wins[1] = c->frame;
XRestackWindows(dpy, wins, 2);
}
@@ -1675,7 +1675,7 @@ tabfocus(struct Tab *tab, int gotodesk)
tabhidemenus(wm.prevfocused->selcol->selrow->seltab, ADD);
if (tab == NULL) {
wm.focused = NULL;
- XSetInputFocus(dpy, wm.wmcheckwin, RevertToParent, CurrentTime);
+ XSetInputFocus(dpy, wm.focuswin, RevertToParent, CurrentTime);
ewmhsetactivewindow(None);
} else {
c = tab->row->col->c;
diff --git a/xdraw.c b/xdraw.c
@@ -98,12 +98,6 @@ getexposed(Window win, Pixmap *pix, int *pw, int *ph)
}
}
}
- if (wm.wmcheckwin == win) {
- *pix = wm.wmcheckpix;
- *pw = 2 * config.borderwidth + config.titlewidth;
- *ph = 2 * config.borderwidth + config.titlewidth;
- return 1;
- }
if (dock.win == win) {
*pix = dock.pix;
*pw = dock.w;
@@ -717,9 +711,17 @@ copypixmap(Window win)
void
inittheme(void)
{
+ Pixmap pix;
int i, j;
- gc = XCreateGC(dpy, wm.wmcheckwin, GCFillStyle, &(XGCValues){.fill_style = FillSolid});
+ pix = XCreatePixmap(
+ dpy,
+ wm.dragwin,
+ 2 * config.borderwidth + config.titlewidth,
+ 2 * config.borderwidth + config.titlewidth,
+ depth
+ );
+ gc = XCreateGC(dpy, wm.dragwin, GCFillStyle, &(XGCValues){.fill_style = FillSolid});
config.corner = config.borderwidth + config.titlewidth;
config.divwidth = config.borderwidth;
wm.minsize = config.corner * 2 + 10;
@@ -740,20 +742,20 @@ inittheme(void)
}
}
drawbackground(
- wm.wmcheckpix,
+ pix,
0, 0,
2 * config.borderwidth + config.titlewidth,
2 * config.borderwidth + config.titlewidth,
FOCUSED
);
drawborders(
- wm.wmcheckpix,
+ pix,
2 * config.borderwidth + config.titlewidth,
2 * config.borderwidth + config.titlewidth,
FOCUSED
);
drawshadow(
- wm.wmcheckpix,
+ pix,
config.borderwidth,
config.borderwidth,
config.titlewidth,
@@ -761,6 +763,9 @@ inittheme(void)
FOCUSED,
0
);
+ XSetWindowBackgroundPixmap(dpy, wm.dragwin, pix);
+ XClearWindow(dpy, wm.dragwin);
+ XFreePixmap(dpy, pix);
}
/* free font */
diff --git a/xevents.c b/xevents.c
@@ -802,11 +802,11 @@ mouseretab(struct Tab *tab, int xroot, int yroot, int x, int y)
containermoveresize(c, 0);
XUnmapWindow(dpy, tab->title);
XMoveWindow(
- dpy, wm.wmcheckwin,
+ dpy, wm.dragwin,
ev.xmotion.x_root - DNDDIFF - (2 * config.borderwidth + config.titlewidth),
ev.xmotion.y_root - DNDDIFF - (2 * config.borderwidth + config.titlewidth)
);
- XRaiseWindow(dpy, wm.wmcheckwin);
+ XRaiseWindow(dpy, wm.dragwin);
while (!XMaskEvent(dpy, MOUSEEVENTMASK, &ev)) {
switch (ev.type) {
case Expose:
@@ -815,7 +815,7 @@ mouseretab(struct Tab *tab, int xroot, int yroot, int x, int y)
break;
case MotionNotify:
XMoveWindow(
- dpy, wm.wmcheckwin,
+ dpy, wm.dragwin,
ev.xmotion.x_root - DNDDIFF - (2 * config.borderwidth + config.titlewidth),
ev.xmotion.y_root - DNDDIFF - (2 * config.borderwidth + config.titlewidth)
);
@@ -826,7 +826,7 @@ mouseretab(struct Tab *tab, int xroot, int yroot, int x, int y)
}
done:
XMoveWindow(
- dpy, wm.wmcheckwin,
+ dpy, wm.dragwin,
- (2 * config.borderwidth + config.titlewidth),
- (2 * config.borderwidth + config.titlewidth)
);
@@ -1621,6 +1621,8 @@ xeventdestroynotify(XEvent *e)
if (obj->win == ev->window && (*unmanagefuncs[obj->type])(obj, 0)) {
wm.setclientlist = 1;
}
+ } else if (ev->window == wm.checkwin) {
+ wm.running = 0;
}
}
@@ -1704,7 +1706,7 @@ xeventkeypress(XEvent *e)
if (!config.disablealttab && ev->keycode == config.tabkeycode) {
alttab(ev->state & ShiftMask);
}
- if (ev->window == wm.wmcheckwin) {
+ if (ev->window == wm.checkwin) {
e->xkey.window = root;
XSendEvent(dpy, root, False, KeyPressMask, e);
}
diff --git a/xhints.c b/xhints.c
@@ -57,9 +57,9 @@ void
ewmhinit(const char *wmname)
{
/* set window and property that indicates that the wm is ewmh compliant */
- XChangeProperty(dpy, wm.wmcheckwin, atoms[_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wm.wmcheckwin, 1);
- XChangeProperty(dpy, wm.wmcheckwin, atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8, PropModeReplace, (unsigned char *)wmname, strlen(wmname));
- XChangeProperty(dpy, root, atoms[_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wm.wmcheckwin, 1);
+ XChangeProperty(dpy, wm.checkwin, atoms[_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wm.checkwin, 1);
+ XChangeProperty(dpy, wm.checkwin, atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8, PropModeReplace, (unsigned char *)wmname, strlen(wmname));
+ XChangeProperty(dpy, root, atoms[_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wm.checkwin, 1);
/* set properties that the window manager supports */
XChangeProperty(dpy, root, atoms[_NET_SUPPORTED], XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, ATOM_LAST);