ref: 3b85c767fec3d7c9852f2e86afc89554bfabd02d
parent: 76ddc13f7d22c5ba35c56b9073ec0ca4c85446f0
author: mischief <mischief@offblast.org>
date: Mon Nov 9 05:30:08 EST 2020
gui-x11: handle WM_DELETE_WINDOW messages previously drawterm did not handle the ICCCM[1] protocol for graceful window closure. most if not all window managers will send this message, but it is implemented inconsistently. some will forcibly terminate the X11 client's connection if it doesn't handle it, and others will just give up. some prompt for forcible termination. in any case, now we handle it. to make this change work, we also setup the X11 window in the xkmcon connection, because otherwise it seems not possible to receive the ClientMessage in our event handler. without this the event would instead be sent to the xdisplay connection, which we did not monitor for events. [1] https://www.x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#window_deletion
--- a/gui-x11/x11.c
+++ b/gui-x11/x11.c
@@ -120,6 +120,7 @@
static Atom text;
static Atom compoundtext;
static Atom wmpid;
+static Atom wmdelete;
static Drawable xdrawable;
static void xexpose(XEvent*);
@@ -319,11 +320,11 @@
attrs.background_pixel = 0;
attrs.border_pixel = 0;
/* attrs.override_redirect = 1;*/ /* WM leave me alone! |CWOverrideRedirect */
- xdrawable = XCreateWindow(xdisplay, rootwin, x, y, Dx(r), Dy(r), 0,
+ xdrawable = XCreateWindow(xkmcon, rootwin, x, y, Dx(r), Dy(r), 0,
xscreendepth, InputOutput, xvis, CWBackPixel|CWBorderPixel|CWColormap, &attrs);
/* load the given bitmap data and create an X pixmap containing it. */
- icon_pixmap = XCreateBitmapFromData(xdisplay,
+ icon_pixmap = XCreateBitmapFromData(xkmcon,
rootwin, (char *)glenda_t_bits,
glenda_t_width, glenda_t_height);
@@ -348,7 +349,7 @@
classhints.res_class = "Drawterm";
argv[0] = "drawterm";
argv[1] = nil;
- XSetWMProperties(xdisplay, xdrawable,
+ XSetWMProperties(xkmcon, xdrawable,
&name, /* XA_WM_NAME property for ICCCM */
&name, /* XA_WM_ICON_NAME */
argv, /* XA_WM_COMMAND */
@@ -356,10 +357,10 @@
&normalhints, /* XA_WM_NORMAL_HINTS */
&hints, /* XA_WM_HINTS */
&classhints); /* XA_WM_CLASS */
- XFlush(xdisplay);
+ XFlush(xkmcon);
if ((wmpid = XInternAtom(xdisplay, "_NET_WM_PID", False)) != None) {
pid = (unsigned long) getpid();
- XChangeProperty(xdisplay, xdrawable,
+ XChangeProperty(xkmcon, xdrawable,
wmpid, /* Atom property */
XA_CARDINAL, /* Atom type */
32, /* int format, 32 really is "long" */
@@ -366,14 +367,16 @@
PropModeReplace, /* int mode */
(uchar *)&pid, /* unsigned char * data */
1); /* int nelements */
- XFlush(xdisplay);
+ XFlush(xkmcon);
}
/*
* put the window on the screen
*/
- XMapWindow(xdisplay, xdrawable);
- XFlush(xdisplay);
+ wmdelete = XInternAtom(xkmcon, "WM_DELETE_WINDOW", True);
+ XSetWMProtocols(xkmcon, xdrawable, &wmdelete, 1);
+ XMapWindow(xkmcon, xdrawable);
+ XFlush(xkmcon);
screensize(r, xscreenchan);
if(gscreen == nil)
@@ -541,7 +544,6 @@
XSelectInput(xkmcon, xdrawable, mask);
for(;;) {
- //XWindowEvent(xkmcon, xdrawable, mask, &event);
XNextEvent(xkmcon, &event);
xselect(&event, xkmcon);
xkeyboard(&event);
@@ -695,11 +697,19 @@
xdestroy(XEvent *e)
{
XDestroyWindowEvent *xe;
- if(e->type != DestroyNotify)
- return;
- xe = (XDestroyWindowEvent*)e;
- if(xe->window == xdrawable)
- exit(0);
+ XClientMessageEvent *ce;
+
+ switch(e->type){
+ case ClientMessage:
+ /* Handle WM_DELETE_WINDOW */
+ ce = (XClientMessageEvent*)e;
+ if(ce->window == xdrawable && ce->data.l[0] == wmdelete)
+ exit(0);
+ case DestroyNotify:
+ xe = (XDestroyWindowEvent*)e;
+ if(xe->window == xdrawable)
+ exit(0);
+ }
}
static void