aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/border.h5
-rw-r--r--include/container.h19
-rw-r--r--include/layout.h6
-rw-r--r--sway/border.c131
-rw-r--r--sway/commands.c5
-rw-r--r--sway/container.c24
-rw-r--r--sway/focus.c5
-rw-r--r--sway/layout.c115
8 files changed, 233 insertions, 77 deletions
diff --git a/include/border.h b/include/border.h
index 85c656e0..c99c02ea 100644
--- a/include/border.h
+++ b/include/border.h
@@ -3,6 +3,11 @@
#include <wlc/wlc.h>
#include "container.h"
+struct border {
+ unsigned char *buffer;
+ struct wlc_geometry geometry;
+};
+
void render_view_borders(wlc_handle view);
void update_view_border(swayc_t *view);
void map_update_view_border(swayc_t *view, void *data);
diff --git a/include/container.h b/include/container.h
index 29d4ea12..ae57d1e3 100644
--- a/include/container.h
+++ b/include/container.h
@@ -2,9 +2,12 @@
#define _SWAY_CONTAINER_H
#include <sys/types.h>
#include <wlc/wlc.h>
+
+#include "list.h"
+
typedef struct sway_container swayc_t;
-#include "layout.h"
+extern swayc_t root_container;
/**
* Different kinds of containers.
@@ -76,6 +79,12 @@ struct sway_container {
double x, y;
/**
+ * Cached geometry used to store view/container geometry when switching
+ * between tabbed/stacked and horizontal/vertical layouts.
+ */
+ struct wlc_geometry cached_geometry;
+
+ /**
* False if this view is invisible. It could be in the scratchpad or on a
* workspace that is not shown.
*/
@@ -120,7 +129,7 @@ struct sway_container {
* If this container is a view, this may be set to the window's decoration
* buffer (or NULL).
*/
- unsigned char *border;
+ struct border *border;
enum swayc_border_types border_type;
struct wlc_geometry border_geometry;
struct wlc_geometry title_bar_geometry;
@@ -248,6 +257,12 @@ bool swayc_is_child_of(swayc_t *child, swayc_t *parent);
bool swayc_is_tabbed_stacked(swayc_t *view);
/**
+ * Returns the top most tabbed or stacked parent container. Returns NULL if
+ * view is not in a tabbed/stacked layout.
+ */
+swayc_t *swayc_tabbed_stacked_parent(swayc_t *view);
+
+/**
* Returns the gap (padding) of the container.
*
* This returns the inner gaps for a view, the outer gaps for a workspace, and
diff --git a/include/layout.h b/include/layout.h
index 84552754..c05e9e69 100644
--- a/include/layout.h
+++ b/include/layout.h
@@ -7,8 +7,6 @@
#include "container.h"
#include "focus.h"
-extern swayc_t root_container;
-
extern list_t *scratchpad;
extern int min_sane_w;
@@ -55,6 +53,10 @@ void move_container_to(swayc_t* container, swayc_t* destination);
void move_workspace_to(swayc_t* workspace, swayc_t* destination);
// Layout
+/**
+ * Update child container geometries when switching between layouts.
+ */
+void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout);
void update_geometry(swayc_t *view);
void arrange_windows(swayc_t *container, double width, double height);
diff --git a/sway/border.c b/sway/border.c
index 2eefbbf5..cc329b6a 100644
--- a/sway/border.c
+++ b/sway/border.c
@@ -20,28 +20,31 @@ void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
(color >> (3*8) & 0xFF) / 255.0);
}
-static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry geo, cairo_surface_t **surface) {
+static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry g, cairo_surface_t **surface) {
+ if (view->border == NULL) {
+ view->border = malloc(sizeof(struct border));
+ }
cairo_t *cr;
- view->border_geometry = geo;
- int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, geo.size.w);
- view->border = calloc(stride * geo.size.h, sizeof(unsigned char));
- if (!view->border) {
+ int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, g.size.w);
+ view->border->buffer = calloc(stride * g.size.h, sizeof(unsigned char));
+ view->border->geometry = g;
+ if (!view->border->buffer) {
sway_log(L_DEBUG, "Unable to allocate buffer");
return NULL;
}
- *surface = cairo_image_surface_create_for_data(view->border,
- CAIRO_FORMAT_ARGB32, geo.size.w, geo.size.h, stride);
+ *surface = cairo_image_surface_create_for_data(view->border->buffer,
+ CAIRO_FORMAT_ARGB32, g.size.w, g.size.h, stride);
if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) {
free(view->border);
- view->border = NULL;
+ view->border->buffer = NULL;
sway_log(L_DEBUG, "Unable to allocate surface");
return NULL;
}
cr = cairo_create(*surface);
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy(*surface);
- free(view->border);
- view->border = NULL;
+ free(view->border->buffer);
+ view->border->buffer = NULL;
sway_log(L_DEBUG, "Unable to create cairo context");
return NULL;
}
@@ -92,15 +95,19 @@ int get_font_text_height(const char *font) {
}
static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors, bool top) {
+ struct wlc_geometry *g = &view->border->geometry;
struct wlc_geometry *b = &view->border_geometry;
struct wlc_geometry *v = &view->actual_geometry;
+ int x = b->origin.x - g->origin.x;
+ int y = b->origin.y - g->origin.y;
+
// left border
int left_border = v->origin.x - b->origin.x;
if (left_border > 0) {
render_sharp_line(cr,
colors->child_border,
- 0, 0,
+ x, y,
left_border,
b->size.h);
}
@@ -110,8 +117,8 @@ static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *col
if (right_border > 0) {
render_sharp_line(cr,
colors->child_border,
- b->size.w - right_border,
- 0,
+ x + b->size.w - right_border,
+ y,
right_border,
b->size.h);
}
@@ -121,7 +128,7 @@ static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *col
if (top && top_border > 0) {
render_sharp_line(cr,
colors->child_border,
- 0, 0,
+ x, y,
b->size.w,
top_border);
}
@@ -131,16 +138,15 @@ static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *col
if (bottom_border > 0) {
render_sharp_line(cr,
colors->child_border,
- 0,
- b->size.h - bottom_border,
+ x,
+ y + b->size.h - bottom_border,
b->size.w,
bottom_border);
}
}
-static void render_title_bar(swayc_t *view, cairo_t *cr, struct border_colors *colors) {
+static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, struct border_colors *colors) {
struct wlc_geometry *tb = &view->title_bar_geometry;
- struct wlc_geometry *b = &view->border_geometry;
int x = MIN(tb->origin.x, tb->origin.x - b->origin.x);
int y = MIN(tb->origin.y, tb->origin.y - b->origin.y);
@@ -197,6 +203,34 @@ void map_update_view_border(swayc_t *view, void *data) {
}
}
+void update_tabbed_stacked_titlebars(swayc_t *c, cairo_t *cr, struct wlc_geometry *g, swayc_t *focused, swayc_t *focused_inactive) {
+ if (c->type == C_CONTAINER) {
+ if (c->parent->focused == c) {
+ render_title_bar(c, cr, g, &config->border_colors.focused_inactive);
+ } else {
+ render_title_bar(c, cr, g, &config->border_colors.unfocused);
+ }
+
+ if (!c->visible) {
+ return;
+ }
+
+ int i;
+ for (i = 0; i < c->children->length; ++i) {
+ swayc_t *child = c->children->items[i];
+ update_tabbed_stacked_titlebars(child, cr, g, focused, focused_inactive);
+ }
+ } else {
+ if (focused == c) {
+ render_title_bar(c, cr, g, &config->border_colors.focused);
+ } else if (focused_inactive == c) {
+ render_title_bar(c, cr, g, &config->border_colors.focused_inactive);
+ } else {
+ render_title_bar(c, cr, g, &config->border_colors.unfocused);
+ }
+ }
+}
+
void update_view_border(swayc_t *view) {
if (!view->visible) {
return;
@@ -205,12 +239,12 @@ void update_view_border(swayc_t *view) {
cairo_t *cr = NULL;
cairo_surface_t *surface = NULL;
- if (view->border) {
- free(view->border);
- view->border = NULL;
+ if (view->border && view->border->buffer) {
+ free(view->border->buffer);
+ view->border->buffer = NULL;
}
- // get focused and focused_intactive views
+ // get focused and focused_inactive views
swayc_t *focused = get_focused_view(&root_container);
swayc_t *container = swayc_parent_by_type(view, C_CONTAINER);
swayc_t *focused_inactive = NULL;
@@ -223,30 +257,27 @@ void update_view_border(swayc_t *view) {
}
}
- swayc_t *p = view->parent;
-
- if (swayc_is_tabbed_stacked(view)) {
- cr = create_border_buffer(view, view->border_geometry, &surface);
- if (focused == view) {
+ // for tabbed/stacked layouts the focused view has to draw all the
+ // titlebars of the hidden views.
+ swayc_t *p = swayc_tabbed_stacked_parent(view);
+ if (p && view->parent->focused == view) {
+ struct wlc_geometry g = {
+ .origin = {
+ .x = p->x,
+ .y = p->y
+ },
+ .size = {
+ .w = p->width,
+ .h = p->height
+ }
+ };
+ cr = create_border_buffer(view, g, &surface);
+ if (view == focused) {
render_borders(view, cr, &config->border_colors.focused, false);
- } else if (focused_inactive == view) {
- render_borders(view, cr, &config->border_colors.focused_inactive, false);
} else {
- render_borders(view, cr, &config->border_colors.unfocused, false);
- }
-
- int i;
- for (i = 0; i < p->children->length; ++i) {
- swayc_t *child = p->children->items[i];
-
- if (focused == child) {
- render_title_bar(child, cr, &config->border_colors.focused);
- } else if (focused_inactive == child) {
- render_title_bar(child, cr, &config->border_colors.focused_inactive);
- } else {
- render_title_bar(child, cr, &config->border_colors.unfocused);
- }
+ render_borders(view, cr, &config->border_colors.focused_inactive, false);
}
+ update_tabbed_stacked_titlebars(p, cr, &g, focused, focused_inactive);
} else {
switch (view->border_type) {
case B_NONE:
@@ -274,13 +305,16 @@ void update_view_border(swayc_t *view) {
if (focused == view) {
render_borders(view, cr, &config->border_colors.focused, false);
- render_title_bar(view, cr, &config->border_colors.focused);
+ render_title_bar(view, cr, &view->border_geometry,
+ &config->border_colors.focused);
} else if (focused_inactive == view) {
render_borders(view, cr, &config->border_colors.focused_inactive, false);
- render_title_bar(view, cr, &config->border_colors.focused_inactive);
+ render_title_bar(view, cr, &view->border_geometry,
+ &config->border_colors.focused_inactive);
} else {
render_borders(view, cr, &config->border_colors.unfocused, false);
- render_title_bar(view, cr, &config->border_colors.unfocused);
+ render_title_bar(view, cr, &view->border_geometry,
+ &config->border_colors.unfocused);
}
break;
@@ -291,6 +325,7 @@ void update_view_border(swayc_t *view) {
cairo_surface_flush(surface);
cairo_surface_destroy(surface);
}
+
if (cr) {
cairo_destroy(cr);
}
@@ -316,7 +351,7 @@ void render_view_borders(wlc_handle view) {
}
}
- if (c->border) {
- wlc_pixels_write(WLC_RGBA8888, &c->border_geometry, c->border);
+ if (c->border && c->border->buffer) {
+ wlc_pixels_write(WLC_RGBA8888, &c->border->geometry, c->border->buffer);
}
}
diff --git a/sway/commands.c b/sway/commands.c
index ad5416f7..ff1ddc5b 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -1759,6 +1759,8 @@ static struct cmd_results *cmd_layout(int argc, char **argv) {
parent = parent->parent;
}
+ enum swayc_layouts old_layout = parent->layout;
+
if (strcasecmp(argv[0], "default") == 0) {
parent->layout = parent->prev_layout;
if (parent->layout == L_NONE) {
@@ -1795,6 +1797,8 @@ static struct cmd_results *cmd_layout(int argc, char **argv) {
}
}
+ update_layout_geometry(parent, old_layout);
+
arrange_windows(parent, parent->width, parent->height);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
@@ -2032,6 +2036,7 @@ static struct cmd_results *_do_split(int argc, char **argv, int layout) {
/* regular case where new split container is build around focused container
* or in case of workspace, container inherits its children */
sway_log(L_DEBUG, "Adding new container around current focused container");
+ sway_log(L_INFO, "FOCUSED SIZE: %.f %.f", focused->width, focused->height);
swayc_t *parent = new_container(focused, layout);
set_focused_container(focused);
arrange_windows(parent, -1, -1);
diff --git a/sway/container.c b/sway/container.c
index 42f6a69a..f4258c84 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -8,6 +8,7 @@
#include "container.h"
#include "workspace.h"
#include "focus.h"
+#include "border.h"
#include "layout.h"
#include "input_state.h"
#include "log.h"
@@ -64,7 +65,12 @@ static void free_swayc(swayc_t *cont) {
if (cont->bg_pid != 0) {
terminate_swaybg(cont->bg_pid);
}
- free(cont->border);
+ if (cont->border) {
+ if (cont->border->buffer) {
+ free(cont->border->buffer);
+ }
+ free(cont->border);
+ }
free(cont);
}
@@ -211,6 +217,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
cont->x = child->x;
cont->y = child->y;
cont->visible = child->visible;
+ cont->cached_geometry = child->cached_geometry;
/* Container inherits all of workspaces children, layout and whatnot */
if (child->type == C_WORKSPACE) {
@@ -812,3 +819,18 @@ bool swayc_is_tabbed_stacked(swayc_t *view) {
return (view->parent->layout == L_TABBED
|| view->parent->layout == L_STACKED);
}
+
+swayc_t *swayc_tabbed_stacked_parent(swayc_t *view) {
+ swayc_t *parent = NULL;
+ if (!ASSERT_NONNULL(view)) {
+ return NULL;
+ }
+ do {
+ view = view->parent;
+ if (view->layout == L_TABBED || view->layout == L_STACKED) {
+ parent = view;
+ }
+ } while (view && view->type != C_WORKSPACE);
+
+ return parent;
+}
diff --git a/sway/focus.c b/sway/focus.c
index 8ce22456..b4dfc423 100644
--- a/sway/focus.c
+++ b/sway/focus.c
@@ -149,8 +149,9 @@ bool set_focused_container(swayc_t *c) {
}
// rearrange if parent container is tabbed/stacked
- if (swayc_is_tabbed_stacked(p)) {
- arrange_windows(p->parent, -1, -1);
+ swayc_t *parent = swayc_tabbed_stacked_parent(p);
+ if (parent != NULL) {
+ arrange_windows(parent, -1, -1);
}
} else if (p->type == C_WORKSPACE) {
// remove previous focus if view_focus is unlocked
diff --git a/sway/layout.c b/sway/layout.c
index 65ca2402..801f6f6b 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -3,7 +3,6 @@
#include <math.h>
#include <wlc/wlc.h>
#include "extensions.h"
-#include "layout.h"
#include "log.h"
#include "list.h"
#include "config.h"
@@ -13,6 +12,7 @@
#include "output.h"
#include "ipc-server.h"
#include "border.h"
+#include "layout.h"
swayc_t root_container;
list_t *scratchpad;
@@ -442,12 +442,49 @@ static void update_border_geometry_floating(swayc_t *c, struct wlc_geometry *geo
update_view_border(c);
}
+void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout) {
+ switch (parent->layout) {
+ case L_TABBED:
+ case L_STACKED:
+ if (prev_layout != L_TABBED && prev_layout != L_STACKED) {
+ // cache current geometry for all non-float children
+ int i;
+ for (i = 0; i < parent->children->length; ++i) {
+ swayc_t *child = parent->children->items[i];
+ child->cached_geometry.origin.x = child->x;
+ child->cached_geometry.origin.y = child->y;
+ child->cached_geometry.size.w = child->width;
+ child->cached_geometry.size.h = child->height;
+ }
+ }
+ break;
+ default:
+ if (prev_layout == L_TABBED || prev_layout == L_STACKED) {
+ // recover cached geometry for all non-float children
+ int i;
+ for (i = 0; i < parent->children->length; ++i) {
+ swayc_t *child = parent->children->items[i];
+ // only recoverer cached geometry if non-zero
+ if (!wlc_geometry_equals(&child->cached_geometry, &wlc_geometry_zero)) {
+ child->x = child->cached_geometry.origin.x;
+ child->y = child->cached_geometry.origin.y;
+ child->width = child->cached_geometry.size.w;
+ child->height = child->cached_geometry.size.h;
+ }
+ }
+ }
+ break;
+ }
+}
+
void update_geometry(swayc_t *container) {
- if (container->type != C_VIEW) {
+ if (container->type != C_VIEW && container->type != C_CONTAINER) {
return;
}
+
swayc_t *ws = swayc_parent_by_type(container, C_WORKSPACE);
swayc_t *op = ws->parent;
+ swayc_t *parent = container->parent;
int gap = container->is_floating ? 0 : swayc_gap(container);
if (gap % 2 != 0) {
// because gaps are implemented as "half sized margins" it's currently
@@ -455,24 +492,14 @@ void update_geometry(swayc_t *container) {
gap -= 1;
}
- int width = container->width;
- int height = container->height;
-
- // use parent size if window is in a stacked/tabbed layout
- swayc_t *parent = container->parent;
- if (swayc_is_tabbed_stacked(container)) {
- width = parent->width;
- height = parent->height;
- }
-
struct wlc_geometry geometry = {
.origin = {
.x = container->x + gap/2 < op->width ? container->x + gap/2 : op->width-1,
.y = container->y + gap/2 < op->height ? container->y + gap/2 : op->height-1
},
.size = {
- .w = width > gap ? width - gap : 1,
- .h = height > gap ? height - gap : 1,
+ .w = container->width > gap ? container->width - gap : 1,
+ .h = container->height > gap ? container->height - gap : 1,
}
};
if (swayc_is_fullscreen(container)) {
@@ -492,16 +519,16 @@ void update_geometry(swayc_t *container) {
// with gap, and align correctly).
if (container->x - gap <= ws->x) {
geometry.origin.x = ws->x;
- geometry.size.w = width - gap/2;
+ geometry.size.w = container->width - gap/2;
}
if (container->y - gap <= ws->y) {
geometry.origin.y = ws->y;
- geometry.size.h = height - gap/2;
+ geometry.size.h = container->height - gap/2;
}
- if (container->x + width + gap >= ws->x + ws->width) {
+ if (container->x + container->width + gap >= ws->x + ws->width) {
geometry.size.w = ws->x + ws->width - geometry.origin.x;
}
- if (container->y + height + gap >= ws->y + ws->height) {
+ if (container->y + container->height + gap >= ws->y + ws->height) {
geometry.size.h = ws->y + ws->height - geometry.origin.y;
}
}
@@ -637,10 +664,14 @@ void update_geometry(swayc_t *container) {
container->actual_geometry = geometry;
- update_view_border(container);
+ if (container->type == C_VIEW) {
+ update_view_border(container);
+ }
}
- wlc_view_set_geometry(container->handle, 0, &geometry);
+ if (container->type == C_VIEW) {
+ wlc_view_set_geometry(container->handle, 0, &geometry);
+ }
}
static void arrange_windows_r(swayc_t *container, double width, double height) {
@@ -736,6 +767,22 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
container->height = height;
x = container->x;
y = container->y;
+
+ // update container size if it's a child in a tabbed/stacked layout
+ if (swayc_is_tabbed_stacked(container)) {
+ // Use parent geometry as a base for calculating
+ // container geometry
+ container->width = container->parent->width;
+ container->height = container->parent->height;
+ container->x = container->parent->x;
+ container->y = container->parent->y;
+ update_geometry(container);
+ width = container->width = container->actual_geometry.size.w;
+ height = container->height = container->actual_geometry.size.h;
+ x = container->x = container->actual_geometry.origin.x;
+ y = container->y = container->actual_geometry.origin.y;
+ }
+
break;
}
@@ -760,11 +807,17 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
if (scale > 0.1) {
scale = width / scale;
sway_log(L_DEBUG, "Arranging %p horizontally", container);
+ swayc_t *focused = NULL;
for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i];
sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale);
child->x = x;
child->y = y;
+
+ if (child == container->focused) {
+ focused = child;
+ }
+
if (i == container->children->length - 1) {
double remaining_width = container->x + width - x;
arrange_windows_r(child, remaining_width, height);
@@ -773,6 +826,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
}
x += child->width;
}
+
+ // update focused view border last because it may
+ // depend on the title bar geometry of its siblings.
+ if (focused && container->children->length > 1) {
+ update_view_border(focused);
+ }
}
break;
case L_VERT:
@@ -792,11 +851,17 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
if (scale > 0.1) {
scale = height / scale;
sway_log(L_DEBUG, "Arranging %p vertically", container);
+ swayc_t *focused = NULL;
for (i = 0; i < container->children->length; ++i) {
swayc_t *child = container->children->items[i];
sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, height, scale);
child->x = x;
child->y = y;
+
+ if (child == container->focused) {
+ focused = child;
+ }
+
if (i == container->children->length - 1) {
double remaining_height = container->y + height - y;
arrange_windows_r(child, width, remaining_height);
@@ -805,6 +870,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
}
y += child->height;
}
+
+ // update focused view border last because it may
+ // depend on the title bar geometry of its siblings.
+ if (focused && container->children->length > 1) {
+ update_view_border(focused);
+ }
}
break;
case L_TABBED:
@@ -818,12 +889,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
if (child == container->focused) {
focused = child;
} else {
- arrange_windows_r(child, -1, -1);
+ arrange_windows_r(child, width, height);
}
}
if (focused) {
- arrange_windows_r(focused, -1, -1);
+ arrange_windows_r(focused, width, height);
}
break;
}