From 53915f4a7090d26345c9a0db99ed0e49b19fdb5b Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Sun, 19 Apr 2015 03:11:33 +0000 Subject: [PATCH] Shutdown gracefully - Add a client message that's sent from sys_exit so that we don't kill the connection before existing - This also sets up the EWMH control window --- sys-xcb.c | 86 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/sys-xcb.c b/sys-xcb.c index b1176a8..1da2f66 100644 --- a/sys-xcb.c +++ b/sys-xcb.c @@ -70,6 +70,8 @@ static list_t *screens; static void *cache; static xcb_pixmap_t colors[NCOLORS]; static unsigned int grabbed; +static int running; +static xcb_window_t control; static xcb_atom_t wm_protos; static xcb_atom_t wm_delete; @@ -731,6 +733,15 @@ static void on_configure_request(xcb_configure_request_event_t *event) (const char *)&resp); } +static void on_client_message(xcb_client_message_event_t *event) +{ + printf("on_client_message: xcb=%-8u\n", event->window); + if (event->window == control && + event->type == wm_protos && + event->data.data32[0] == wm_delete) + running = 0; +} + /* Generic Event */ static void on_event(xcb_generic_event_t *event) { @@ -785,6 +796,9 @@ static void on_event(xcb_generic_event_t *event) case XCB_CONFIGURE_REQUEST: on_configure_request((xcb_configure_request_event_t *)event); break; + case XCB_CLIENT_MESSAGE: + on_client_message((xcb_client_message_event_t *)event); + break; /* Unknown events */ default: @@ -1005,6 +1019,9 @@ void sys_init(void) { printf("sys_init\n"); + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + /* Load configuration */ stack = conf_get_int("main.stack", stack); border = conf_get_int("main.border", border); @@ -1022,6 +1039,14 @@ void sys_init(void) root = iter.data->root; colormap = iter.data->default_colormap; + /* Request substructure redirect */ + events = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; + cookie = xcb_change_window_attributes_checked(conn, root, + XCB_CW_EVENT_MASK, &events); + if ((err = xcb_request_check(conn, cookie))) + error("another window manager is already running"); + /* Setup X Atoms */ wm_protos = do_intern_atom("WM_PROTOCOLS"); wm_delete = do_intern_atom("WM_DELETE_WINDOW"); @@ -1032,6 +1057,19 @@ void sys_init(void) if (!do_ewmh_init_atoms()) error("ewmh setup failed"); + /* Set EWMH wm window */ + control = xcb_generate_id(conn); + cookie = xcb_create_window_checked(conn, 0, control, root, + 0, 0, 1, 1, 0, 0, 0, 0, NULL); + if ((err = xcb_request_check(conn, cookie))) + error("can't create control window"); + cookie = xcb_ewmh_set_wm_name_checked(&ewmh, control, 5, "wmpus"); + if ((err = xcb_request_check(conn, cookie))) + error("can't set wm name"); + cookie = xcb_ewmh_set_supporting_wm_check_checked(&ewmh, root, control); + if ((err = xcb_request_check(conn, cookie))) + error("can't set control window"); + /* Setup for for ST_CLOSE */ xcb_set_close_down_mode(conn, XCB_CLOSE_DOWN_DESTROY_ALL); @@ -1043,16 +1081,6 @@ void sys_init(void) colors[CLR_FOCUS] = do_alloc_color(0xFF6060); colors[CLR_UNFOCUS] = do_alloc_color(0xD8D8FF); colors[CLR_URGENT] = do_alloc_color(0xFF0000); - - /* Request substructure redirect */ - xcb_void_cookie_t cookie; - xcb_generic_error_t *err; - events = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; - cookie = xcb_change_window_attributes_checked(conn, root, - XCB_CW_EVENT_MASK, &events); - if ((err = xcb_request_check(conn, cookie))) - error("another window manager is already running"); } void sys_run(void) @@ -1080,7 +1108,8 @@ void sys_run(void) } /* Main loop */ - while (1) + running = 1; + while (running) { int status; xcb_generic_event_t *event; @@ -1096,17 +1125,36 @@ void sys_run(void) void sys_exit(void) { printf("sys_exit\n"); - if (conn) - xcb_disconnect(conn); - conn = NULL; + + xcb_client_message_event_t msg = { + .response_type = XCB_CLIENT_MESSAGE, + .format = 32, + .window = control, + .type = wm_protos, + .data.data32[0] = wm_delete, + .data.data32[1] = XCB_CURRENT_TIME, + }; + xcb_send_event(conn, 0, control, XCB_EVENT_MASK_NO_EVENT, + (const char *)&msg); + xcb_flush(conn); } void sys_free(void) { printf("sys_free\n"); - if (conn) { - xcb_ewmh_connection_wipe(&ewmh); - xcb_disconnect(conn); - } - conn = NULL; + + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + + cookie = xcb_delete_property_checked(conn, root, + ewmh._NET_SUPPORTING_WM_CHECK); + if ((err = xcb_request_check(conn, cookie))) + warn("can't remove control window"); + + cookie = xcb_destroy_window_checked(conn, control); + if ((err = xcb_request_check(conn, cookie))) + warn("can't destroy control window"); + + xcb_ewmh_connection_wipe(&ewmh); + xcb_disconnect(conn); } -- 2.43.2