71 static
con_state *state_for_frame(xcb_window_t window) {
74 if (state->
id == window)
78 ELOG(
"No state found\n");
95 xcb_visualid_t visual = XCB_COPY_FROM_PARENT;
96 xcb_colormap_t win_colormap = XCB_NONE;
97 if (depth !=
root_depth && depth != XCB_COPY_FROM_PARENT) {
101 win_colormap = xcb_generate_id(
conn);
102 xcb_create_colormap_checked(
conn, XCB_COLORMAP_ALLOC_NONE, win_colormap,
root, visual);
108 mask |= XCB_CW_BACK_PIXEL;
111 mask |= XCB_CW_BORDER_PIXEL;
115 mask |= XCB_CW_OVERRIDE_REDIRECT;
119 mask |= XCB_CW_EVENT_MASK;
122 mask |= XCB_CW_COLORMAP;
123 values[4] = win_colormap;
126 mask = XCB_CW_OVERRIDE_REDIRECT;
130 mask |= XCB_CW_EVENT_MASK;
133 mask |= XCB_CW_COLORMAP;
137 Rect dims = { -15, -15, 10, 10 };
140 if (win_colormap != XCB_NONE)
141 xcb_free_colormap(
conn, win_colormap);
149 DLOG(
"adding new state for window id 0x%08x\n", state->
id);
161 if ((state = state_for_frame(con->
frame)) == NULL) {
162 ELOG(
"window state not found\n");
166 DLOG(
"resetting state %p to initial\n", state);
180 if ((state = state_for_frame(con->
frame)) == NULL) {
181 ELOG(
"window state for con not found\n");
194 struct con_state *state_src, *state_dest;
196 if ((state_src = state_for_frame(src->
frame)) == NULL) {
197 ELOG(
"window state for src not found\n");
201 if ((state_dest = state_for_frame(dest->
frame)) == NULL) {
202 ELOG(
"window state for dest not found\n");
206 state_dest->
con = state_src->
con;
207 state_src->
con = NULL;
209 Rect zero = { 0, 0, 0, 0 };
212 DLOG(
"COPYING RECT\n");
226 state = state_for_frame(con->
frame);
241 xcb_get_property_cookie_t cookie;
250 for (uint32_t i = 0; i < protocols.atoms_len; i++)
251 if (protocols.atoms[i] == atom)
267 LOG(
"Killing specific window 0x%08x\n", window);
268 xcb_destroy_window(
conn, window);
270 LOG(
"Killing the X11 client which owns window 0x%08x\n", window);
271 xcb_kill_client(
conn, window);
280 xcb_client_message_event_t *ev = event;
282 ev->response_type = XCB_CLIENT_MESSAGE;
284 ev->type = A_WM_PROTOCOLS;
286 ev->data.data32[0] = A_WM_DELETE_WINDOW;
287 ev->data.data32[1] = XCB_CURRENT_TIME;
289 LOG(
"Sending WM_DELETE to the client\n");
290 xcb_send_event(
conn,
false, window, XCB_EVENT_MASK_NO_EVENT, (
char*)ev);
310 parent->
layout != L_STACKED &&
311 parent->
layout != L_TABBED) ||
312 con->
type == CT_FLOATING_CON)
322 if (leaf && con->
pixmap == XCB_NONE)
333 else if (con ==
TAILQ_FIRST(&(parent->focus_head)))
372 if (con->
window != NULL) {
373 xcb_rectangle_t background[] = {
384 for (
int i = 0; i < 4; i++)
385 DLOG(
"rect is (%d, %d) with %d x %d\n",
394 xcb_poly_fill_rectangle(
conn, con->
pixmap, con->
pm_gc,
sizeof(background) /
sizeof(xcb_rectangle_t), background);
398 if (p->border_style !=
BS_NONE && p->con_is_leaf) {
402 DLOG(
"border_rect spans (%d, %d) with %d x %d\n", br.
x, br.
y, br.
width, br.
height);
410 xcb_change_gc(
conn,
con->
pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->background });
411 xcb_rectangle_t borders[] = {
412 { 0, 0, br.
x, r->height },
413 { 0, r->height + br.
height + br.
y, r->width, r->height },
414 { r->width + br.
width + br.
x, 0, r->width, r->height }
430 xcb_change_gc(
conn,
con->
pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->indicator });
433 { r->width + br.
width + br.
x, 0, r->width, r->height + br.
height } });
435 xcb_poly_fill_rectangle(
conn, con->pixmap, con->pm_gc, 1, (xcb_rectangle_t[]){
436 { br.
x, r->height + br.
height + br.
y, r->width - (2 * br.
x), r->height } });
447 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->background });
448 xcb_rectangle_t drect = { con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height };
449 xcb_poly_fill_rectangle(
conn, parent->pixmap, parent->pm_gc, 1, &drect);
452 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->border });
453 Rect *dr = &(con->deco_rect);
454 xcb_segment_t segments[] = {
456 dr->x + dr->width - 1, dr->y },
458 { dr->x + 2, dr->y + dr->height - 1,
459 dr->x + dr->width - 3, dr->y + dr->height - 1 }
461 xcb_poly_segment(
conn, parent->pixmap, parent->pm_gc, 2, segments);
467 struct Window *win = con->window;
468 if (win == NULL || win->
name_x == NULL) {
471 draw_text(
"another container", strlen(
"another container"),
false,
472 parent->pixmap, parent->pm_gc,
473 con->deco_rect.x + 2, con->deco_rect.y + text_offset_y,
474 con->deco_rect.width - 2);
478 int indent_level = 0,
480 Con *il_parent = parent;
481 if (il_parent->
layout != L_STACKED) {
484 if (il_parent->
layout == L_STACKED)
486 if (il_parent->
type == CT_WORKSPACE || il_parent->
type == CT_DOCKAREA || il_parent->
type == CT_OUTPUT)
488 il_parent = il_parent->
parent;
493 int indent_px = (indent_level * 5) * indent_mult;
496 parent->pixmap, parent->pm_gc,
497 con->deco_rect.x + 2 + indent_px, con->deco_rect.y + text_offset_y,
498 con->deco_rect.width - 2 - indent_px);
507 if (parent->layout == L_TABBED &&
TAILQ_NEXT(con, nodes) != NULL) {
508 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->border });
510 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->background });
512 xcb_poly_line(
conn, XCB_COORD_MODE_ORIGIN, parent->pixmap, parent->pm_gc, 4,
514 { dr->x + dr->width - 1, dr->y },
515 { dr->x + dr->width - 1, dr->y + dr->height },
516 { dr->x + dr->width - 2, dr->y },
517 { dr->x + dr->width - 2, dr->y + dr->height }
520 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->border });
521 xcb_poly_segment(
conn, parent->pixmap, parent->pm_gc, 2, segments);
524 xcb_copy_area(
conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
543 TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
550 if ((con->
type != CT_ROOT && con->
type != CT_OUTPUT) &&
567 state = state_for_frame(con->
frame);
569 if (state->
name != NULL) {
570 DLOG(
"pushing name %s for con %p\n", state->
name, con);
572 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE, con->
frame,
577 if (con->
window == NULL) {
580 uint32_t max_y = 0, max_height = 0;
583 if (dr->
y >= max_y && dr->
height >= max_height) {
588 rect.
height = max_y + max_height;
596 DLOG(
"Reparenting child window\n");
601 uint32_t values[] = { XCB_NONE };
602 xcb_change_window_attributes(
conn, state->
old_frame, XCB_CW_EVENT_MASK, values);
603 xcb_change_window_attributes(
conn, con->
window->
id, XCB_CW_EVENT_MASK, values);
608 xcb_change_window_attributes(
conn, state->
old_frame, XCB_CW_EVENT_MASK, values);
610 xcb_change_window_attributes(
conn, con->
window->
id, XCB_CW_EVENT_MASK, values);
616 DLOG(
"ignore_unmap for reparenting of con %p (win 0x%08x) is now %d\n",
620 bool fake_notify =
false;
622 if (memcmp(&(state->
rect), &rect,
sizeof(
Rect)) != 0 &&
653 uint32_t values[] = { 0 };
654 xcb_create_gc(
conn, con->
pm_gc, con->
pixmap, XCB_GC_GRAPHICS_EXPOSURES, values);
669 DLOG(
"setting rect (%d, %d, %d, %d)\n", rect.
x, rect.
y, rect.
width, rect.
height);
676 if (con->
pixmap != XCB_NONE)
680 memcpy(&(state->
rect), &rect,
sizeof(
Rect));
685 if (con->
window != NULL &&
687 DLOG(
"setting window rect (%d, %d, %d, %d)\n",
700 xcb_void_cookie_t cookie;
702 if (con->
window != NULL) {
706 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE, con->
window->
id,
707 A_WM_STATE, A_WM_STATE, 32, 2, data);
717 xcb_change_window_attributes(
conn, con->
window->
id, XCB_CW_EVENT_MASK, values);
718 DLOG(
"mapping child window (serial %d)\n", cookie.sequence);
722 cookie = xcb_map_window(
conn, con->
frame);
725 xcb_change_window_attributes(
conn, con->
frame, XCB_CW_EVENT_MASK, values);
728 if (con->
pixmap != XCB_NONE)
732 DLOG(
"mapping container %08x (serial %d)\n", con->
frame, cookie.sequence);
739 DLOG(
"Sending fake configure notify\n");
764 state = state_for_frame(con->
frame);
770 xcb_void_cookie_t cookie;
771 if (con->
window != NULL) {
774 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE, con->
window->
id,
775 A_WM_STATE, A_WM_STATE, 32, 2, data);
778 cookie = xcb_unmap_window(
conn, con->
frame);
779 DLOG(
"unmapping container (serial %d)\n", cookie.sequence);
783 if (con->
window != NULL) {
794 TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
811 xcb_query_pointer_cookie_t pointercookie;
815 pointercookie = xcb_query_pointer(
conn,
root);
818 DLOG(
"-- PUSHING WINDOW STACK --\n");
820 uint32_t values[1] = { XCB_NONE };
823 xcb_change_window_attributes(
conn, state->
id, XCB_CW_EVENT_MASK, values);
826 bool order_changed =
false;
827 bool stacking_changed =
false;
846 memcpy(walk++, &(state->
con->
window->
id),
sizeof(xcb_window_t));
851 if (prev != old_prev)
852 order_changed =
true;
854 stacking_changed =
true;
857 mask |= XCB_CONFIG_WINDOW_SIBLING;
858 mask |= XCB_CONFIG_WINDOW_STACK_MODE;
859 uint32_t values[] = {state->
id, XCB_STACK_MODE_ABOVE};
861 xcb_configure_window(
conn, prev->
id, mask, values);
868 if (stacking_changed)
871 DLOG(
"PUSHING CHANGES\n");
875 xcb_query_pointer_reply_t *pointerreply = xcb_query_pointer_reply(
conn, pointercookie, NULL);
877 ELOG(
"Could not query pointer position, not warping pointer\n");
879 int mid_x = warp_to->
x + (warp_to->
width / 2);
880 int mid_y = warp_to->
y + (warp_to->
height / 2);
884 if (current != target)
885 xcb_warp_pointer(
conn, XCB_NONE,
root, 0, 0, 0, 0, mid_x, mid_y);
894 xcb_change_window_attributes(
conn, state->
id, XCB_CW_EVENT_MASK, values);
910 bool set_focus =
true;
913 DLOG(
"Updating focus by sending WM_TAKE_FOCUS to window 0x%08x (focused: %p / %s)\n",
917 DLOG(
"set_focus = %d\n", set_focus);
929 xcb_set_input_focus(
conn, XCB_INPUT_FOCUS_POINTER_ROOT, to_focus, XCB_CURRENT_TIME);
943 DLOG(
"Still no window focused, better set focus to the root window\n");
944 xcb_set_input_focus(
conn, XCB_INPUT_FOCUS_POINTER_ROOT,
root, XCB_CURRENT_TIME);
949 DLOG(
"ENDING CHANGES\n");
962 xcb_change_window_attributes(
conn, state->
id, XCB_CW_EVENT_MASK, values);
987 state = state_for_frame(con->
frame);
1003 if ((state = state_for_frame(con->
frame)) == NULL) {
1004 ELOG(
"window state not found\n");
1017 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE,
root, A_I3_SOCKET_PATH, A_UTF8_STRING, 8,
1020 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE,
root, A_I3_CONFIG_PATH, A_UTF8_STRING, 8,
1022 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE,
root, A_I3_SHMLOG_PATH, A_UTF8_STRING, 8,
1048 xcb_change_window_attributes(
conn, state->
id, XCB_CW_EVENT_MASK, values);