+#undef I3__FILE__
+#define I3__FILE__ "con.c"
/*
* vim:ts=4:sw=4:expandtab
*
* 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)) {
+ workspace_is_visible(workspace) &&
+ workspace->name[0] != '_' &&
+ workspace->name[1] != '_') {
DLOG("Moved to a different output, focusing target\n");
} else {
/* Descend focus stack in case focus_next is a workspace which can
*
*/
Rect con_border_style_rect(Con *con) {
- switch (con_border_style(con)) {
+ adjacent_t borders_to_hide = ADJ_NONE;
+ Rect result;
+ /* Shortcut to avoid calling con_adjacent_borders() on dock containers. */
+ int border_style = con_border_style(con);
+ if (border_style == BS_NONE)
+ return (Rect){ 0, 0, 0, 0 };
+ borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders;
+ switch (border_style) {
case BS_NORMAL:
- return (Rect){2, 0, -(2 * 2), -2};
+ result = (Rect){2, 0, -(2 * 2), -2};
+ if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) {
+ result.x -= 2;
+ result.width += 2;
+ }
+ if (borders_to_hide & ADJ_RIGHT_SCREEN_EDGE) {
+ result.width += 2;
+ }
+ /* With normal borders we never hide the upper border */
+ if (borders_to_hide & ADJ_LOWER_SCREEN_EDGE) {
+ result.height += 2;
+ }
+ return result;
case BS_1PIXEL:
- return (Rect){1, 1, -2, -2};
+ result = (Rect){1, 1, -2, -2};
+ if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) {
+ result.x -= 1;
+ result.width += 1;
+ }
+ if (borders_to_hide & ADJ_RIGHT_SCREEN_EDGE) {
+ result.width += 1;
+ }
+ if (borders_to_hide & ADJ_UPPER_SCREEN_EDGE) {
+ result.y -= 1;
+ result.height += 1;
+ }
+ if (borders_to_hide & ADJ_LOWER_SCREEN_EDGE) {
+ result.height += 1;
+ }
+ return result;
case BS_NONE:
return (Rect){0, 0, 0, 0};
}
}
+/*
+ * Returns adjacent borders of the window. We need this if hide_edge_borders is
+ * enabled.
+ */
+adjacent_t con_adjacent_borders(Con *con) {
+ adjacent_t result = ADJ_NONE;
+ Con *workspace = con_get_workspace(con);
+ if (con->rect.x == workspace->rect.x)
+ result |= ADJ_LEFT_SCREEN_EDGE;
+ if (con->rect.x + con->rect.width == workspace->rect.x + workspace->rect.width)
+ result |= ADJ_RIGHT_SCREEN_EDGE;
+ if (con->rect.y == workspace->rect.y)
+ result |= ADJ_UPPER_SCREEN_EDGE;
+ if (con->rect.y + con->rect.height == workspace->rect.y + workspace->rect.height)
+ result |= ADJ_LOWER_SCREEN_EDGE;
+ return result;
+}
+
/*
* Use this function to get a container’s border style. This is important
* because when inside a stack, the border style is always BS_NORMAL.
*
*/
void con_set_layout(Con *con, int layout) {
+ DLOG("con_set_layout(%p, %d), con->type = %d\n",
+ con, layout, con->type);
+
+ /* Users can focus workspaces, but not any higher in the hierarchy.
+ * Focus on the workspace is a special case, since in every other case, the
+ * user means "change the layout of the parent split container". */
+ if (con->type != CT_WORKSPACE)
+ con = con->parent;
+
+ /* We fill in last_split_layout when switching to a different layout
+ * since there are many places in the code that don’t use
+ * con_set_layout(). */
+ if (con->layout == L_SPLITH || con->layout == L_SPLITV)
+ con->last_split_layout = con->layout;
+
/* When the container type is CT_WORKSPACE, the user wants to change the
* whole workspace into stacked/tabbed mode. To do this and still allow
* intuitive operations (like level-up and then opening a new window), we
* need to create a new split container. */
- if (con->type == CT_WORKSPACE) {
+ if (con->type == CT_WORKSPACE &&
+ (layout == L_STACKED || layout == L_TABBED)) {
DLOG("Creating new split container\n");
/* 1: create a new split container */
Con *new = con_new(NULL, NULL);
/* 2: Set the requested layout on the split container and mark it as
* split. */
- con_set_layout(new, layout);
+ new->layout = layout;
+ new->last_split_layout = con->last_split_layout;
new->split = true;
Con *old_focused = TAILQ_FIRST(&(con->focus_head));
if (con->layout == L_DEFAULT)
con->layout = L_SPLITH;
} else {
- /* We fill in last_split_layout when switching to a different layout
- * since there are many places in the code that don’t use
- * con_set_layout(). */
- if (con->layout == L_SPLITH || con->layout == L_SPLITV)
- con->last_split_layout = con->layout;
con->layout = layout;
}
}
*
*/
void con_toggle_layout(Con *con, const char *toggle_mode) {
+ Con *parent = con;
+ /* Users can focus workspaces, but not any higher in the hierarchy.
+ * Focus on the workspace is a special case, since in every other case, the
+ * user means "change the layout of the parent split container". */
+ if (con->type != CT_WORKSPACE)
+ parent = con->parent;
+ DLOG("con_toggle_layout(%p, %s), parent = %p\n", con, toggle_mode, parent);
+
if (strcmp(toggle_mode, "split") == 0) {
/* Toggle between splits. When the current layout is not a split
* layout, we just switch back to last_split_layout. Otherwise, we
* change to the opposite split layout. */
- if (con->layout != L_SPLITH && con->layout != L_SPLITV)
- con_set_layout(con, con->last_split_layout);
+ if (parent->layout != L_SPLITH && parent->layout != L_SPLITV)
+ con_set_layout(con, parent->last_split_layout);
else {
- if (con->layout == L_SPLITH)
+ if (parent->layout == L_SPLITH)
con_set_layout(con, L_SPLITV);
else con_set_layout(con, L_SPLITH);
}
} else {
- if (con->layout == L_STACKED)
+ if (parent->layout == L_STACKED)
con_set_layout(con, L_TABBED);
- else if (con->layout == L_TABBED) {
+ else if (parent->layout == L_TABBED) {
if (strcmp(toggle_mode, "all") == 0)
con_set_layout(con, L_SPLITH);
- else con_set_layout(con, con->last_split_layout);
- } else if (con->layout == L_SPLITH || con->layout == L_SPLITV) {
+ else con_set_layout(con, parent->last_split_layout);
+ } else if (parent->layout == L_SPLITH || parent->layout == L_SPLITV) {
if (strcmp(toggle_mode, "all") == 0) {
/* When toggling through all modes, we toggle between
* splith/splitv, whereas normally we just directly jump to
* stacked. */
- if (con->layout == L_SPLITH)
+ if (parent->layout == L_SPLITH)
con_set_layout(con, L_SPLITV);
else con_set_layout(con, L_STACKED);
} else {
while (fs && fs->fullscreen_mode == CF_NONE)
fs = fs->parent;
+ /* fs must be non-NULL since the workspace con doesn’t have CF_NONE and
+ * there always has to be a workspace con in the hierarchy. */
+ assert(fs != NULL);
/* The most common case is we hit the workspace level. In this
* situation, changing focus is also harmless. */
assert(fs->fullscreen_mode != CF_NONE);