-void reparent_window(xcb_connection_t *conn, xcb_window_t child,
- xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
- int16_t x, int16_t y, uint16_t width, uint16_t height) {
-
- xcb_get_property_cookie_t wm_type_cookie, strut_cookie;
-
- /* Place requests for properties ASAP */
- wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
- strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
-
- Client *new = table_get(byChild, child);
-
- /* Events for already managed windows should already be filtered in manage_window() */
- assert(new == NULL);
-
- printf("reparenting new client\n");
- new = calloc(sizeof(Client), 1);
- new->force_reconfigure = true;
- uint32_t mask = 0;
- uint32_t values[3];
-
- /* Update the data structures */
- Client *old_focused = CUR_CELL->currently_focused;
- CUR_CELL->currently_focused = new;
- new->container = CUR_CELL;
-
- new->frame = xcb_generate_id(conn);
- new->child = child;
- new->rect.width = width;
- new->rect.height = height;
-
- /* Don’t generate events for our new window, it should *not* be managed */
- mask |= XCB_CW_OVERRIDE_REDIRECT;
- values[0] = 1;
-
- /* We want to know when… */
- mask |= XCB_CW_EVENT_MASK;
- values[1] = XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed/released */
- XCB_EVENT_MASK_BUTTON_RELEASE |
- XCB_EVENT_MASK_EXPOSURE | /* …our window needs to be redrawn */
- XCB_EVENT_MASK_ENTER_WINDOW; /* …user moves cursor inside our window */
-
- printf("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
-
- i3Font *font = load_font(conn, config.font);
- width = min(width, c_ws->rect.x + c_ws->rect.width);
- height = min(height, c_ws->rect.y + c_ws->rect.height);
-
- Rect framerect = {x, y,
- width + 2 + 2, /* 2 px border at each side */
- height + 2 + 2 + font->height}; /* 2 px border plus font’s height */
-
- /* Yo dawg, I heard you like windows, so I create a window around your window… */
- new->frame = create_window(conn, framerect, XCB_WINDOW_CLASS_INPUT_OUTPUT, mask, values);
-
- /* Put the client inside the save set. Upon termination (whether killed or normal exit
- does not matter) of the window manager, these clients will be correctly reparented
- to their most closest living ancestor (= cleanup) */
- xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
-
- /* Generate a graphics context for the titlebar */
- new->titlegc = xcb_generate_id(conn);
- xcb_create_gc(conn, new->titlegc, new->frame, 0, 0);
-
- /* Put our data structure (Client) into the table */
- table_put(byParent, new->frame, new);
- table_put(byChild, child, new);
-
- /* Moves the original window into the new frame we've created for it */
- new->awaiting_useless_unmap = true;
- xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, child, new->frame, 0, font->height);
- check_error(conn, cookie, "Could not reparent window");
-
- /* We are interested in property changes */
- mask = XCB_CW_EVENT_MASK;
- values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
- XCB_EVENT_MASK_STRUCTURE_NOTIFY |
- XCB_EVENT_MASK_ENTER_WINDOW;
- cookie = xcb_change_window_attributes_checked(conn, child, mask, values);
- check_error(conn, cookie, "Could not change window attributes");
-
- /* We need to grab the mouse buttons for click to focus */
- xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
- XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
- 1 /* left mouse button */,
- XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
-
- /* Focus the new window */
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
-
- /* Get _NET_WM_WINDOW_TYPE (to see if it’s a dock) */
- xcb_atom_t *atom;
- xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
- if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
- for (int i = 0; i < xcb_get_property_value_length(preply); i++)
- if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
- printf("Window is a dock.\n");
- new->dock = true;
- new->titlebar_position = TITLEBAR_OFF;
- new->force_reconfigure = true;
- new->container = NULL;
- SLIST_INSERT_HEAD(&(c_ws->dock_clients), new, dock_clients);
- }
- }