summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Mikkel Oscar Lyderik <mikkeloscar@gmail.com>2016-04-20 00:22:15 +0200
committerLibravatar Mikkel Oscar Lyderik <mikkeloscar@gmail.com>2016-04-25 00:00:49 +0200
commit3e1f78ab26e8bc6b6cefd53ee137e97533c2695e (patch)
treef158bcae9fce9af29a35bd3ec0e32b81bff87662
parentUse tabs for indentation (diff)
downloadsway-3e1f78ab26e8bc6b6cefd53ee137e97533c2695e.tar.gz
sway-3e1f78ab26e8bc6b6cefd53ee137e97533c2695e.tar.zst
sway-3e1f78ab26e8bc6b6cefd53ee137e97533c2695e.zip
Add support for nested tabbed/stacked containers
-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 @@
3#include <wlc/wlc.h> 3#include <wlc/wlc.h>
4#include "container.h" 4#include "container.h"
5 5
6struct border {
7 unsigned char *buffer;
8 struct wlc_geometry geometry;
9};
10
6void render_view_borders(wlc_handle view); 11void render_view_borders(wlc_handle view);
7void update_view_border(swayc_t *view); 12void update_view_border(swayc_t *view);
8void map_update_view_border(swayc_t *view, void *data); 13void 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 @@
2#define _SWAY_CONTAINER_H 2#define _SWAY_CONTAINER_H
3#include <sys/types.h> 3#include <sys/types.h>
4#include <wlc/wlc.h> 4#include <wlc/wlc.h>
5
6#include "list.h"
7
5typedef struct sway_container swayc_t; 8typedef struct sway_container swayc_t;
6 9
7#include "layout.h" 10extern swayc_t root_container;
8 11
9/** 12/**
10 * Different kinds of containers. 13 * Different kinds of containers.
@@ -76,6 +79,12 @@ struct sway_container {
76 double x, y; 79 double x, y;
77 80
78 /** 81 /**
82 * Cached geometry used to store view/container geometry when switching
83 * between tabbed/stacked and horizontal/vertical layouts.
84 */
85 struct wlc_geometry cached_geometry;
86
87 /**
79 * False if this view is invisible. It could be in the scratchpad or on a 88 * False if this view is invisible. It could be in the scratchpad or on a
80 * workspace that is not shown. 89 * workspace that is not shown.
81 */ 90 */
@@ -120,7 +129,7 @@ struct sway_container {
120 * If this container is a view, this may be set to the window's decoration 129 * If this container is a view, this may be set to the window's decoration
121 * buffer (or NULL). 130 * buffer (or NULL).
122 */ 131 */
123 unsigned char *border; 132 struct border *border;
124 enum swayc_border_types border_type; 133 enum swayc_border_types border_type;
125 struct wlc_geometry border_geometry; 134 struct wlc_geometry border_geometry;
126 struct wlc_geometry title_bar_geometry; 135 struct wlc_geometry title_bar_geometry;
@@ -248,6 +257,12 @@ bool swayc_is_child_of(swayc_t *child, swayc_t *parent);
248bool swayc_is_tabbed_stacked(swayc_t *view); 257bool swayc_is_tabbed_stacked(swayc_t *view);
249 258
250/** 259/**
260 * Returns the top most tabbed or stacked parent container. Returns NULL if
261 * view is not in a tabbed/stacked layout.
262 */
263swayc_t *swayc_tabbed_stacked_parent(swayc_t *view);
264
265/**
251 * Returns the gap (padding) of the container. 266 * Returns the gap (padding) of the container.
252 * 267 *
253 * This returns the inner gaps for a view, the outer gaps for a workspace, and 268 * 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 @@
7#include "container.h" 7#include "container.h"
8#include "focus.h" 8#include "focus.h"
9 9
10extern swayc_t root_container;
11
12extern list_t *scratchpad; 10extern list_t *scratchpad;
13 11
14extern int min_sane_w; 12extern int min_sane_w;
@@ -55,6 +53,10 @@ void move_container_to(swayc_t* container, swayc_t* destination);
55void move_workspace_to(swayc_t* workspace, swayc_t* destination); 53void move_workspace_to(swayc_t* workspace, swayc_t* destination);
56 54
57// Layout 55// Layout
56/**
57 * Update child container geometries when switching between layouts.
58 */
59void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout);
58void update_geometry(swayc_t *view); 60void update_geometry(swayc_t *view);
59void arrange_windows(swayc_t *container, double width, double height); 61void arrange_windows(swayc_t *container, double width, double height);
60 62
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) {
20 (color >> (3*8) & 0xFF) / 255.0); 20 (color >> (3*8) & 0xFF) / 255.0);
21} 21}
22 22
23static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry geo, cairo_surface_t **surface) { 23static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry g, cairo_surface_t **surface) {
24 if (view->border == NULL) {
25 view->border = malloc(sizeof(struct border));
26 }
24 cairo_t *cr; 27 cairo_t *cr;
25 view->border_geometry = geo; 28 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, g.size.w);
26 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, geo.size.w); 29 view->border->buffer = calloc(stride * g.size.h, sizeof(unsigned char));
27 view->border = calloc(stride * geo.size.h, sizeof(unsigned char)); 30 view->border->geometry = g;
28 if (!view->border) { 31 if (!view->border->buffer) {
29 sway_log(L_DEBUG, "Unable to allocate buffer"); 32 sway_log(L_DEBUG, "Unable to allocate buffer");
30 return NULL; 33 return NULL;
31 } 34 }
32 *surface = cairo_image_surface_create_for_data(view->border, 35 *surface = cairo_image_surface_create_for_data(view->border->buffer,
33 CAIRO_FORMAT_ARGB32, geo.size.w, geo.size.h, stride); 36 CAIRO_FORMAT_ARGB32, g.size.w, g.size.h, stride);
34 if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) { 37 if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) {
35 free(view->border); 38 free(view->border);
36 view->border = NULL; 39 view->border->buffer = NULL;
37 sway_log(L_DEBUG, "Unable to allocate surface"); 40 sway_log(L_DEBUG, "Unable to allocate surface");
38 return NULL; 41 return NULL;
39 } 42 }
40 cr = cairo_create(*surface); 43 cr = cairo_create(*surface);
41 if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { 44 if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
42 cairo_surface_destroy(*surface); 45 cairo_surface_destroy(*surface);
43 free(view->border); 46 free(view->border->buffer);
44 view->border = NULL; 47 view->border->buffer = NULL;
45 sway_log(L_DEBUG, "Unable to create cairo context"); 48 sway_log(L_DEBUG, "Unable to create cairo context");
46 return NULL; 49 return NULL;
47 } 50 }
@@ -92,15 +95,19 @@ int get_font_text_height(const char *font) {
92} 95}
93 96
94static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors, bool top) { 97static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors, bool top) {
98 struct wlc_geometry *g = &view->border->geometry;
95 struct wlc_geometry *b = &view->border_geometry; 99 struct wlc_geometry *b = &view->border_geometry;
96 struct wlc_geometry *v = &view->actual_geometry; 100 struct wlc_geometry *v = &view->actual_geometry;
97 101
102 int x = b->origin.x - g->origin.x;
103 int y = b->origin.y - g->origin.y;
104
98 // left border 105 // left border
99 int left_border = v->origin.x - b->origin.x; 106 int left_border = v->origin.x - b->origin.x;
100 if (left_border > 0) { 107 if (left_border > 0) {
101 render_sharp_line(cr, 108 render_sharp_line(cr,
102 colors->child_border, 109 colors->child_border,
103 0, 0, 110 x, y,
104 left_border, 111 left_border,
105 b->size.h); 112 b->size.h);
106 } 113 }
@@ -110,8 +117,8 @@ static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *col
110 if (right_border > 0) { 117 if (right_border > 0) {
111 render_sharp_line(cr, 118 render_sharp_line(cr,
112 colors->child_border, 119 colors->child_border,
113 b->size.w - right_border, 120 x + b->size.w - right_border,
114 0, 121 y,
115 right_border, 122 right_border,
116 b->size.h); 123 b->size.h);
117 } 124 }
@@ -121,7 +128,7 @@ static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *col
121 if (top && top_border > 0) { 128 if (top && top_border > 0) {
122 render_sharp_line(cr, 129 render_sharp_line(cr,
123 colors->child_border, 130 colors->child_border,
124 0, 0, 131 x, y,
125 b->size.w, 132 b->size.w,
126 top_border); 133 top_border);
127 } 134 }
@@ -131,16 +138,15 @@ static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *col
131 if (bottom_border > 0) { 138 if (bottom_border > 0) {
132 render_sharp_line(cr, 139 render_sharp_line(cr,
133 colors->child_border, 140 colors->child_border,
134 0, 141 x,
135 b->size.h - bottom_border, 142 y + b->size.h - bottom_border,
136 b->size.w, 143 b->size.w,
137 bottom_border); 144 bottom_border);
138 } 145 }
139} 146}
140 147
141static void render_title_bar(swayc_t *view, cairo_t *cr, struct border_colors *colors) { 148static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, struct border_colors *colors) {
142 struct wlc_geometry *tb = &view->title_bar_geometry; 149 struct wlc_geometry *tb = &view->title_bar_geometry;
143 struct wlc_geometry *b = &view->border_geometry;
144 int x = MIN(tb->origin.x, tb->origin.x - b->origin.x); 150 int x = MIN(tb->origin.x, tb->origin.x - b->origin.x);
145 int y = MIN(tb->origin.y, tb->origin.y - b->origin.y); 151 int y = MIN(tb->origin.y, tb->origin.y - b->origin.y);
146 152
@@ -197,6 +203,34 @@ void map_update_view_border(swayc_t *view, void *data) {
197 } 203 }
198} 204}
199 205
206void update_tabbed_stacked_titlebars(swayc_t *c, cairo_t *cr, struct wlc_geometry *g, swayc_t *focused, swayc_t *focused_inactive) {
207 if (c->type == C_CONTAINER) {
208 if (c->parent->focused == c) {
209 render_title_bar(c, cr, g, &config->border_colors.focused_inactive);
210 } else {
211 render_title_bar(c, cr, g, &config->border_colors.unfocused);
212 }
213
214 if (!c->visible) {
215 return;
216 }
217
218 int i;
219 for (i = 0; i < c->children->length; ++i) {
220 swayc_t *child = c->children->items[i];
221 update_tabbed_stacked_titlebars(child, cr, g, focused, focused_inactive);
222 }
223 } else {
224 if (focused == c) {
225 render_title_bar(c, cr, g, &config->border_colors.focused);
226 } else if (focused_inactive == c) {
227 render_title_bar(c, cr, g, &config->border_colors.focused_inactive);
228 } else {
229 render_title_bar(c, cr, g, &config->border_colors.unfocused);
230 }
231 }
232}
233
200void update_view_border(swayc_t *view) { 234void update_view_border(swayc_t *view) {
201 if (!view->visible) { 235 if (!view->visible) {
202 return; 236 return;
@@ -205,12 +239,12 @@ void update_view_border(swayc_t *view) {
205 cairo_t *cr = NULL; 239 cairo_t *cr = NULL;
206 cairo_surface_t *surface = NULL; 240 cairo_surface_t *surface = NULL;
207 241
208 if (view->border) { 242 if (view->border && view->border->buffer) {
209 free(view->border); 243 free(view->border->buffer);
210 view->border = NULL; 244 view->border->buffer = NULL;
211 } 245 }
212 246
213 // get focused and focused_intactive views 247 // get focused and focused_inactive views
214 swayc_t *focused = get_focused_view(&root_container); 248 swayc_t *focused = get_focused_view(&root_container);
215 swayc_t *container = swayc_parent_by_type(view, C_CONTAINER); 249 swayc_t *container = swayc_parent_by_type(view, C_CONTAINER);
216 swayc_t *focused_inactive = NULL; 250 swayc_t *focused_inactive = NULL;
@@ -223,30 +257,27 @@ void update_view_border(swayc_t *view) {
223 } 257 }
224 } 258 }
225 259
226 swayc_t *p = view->parent; 260 // for tabbed/stacked layouts the focused view has to draw all the
227 261 // titlebars of the hidden views.
228 if (swayc_is_tabbed_stacked(view)) { 262 swayc_t *p = swayc_tabbed_stacked_parent(view);
229 cr = create_border_buffer(view, view->border_geometry, &surface); 263 if (p && view->parent->focused == view) {
230 if (focused == view) { 264 struct wlc_geometry g = {
265 .origin = {
266 .x = p->x,
267 .y = p->y
268 },
269 .size = {
270 .w = p->width,
271 .h = p->height
272 }
273 };
274 cr = create_border_buffer(view, g, &surface);
275 if (view == focused) {
231 render_borders(view, cr, &config->border_colors.focused, false); 276 render_borders(view, cr, &config->border_colors.focused, false);
232 } else if (focused_inactive == view) {
233 render_borders(view, cr, &config->border_colors.focused_inactive, false);
234 } else { 277 } else {
235 render_borders(view, cr, &config->border_colors.unfocused, false); 278 render_borders(view, cr, &config->border_colors.focused_inactive, false);
236 }
237
238 int i;
239 for (i = 0; i < p->children->length; ++i) {
240 swayc_t *child = p->children->items[i];
241
242 if (focused == child) {
243 render_title_bar(child, cr, &config->border_colors.focused);
244 } else if (focused_inactive == child) {
245 render_title_bar(child, cr, &config->border_colors.focused_inactive);
246 } else {
247 render_title_bar(child, cr, &config->border_colors.unfocused);
248 }
249 } 279 }
280 update_tabbed_stacked_titlebars(p, cr, &g, focused, focused_inactive);
250 } else { 281 } else {
251 switch (view->border_type) { 282 switch (view->border_type) {
252 case B_NONE: 283 case B_NONE:
@@ -274,13 +305,16 @@ void update_view_border(swayc_t *view) {
274 305
275 if (focused == view) { 306 if (focused == view) {
276 render_borders(view, cr, &config->border_colors.focused, false); 307 render_borders(view, cr, &config->border_colors.focused, false);
277 render_title_bar(view, cr, &config->border_colors.focused); 308 render_title_bar(view, cr, &view->border_geometry,
309 &config->border_colors.focused);
278 } else if (focused_inactive == view) { 310 } else if (focused_inactive == view) {
279 render_borders(view, cr, &config->border_colors.focused_inactive, false); 311 render_borders(view, cr, &config->border_colors.focused_inactive, false);
280 render_title_bar(view, cr, &config->border_colors.focused_inactive); 312 render_title_bar(view, cr, &view->border_geometry,
313 &config->border_colors.focused_inactive);
281 } else { 314 } else {
282 render_borders(view, cr, &config->border_colors.unfocused, false); 315 render_borders(view, cr, &config->border_colors.unfocused, false);
283 render_title_bar(view, cr, &config->border_colors.unfocused); 316 render_title_bar(view, cr, &view->border_geometry,
317 &config->border_colors.unfocused);
284 } 318 }
285 319
286 break; 320 break;
@@ -291,6 +325,7 @@ void update_view_border(swayc_t *view) {
291 cairo_surface_flush(surface); 325 cairo_surface_flush(surface);
292 cairo_surface_destroy(surface); 326 cairo_surface_destroy(surface);
293 } 327 }
328
294 if (cr) { 329 if (cr) {
295 cairo_destroy(cr); 330 cairo_destroy(cr);
296 } 331 }
@@ -316,7 +351,7 @@ void render_view_borders(wlc_handle view) {
316 } 351 }
317 } 352 }
318 353
319 if (c->border) { 354 if (c->border && c->border->buffer) {
320 wlc_pixels_write(WLC_RGBA8888, &c->border_geometry, c->border); 355 wlc_pixels_write(WLC_RGBA8888, &c->border->geometry, c->border->buffer);
321 } 356 }
322} 357}
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) {
1759 parent = parent->parent; 1759 parent = parent->parent;
1760 } 1760 }
1761 1761
1762 enum swayc_layouts old_layout = parent->layout;
1763
1762 if (strcasecmp(argv[0], "default") == 0) { 1764 if (strcasecmp(argv[0], "default") == 0) {
1763 parent->layout = parent->prev_layout; 1765 parent->layout = parent->prev_layout;
1764 if (parent->layout == L_NONE) { 1766 if (parent->layout == L_NONE) {
@@ -1795,6 +1797,8 @@ static struct cmd_results *cmd_layout(int argc, char **argv) {
1795 } 1797 }
1796 } 1798 }
1797 1799
1800 update_layout_geometry(parent, old_layout);
1801
1798 arrange_windows(parent, parent->width, parent->height); 1802 arrange_windows(parent, parent->width, parent->height);
1799 1803
1800 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 1804 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
@@ -2032,6 +2036,7 @@ static struct cmd_results *_do_split(int argc, char **argv, int layout) {
2032 /* regular case where new split container is build around focused container 2036 /* regular case where new split container is build around focused container
2033 * or in case of workspace, container inherits its children */ 2037 * or in case of workspace, container inherits its children */
2034 sway_log(L_DEBUG, "Adding new container around current focused container"); 2038 sway_log(L_DEBUG, "Adding new container around current focused container");
2039 sway_log(L_INFO, "FOCUSED SIZE: %.f %.f", focused->width, focused->height);
2035 swayc_t *parent = new_container(focused, layout); 2040 swayc_t *parent = new_container(focused, layout);
2036 set_focused_container(focused); 2041 set_focused_container(focused);
2037 arrange_windows(parent, -1, -1); 2042 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 @@
8#include "container.h" 8#include "container.h"
9#include "workspace.h" 9#include "workspace.h"
10#include "focus.h" 10#include "focus.h"
11#include "border.h"
11#include "layout.h" 12#include "layout.h"
12#include "input_state.h" 13#include "input_state.h"
13#include "log.h" 14#include "log.h"
@@ -64,7 +65,12 @@ static void free_swayc(swayc_t *cont) {
64 if (cont->bg_pid != 0) { 65 if (cont->bg_pid != 0) {
65 terminate_swaybg(cont->bg_pid); 66 terminate_swaybg(cont->bg_pid);
66 } 67 }
67 free(cont->border); 68 if (cont->border) {
69 if (cont->border->buffer) {
70 free(cont->border->buffer);
71 }
72 free(cont->border);
73 }
68 free(cont); 74 free(cont);
69} 75}
70 76
@@ -211,6 +217,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) {
211 cont->x = child->x; 217 cont->x = child->x;
212 cont->y = child->y; 218 cont->y = child->y;
213 cont->visible = child->visible; 219 cont->visible = child->visible;
220 cont->cached_geometry = child->cached_geometry;
214 221
215 /* Container inherits all of workspaces children, layout and whatnot */ 222 /* Container inherits all of workspaces children, layout and whatnot */
216 if (child->type == C_WORKSPACE) { 223 if (child->type == C_WORKSPACE) {
@@ -812,3 +819,18 @@ bool swayc_is_tabbed_stacked(swayc_t *view) {
812 return (view->parent->layout == L_TABBED 819 return (view->parent->layout == L_TABBED
813 || view->parent->layout == L_STACKED); 820 || view->parent->layout == L_STACKED);
814} 821}
822
823swayc_t *swayc_tabbed_stacked_parent(swayc_t *view) {
824 swayc_t *parent = NULL;
825 if (!ASSERT_NONNULL(view)) {
826 return NULL;
827 }
828 do {
829 view = view->parent;
830 if (view->layout == L_TABBED || view->layout == L_STACKED) {
831 parent = view;
832 }
833 } while (view && view->type != C_WORKSPACE);
834
835 return parent;
836}
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) {
149 } 149 }
150 150
151 // rearrange if parent container is tabbed/stacked 151 // rearrange if parent container is tabbed/stacked
152 if (swayc_is_tabbed_stacked(p)) { 152 swayc_t *parent = swayc_tabbed_stacked_parent(p);
153 arrange_windows(p->parent, -1, -1); 153 if (parent != NULL) {
154 arrange_windows(parent, -1, -1);
154 } 155 }
155 } else if (p->type == C_WORKSPACE) { 156 } else if (p->type == C_WORKSPACE) {
156 // remove previous focus if view_focus is unlocked 157 // 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 @@
3#include <math.h> 3#include <math.h>
4#include <wlc/wlc.h> 4#include <wlc/wlc.h>
5#include "extensions.h" 5#include "extensions.h"
6#include "layout.h"
7#include "log.h" 6#include "log.h"
8#include "list.h" 7#include "list.h"
9#include "config.h" 8#include "config.h"
@@ -13,6 +12,7 @@
13#include "output.h" 12#include "output.h"
14#include "ipc-server.h" 13#include "ipc-server.h"
15#include "border.h" 14#include "border.h"
15#include "layout.h"
16 16
17swayc_t root_container; 17swayc_t root_container;
18list_t *scratchpad; 18list_t *scratchpad;
@@ -442,12 +442,49 @@ static void update_border_geometry_floating(swayc_t *c, struct wlc_geometry *geo
442 update_view_border(c); 442 update_view_border(c);
443} 443}
444 444
445void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout) {
446 switch (parent->layout) {
447 case L_TABBED:
448 case L_STACKED:
449 if (prev_layout != L_TABBED && prev_layout != L_STACKED) {
450 // cache current geometry for all non-float children
451 int i;
452 for (i = 0; i < parent->children->length; ++i) {
453 swayc_t *child = parent->children->items[i];
454 child->cached_geometry.origin.x = child->x;
455 child->cached_geometry.origin.y = child->y;
456 child->cached_geometry.size.w = child->width;
457 child->cached_geometry.size.h = child->height;
458 }
459 }
460 break;
461 default:
462 if (prev_layout == L_TABBED || prev_layout == L_STACKED) {
463 // recover cached geometry for all non-float children
464 int i;
465 for (i = 0; i < parent->children->length; ++i) {
466 swayc_t *child = parent->children->items[i];
467 // only recoverer cached geometry if non-zero
468 if (!wlc_geometry_equals(&child->cached_geometry, &wlc_geometry_zero)) {
469 child->x = child->cached_geometry.origin.x;
470 child->y = child->cached_geometry.origin.y;
471 child->width = child->cached_geometry.size.w;
472 child->height = child->cached_geometry.size.h;
473 }
474 }
475 }
476 break;
477 }
478}
479
445void update_geometry(swayc_t *container) { 480void update_geometry(swayc_t *container) {
446 if (container->type != C_VIEW) { 481 if (container->type != C_VIEW && container->type != C_CONTAINER) {
447 return; 482 return;
448 } 483 }
484
449 swayc_t *ws = swayc_parent_by_type(container, C_WORKSPACE); 485 swayc_t *ws = swayc_parent_by_type(container, C_WORKSPACE);
450 swayc_t *op = ws->parent; 486 swayc_t *op = ws->parent;
487 swayc_t *parent = container->parent;
451 int gap = container->is_floating ? 0 : swayc_gap(container); 488 int gap = container->is_floating ? 0 : swayc_gap(container);
452 if (gap % 2 != 0) { 489 if (gap % 2 != 0) {
453 // because gaps are implemented as "half sized margins" it's currently 490 // because gaps are implemented as "half sized margins" it's currently
@@ -455,24 +492,14 @@ void update_geometry(swayc_t *container) {
455 gap -= 1; 492 gap -= 1;
456 } 493 }
457 494
458 int width = container->width;
459 int height = container->height;
460
461 // use parent size if window is in a stacked/tabbed layout
462 swayc_t *parent = container->parent;
463 if (swayc_is_tabbed_stacked(container)) {
464 width = parent->width;
465 height = parent->height;
466 }
467
468 struct wlc_geometry geometry = { 495 struct wlc_geometry geometry = {
469 .origin = { 496 .origin = {
470 .x = container->x + gap/2 < op->width ? container->x + gap/2 : op->width-1, 497 .x = container->x + gap/2 < op->width ? container->x + gap/2 : op->width-1,
471 .y = container->y + gap/2 < op->height ? container->y + gap/2 : op->height-1 498 .y = container->y + gap/2 < op->height ? container->y + gap/2 : op->height-1
472 }, 499 },
473 .size = { 500 .size = {
474 .w = width > gap ? width - gap : 1, 501 .w = container->width > gap ? container->width - gap : 1,
475 .h = height > gap ? height - gap : 1, 502 .h = container->height > gap ? container->height - gap : 1,
476 } 503 }
477 }; 504 };
478 if (swayc_is_fullscreen(container)) { 505 if (swayc_is_fullscreen(container)) {
@@ -492,16 +519,16 @@ void update_geometry(swayc_t *container) {
492 // with gap, and align correctly). 519 // with gap, and align correctly).
493 if (container->x - gap <= ws->x) { 520 if (container->x - gap <= ws->x) {
494 geometry.origin.x = ws->x; 521 geometry.origin.x = ws->x;
495 geometry.size.w = width - gap/2; 522 geometry.size.w = container->width - gap/2;
496 } 523 }
497 if (container->y - gap <= ws->y) { 524 if (container->y - gap <= ws->y) {
498 geometry.origin.y = ws->y; 525 geometry.origin.y = ws->y;
499 geometry.size.h = height - gap/2; 526 geometry.size.h = container->height - gap/2;
500 } 527 }
501 if (container->x + width + gap >= ws->x + ws->width) { 528 if (container->x + container->width + gap >= ws->x + ws->width) {
502 geometry.size.w = ws->x + ws->width - geometry.origin.x; 529 geometry.size.w = ws->x + ws->width - geometry.origin.x;
503 } 530 }
504 if (container->y + height + gap >= ws->y + ws->height) { 531 if (container->y + container->height + gap >= ws->y + ws->height) {
505 geometry.size.h = ws->y + ws->height - geometry.origin.y; 532 geometry.size.h = ws->y + ws->height - geometry.origin.y;
506 } 533 }
507 } 534 }
@@ -637,10 +664,14 @@ void update_geometry(swayc_t *container) {
637 664
638 container->actual_geometry = geometry; 665 container->actual_geometry = geometry;
639 666
640 update_view_border(container); 667 if (container->type == C_VIEW) {
668 update_view_border(container);
669 }
641 } 670 }
642 671
643 wlc_view_set_geometry(container->handle, 0, &geometry); 672 if (container->type == C_VIEW) {
673 wlc_view_set_geometry(container->handle, 0, &geometry);
674 }
644} 675}
645 676
646static void arrange_windows_r(swayc_t *container, double width, double height) { 677static 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) {
736 container->height = height; 767 container->height = height;
737 x = container->x; 768 x = container->x;
738 y = container->y; 769 y = container->y;
770
771 // update container size if it's a child in a tabbed/stacked layout
772 if (swayc_is_tabbed_stacked(container)) {
773 // Use parent geometry as a base for calculating
774 // container geometry
775 container->width = container->parent->width;
776 container->height = container->parent->height;
777 container->x = container->parent->x;
778 container->y = container->parent->y;
779 update_geometry(container);
780 width = container->width = container->actual_geometry.size.w;
781 height = container->height = container->actual_geometry.size.h;
782 x = container->x = container->actual_geometry.origin.x;
783 y = container->y = container->actual_geometry.origin.y;
784 }
785
739 break; 786 break;
740 } 787 }
741 788
@@ -760,11 +807,17 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
760 if (scale > 0.1) { 807 if (scale > 0.1) {
761 scale = width / scale; 808 scale = width / scale;
762 sway_log(L_DEBUG, "Arranging %p horizontally", container); 809 sway_log(L_DEBUG, "Arranging %p horizontally", container);
810 swayc_t *focused = NULL;
763 for (i = 0; i < container->children->length; ++i) { 811 for (i = 0; i < container->children->length; ++i) {
764 swayc_t *child = container->children->items[i]; 812 swayc_t *child = container->children->items[i];
765 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale); 813 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale);
766 child->x = x; 814 child->x = x;
767 child->y = y; 815 child->y = y;
816
817 if (child == container->focused) {
818 focused = child;
819 }
820
768 if (i == container->children->length - 1) { 821 if (i == container->children->length - 1) {
769 double remaining_width = container->x + width - x; 822 double remaining_width = container->x + width - x;
770 arrange_windows_r(child, remaining_width, height); 823 arrange_windows_r(child, remaining_width, height);
@@ -773,6 +826,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
773 } 826 }
774 x += child->width; 827 x += child->width;
775 } 828 }
829
830 // update focused view border last because it may
831 // depend on the title bar geometry of its siblings.
832 if (focused && container->children->length > 1) {
833 update_view_border(focused);
834 }
776 } 835 }
777 break; 836 break;
778 case L_VERT: 837 case L_VERT:
@@ -792,11 +851,17 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
792 if (scale > 0.1) { 851 if (scale > 0.1) {
793 scale = height / scale; 852 scale = height / scale;
794 sway_log(L_DEBUG, "Arranging %p vertically", container); 853 sway_log(L_DEBUG, "Arranging %p vertically", container);
854 swayc_t *focused = NULL;
795 for (i = 0; i < container->children->length; ++i) { 855 for (i = 0; i < container->children->length; ++i) {
796 swayc_t *child = container->children->items[i]; 856 swayc_t *child = container->children->items[i];
797 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, height, scale); 857 sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, height, scale);
798 child->x = x; 858 child->x = x;
799 child->y = y; 859 child->y = y;
860
861 if (child == container->focused) {
862 focused = child;
863 }
864
800 if (i == container->children->length - 1) { 865 if (i == container->children->length - 1) {
801 double remaining_height = container->y + height - y; 866 double remaining_height = container->y + height - y;
802 arrange_windows_r(child, width, remaining_height); 867 arrange_windows_r(child, width, remaining_height);
@@ -805,6 +870,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
805 } 870 }
806 y += child->height; 871 y += child->height;
807 } 872 }
873
874 // update focused view border last because it may
875 // depend on the title bar geometry of its siblings.
876 if (focused && container->children->length > 1) {
877 update_view_border(focused);
878 }
808 } 879 }
809 break; 880 break;
810 case L_TABBED: 881 case L_TABBED:
@@ -818,12 +889,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
818 if (child == container->focused) { 889 if (child == container->focused) {
819 focused = child; 890 focused = child;
820 } else { 891 } else {
821 arrange_windows_r(child, -1, -1); 892 arrange_windows_r(child, width, height);
822 } 893 }
823 } 894 }
824 895
825 if (focused) { 896 if (focused) {
826 arrange_windows_r(focused, -1, -1); 897 arrange_windows_r(focused, width, height);
827 } 898 }
828 break; 899 break;
829 } 900 }