shod

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Mshod.1 | 8++++++++
Mshod.c | 43+++++++++++--------------------------------
Mshod.h | 20+++++++-------------
Mshodc.c | 18+++++++++++++++++-
Mxcontainer.c | 8++++----
Mxdraw.c | 25+++++++++++++++----------
Mxevents.c | 12+++++++-----
Mxhints.c | 6+++---
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);