/** The map request event handler. * \param ev The event. */ static void event_handle_maprequest(xcb_map_request_event_t *ev) { client_t *c; xcb_get_window_attributes_cookie_t wa_c; xcb_get_window_attributes_reply_t *wa_r; xcb_get_geometry_cookie_t geom_c; xcb_get_geometry_reply_t *geom_r; wa_c = xcb_get_window_attributes_unchecked(globalconf.connection, ev->window); if(!(wa_r = xcb_get_window_attributes_reply(globalconf.connection, wa_c, NULL))) return; if(wa_r->override_redirect) goto bailout; if(xembed_getbywin(&globalconf.embedded, ev->window)) { xcb_map_window(globalconf.connection, ev->window); xembed_window_activate(globalconf.connection, ev->window); } else if((c = client_getbywin(ev->window))) { /* Check that it may be visible, but not asked to be hidden */ if(client_on_selected_tags(c) && !c->hidden) { lua_State *L = globalconf_get_lua_State(); luaA_object_push(L, c); client_set_minimized(L, -1, false); lua_pop(L, 1); /* it will be raised, so just update ourself */ client_raise(c); } } else { geom_c = xcb_get_geometry_unchecked(globalconf.connection, ev->window); if(!(geom_r = xcb_get_geometry_reply(globalconf.connection, geom_c, NULL))) { goto bailout; } client_manage(ev->window, geom_r, wa_r); p_delete(&geom_r); } bailout: p_delete(&wa_r); }
/** The property notify event handler. * \param state currently unused * \param window The window to obtain update the property with. * \param name The protocol atom, currently unused. * \param reply (Optional) An existing reply. */ static int property_handle_xembed_info(uint8_t state, xcb_window_t window, xcb_atom_t name, xcb_get_property_reply_t *reply) { xembed_window_t *emwin = xembed_getbywin(&globalconf.embedded, window); if(emwin) xembed_property_update(globalconf.connection, emwin, reply); return 0; }
/** Handle a systray request. * \param embed_win The window to embed. * \param phys_screen The physical monitor to display on. * \param info The embedding info * \return 0 on no error. */ int systray_request_handle(xcb_window_t embed_win, int phys_screen, xembed_info_t *info) { xembed_window_t em; xcb_get_property_cookie_t em_cookie; const uint32_t select_input_val[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_ENTER_WINDOW }; /* check if not already trayed */ if(xembed_getbywin(&globalconf.embedded, embed_win)) return -1; p_clear(&em_cookie, 1); if(!info) em_cookie = xembed_info_get_unchecked(globalconf.connection, embed_win); xcb_change_window_attributes(globalconf.connection, embed_win, XCB_CW_EVENT_MASK, select_input_val); window_state_set(embed_win, XCB_ICCCM_WM_STATE_WITHDRAWN); /* we grab the window, but also make sure it's automatically reparented back * to the root window if we should die. */ xcb_change_save_set(globalconf.connection, XCB_SET_MODE_INSERT, embed_win); xcb_reparent_window(globalconf.connection, embed_win, globalconf.screens.tab[phys_screen].systray.window, 0, 0); em.win = embed_win; em.phys_screen = phys_screen; if(info) em.info = *info; else xembed_info_get_reply(globalconf.connection, em_cookie, &em.info); xembed_embedded_notify(globalconf.connection, em.win, globalconf.screens.tab[phys_screen].systray.window, MIN(XEMBED_VERSION, em.info.version)); xembed_window_array_append(&globalconf.embedded, em); widget_invalidate_bytype(widget_systray); return 0; }
/** Handle a systray request. * \param embed_win The window to embed. */ int systray_request_handle(xcb_window_t embed_win, int phys_screen, xembed_info_t *info) { xembed_window_t em; xcb_get_property_cookie_t em_cookie; int i; const uint32_t select_input_val[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_ENTER_WINDOW }; /* check if not already trayed */ if(xembed_getbywin(&globalconf.embedded, embed_win)) return -1; p_clear(&em_cookie, 1); if(!info) em_cookie = xembed_info_get_unchecked(globalconf.connection, embed_win); xcb_change_window_attributes(globalconf.connection, embed_win, XCB_CW_EVENT_MASK, select_input_val); window_state_set(embed_win, XCB_WM_STATE_WITHDRAWN); xcb_reparent_window(globalconf.connection, embed_win, globalconf.screens[phys_screen].systray.window, 0, 0); em.win = embed_win; em.phys_screen = phys_screen; if(info) em.info = *info; else xembed_info_get_reply(globalconf.connection, em_cookie, &em.info); xembed_embedded_notify(globalconf.connection, em.win, globalconf.screens[phys_screen].systray.window, MIN(XEMBED_VERSION, em.info.version)); xembed_window_array_append(&globalconf.embedded, em); for(i = 0; i < globalconf.nscreen; i++) widget_invalidate_bytype(i, widget_systray); return 0; }
/** The property notify event handler. * \param state currently unused * \param window The window to obtain update the property with. * \param name The protocol atom, currently unused. * \param reply (Optional) An existing reply. */ static int property_handle_xembed_info(uint8_t state, xcb_window_t window) { xembed_window_t *emwin = xembed_getbywin(&globalconf.embedded, window); if(emwin) { xcb_get_property_cookie_t cookie = xcb_get_property(globalconf.connection, 0, window, _XEMBED_INFO, XCB_GET_PROPERTY_TYPE_ANY, 0, 3); xcb_get_property_reply_t *propr = xcb_get_property_reply(globalconf.connection, cookie, 0); xembed_property_update(globalconf.connection, emwin, propr); p_delete(&propr); } return 0; }
/** The configure event handler. * \param ev The event. */ static void event_handle_configurerequest(xcb_configure_request_event_t *ev) { client_t *c; if((c = client_getbywin(ev->window))) { area_t geometry = c->geometry; uint16_t bw = c->border_width; uint16_t tb_left = c->titlebar[CLIENT_TITLEBAR_LEFT].size; uint16_t tb_right = c->titlebar[CLIENT_TITLEBAR_RIGHT].size; uint16_t tb_top = c->titlebar[CLIENT_TITLEBAR_TOP].size; uint16_t tb_bottom = c->titlebar[CLIENT_TITLEBAR_BOTTOM].size; uint16_t deco_left = bw + tb_left; uint16_t deco_right = bw + tb_right; uint16_t deco_top = bw + tb_top; uint16_t deco_bottom = bw + tb_bottom; int16_t diff_w = 0, diff_h = 0, diff_border = 0; lua_State *L = globalconf_get_lua_State(); if(ev->value_mask & XCB_CONFIG_WINDOW_X) { int16_t diff = 0; geometry.x = ev->x; xwindow_translate_for_gravity(c->size_hints.win_gravity, deco_left, 0, deco_right, 0, &diff, NULL); geometry.x += diff; } if(ev->value_mask & XCB_CONFIG_WINDOW_Y) { int16_t diff = 0; geometry.y = ev->y; xwindow_translate_for_gravity(c->size_hints.win_gravity, 0, deco_top, 0, deco_bottom, NULL, &diff); geometry.y += diff; } if(ev->value_mask & XCB_CONFIG_WINDOW_WIDTH) { uint16_t old_w = geometry.width; geometry.width = ev->width; /* The ConfigureRequest specifies the size of the client window, we want the frame */ geometry.width += tb_left + tb_right; diff_w = geometry.width - old_w; } if(ev->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { uint16_t old_h = geometry.height; geometry.height = ev->height; /* The ConfigureRequest specifies the size of the client window, we want the frame */ geometry.height += tb_top + tb_bottom; diff_h = geometry.height - old_h; } if(ev->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) { diff_border = ev->border_width - bw; diff_h += diff_border; diff_w += diff_border; luaA_object_push(L, c); window_set_border_width(L, -1, ev->border_width); lua_pop(L, 1); } /* If the client resizes without moving itself, apply window gravity */ if(c->size_hints.flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY) { int16_t diff_x = 0, diff_y = 0; xwindow_translate_for_gravity(c->size_hints.win_gravity, diff_border, diff_border, diff_w, diff_h, &diff_x, &diff_y); if(!(ev->value_mask & XCB_CONFIG_WINDOW_X)) geometry.x += diff_x; if(!(ev->value_mask & XCB_CONFIG_WINDOW_Y)) geometry.y += diff_y; } c->got_configure_request = true; /* Request the changes to be applied */ luaA_object_push(L, c); lua_pushstring(L, "ewmh"); /* context */ lua_newtable(L); /* props */ /* area, it needs to be directly in the `hints` table to comply with the "protocol" */ lua_pushstring(L, "x"); lua_pushinteger(L, geometry.x); lua_rawset(L, -3); lua_pushstring(L, "y"); lua_pushinteger(L, geometry.y); lua_rawset(L, -3); lua_pushstring(L, "width"); lua_pushinteger(L, geometry.width); lua_rawset(L, -3); lua_pushstring(L, "height"); lua_pushinteger(L, geometry.height); lua_rawset(L, -3); luaA_object_emit_signal(L, -3, "request::geometry", 2); lua_pop(L, 1); } else if (xembed_getbywin(&globalconf.embedded, ev->window)) { /* Ignore this so that systray icons cannot resize themselves. * We decide their size! * However, Xembed says that we act like a WM to the embedded window and * thus we have to send a synthetic configure notify informing the * window that its configure request was denied. */ xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry_unchecked(globalconf.connection, ev->window); xcb_translate_coordinates_cookie_t coords_cookie = xcb_translate_coordinates_unchecked(globalconf.connection, ev->window, globalconf.screen->root, 0, 0); xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(globalconf.connection, geom_cookie, NULL); xcb_translate_coordinates_reply_t *coords = xcb_translate_coordinates_reply(globalconf.connection, coords_cookie, NULL); if (geom && coords) { xwindow_configure(ev->window, (area_t) { .x = coords->dst_x, .y = coords->dst_y, .width = geom->width, .height = geom->height }, 0);
/** The configure event handler. * \param ev The event. */ static void event_handle_configurerequest(xcb_configure_request_event_t *ev) { client_t *c; if((c = client_getbywin(ev->window))) { area_t geometry = c->geometry; uint16_t bw = c->border_width; uint16_t tb_left = c->titlebar[CLIENT_TITLEBAR_LEFT].size; uint16_t tb_right = c->titlebar[CLIENT_TITLEBAR_RIGHT].size; uint16_t tb_top = c->titlebar[CLIENT_TITLEBAR_TOP].size; uint16_t tb_bottom = c->titlebar[CLIENT_TITLEBAR_BOTTOM].size; uint16_t deco_left = bw + tb_left; uint16_t deco_right = bw + tb_right; uint16_t deco_top = bw + tb_top; uint16_t deco_bottom = bw + tb_bottom; int16_t diff_w = 0, diff_h = 0, diff_border = 0; if(ev->value_mask & XCB_CONFIG_WINDOW_X) { int16_t diff = 0; geometry.x = ev->x; xwindow_translate_for_gravity(c->size_hints.win_gravity, deco_left, 0, deco_right, 0, &diff, NULL); geometry.x += diff; } if(ev->value_mask & XCB_CONFIG_WINDOW_Y) { int16_t diff = 0; geometry.y = ev->y; xwindow_translate_for_gravity(c->size_hints.win_gravity, 0, deco_top, 0, deco_bottom, NULL, &diff); geometry.y += diff; } if(ev->value_mask & XCB_CONFIG_WINDOW_WIDTH) { uint16_t old_w = geometry.width; geometry.width = ev->width; /* The ConfigureRequest specifies the size of the client window, we want the frame */ geometry.width += tb_left + tb_right; diff_w = geometry.width - old_w; } if(ev->value_mask & XCB_CONFIG_WINDOW_HEIGHT) { uint16_t old_h = geometry.height; geometry.height = ev->height; /* The ConfigureRequest specifies the size of the client window, we want the frame */ geometry.height += tb_top + tb_bottom; diff_h = geometry.height - old_h; } if(ev->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) { lua_State *L = globalconf_get_lua_State(); diff_border = ev->border_width - bw; diff_h += diff_border; diff_w += diff_border; luaA_object_push(L, c); window_set_border_width(L, -1, ev->border_width); lua_pop(L, 1); } /* If the client resizes without moving itself, apply window gravity */ if(c->size_hints.flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY) { int16_t diff_x = 0, diff_y = 0; xwindow_translate_for_gravity(c->size_hints.win_gravity, diff_border, diff_border, diff_w, diff_h, &diff_x, &diff_y); if(!(ev->value_mask & XCB_CONFIG_WINDOW_X)) geometry.x += diff_x; if(!(ev->value_mask & XCB_CONFIG_WINDOW_Y)) geometry.y += diff_y; } if(!client_resize(c, geometry, false)) /* ICCCM 4.1.5 / 4.2.3, if nothing was changed, send an event saying so */ client_send_configure(c); } else if (xembed_getbywin(&globalconf.embedded, ev->window)) { /* Ignore this so that systray icons cannot resize themselves. * We decide their size! */ } else event_handle_configurerequest_configure_window(ev); }
} /** The property notify event handler. * \param data currently unused. * \param connection The connection to the X server. * \param ev The event. */ static int property_handle_xembed_info(void *data __attribute__ ((unused)), xcb_connection_t *connection, uint8_t state, xcb_window_t window, xcb_atom_t name, xcb_get_property_reply_t *reply) { xembed_window_t *emwin = xembed_getbywin(globalconf.embedded, window); if(emwin) xembed_property_update(connection, emwin, reply); return 0; } static int property_handle_xrootpmap_id(void *data __attribute__ ((unused)), xcb_connection_t *connection, uint8_t state, xcb_window_t window, xcb_atom_t name, xcb_get_property_reply_t *reply) {