/*
* Create a new container (and attach it to the given parent, if not NULL).
- * This function initializes the data structures and creates the appropriate
- * X11 IDs using x_con_init().
+ * This function only initializes the data structures.
*
*/
-Con *con_new(Con *parent, i3Window *window) {
+Con *con_new_skeleton(Con *parent, i3Window *window) {
Con *new = scalloc(sizeof(Con));
new->on_remove_child = con_on_remove_child;
TAILQ_INSERT_TAIL(&all_cons, new, all_cons);
+ new->aspect_ratio = 0.0;
new->type = CT_CON;
new->window = window;
new->border_style = config.default_border;
new->current_border_width = -1;
+ if (window)
+ new->depth = window->depth;
+ else
+ new->depth = XCB_COPY_FROM_PARENT;
static int cnt = 0;
DLOG("opening window %d\n", cnt);
cnt++;
if ((cnt % (sizeof(colors) / sizeof(char*))) == 0)
cnt = 0;
- if (window)
- x_con_init(new, window->depth);
- else
- x_con_init(new, XCB_COPY_FROM_PARENT);
TAILQ_INIT(&(new->floating_head));
TAILQ_INIT(&(new->nodes_head));
return new;
}
+/* A wrapper for con_new_skeleton, to retain the old con_new behaviour
+ *
+ */
+Con *con_new(Con *parent, i3Window *window) {
+ Con *new = con_new_skeleton(parent, window);
+ x_con_init(new, new->depth);
+ return new;
+}
+
/*
* Attaches the given container to the given parent. This happens when moving
* a container or when inserting a new container at a specific place in the
return TAILQ_EMPTY(&(con->nodes_head));
}
+/**
+ * Returns true if this node has regular or floating children.
+ *
+ */
+bool con_has_children(Con *con) {
+ return (!con_is_leaf(con) || !TAILQ_EMPTY(&(con->floating_head)));
+}
+
/*
* Returns true if a container should be considered split.
*
}
/*
- * Toggles fullscreen mode for the given container. Fullscreen mode will not be
- * entered when there already is a fullscreen container on this workspace.
+ * Toggles fullscreen mode for the given container. If there already is a
+ * fullscreen container on this workspace, fullscreen will be disabled and then
+ * enabled for the container the user wants to have in fullscreen mode.
*
*/
void con_toggle_fullscreen(Con *con, int fullscreen_mode) {
}
if (con->type == CT_WORKSPACE) {
- con = workspace_encapsulate(con);
- if (con == NULL) {
- ELOG("Workspace failed to move its contents into a container!\n");
- return;
- }
-
/* Re-parent all of the old workspace's floating windows. */
Con *child;
while (!TAILQ_EMPTY(&(source_ws->floating_head))) {
child = TAILQ_FIRST(&(source_ws->floating_head));
con_move_to_workspace(child, workspace, true, true);
}
+
+ /* If there are no non-floating children, ignore the workspace. */
+ if (con_is_leaf(con))
+ return;
+
+ con = workspace_encapsulate(con);
+ if (con == NULL) {
+ ELOG("Workspace failed to move its contents into a container!\n");
+ return;
+ }
}
/* Save the current workspace. So we can call workspace_show() by the end
con_focus(old_focus);
}
- /* 8: when moving to a visible workspace on a different output, we keep the
- * con focused. Otherwise, we leave the focus on the current workspace as we
- * don’t want to focus invisible workspaces */
- if (source_output != dest_output &&
- workspace_is_visible(workspace) &&
- !con_is_internal(workspace)) {
- DLOG("Moved to a different output, focusing target\n");
- } else {
- /* Descend focus stack in case focus_next is a workspace which can
- * occur if we move to the same workspace. Also show current workspace
- * to ensure it is focused. */
- workspace_show(current_ws);
-
- /* Set focus only if con was on current workspace before moving.
- * Otherwise we would give focus to some window on different workspace. */
- if (source_ws == current_ws)
+ /* 8: when moving to another workspace, we leave the focus on the current
+ * workspace. (see also #809) */
+
+ /* Descend focus stack in case focus_next is a workspace which can
+ * occur if we move to the same workspace. Also show current workspace
+ * to ensure it is focused. */
+ workspace_show(current_ws);
+
+ /* Set focus only if con was on current workspace before moving.
+ * Otherwise we would give focus to some window on different workspace. */
+ if (source_ws == current_ws)
con_focus(con_descend_focused(focus_next));
+
+ /* If anything within the container is associated with a startup sequence,
+ * delete it so child windows won't be created on the old workspace. */
+ struct Startup_Sequence *sequence;
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *startup_id_reply;
+
+ if (!con_is_leaf(con)) {
+ Con *child;
+ TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
+ if (!child->window)
+ continue;
+
+ cookie = xcb_get_property(conn, false, child->window->id,
+ A__NET_STARTUP_ID, XCB_GET_PROPERTY_TYPE_ANY, 0, 512);
+ startup_id_reply = xcb_get_property_reply(conn, cookie, NULL);
+
+ sequence = startup_sequence_get(child->window, startup_id_reply, true);
+ if (sequence != NULL)
+ startup_sequence_delete(sequence);
+ }
+ }
+
+ if (con->window) {
+ cookie = xcb_get_property(conn, false, con->window->id,
+ A__NET_STARTUP_ID, XCB_GET_PROPERTY_TYPE_ANY, 0, 512);
+ startup_id_reply = xcb_get_property_reply(conn, cookie, NULL);
+
+ sequence = startup_sequence_get(con->window, startup_id_reply, true);
+ if (sequence != NULL)
+ startup_sequence_delete(sequence);
}
CALL(parent, on_remove_child);
*/
Con *con_descend_direction(Con *con, direction_t direction) {
Con *most = NULL;
+ Con *current;
int orientation = con_orientation(con);
DLOG("con_descend_direction(%p, orientation %d, direction %d)\n", con, orientation, direction);
if (direction == D_LEFT || direction == D_RIGHT) {
/* Wrong orientation. We use the last focused con. Within that con,
* we recurse to chose the left/right con or at least the last
* focused one. */
- most = TAILQ_FIRST(&(con->focus_head));
+ TAILQ_FOREACH(current, &(con->focus_head), focused) {
+ if (current->type != CT_FLOATING_CON) {
+ most = current;
+ break;
+ }
+ }
} else {
/* If the con has no orientation set, it’s not a split container
* but a container with a client window, so stop recursing */
/* Wrong orientation. We use the last focused con. Within that con,
* we recurse to chose the top/bottom con or at least the last
* focused one. */
- most = TAILQ_FIRST(&(con->focus_head));
+ TAILQ_FOREACH(current, &(con->focus_head), focused) {
+ if (current->type != CT_FLOATING_CON) {
+ most = current;
+ break;
+ }
+ }
} else {
/* If the con has no orientation set, it’s not a split container
* but a container with a client window, so stop recursing */
} else {
result = (Rect){border_width, border_width, -(2 * border_width), -(2 * border_width)};
}
+
+ /* Floating windows are never adjacent to any other window, so
+ don’t hide their border(s). This prevents bug #998. */
+ if (con_is_floating(con))
+ return result;
+
if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) {
result.x -= border_width;
result.width += border_width;
con->current_border_width = border_width;
bsr = con_border_style_rect(con);
int deco_height =
- (con->border_style == BS_NORMAL ? config.font.height + 5 : 0);
+ (con->border_style == BS_NORMAL ? render_deco_height() : 0);
con->rect.x -= bsr.x;
con->rect.y -= bsr.y;
* new split container before).
*
*/
-void con_set_layout(Con *con, int layout) {
+void con_set_layout(Con *con, layout_t layout) {
DLOG("con_set_layout(%p, %d), con->type = %d\n",
con, layout, con->type);
* not be closed when the last child was removed */
if (con->type == CT_OUTPUT ||
con->type == CT_ROOT ||
- con->type == CT_DOCKAREA) {
- DLOG("not handling, type = %d\n", con->type);
+ con->type == CT_DOCKAREA ||
+ (con->parent != NULL && con->parent->type == CT_OUTPUT)) {
+ DLOG("not handling, type = %d, name = %s\n", con->type, con->name);
return;
}
}
con_force_split_parents_redraw(con);
+ con->urgent = con_has_urgent_child(con);
+ con_update_parents_urgency(con);
/* TODO: check if this container would swallow any other client and
* don’t close it automatically. */
}
}
+/*
+ * Set urgency flag to the container, all the parent containers and the workspace.
+ *
+ */
+void con_set_urgency(Con *con, bool urgent) {
+ if (focused == con) {
+ DLOG("Ignoring urgency flag for current client\n");
+ con->window->urgent.tv_sec = 0;
+ con->window->urgent.tv_usec = 0;
+ return;
+ }
+
+ if (con->urgency_timer == NULL) {
+ con->urgent = urgent;
+ } else
+ DLOG("Discarding urgency WM_HINT because timer is running\n");
+
+ //CLIENT_LOG(con);
+ if (con->window) {
+ if (con->urgent) {
+ gettimeofday(&con->window->urgent, NULL);
+ } else {
+ con->window->urgent.tv_sec = 0;
+ con->window->urgent.tv_usec = 0;
+ }
+ }
+
+ con_update_parents_urgency(con);
+
+ if (con->urgent == urgent)
+ LOG("Urgency flag changed to %d\n", con->urgent);
+
+ Con *ws;
+ /* Set the urgency flag on the workspace, if a workspace could be found
+ * (for dock clients, that is not the case). */
+ if ((ws = con_get_workspace(con)) != NULL)
+ workspace_update_urgent_flag(ws);
+}
+
/*
* Create a string representing the subtree under con.
*
buf = sstrdup("T[");
else if (con->layout == L_STACKED)
buf = sstrdup("S[");
+ else {
+ ELOG("BUG: Code not updated to account for new layout type\n");
+ assert(false);
+ }
/* 2) append representation of children */
Con *child;