00001
00002
00003
00004
00005 #include "all.h"
00006
00007
00008 xcb_window_t focused_id = XCB_NONE;
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 typedef struct con_state {
00019 xcb_window_t id;
00020 bool mapped;
00021 bool unmap_now;
00022 bool child_mapped;
00023
00024
00025
00026
00027 bool need_reparent;
00028 xcb_window_t old_frame;
00029
00030 Rect rect;
00031 Rect window_rect;
00032
00033 bool initial;
00034
00035 char *name;
00036
00037 CIRCLEQ_ENTRY(con_state) state;
00038 CIRCLEQ_ENTRY(con_state) old_state;
00039 } con_state;
00040
00041 CIRCLEQ_HEAD(state_head, con_state) state_head =
00042 CIRCLEQ_HEAD_INITIALIZER(state_head);
00043
00044 CIRCLEQ_HEAD(old_state_head, con_state) old_state_head =
00045 CIRCLEQ_HEAD_INITIALIZER(old_state_head);
00046
00047
00048
00049
00050
00051
00052
00053
00054 static con_state *state_for_frame(xcb_window_t window) {
00055 con_state *state;
00056 CIRCLEQ_FOREACH(state, &state_head, state)
00057 if (state->id == window)
00058 return state;
00059
00060
00061 ELOG("No state found\n");
00062 assert(false);
00063 return NULL;
00064 }
00065
00066
00067
00068
00069
00070
00071 void x_con_init(Con *con) {
00072
00073
00074
00075 uint32_t mask = 0;
00076 uint32_t values[2];
00077
00078
00079 mask |= XCB_CW_OVERRIDE_REDIRECT;
00080 values[0] = 1;
00081
00082
00083 mask |= XCB_CW_EVENT_MASK;
00084 values[1] = FRAME_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW;
00085
00086 Rect dims = { -15, -15, 10, 10 };
00087 con->frame = create_window(conn, dims, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCURSOR_CURSOR_POINTER, false, mask, values);
00088
00089 struct con_state *state = scalloc(sizeof(struct con_state));
00090 state->id = con->frame;
00091 state->mapped = false;
00092 state->initial = true;
00093 CIRCLEQ_INSERT_HEAD(&state_head, state, state);
00094 CIRCLEQ_INSERT_HEAD(&old_state_head, state, old_state);
00095 DLOG("adding new state for window id 0x%08x\n", state->id);
00096 }
00097
00098
00099
00100
00101
00102
00103
00104 void x_reinit(Con *con) {
00105 struct con_state *state;
00106
00107 if ((state = state_for_frame(con->frame)) == NULL) {
00108 ELOG("window state not found\n");
00109 return;
00110 }
00111
00112 DLOG("resetting state %p to initial\n", state);
00113 state->initial = true;
00114 state->child_mapped = false;
00115 memset(&(state->window_rect), 0, sizeof(Rect));
00116 }
00117
00118
00119
00120
00121
00122
00123 void x_reparent_child(Con *con, Con *old) {
00124 struct con_state *state;
00125 if ((state = state_for_frame(con->frame)) == NULL) {
00126 ELOG("window state for con not found\n");
00127 return;
00128 }
00129
00130 state->need_reparent = true;
00131 state->old_frame = old->frame;
00132 }
00133
00134
00135
00136
00137
00138 void x_move_win(Con *src, Con *dest) {
00139 struct con_state *state_src, *state_dest;
00140
00141 if ((state_src = state_for_frame(src->frame)) == NULL) {
00142 ELOG("window state for src not found\n");
00143 return;
00144 }
00145
00146 if ((state_dest = state_for_frame(dest->frame)) == NULL) {
00147 ELOG("window state for dest not found\n");
00148 return;
00149 }
00150
00151 Rect zero = { 0, 0, 0, 0 };
00152 if (memcmp(&(state_dest->window_rect), &(zero), sizeof(Rect)) == 0) {
00153 memcpy(&(state_dest->window_rect), &(state_src->window_rect), sizeof(Rect));
00154 DLOG("COPYING RECT\n");
00155 }
00156 }
00157
00158
00159
00160
00161
00162 void x_con_kill(Con *con) {
00163 con_state *state;
00164
00165 xcb_destroy_window(conn, con->frame);
00166 xcb_free_pixmap(conn, con->pixmap);
00167 xcb_free_gc(conn, con->pm_gc);
00168 state = state_for_frame(con->frame);
00169 CIRCLEQ_REMOVE(&state_head, state, state);
00170 CIRCLEQ_REMOVE(&old_state_head, state, old_state);
00171 FREE(state->name);
00172 free(state);
00173
00174
00175 focused_id = XCB_NONE;
00176 }
00177
00178
00179
00180
00181
00182 bool window_supports_protocol(xcb_window_t window, xcb_atom_t atom) {
00183 xcb_get_property_cookie_t cookie;
00184 xcb_icccm_get_wm_protocols_reply_t protocols;
00185 bool result = false;
00186
00187 cookie = xcb_icccm_get_wm_protocols(conn, window, A_WM_PROTOCOLS);
00188 if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &protocols, NULL) != 1)
00189 return false;
00190
00191
00192 for (uint32_t i = 0; i < protocols.atoms_len; i++)
00193 if (protocols.atoms[i] == atom)
00194 result = true;
00195
00196 xcb_icccm_get_wm_protocols_reply_wipe(&protocols);
00197
00198 return result;
00199 }
00200
00201
00202
00203
00204
00205 void x_window_kill(xcb_window_t window, kill_window_t kill_window) {
00206
00207 if (!window_supports_protocol(window, A_WM_DELETE_WINDOW)) {
00208 if (kill_window == KILL_WINDOW) {
00209 LOG("Killing specific window 0x%08x\n", window);
00210 xcb_destroy_window(conn, window);
00211 } else {
00212 LOG("Killing the X11 client which owns window 0x%08x\n", window);
00213 xcb_kill_client(conn, window);
00214 }
00215 return;
00216 }
00217
00218
00219
00220
00221 void *event = scalloc(32);
00222 xcb_client_message_event_t *ev = event;
00223
00224 ev->response_type = XCB_CLIENT_MESSAGE;
00225 ev->window = window;
00226 ev->type = A_WM_PROTOCOLS;
00227 ev->format = 32;
00228 ev->data.data32[0] = A_WM_DELETE_WINDOW;
00229 ev->data.data32[1] = XCB_CURRENT_TIME;
00230
00231 LOG("Sending WM_DELETE to the client\n");
00232 xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char*)ev);
00233 xcb_flush(conn);
00234 free(event);
00235 }
00236
00237
00238
00239
00240
00241 void x_draw_decoration(Con *con) {
00242 Con *parent = con->parent;
00243
00244
00245
00246
00247
00248
00249
00250 if ((!con_is_leaf(con) &&
00251 parent->layout != L_STACKED &&
00252 parent->layout != L_TABBED) ||
00253 con->type == CT_FLOATING_CON)
00254 return;
00255 DLOG("decoration should be rendered for con %p\n", con);
00256
00257
00258 if (con->rect.height == 0) {
00259 DLOG("height == 0, not rendering\n");
00260 return;
00261 }
00262
00263
00264
00265
00266 if (con->pixmap == XCB_NONE) {
00267 DLOG("pixmap not yet created, not rendering\n");
00268 return;
00269 }
00270
00271
00272 struct deco_render_params *p = scalloc(sizeof(struct deco_render_params));
00273
00274
00275 if (con->urgent)
00276 p->color = &config.client.urgent;
00277 else if (con == focused)
00278 p->color = &config.client.focused;
00279 else if (con == TAILQ_FIRST(&(parent->focus_head)))
00280 p->color = &config.client.focused_inactive;
00281 else
00282 p->color = &config.client.unfocused;
00283
00284 p->border_style = con_border_style(con);
00285
00286 Rect *r = &(con->rect);
00287 Rect *w = &(con->window_rect);
00288 p->con_rect = (struct width_height){ r->width, r->height };
00289 p->con_window_rect = (struct width_height){ w->width, w->height };
00290 p->con_deco_rect = con->deco_rect;
00291 p->background = config.client.background;
00292 p->con_is_leaf = con_is_leaf(con);
00293 p->font = config.font.id;
00294
00295 if (con->deco_render_params != NULL &&
00296 (con->window == NULL || !con->window->name_x_changed) &&
00297 !parent->pixmap_recreated &&
00298 !con->pixmap_recreated &&
00299 memcmp(p, con->deco_render_params, sizeof(struct deco_render_params)) == 0) {
00300 DLOG("CACHE HIT, copying existing pixmaps\n");
00301 free(p);
00302 goto copy_pixmaps;
00303 }
00304
00305 DLOG("CACHE MISS\n");
00306 Con *next = con;
00307 while ((next = TAILQ_NEXT(next, nodes))) {
00308 DLOG("Also invalidating cache of %p\n", next);
00309 FREE(next->deco_render_params);
00310 }
00311
00312 FREE(con->deco_render_params);
00313 con->deco_render_params = p;
00314
00315 if (con->window != NULL && con->window->name_x_changed)
00316 con->window->name_x_changed = false;
00317
00318 parent->pixmap_recreated = false;
00319 con->pixmap_recreated = false;
00320
00321
00322 if (con->window != NULL) {
00323 xcb_rectangle_t background[] = {
00324
00325 { 0, 0, r->width, w->y },
00326
00327 { 0, (w->y + w->height), r->width, r->height - (w->y + w->height) },
00328
00329 { 0, 0, w->x, r->height },
00330
00331 { w->x + w->width, 0, r->width - (w->x + w->width), r->height }
00332 };
00333 #if 0
00334 for (int i = 0; i < 4; i++)
00335 DLOG("rect is (%d, %d) with %d x %d\n",
00336 background[i].x,
00337 background[i].y,
00338 background[i].width,
00339 background[i].height
00340 );
00341 #endif
00342
00343 xcb_change_gc_single(conn, con->pm_gc, XCB_GC_FOREGROUND, config.client.background);
00344 xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, sizeof(background) / sizeof(xcb_rectangle_t), background);
00345 }
00346
00347
00348 if (p->border_style != BS_NONE && p->con_is_leaf) {
00349 Rect br = con_border_style_rect(con);
00350 #if 0
00351 DLOG("con->rect spans %d x %d\n", con->rect.width, con->rect.height);
00352 DLOG("border_rect spans (%d, %d) with %d x %d\n", br.x, br.y, br.width, br.height);
00353 DLOG("window_rect spans (%d, %d) with %d x %d\n", con->window_rect.x, con->window_rect.y, con->window_rect.width, con->window_rect.height);
00354 #endif
00355
00356
00357
00358
00359
00360 xcb_change_gc_single(conn, con->pm_gc, XCB_GC_FOREGROUND, p->color->background);
00361 xcb_rectangle_t borders[] = {
00362 { 0, 0, br.x, r->height },
00363 { 0, r->height + br.height + br.y, r->width, r->height },
00364 { r->width + br.width + br.x, 0, r->width, r->height }
00365 };
00366 xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 3, borders);
00367
00368 if (p->border_style == BS_1PIXEL) {
00369 xcb_rectangle_t topline = { br.x, 0, con->rect.width + br.width + br.x, br.y };
00370 xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &topline);
00371 }
00372 }
00373
00374
00375
00376 if (p->border_style != BS_NORMAL) {
00377 DLOG("border style not BS_NORMAL, aborting rendering of decoration\n");
00378 goto copy_pixmaps;
00379 }
00380
00381
00382 xcb_change_gc_single(conn, parent->pm_gc, XCB_GC_FOREGROUND, p->color->background);
00383 xcb_rectangle_t drect = { con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height };
00384 xcb_poly_fill_rectangle(conn, parent->pixmap, parent->pm_gc, 1, &drect);
00385
00386
00387 xcb_change_gc_single(conn, parent->pm_gc, XCB_GC_FOREGROUND, p->color->border);
00388 Rect *dr = &(con->deco_rect);
00389 xcb_segment_t segments[] = {
00390 { dr->x, dr->y,
00391 dr->x + dr->width, dr->y },
00392
00393 { dr->x, dr->y + dr->height - 1,
00394 dr->x + dr->width, dr->y + dr->height - 1 }
00395 };
00396 xcb_poly_segment(conn, parent->pixmap, parent->pm_gc, 2, segments);
00397
00398
00399 uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
00400 uint32_t values[] = { p->color->text, p->color->background, config.font.id };
00401 xcb_change_gc(conn, parent->pm_gc, mask, values);
00402 int text_offset_y = config.font.height + (con->deco_rect.height - config.font.height) / 2 - 1;
00403
00404 struct Window *win = con->window;
00405 if (win == NULL || win->name_x == NULL) {
00406
00407
00408 xcb_image_text_8(
00409 conn,
00410 strlen("another container"),
00411 parent->pixmap,
00412 parent->pm_gc,
00413 con->deco_rect.x + 2,
00414 con->deco_rect.y + text_offset_y,
00415 "another container"
00416 );
00417
00418 goto copy_pixmaps;
00419 }
00420
00421 int indent_level = 0,
00422 indent_mult = 0;
00423 Con *il_parent = parent;
00424 if (il_parent->layout != L_STACKED) {
00425 while (1) {
00426 DLOG("il_parent = %p, layout = %d\n", il_parent, il_parent->layout);
00427 if (il_parent->layout == L_STACKED)
00428 indent_level++;
00429 if (il_parent->type == CT_WORKSPACE || il_parent->type == CT_DOCKAREA || il_parent->type == CT_OUTPUT)
00430 break;
00431 il_parent = il_parent->parent;
00432 indent_mult++;
00433 }
00434 }
00435 DLOG("indent_level = %d, indent_mult = %d\n", indent_level, indent_mult);
00436 int indent_px = (indent_level * 5) * indent_mult;
00437
00438 if (win->uses_net_wm_name)
00439 xcb_image_text_16(
00440 conn,
00441 win->name_len,
00442 parent->pixmap,
00443 parent->pm_gc,
00444 con->deco_rect.x + 2 + indent_px,
00445 con->deco_rect.y + text_offset_y,
00446 (xcb_char2b_t*)win->name_x
00447 );
00448 else
00449 xcb_image_text_8(
00450 conn,
00451 win->name_len,
00452 parent->pixmap,
00453 parent->pm_gc,
00454 con->deco_rect.x + 2 + indent_px,
00455 con->deco_rect.y + text_offset_y,
00456 win->name_x
00457 );
00458
00459 copy_pixmaps:
00460 xcb_copy_area(conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
00461 }
00462
00463
00464
00465
00466
00467
00468
00469 void x_deco_recurse(Con *con) {
00470 Con *current;
00471 bool leaf = TAILQ_EMPTY(&(con->nodes_head)) &&
00472 TAILQ_EMPTY(&(con->floating_head));
00473 con_state *state = state_for_frame(con->frame);
00474
00475 if (!leaf) {
00476 TAILQ_FOREACH(current, &(con->nodes_head), nodes)
00477 x_deco_recurse(current);
00478
00479 TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
00480 x_deco_recurse(current);
00481
00482 if (state->mapped)
00483 xcb_copy_area(conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
00484 }
00485
00486 if ((con->type != CT_ROOT && con->type != CT_OUTPUT) &&
00487 con->mapped)
00488 x_draw_decoration(con);
00489 }
00490
00491
00492
00493
00494
00495
00496
00497 void x_push_node(Con *con) {
00498 Con *current;
00499 con_state *state;
00500 Rect rect = con->rect;
00501
00502
00503 state = state_for_frame(con->frame);
00504
00505 if (state->name != NULL) {
00506 DLOG("pushing name %s for con %p\n", state->name, con);
00507
00508 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->frame,
00509 A_WM_NAME, A_STRING, 8, strlen(state->name), state->name);
00510 FREE(state->name);
00511 }
00512
00513 if (con->window == NULL) {
00514
00515
00516 uint32_t max_y = 0, max_height = 0;
00517 TAILQ_FOREACH(current, &(con->nodes_head), nodes) {
00518 Rect *dr = &(current->deco_rect);
00519 if (dr->y >= max_y && dr->height >= max_height) {
00520 max_y = dr->y;
00521 max_height = dr->height;
00522 }
00523 }
00524 rect.height = max_y + max_height;
00525 if (rect.height == 0) {
00526 DLOG("Unmapping container %p because it does not contain anything.\n", con);
00527 con->mapped = false;
00528 }
00529 }
00530
00531
00532
00533 if (state->need_reparent && con->window != NULL) {
00534 DLOG("Reparenting child window\n");
00535
00536
00537
00538
00539 uint32_t values[] = { XCB_NONE };
00540 xcb_change_window_attributes(conn, state->old_frame, XCB_CW_EVENT_MASK, values);
00541 xcb_change_window_attributes(conn, con->window->id, XCB_CW_EVENT_MASK, values);
00542
00543 xcb_reparent_window(conn, con->window->id, con->frame, 0, 0);
00544
00545 values[0] = FRAME_EVENT_MASK;
00546 xcb_change_window_attributes(conn, state->old_frame, XCB_CW_EVENT_MASK, values);
00547 values[0] = CHILD_EVENT_MASK;
00548 xcb_change_window_attributes(conn, con->window->id, XCB_CW_EVENT_MASK, values);
00549
00550 state->old_frame = XCB_NONE;
00551 state->need_reparent = false;
00552
00553 con->ignore_unmap++;
00554 DLOG("ignore_unmap for reparenting of con %p (win 0x%08x) is now %d\n",
00555 con, con->window->id, con->ignore_unmap);
00556 }
00557
00558 bool fake_notify = false;
00559
00560 if (memcmp(&(state->rect), &rect, sizeof(Rect)) != 0 &&
00561 rect.height > 0) {
00562
00563
00564
00565
00566
00567
00568
00569
00570 if ((state->rect.width != rect.width ||
00571 state->rect.height != rect.height)) {
00572 DLOG("CACHE: creating new pixmap for con %p (old: %d x %d, new: %d x %d)\n",
00573 con, state->rect.width, state->rect.height,
00574 rect.width, rect.height);
00575 if (con->pixmap == 0) {
00576 con->pixmap = xcb_generate_id(conn);
00577 con->pm_gc = xcb_generate_id(conn);
00578 } else {
00579 xcb_free_pixmap(conn, con->pixmap);
00580 xcb_free_gc(conn, con->pm_gc);
00581 }
00582 xcb_create_pixmap(conn, root_depth, con->pixmap, con->frame, rect.width, rect.height);
00583
00584
00585
00586
00587
00588 uint32_t values[] = { 0 };
00589 xcb_create_gc(conn, con->pm_gc, con->pixmap, XCB_GC_GRAPHICS_EXPOSURES, values);
00590
00591 con->pixmap_recreated = true;
00592
00593
00594
00595 if (!con->parent ||
00596 con->parent->layout != L_STACKED ||
00597 TAILQ_FIRST(&(con->parent->focus_head)) == con)
00598
00599
00600
00601 x_deco_recurse(con);
00602 }
00603
00604 DLOG("setting rect (%d, %d, %d, %d)\n", rect.x, rect.y, rect.width, rect.height);
00605
00606
00607
00608
00609 xcb_flush(conn);
00610 xcb_set_window_rect(conn, con->frame, rect);
00611 if (con->pixmap != XCB_NONE)
00612 xcb_copy_area(conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
00613 xcb_flush(conn);
00614
00615 memcpy(&(state->rect), &rect, sizeof(Rect));
00616 fake_notify = true;
00617 }
00618
00619
00620 if (con->window != NULL &&
00621 memcmp(&(state->window_rect), &(con->window_rect), sizeof(Rect)) != 0) {
00622 DLOG("setting window rect (%d, %d, %d, %d)\n",
00623 con->window_rect.x, con->window_rect.y, con->window_rect.width, con->window_rect.height);
00624 xcb_set_window_rect(conn, con->window->id, con->window_rect);
00625 memcpy(&(state->window_rect), &(con->window_rect), sizeof(Rect));
00626 fake_notify = true;
00627 }
00628
00629
00630
00631
00632
00633 if ((state->mapped != con->mapped || (con->mapped && state->initial)) &&
00634 con->mapped) {
00635 xcb_void_cookie_t cookie;
00636
00637 if (con->window != NULL) {
00638
00639
00640 long data[] = { XCB_ICCCM_WM_STATE_NORMAL, XCB_NONE };
00641 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id,
00642 A_WM_STATE, A_WM_STATE, 32, 2, data);
00643 }
00644
00645 uint32_t values[1];
00646 if (!state->child_mapped && con->window != NULL) {
00647 cookie = xcb_map_window(conn, con->window->id);
00648
00649
00650
00651 values[0] = CHILD_EVENT_MASK;
00652 xcb_change_window_attributes(conn, con->window->id, XCB_CW_EVENT_MASK, values);
00653 DLOG("mapping child window (serial %d)\n", cookie.sequence);
00654 state->child_mapped = true;
00655 }
00656
00657 cookie = xcb_map_window(conn, con->frame);
00658
00659 values[0] = FRAME_EVENT_MASK;
00660 xcb_change_window_attributes(conn, con->frame, XCB_CW_EVENT_MASK, values);
00661
00662
00663 if (con->pixmap != XCB_NONE)
00664 xcb_copy_area(conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
00665 xcb_flush(conn);
00666
00667 DLOG("mapping container %08x (serial %d)\n", con->frame, cookie.sequence);
00668 state->mapped = con->mapped;
00669 }
00670
00671 state->unmap_now = (state->mapped != con->mapped) && !con->mapped;
00672
00673 if (fake_notify) {
00674 DLOG("Sending fake configure notify\n");
00675 fake_absolute_configure_notify(con);
00676 }
00677
00678
00679
00680
00681 TAILQ_FOREACH(current, &(con->focus_head), focused)
00682 x_push_node(current);
00683 }
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694 static void x_push_node_unmaps(Con *con) {
00695 Con *current;
00696 con_state *state;
00697
00698
00699 state = state_for_frame(con->frame);
00700
00701
00702
00703
00704 if (state->unmap_now) {
00705 xcb_void_cookie_t cookie;
00706 if (con->window != NULL) {
00707
00708 long data[] = { XCB_ICCCM_WM_STATE_WITHDRAWN, XCB_NONE };
00709 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id,
00710 A_WM_STATE, A_WM_STATE, 32, 2, data);
00711 }
00712
00713 cookie = xcb_unmap_window(conn, con->frame);
00714 DLOG("unmapping container (serial %d)\n", cookie.sequence);
00715
00716
00717
00718 if (con->window != NULL) {
00719 con->ignore_unmap++;
00720 DLOG("ignore_unmap for con %p (frame 0x%08x) now %d\n", con, con->frame, con->ignore_unmap);
00721 }
00722 state->mapped = con->mapped;
00723 }
00724
00725
00726 TAILQ_FOREACH(current, &(con->nodes_head), nodes)
00727 x_push_node_unmaps(current);
00728
00729 TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
00730 x_push_node_unmaps(current);
00731 }
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 void x_push_changes(Con *con) {
00745 con_state *state;
00746
00747 DLOG("-- PUSHING WINDOW STACK --\n");
00748
00749 uint32_t values[1] = { XCB_NONE };
00750 CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
00751 if (state->mapped)
00752 xcb_change_window_attributes(conn, state->id, XCB_CW_EVENT_MASK, values);
00753 }
00754
00755 bool order_changed = false;
00756
00757 CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
00758
00759 con_state *prev = CIRCLEQ_PREV(state, state);
00760 con_state *old_prev = CIRCLEQ_PREV(state, old_state);
00761 if (prev != old_prev)
00762 order_changed = true;
00763 if ((state->initial || order_changed) && prev != CIRCLEQ_END(&state_head)) {
00764 DLOG("Stacking 0x%08x above 0x%08x\n", prev->id, state->id);
00765 uint32_t mask = 0;
00766 mask |= XCB_CONFIG_WINDOW_SIBLING;
00767 mask |= XCB_CONFIG_WINDOW_STACK_MODE;
00768 uint32_t values[] = {state->id, XCB_STACK_MODE_ABOVE};
00769
00770 xcb_configure_window(conn, prev->id, mask, values);
00771 }
00772 state->initial = false;
00773 }
00774
00775 values[0] = FRAME_EVENT_MASK;
00776 CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
00777 if (state->mapped)
00778 xcb_change_window_attributes(conn, state->id, XCB_CW_EVENT_MASK, values);
00779 }
00780
00781
00782 DLOG("\n\n PUSHING CHANGES\n\n");
00783 x_push_node(con);
00784 x_deco_recurse(con);
00785
00786 xcb_window_t to_focus = focused->frame;
00787 if (focused->window != NULL)
00788 to_focus = focused->window->id;
00789
00790 DLOG("focused_id = 0x%08x, to_focus = 0x%08x\n", focused_id, to_focus);
00791 if (focused_id != to_focus) {
00792 if (!focused->mapped) {
00793 DLOG("Not updating focus (to %p / %s), focused window is not mapped.\n", focused, focused->name);
00794
00795 focused_id = XCB_NONE;
00796 } else {
00797 DLOG("Updating focus (focused: %p / %s)\n", focused, focused->name);
00798
00799
00800
00801 if (focused->window != NULL) {
00802 values[0] = CHILD_EVENT_MASK & ~(XCB_EVENT_MASK_FOCUS_CHANGE);
00803 xcb_change_window_attributes(conn, focused->window->id, XCB_CW_EVENT_MASK, values);
00804 }
00805 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, to_focus, XCB_CURRENT_TIME);
00806 if (focused->window != NULL) {
00807 values[0] = CHILD_EVENT_MASK;
00808 xcb_change_window_attributes(conn, focused->window->id, XCB_CW_EVENT_MASK, values);
00809 }
00810
00811 if (focused->window != NULL &&
00812 focused->window->needs_take_focus) {
00813 send_take_focus(to_focus);
00814 }
00815
00816 ewmh_update_active_window(to_focus);
00817 focused_id = to_focus;
00818 }
00819 }
00820
00821 if (focused_id == XCB_NONE) {
00822 DLOG("Still no window focused, better set focus to the root window\n");
00823 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, root, XCB_CURRENT_TIME);
00824 focused_id = root;
00825 }
00826
00827 xcb_flush(conn);
00828 DLOG("\n\n ENDING CHANGES\n\n");
00829
00830
00831
00832
00833
00834
00835
00836
00837 values[0] = FRAME_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW;
00838 CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
00839 if (!state->unmap_now)
00840 continue;
00841 xcb_change_window_attributes(conn, state->id, XCB_CW_EVENT_MASK, values);
00842 }
00843
00844
00845 x_push_node_unmaps(con);
00846
00847
00848 CIRCLEQ_FOREACH(state, &state_head, state) {
00849 CIRCLEQ_REMOVE(&old_state_head, state, old_state);
00850 CIRCLEQ_INSERT_TAIL(&old_state_head, state, old_state);
00851 }
00852
00853
00854
00855
00856 xcb_flush(conn);
00857 }
00858
00859
00860
00861
00862
00863
00864 void x_raise_con(Con *con) {
00865 con_state *state;
00866 state = state_for_frame(con->frame);
00867
00868
00869 CIRCLEQ_REMOVE(&state_head, state, state);
00870 CIRCLEQ_INSERT_HEAD(&state_head, state, state);
00871 }
00872
00873
00874
00875
00876
00877
00878
00879 void x_set_name(Con *con, const char *name) {
00880 struct con_state *state;
00881
00882 if ((state = state_for_frame(con->frame)) == NULL) {
00883 ELOG("window state not found\n");
00884 return;
00885 }
00886
00887 FREE(state->name);
00888 state->name = sstrdup(name);
00889 }
00890
00891
00892
00893
00894
00895 void x_set_i3_atoms() {
00896 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_SOCKET_PATH, A_UTF8_STRING, 8,
00897 (current_socketpath == NULL ? 0 : strlen(current_socketpath)),
00898 current_socketpath);
00899 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_CONFIG_PATH, A_UTF8_STRING, 8,
00900 strlen(current_configpath), current_configpath);
00901 }