From: Michael D. Lowis Date: Thu, 22 Dec 2016 18:19:37 +0000 (-0500) Subject: Implemented a fix for window managers being able to kill the editor with no warning X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=bc3cad57e810b8964396cdd0d90b1e924abbae0f;p=projs%2Ftide.git Implemented a fix for window managers being able to kill the editor with no warning --- diff --git a/TODO.md b/TODO.md index 7a7c9a7..37149b6 100644 --- a/TODO.md +++ b/TODO.md @@ -14,7 +14,6 @@ Up Next: The Rest: * Auto-save on focus change or quit -* Implement EWMH hooks to prevent window manager killing client with modifications * Implement X Selection protocol for handling clipboard and primary selections * add a distinct state for pointer move versus drag * Add a SaveAs tag that takes an argument for the filename to save as diff --git a/inc/x11.h b/inc/x11.h index b5fda7e..7563f54 100644 --- a/inc/x11.h +++ b/inc/x11.h @@ -18,6 +18,7 @@ typedef struct { void (*redraw)(int width, int height); void (*handle_key)(int mods, uint32_t rune); void (*handle_mouse)(MouseAct act, MouseBtn btn, int x, int y); + void (*shutdown)(void); uint32_t palette[16]; } XConfig; diff --git a/libx/x11.c b/libx/x11.c index 1232adb..26d25a1 100644 --- a/libx/x11.c +++ b/libx/x11.c @@ -99,6 +99,12 @@ void x11_window(char* name, int width, int height) { X.height, 0, X.depth, Config->palette[0]); + + /* register interest in the delete window message */ + Atom wmDeleteMessage = XInternAtom(X.display, "WM_DELETE_WINDOW", False); + XSetWMProtocols(X.display, X.window, &wmDeleteMessage, 1); + + /* setup window attributes and events */ XSetWindowAttributes swa; swa.backing_store = WhenMapped; swa.bit_gravity = NorthWestGravity; @@ -113,12 +119,15 @@ void x11_window(char* name, int width, int height) { | KeyPressMask | ExposureMask | FocusChangeMask); + /* set input methods */ if ((X.xim = XOpenIM(X.display, 0, 0, 0))) X.xic = XCreateIC(X.xim, XNInputStyle, XIMPreeditNothing|XIMStatusNothing, XNClientWindow, X.window, XNFocusWindow, X.window, NULL); + /* initialize pixmap and drawing context */ X.pixmap = XCreatePixmap(X.display, X.window, width, height, X.depth); X.xft = XftDrawCreate(X.display, X.pixmap, X.visual, X.colormap); + /* initialize the graphics context */ XGCValues gcv; gcv.foreground = WhitePixel(X.display, X.screen); @@ -262,7 +271,7 @@ void x11_loop(void) { XPeekEvent(X.display,&e); while (XPending(X.display)) { XNextEvent(X.display, &e); - if (!XFilterEvent(&e, None)) + if (!XFilterEvent(&e, None)) { switch (e.type) { case FocusIn: if (X.xic) XSetICFocus(X.xic); break; case FocusOut: if (X.xic) XUnsetICFocus(X.xic); break; @@ -270,6 +279,12 @@ void x11_loop(void) { case ButtonRelease: handle_mouse(&e); break; case ButtonPress: handle_mouse(&e); break; case MotionNotify: handle_mouse(&e); break; + case ClientMessage: { + Atom wmDeleteMessage = XInternAtom(X.display, "WM_DELETE_WINDOW", False); + if (e.xclient.data.l[0] == wmDeleteMessage) + Config->shutdown(); + } + break; case ConfigureNotify: // Resize the window if (e.xconfigure.width != X.width || e.xconfigure.height != X.height) { X.width = e.xconfigure.width; @@ -279,6 +294,7 @@ void x11_loop(void) { } break; } + } } if (Running) { /* redraw the window */ diff --git a/tests/xedit.c b/tests/xedit.c index 5c203cf..c4d76d3 100644 --- a/tests/xedit.c +++ b/tests/xedit.c @@ -66,6 +66,10 @@ static void redraw(int width, int height) { /* do nothing for unit testing */ } +void x11_deinit(void) { + mockexit(0); +} + /* Unit Tests *****************************************************************************/ TEST_SUITE(XeditTests) { diff --git a/xedit.c b/xedit.c index 3eea775..3cda95a 100644 --- a/xedit.c +++ b/xedit.c @@ -98,6 +98,7 @@ static XConfig Config = { .redraw = redraw, .handle_key = key_handler, .handle_mouse = mouse_handler, + .shutdown = quit, .palette = COLOR_PALETTE }; @@ -485,7 +486,7 @@ static void quit(void) { static uint64_t before = 0; uint64_t now = getmillis(); if (!getbuf(EDIT)->modified || (now-before) <= 250) { - exit(0); + x11_deinit(); } else { view_append(getview(TAGS), "File is modified. Repeat action twice in < 250ms to quit.");