mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Add support for nested tabbed/stacked containers
This commit is contained in:
		
							parent
							
								
									3955c66ce8
								
							
						
					
					
						commit
						3e1f78ab26
					
				
					 8 changed files with 234 additions and 78 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +78,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -247,6 +256,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.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										133
									
								
								sway/border.c
									
										
									
									
									
								
							
							
						
						
									
										133
									
								
								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) {
 | 
			
		||||
			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);
 | 
			
		||||
	// 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 {
 | 
			
		||||
			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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										115
									
								
								sway/layout.c
									
										
									
									
									
								
							
							
						
						
									
										115
									
								
								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;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue