/*
* vim:ts=4:sw=4:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
+ *
+ * x.c: Interface to X11, transfers our in-memory state to X11 (see also
+ * render.c). Basically a big state machine.
+ *
*/
-
#include "all.h"
/* Stores the X11 window ID of the currently focused window */
static xcb_window_t *btt_stack;
static int btt_stack_num;
+/* Stores coordinates to warp mouse pointer to if set */
+static Rect *warp_to;
+
/*
* Describes the X11 state we may modify (map state, position, window stack).
* There is one entry per container. The state represents the current situation
*/
void x_draw_decoration(Con *con) {
Con *parent = con->parent;
+ bool leaf = con_is_leaf(con);
/* This code needs to run for:
* • leaf containers
* • non-leaf containers which are in a stacked/tabbed container
* It does not need to run for:
* • floating containers (they don’t have a decoration)
*/
- if ((!con_is_leaf(con) &&
+ if ((!leaf &&
parent->layout != L_STACKED &&
parent->layout != L_TABBED) ||
con->type == CT_FLOATING_CON)
return;
- DLOG("decoration should be rendered for con %p\n", con);
/* Skip containers whose height is 0 (for example empty dockareas) */
- if (con->rect.height == 0) {
- DLOG("height == 0, not rendering\n");
+ if (con->rect.height == 0)
return;
- }
/* Skip containers whose pixmap has not yet been created (can happen when
* decoration rendering happens recursively for a window for which
* x_push_node() was not yet called) */
- if (con->pixmap == XCB_NONE) {
- DLOG("pixmap not yet created, not rendering\n");
+ if (leaf && con->pixmap == XCB_NONE)
return;
- }
/* 1: build deco_params and compare with cache */
struct deco_render_params *p = scalloc(sizeof(struct deco_render_params));
/* find out which colors to use */
if (con->urgent)
p->color = &config.client.urgent;
- else if (con == focused)
+ else if (con == focused || con_inside_focused(con))
p->color = &config.client.focused;
else if (con == TAILQ_FIRST(&(parent->focus_head)))
p->color = &config.client.focused_inactive;
!parent->pixmap_recreated &&
!con->pixmap_recreated &&
memcmp(p, con->deco_render_params, sizeof(struct deco_render_params)) == 0) {
- DLOG("CACHE HIT, copying existing pixmaps\n");
free(p);
goto copy_pixmaps;
}
- DLOG("CACHE MISS\n");
Con *next = con;
while ((next = TAILQ_NEXT(next, nodes))) {
- DLOG("Also invalidating cache of %p\n", next);
FREE(next->deco_render_params);
}
/* if this is a borderless/1pixel window, we don’t * need to render the
* decoration. */
- if (p->border_style != BS_NORMAL) {
- DLOG("border style not BS_NORMAL, aborting rendering of decoration\n");
+ if (p->border_style != BS_NORMAL)
goto copy_pixmaps;
- }
/* 4: paint the bar */
xcb_change_gc_single(conn, parent->pm_gc, XCB_GC_FOREGROUND, p->color->background);
Con *il_parent = parent;
if (il_parent->layout != L_STACKED) {
while (1) {
- DLOG("il_parent = %p, layout = %d\n", il_parent, il_parent->layout);
+ //DLOG("il_parent = %p, layout = %d\n", il_parent, il_parent->layout);
if (il_parent->layout == L_STACKED)
indent_level++;
if (il_parent->type == CT_WORKSPACE || il_parent->type == CT_DOCKAREA || il_parent->type == CT_OUTPUT)
indent_mult++;
}
}
- DLOG("indent_level = %d, indent_mult = %d\n", indent_level, indent_mult);
+ //DLOG("indent_level = %d, indent_mult = %d\n", indent_level, indent_mult);
int indent_px = (indent_level * 5) * indent_mult;
if (win->uses_net_wm_name)
}
if ((con->type != CT_ROOT && con->type != CT_OUTPUT) &&
- con->mapped)
+ (!leaf || con->mapped))
x_draw_decoration(con);
}
DLOG("pushing name %s for con %p\n", state->name, con);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->frame,
- A_WM_NAME, A_STRING, 8, strlen(state->name), state->name);
+ XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, strlen(state->name), state->name);
FREE(state->name);
}
}
}
rect.height = max_y + max_height;
- if (rect.height == 0) {
- DLOG("Unmapping container %p because it does not contain anything.\n", con);
+ if (rect.height == 0)
con->mapped = false;
- }
}
/* reparent the child window (when the window was moved due to a sticky
* (height == 0). */
if ((state->rect.width != rect.width ||
state->rect.height != rect.height)) {
- DLOG("CACHE: creating new pixmap for con %p (old: %d x %d, new: %d x %d)\n",
- con, state->rect.width, state->rect.height,
- rect.width, rect.height);
if (con->pixmap == 0) {
con->pixmap = xcb_generate_id(conn);
con->pm_gc = xcb_generate_id(conn);
*/
void x_push_changes(Con *con) {
con_state *state;
+ xcb_query_pointer_cookie_t pointercookie;
+
+ /* If we need to warp later, we request the pointer position as soon as possible */
+ if (warp_to) {
+ pointercookie = xcb_query_pointer(conn, root);
+ }
DLOG("-- PUSHING WINDOW STACK --\n");
//DLOG("Disabling EnterNotify\n");
order_changed = true;
if ((state->initial || order_changed) && prev != CIRCLEQ_END(&state_head)) {
stacking_changed = true;
- DLOG("Stacking 0x%08x above 0x%08x\n", prev->id, state->id);
+ //DLOG("Stacking 0x%08x above 0x%08x\n", prev->id, state->id);
uint32_t mask = 0;
mask |= XCB_CONFIG_WINDOW_SIBLING;
mask |= XCB_CONFIG_WINDOW_STACK_MODE;
if (stacking_changed)
ewmh_update_client_list_stacking(btt_stack, btt_stack_num);
+ DLOG("PUSHING CHANGES\n");
+ x_push_node(con);
+
//DLOG("Re-enabling EnterNotify\n");
values[0] = FRAME_EVENT_MASK;
CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
}
//DLOG("Done, EnterNotify re-enabled\n");
- DLOG("\n\n PUSHING CHANGES\n\n");
- x_push_node(con);
x_deco_recurse(con);
xcb_window_t to_focus = focused->frame;
if (focused->window != NULL)
to_focus = focused->window->id;
- DLOG("focused_id = 0x%08x, to_focus = 0x%08x\n", focused_id, to_focus);
if (focused_id != to_focus) {
if (!focused->mapped) {
DLOG("Not updating focus (to %p / %s), focused window is not mapped.\n", focused, focused->name);
focused_id = root;
}
+ if (warp_to) {
+ xcb_query_pointer_reply_t *pointerreply = xcb_query_pointer_reply(conn, pointercookie, NULL);
+ if (!pointerreply) {
+ ELOG("Could not query pointer position, not warping pointer\n");
+ } else {
+ int mid_x = warp_to->x + (warp_to->width / 2);
+ int mid_y = warp_to->y + (warp_to->height / 2);
+
+ Output *current = get_output_containing(pointerreply->root_x, pointerreply->root_y);
+ Output *target = get_output_containing(mid_x, mid_y);
+ if (current != target)
+ xcb_warp_pointer(conn, XCB_NONE, root, 0, 0, 0, 0, mid_x, mid_y);
+ }
+ warp_to = NULL;
+ }
+
xcb_flush(conn);
- DLOG("\n\n ENDING CHANGES\n\n");
+ DLOG("ENDING CHANGES\n");
/* Disable EnterWindow events for windows which will be unmapped in
* x_push_node_unmaps() now. Unmapping windows happens when switching
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A_I3_CONFIG_PATH, A_UTF8_STRING, 8,
strlen(current_configpath), current_configpath);
}
+
+/*
+ * Set warp_to coordinates. This will trigger on the next call to
+ * x_push_changes().
+ *
+ */
+void x_set_warp_to(Rect *rect)
+{
+ warp_to = rect;
+}