mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Merge branch 'master' into fix-swaylock-hotplugging
This commit is contained in:
		
						commit
						cd0fca2ebf
					
				
					 20 changed files with 990 additions and 338 deletions
				
			
		| 
						 | 
					@ -29,7 +29,8 @@ struct sway_cursor {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sway_cursor_destroy(struct sway_cursor *cursor);
 | 
					void sway_cursor_destroy(struct sway_cursor *cursor);
 | 
				
			||||||
struct sway_cursor *sway_cursor_create(struct sway_seat *seat);
 | 
					struct sway_cursor *sway_cursor_create(struct sway_seat *seat);
 | 
				
			||||||
void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec);
 | 
					void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
 | 
							bool allow_refocusing);
 | 
				
			||||||
void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec,
 | 
					void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
	uint32_t button, enum wlr_button_state state);
 | 
						uint32_t button, enum wlr_button_state state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,6 +94,12 @@ struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
 | 
				
			||||||
struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
 | 
					struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
 | 
				
			||||||
		struct sway_container *container);
 | 
							struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Return the immediate child of container which was most recently focused.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct sway_container *seat_get_active_child(struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Iterate over the focus-inactive children of the container calling the
 | 
					 * Iterate over the focus-inactive children of the container calling the
 | 
				
			||||||
 * function on each.
 | 
					 * function on each.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,12 @@ extern struct sway_container root_container;
 | 
				
			||||||
struct sway_view;
 | 
					struct sway_view;
 | 
				
			||||||
struct sway_seat;
 | 
					struct sway_seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TITLEBAR_BORDER_THICKNESS 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Padding includes titlebar border
 | 
				
			||||||
 | 
					#define TITLEBAR_H_PADDING 3
 | 
				
			||||||
 | 
					#define TITLEBAR_V_PADDING 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Different kinds of containers.
 | 
					 * Different kinds of containers.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -98,6 +104,8 @@ struct sway_container {
 | 
				
			||||||
		// Passed the previous parent
 | 
							// Passed the previous parent
 | 
				
			||||||
		struct wl_signal reparent;
 | 
							struct wl_signal reparent;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_listener reparent;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *container_create(enum sway_container_type type);
 | 
					struct sway_container *container_create(enum sway_container_type type);
 | 
				
			||||||
| 
						 | 
					@ -160,7 +168,7 @@ struct sway_container *container_parent(struct sway_container *container,
 | 
				
			||||||
 * is a view and the view contains a surface at those coordinates.
 | 
					 * is a view and the view contains a surface at those coordinates.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct sway_container *container_at(struct sway_container *container,
 | 
					struct sway_container *container_at(struct sway_container *container,
 | 
				
			||||||
		double lx, double ly, struct wlr_surface **surface,
 | 
							double ox, double oy, struct wlr_surface **surface,
 | 
				
			||||||
		double *sx, double *sy);
 | 
							double *sx, double *sy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -210,4 +218,9 @@ void container_calculate_title_height(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_notify_child_title_changed(struct sway_container *container);
 | 
					void container_notify_child_title_changed(struct sway_container *container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Return the height of a regular title bar.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					size_t container_titlebar_height(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -274,4 +274,10 @@ bool view_has_mark(struct sway_view *view, char *mark);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_update_marks_textures(struct sway_view *view);
 | 
					void view_update_marks_textures(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns true if there's a possibility the view may be rendered on screen.
 | 
				
			||||||
 | 
					 * Intended for damage tracking.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool view_is_visible(struct sway_view *view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,13 +10,13 @@
 | 
				
			||||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
 | 
					#include "wlr-layer-shell-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum auth_state {
 | 
					enum auth_state {
 | 
				
			||||||
    AUTH_STATE_IDLE,
 | 
						AUTH_STATE_IDLE,
 | 
				
			||||||
    AUTH_STATE_CLEAR,
 | 
						AUTH_STATE_CLEAR,
 | 
				
			||||||
    AUTH_STATE_INPUT,
 | 
						AUTH_STATE_INPUT,
 | 
				
			||||||
    AUTH_STATE_INPUT_NOP,
 | 
						AUTH_STATE_INPUT_NOP,
 | 
				
			||||||
    AUTH_STATE_BACKSPACE,
 | 
						AUTH_STATE_BACKSPACE,
 | 
				
			||||||
    AUTH_STATE_VALIDATING,
 | 
						AUTH_STATE_VALIDATING,
 | 
				
			||||||
    AUTH_STATE_INVALID,
 | 
						AUTH_STATE_INVALID,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct swaylock_args {
 | 
					struct swaylock_args {
 | 
				
			||||||
| 
						 | 
					@ -37,12 +37,14 @@ struct swaylock_state {
 | 
				
			||||||
	struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager;
 | 
						struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager;
 | 
				
			||||||
	struct wl_shm *shm;
 | 
						struct wl_shm *shm;
 | 
				
			||||||
	struct wl_list surfaces;
 | 
						struct wl_list surfaces;
 | 
				
			||||||
 | 
						struct wl_list images;
 | 
				
			||||||
	struct swaylock_args args;
 | 
						struct swaylock_args args;
 | 
				
			||||||
	cairo_surface_t *background_image;
 | 
						cairo_surface_t *background_image;
 | 
				
			||||||
	struct swaylock_password password;
 | 
						struct swaylock_password password;
 | 
				
			||||||
	struct swaylock_xkb xkb;
 | 
						struct swaylock_xkb xkb;
 | 
				
			||||||
	enum auth_state auth_state;
 | 
						enum auth_state auth_state;
 | 
				
			||||||
	bool run_display;
 | 
						bool run_display;
 | 
				
			||||||
 | 
						struct zxdg_output_manager_v1 *zxdg_output_manager;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct swaylock_surface {
 | 
					struct swaylock_surface {
 | 
				
			||||||
| 
						 | 
					@ -50,12 +52,22 @@ struct swaylock_surface {
 | 
				
			||||||
	struct swaylock_state *state;
 | 
						struct swaylock_state *state;
 | 
				
			||||||
	struct wl_output *output;
 | 
						struct wl_output *output;
 | 
				
			||||||
	uint32_t output_global_name;
 | 
						uint32_t output_global_name;
 | 
				
			||||||
 | 
						struct zxdg_output_v1 *xdg_output;
 | 
				
			||||||
	struct wl_surface *surface;
 | 
						struct wl_surface *surface;
 | 
				
			||||||
	struct zwlr_layer_surface_v1 *layer_surface;
 | 
						struct zwlr_layer_surface_v1 *layer_surface;
 | 
				
			||||||
	struct pool_buffer buffers[2];
 | 
						struct pool_buffer buffers[2];
 | 
				
			||||||
	struct pool_buffer *current_buffer;
 | 
						struct pool_buffer *current_buffer;
 | 
				
			||||||
	uint32_t width, height;
 | 
						uint32_t width, height;
 | 
				
			||||||
	int32_t scale;
 | 
						int32_t scale;
 | 
				
			||||||
 | 
						char *output_name;
 | 
				
			||||||
 | 
						struct wl_list link;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// There is exactly one swaylock_image for each -i argument
 | 
				
			||||||
 | 
					struct swaylock_image {
 | 
				
			||||||
 | 
						char *path;
 | 
				
			||||||
 | 
						char *output_name;
 | 
				
			||||||
 | 
						cairo_surface_t *cairo_surface;
 | 
				
			||||||
	struct wl_list link;
 | 
						struct wl_list link;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ wayland_server = dependency('wayland-server')
 | 
				
			||||||
wayland_client = dependency('wayland-client')
 | 
					wayland_client = dependency('wayland-client')
 | 
				
			||||||
wayland_cursor = dependency('wayland-cursor')
 | 
					wayland_cursor = dependency('wayland-cursor')
 | 
				
			||||||
wayland_egl    = dependency('wayland-egl')
 | 
					wayland_egl    = dependency('wayland-egl')
 | 
				
			||||||
wayland_protos = dependency('wayland-protocols')
 | 
					wayland_protos = dependency('wayland-protocols', version: '>=1.14')
 | 
				
			||||||
xkbcommon      = dependency('xkbcommon')
 | 
					xkbcommon      = dependency('xkbcommon')
 | 
				
			||||||
cairo          = dependency('cairo')
 | 
					cairo          = dependency('cairo')
 | 
				
			||||||
pango          = dependency('pango')
 | 
					pango          = dependency('pango')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,16 +29,18 @@ wayland_scanner_server = generator(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
client_protocols = [
 | 
					client_protocols = [
 | 
				
			||||||
	[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
 | 
						[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
 | 
				
			||||||
 | 
						[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
 | 
				
			||||||
	['wlr-layer-shell-unstable-v1.xml'],
 | 
						['wlr-layer-shell-unstable-v1.xml'],
 | 
				
			||||||
	['idle.xml'],
 | 
						['idle.xml'],
 | 
				
			||||||
	['wlr-input-inhibitor-unstable-v1.xml']
 | 
						['wlr-input-inhibitor-unstable-v1.xml'],
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
server_protocols = [
 | 
					server_protocols = [
 | 
				
			||||||
	[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
 | 
						[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
 | 
				
			||||||
	[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
 | 
						[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
 | 
				
			||||||
 | 
						[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
 | 
				
			||||||
	['wlr-layer-shell-unstable-v1.xml'],
 | 
						['wlr-layer-shell-unstable-v1.xml'],
 | 
				
			||||||
	['wlr-input-inhibitor-unstable-v1.xml']
 | 
						['wlr-input-inhibitor-unstable-v1.xml'],
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
client_protos_src = []
 | 
					client_protos_src = []
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ struct cmd_results *cmd_border(int argc, char **argv) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
	if (seat->cursor) {
 | 
						if (seat->cursor) {
 | 
				
			||||||
		cursor_send_pointer_motion(seat->cursor, 0);
 | 
							cursor_send_pointer_motion(seat->cursor, 0, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
						return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,10 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
 | 
				
			||||||
			parent->layout = L_HORIZ;
 | 
								parent->layout = L_HORIZ;
 | 
				
			||||||
		} else if (strcasecmp(argv[0], "splitv") == 0) {
 | 
							} else if (strcasecmp(argv[0], "splitv") == 0) {
 | 
				
			||||||
			parent->layout = L_VERT;
 | 
								parent->layout = L_VERT;
 | 
				
			||||||
 | 
							} else if (strcasecmp(argv[0], "tabbed") == 0) {
 | 
				
			||||||
 | 
								parent->layout = L_TABBED;
 | 
				
			||||||
 | 
							} else if (strcasecmp(argv[0], "stacking") == 0) {
 | 
				
			||||||
 | 
								parent->layout = L_STACKED;
 | 
				
			||||||
		} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
 | 
							} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
 | 
				
			||||||
			if (parent->layout == L_HORIZ) {
 | 
								if (parent->layout == L_HORIZ) {
 | 
				
			||||||
				parent->layout = L_VERT;
 | 
									parent->layout = L_VERT;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
 | 
				
			||||||
		int delta_x = strtol(argv[1], NULL, 10);
 | 
							int delta_x = strtol(argv[1], NULL, 10);
 | 
				
			||||||
		int delta_y = strtol(argv[2], NULL, 10);
 | 
							int delta_y = strtol(argv[2], NULL, 10);
 | 
				
			||||||
		wlr_cursor_move(cursor->cursor, NULL, delta_x, delta_y);
 | 
							wlr_cursor_move(cursor->cursor, NULL, delta_x, delta_y);
 | 
				
			||||||
		cursor_send_pointer_motion(cursor, 0);
 | 
							cursor_send_pointer_motion(cursor, 0, true);
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "set") == 0) {
 | 
						} else if (strcasecmp(argv[0], "set") == 0) {
 | 
				
			||||||
		if (argc < 3) {
 | 
							if (argc < 3) {
 | 
				
			||||||
			return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
 | 
								return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,7 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
 | 
				
			||||||
		float x = strtof(argv[1], NULL) / root_container.width;
 | 
							float x = strtof(argv[1], NULL) / root_container.width;
 | 
				
			||||||
		float y = strtof(argv[2], NULL) / root_container.height;
 | 
							float y = strtof(argv[2], NULL) / root_container.height;
 | 
				
			||||||
		wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y);
 | 
							wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y);
 | 
				
			||||||
		cursor_send_pointer_motion(cursor, 0);
 | 
							cursor_send_pointer_motion(cursor, 0, true);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (argc < 2) {
 | 
							if (argc < 2) {
 | 
				
			||||||
			return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
 | 
								return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -269,17 +269,6 @@ static void render_unmanaged(struct sway_output *output,
 | 
				
			||||||
		render_surface_iterator, &data);
 | 
							render_surface_iterator, &data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void render_view(struct sway_view *view, struct sway_output *output,
 | 
					 | 
				
			||||||
		pixman_region32_t *damage) {
 | 
					 | 
				
			||||||
	struct render_data data = {
 | 
					 | 
				
			||||||
		.output = output,
 | 
					 | 
				
			||||||
		.damage = damage,
 | 
					 | 
				
			||||||
		.alpha = view->swayc->alpha,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	output_view_for_each_surface(
 | 
					 | 
				
			||||||
			view, &data.root_geo, render_surface_iterator, &data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void render_rect(struct wlr_output *wlr_output,
 | 
					static void render_rect(struct wlr_output *wlr_output,
 | 
				
			||||||
		pixman_region32_t *output_damage, const struct wlr_box *_box,
 | 
							pixman_region32_t *output_damage, const struct wlr_box *_box,
 | 
				
			||||||
		float color[static 4]) {
 | 
							float color[static 4]) {
 | 
				
			||||||
| 
						 | 
					@ -310,93 +299,149 @@ damage_finish:
 | 
				
			||||||
	pixman_region32_fini(&damage);
 | 
						pixman_region32_fini(&damage);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void premultiply_alpha(float color[4], float opacity) {
 | 
				
			||||||
 | 
						color[3] *= opacity;
 | 
				
			||||||
 | 
						color[0] *= color[3];
 | 
				
			||||||
 | 
						color[1] *= color[3];
 | 
				
			||||||
 | 
						color[2] *= color[3];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void render_view_surfaces(struct sway_view *view,
 | 
				
			||||||
 | 
							struct sway_output *output, pixman_region32_t *damage) {
 | 
				
			||||||
 | 
						struct render_data data = {
 | 
				
			||||||
 | 
							.output = output,
 | 
				
			||||||
 | 
							.damage = damage,
 | 
				
			||||||
 | 
							.alpha = view->swayc->alpha,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						output_view_for_each_surface(
 | 
				
			||||||
 | 
								view, &data.root_geo, render_surface_iterator, &data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Render decorations for a view with "border normal".
 | 
					 * Render a view's surface and left/bottom/right borders.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void render_view(struct sway_output *output, pixman_region32_t *damage,
 | 
				
			||||||
 | 
							struct sway_container *con, struct border_colors *colors) {
 | 
				
			||||||
 | 
						struct sway_view *view = con->sway_view;
 | 
				
			||||||
 | 
						render_view_surfaces(view, output, damage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_box box;
 | 
				
			||||||
 | 
						float output_scale = output->wlr_output->scale;
 | 
				
			||||||
 | 
						float color[4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (view->border != B_NONE) {
 | 
				
			||||||
 | 
							if (view->border_left) {
 | 
				
			||||||
 | 
								memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
				
			||||||
 | 
								premultiply_alpha(color, con->alpha);
 | 
				
			||||||
 | 
								box.x = con->x;
 | 
				
			||||||
 | 
								box.y = view->y;
 | 
				
			||||||
 | 
								box.width = view->border_thickness;
 | 
				
			||||||
 | 
								box.height = view->height;
 | 
				
			||||||
 | 
								scale_box(&box, output_scale);
 | 
				
			||||||
 | 
								render_rect(output->wlr_output, damage, &box, color);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (view->border_right) {
 | 
				
			||||||
 | 
								if (con->parent->children->length == 1
 | 
				
			||||||
 | 
										&& con->parent->layout == L_HORIZ) {
 | 
				
			||||||
 | 
									memcpy(&color, colors->indicator, sizeof(float) * 4);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								premultiply_alpha(color, con->alpha);
 | 
				
			||||||
 | 
								box.x = view->x + view->width;
 | 
				
			||||||
 | 
								box.y = view->y;
 | 
				
			||||||
 | 
								box.width = view->border_thickness;
 | 
				
			||||||
 | 
								box.height = view->height;
 | 
				
			||||||
 | 
								scale_box(&box, output_scale);
 | 
				
			||||||
 | 
								render_rect(output->wlr_output, damage, &box, color);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (view->border_bottom) {
 | 
				
			||||||
 | 
								if (con->parent->children->length == 1
 | 
				
			||||||
 | 
										&& con->parent->layout == L_VERT) {
 | 
				
			||||||
 | 
									memcpy(&color, colors->indicator, sizeof(float) * 4);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								premultiply_alpha(color, con->alpha);
 | 
				
			||||||
 | 
								box.x = con->x;
 | 
				
			||||||
 | 
								box.y = view->y + view->height;
 | 
				
			||||||
 | 
								box.width = con->width;
 | 
				
			||||||
 | 
								box.height = view->border_thickness;
 | 
				
			||||||
 | 
								scale_box(&box, output_scale);
 | 
				
			||||||
 | 
								render_rect(output->wlr_output, damage, &box, color);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Render a titlebar.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Care must be taken not to render over the same pixel multiple times,
 | 
					 * Care must be taken not to render over the same pixel multiple times,
 | 
				
			||||||
 * otherwise the colors will be incorrect when using opacity.
 | 
					 * otherwise the colors will be incorrect when using opacity.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The height is: 1px border, 3px padding, font height, 3px padding, 1px border
 | 
				
			||||||
 | 
					 * The left side for L_TABBED is: 1px border, 2px padding, title
 | 
				
			||||||
 | 
					 * The left side for other layouts is: 3px padding, title
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void render_container_simple_border_normal(struct sway_output *output,
 | 
					static void render_titlebar(struct sway_output *output,
 | 
				
			||||||
		pixman_region32_t *output_damage,
 | 
							pixman_region32_t *output_damage, struct sway_container *con,
 | 
				
			||||||
		struct sway_container *con, struct border_colors *colors,
 | 
							int x, int y, int width,
 | 
				
			||||||
		struct wlr_texture *title_texture, struct wlr_texture *marks_texture) {
 | 
							struct border_colors *colors, struct wlr_texture *title_texture,
 | 
				
			||||||
 | 
							struct wlr_texture *marks_texture) {
 | 
				
			||||||
	struct wlr_box box;
 | 
						struct wlr_box box;
 | 
				
			||||||
	float color[4];
 | 
						float color[4];
 | 
				
			||||||
	struct sway_view *view = con->sway_view;
 | 
						struct sway_view *view = con->type == C_VIEW ? con->sway_view : NULL;
 | 
				
			||||||
	float output_scale = output->wlr_output->scale;
 | 
						float output_scale = output->wlr_output->scale;
 | 
				
			||||||
 | 
						enum sway_container_layout layout = con->parent->layout;
 | 
				
			||||||
	if (view->border_left) {
 | 
						bool is_last_child =
 | 
				
			||||||
		// Child border - left edge
 | 
							con->parent->children->items[con->parent->children->length - 1] == con;
 | 
				
			||||||
		memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		color[3] *= con->alpha;
 | 
					 | 
				
			||||||
		box.x = con->x;
 | 
					 | 
				
			||||||
		box.y = con->y + 1;
 | 
					 | 
				
			||||||
		box.width = view->border_thickness;
 | 
					 | 
				
			||||||
		box.height = con->height - 1
 | 
					 | 
				
			||||||
			- view->border_thickness * view->border_bottom;
 | 
					 | 
				
			||||||
		scale_box(&box, output_scale);
 | 
					 | 
				
			||||||
		render_rect(output->wlr_output, output_damage, &box, color);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (view->border_right) {
 | 
					 | 
				
			||||||
		// Child border - right edge
 | 
					 | 
				
			||||||
		if (con->parent->children->length == 1
 | 
					 | 
				
			||||||
				&& con->parent->layout == L_HORIZ) {
 | 
					 | 
				
			||||||
			memcpy(&color, colors->indicator, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		color[3] *= con->alpha;
 | 
					 | 
				
			||||||
		box.x = con->x + con->width - view->border_thickness;
 | 
					 | 
				
			||||||
		box.y = con->y + 1;
 | 
					 | 
				
			||||||
		box.width = view->border_thickness;
 | 
					 | 
				
			||||||
		box.height = con->height - 1
 | 
					 | 
				
			||||||
			- view->border_thickness * view->border_bottom;
 | 
					 | 
				
			||||||
		scale_box(&box, output_scale);
 | 
					 | 
				
			||||||
		render_rect(output->wlr_output, output_damage, &box, color);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (view->border_bottom) {
 | 
					 | 
				
			||||||
		// Child border - bottom edge
 | 
					 | 
				
			||||||
		if (con->parent->children->length == 1
 | 
					 | 
				
			||||||
				&& con->parent->layout == L_VERT) {
 | 
					 | 
				
			||||||
			memcpy(&color, colors->indicator, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		color[3] *= con->alpha;
 | 
					 | 
				
			||||||
		box.x = con->x;
 | 
					 | 
				
			||||||
		box.y = con->y + con->height - view->border_thickness;
 | 
					 | 
				
			||||||
		box.width = con->width;
 | 
					 | 
				
			||||||
		box.height = view->border_thickness;
 | 
					 | 
				
			||||||
		scale_box(&box, output_scale);
 | 
					 | 
				
			||||||
		render_rect(output->wlr_output, output_damage, &box, color);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Single pixel bar above title
 | 
						// Single pixel bar above title
 | 
				
			||||||
	memcpy(&color, colors->border, sizeof(float) * 4);
 | 
						memcpy(&color, colors->border, sizeof(float) * 4);
 | 
				
			||||||
	color[3] *= con->alpha;
 | 
						premultiply_alpha(color, con->alpha);
 | 
				
			||||||
	box.x = con->x;
 | 
						box.x = x;
 | 
				
			||||||
	box.y = con->y;
 | 
						box.y = y;
 | 
				
			||||||
	box.width = con->width;
 | 
						box.width = width;
 | 
				
			||||||
	box.height = 1;
 | 
						box.height = TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
	scale_box(&box, output_scale);
 | 
						scale_box(&box, output_scale);
 | 
				
			||||||
	render_rect(output->wlr_output, output_damage, &box, color);
 | 
						render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Single pixel bar below title
 | 
						// Single pixel bar below title
 | 
				
			||||||
	memcpy(&color, colors->border, sizeof(float) * 4);
 | 
						size_t left_offset = 0, right_offset = 0;
 | 
				
			||||||
	color[3] *= con->alpha;
 | 
						bool connects_sides = false;
 | 
				
			||||||
	box.x = con->x + view->border_thickness;
 | 
						if (layout == L_HORIZ || layout == L_VERT ||
 | 
				
			||||||
	box.y = view->y - 1;
 | 
								(layout == L_STACKED && is_last_child)) {
 | 
				
			||||||
	box.width = con->width - view->border_thickness * 2;
 | 
							if (view) {
 | 
				
			||||||
	box.height = 1;
 | 
								left_offset = view->border_left * view->border_thickness;
 | 
				
			||||||
 | 
								right_offset = view->border_right * view->border_thickness;
 | 
				
			||||||
 | 
								connects_sides = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						box.x = x + left_offset;
 | 
				
			||||||
 | 
						box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
						box.width = width - left_offset - right_offset;
 | 
				
			||||||
 | 
						box.height = TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
	scale_box(&box, output_scale);
 | 
						scale_box(&box, output_scale);
 | 
				
			||||||
	render_rect(output->wlr_output, output_damage, &box, color);
 | 
						render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Setting these makes marks and title easier
 | 
						if (layout == L_TABBED) {
 | 
				
			||||||
	size_t inner_x = con->x + view->border_thickness * view->border_left;
 | 
							// Single pixel left edge
 | 
				
			||||||
	size_t inner_width = con->width - view->border_thickness * view->border_left
 | 
							box.x = x;
 | 
				
			||||||
		- view->border_thickness * view->border_right;
 | 
							box.y = y + TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
							box.width = TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
							box.height =
 | 
				
			||||||
 | 
								container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
 | 
				
			||||||
 | 
							scale_box(&box, output_scale);
 | 
				
			||||||
 | 
							render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Single pixel right edge
 | 
				
			||||||
 | 
							box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale;
 | 
				
			||||||
 | 
							render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t inner_width = width - TITLEBAR_H_PADDING * 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Marks
 | 
						// Marks
 | 
				
			||||||
	size_t marks_width = 0;
 | 
						size_t marks_width = 0;
 | 
				
			||||||
| 
						 | 
					@ -404,14 +449,18 @@ static void render_container_simple_border_normal(struct sway_output *output,
 | 
				
			||||||
		struct wlr_box texture_box;
 | 
							struct wlr_box texture_box;
 | 
				
			||||||
		wlr_texture_get_size(marks_texture,
 | 
							wlr_texture_get_size(marks_texture,
 | 
				
			||||||
			&texture_box.width, &texture_box.height);
 | 
								&texture_box.width, &texture_box.height);
 | 
				
			||||||
		texture_box.x = (inner_x + inner_width) * output_scale - texture_box.width;
 | 
							texture_box.x =
 | 
				
			||||||
		texture_box.y = (con->y + view->border_thickness) * output_scale;
 | 
								(x + width - TITLEBAR_H_PADDING) * output_scale - texture_box.width;
 | 
				
			||||||
 | 
							texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		float matrix[9];
 | 
							float matrix[9];
 | 
				
			||||||
		wlr_matrix_project_box(matrix, &texture_box,
 | 
							wlr_matrix_project_box(matrix, &texture_box,
 | 
				
			||||||
			WL_OUTPUT_TRANSFORM_NORMAL,
 | 
								WL_OUTPUT_TRANSFORM_NORMAL,
 | 
				
			||||||
			0.0, output->wlr_output->transform_matrix);
 | 
								0.0, output->wlr_output->transform_matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (inner_width * output_scale < texture_box.width) {
 | 
				
			||||||
 | 
								texture_box.width = inner_width * output_scale;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		render_texture(output->wlr_output, output_damage, marks_texture,
 | 
							render_texture(output->wlr_output, output_damage, marks_texture,
 | 
				
			||||||
			&texture_box, matrix, con->alpha);
 | 
								&texture_box, matrix, con->alpha);
 | 
				
			||||||
		marks_width = texture_box.width;
 | 
							marks_width = texture_box.width;
 | 
				
			||||||
| 
						 | 
					@ -423,8 +472,8 @@ static void render_container_simple_border_normal(struct sway_output *output,
 | 
				
			||||||
		struct wlr_box texture_box;
 | 
							struct wlr_box texture_box;
 | 
				
			||||||
		wlr_texture_get_size(title_texture,
 | 
							wlr_texture_get_size(title_texture,
 | 
				
			||||||
			&texture_box.width, &texture_box.height);
 | 
								&texture_box.width, &texture_box.height);
 | 
				
			||||||
		texture_box.x = inner_x * output_scale;
 | 
							texture_box.x = (x + TITLEBAR_H_PADDING) * output_scale;
 | 
				
			||||||
		texture_box.y = (con->y + view->border_thickness) * output_scale;
 | 
							texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		float matrix[9];
 | 
							float matrix[9];
 | 
				
			||||||
		wlr_matrix_project_box(matrix, &texture_box,
 | 
							wlr_matrix_project_box(matrix, &texture_box,
 | 
				
			||||||
| 
						 | 
					@ -439,104 +488,89 @@ static void render_container_simple_border_normal(struct sway_output *output,
 | 
				
			||||||
		title_width = texture_box.width;
 | 
							title_width = texture_box.width;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Title background - above the text
 | 
						// Padding above title
 | 
				
			||||||
	memcpy(&color, colors->background, sizeof(float) * 4);
 | 
						memcpy(&color, colors->background, sizeof(float) * 4);
 | 
				
			||||||
	color[3] *= con->alpha;
 | 
						premultiply_alpha(color, con->alpha);
 | 
				
			||||||
	box.x = inner_x;
 | 
						box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
	box.y = con->y + 1;
 | 
						box.y = y + TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
	box.width = inner_width;
 | 
						box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2;
 | 
				
			||||||
	box.height = view->border_thickness - 1;
 | 
						box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
	scale_box(&box, output_scale);
 | 
						scale_box(&box, output_scale);
 | 
				
			||||||
	render_rect(output->wlr_output, output_damage, &box, color);
 | 
						render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Title background - below the text
 | 
						// Padding below title
 | 
				
			||||||
	box.y = (con->y + view->border_thickness + config->font_height)
 | 
						box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale;
 | 
				
			||||||
		* output_scale;
 | 
					 | 
				
			||||||
	render_rect(output->wlr_output, output_damage, &box, color);
 | 
						render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Title background - filler between title and marks
 | 
						// Filler between title and marks
 | 
				
			||||||
	box.width = inner_width * output_scale - title_width - marks_width;
 | 
						box.width = inner_width * output_scale - title_width - marks_width;
 | 
				
			||||||
	if (box.width > 0) {
 | 
						if (box.width > 0) {
 | 
				
			||||||
		box.x = inner_x * output_scale + title_width;
 | 
							box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_width;
 | 
				
			||||||
		box.y = (con->y + view->border_thickness) * output_scale;
 | 
							box.y = (y + TITLEBAR_V_PADDING) * output_scale;
 | 
				
			||||||
		box.height = config->font_height * output_scale;
 | 
							box.height = config->font_height * output_scale;
 | 
				
			||||||
		render_rect(output->wlr_output, output_damage, &box, color);
 | 
							render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Padding left of title
 | 
				
			||||||
 | 
						left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
						box.x = x + left_offset;
 | 
				
			||||||
 | 
						box.y = y + TITLEBAR_V_PADDING;
 | 
				
			||||||
 | 
						box.width = TITLEBAR_H_PADDING - left_offset;
 | 
				
			||||||
 | 
						box.height = config->font_height;
 | 
				
			||||||
 | 
						scale_box(&box, output_scale);
 | 
				
			||||||
 | 
						render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Padding right of marks
 | 
				
			||||||
 | 
						right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
						box.x = x + width - TITLEBAR_H_PADDING;
 | 
				
			||||||
 | 
						box.y = y + TITLEBAR_V_PADDING;
 | 
				
			||||||
 | 
						box.width = TITLEBAR_H_PADDING - right_offset;
 | 
				
			||||||
 | 
						box.height = config->font_height;
 | 
				
			||||||
 | 
						scale_box(&box, output_scale);
 | 
				
			||||||
 | 
						render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (connects_sides) {
 | 
				
			||||||
 | 
							// Left pixel in line with bottom bar
 | 
				
			||||||
 | 
							box.x = x;
 | 
				
			||||||
 | 
							box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
							box.width = view->border_thickness * view->border_left;
 | 
				
			||||||
 | 
							box.height = TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
							scale_box(&box, output_scale);
 | 
				
			||||||
 | 
							render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Right pixel in line with bottom bar
 | 
				
			||||||
 | 
							box.x = x + width - view->border_thickness * view->border_right;
 | 
				
			||||||
 | 
							box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
							box.width = view->border_thickness * view->border_right;
 | 
				
			||||||
 | 
							box.height = TITLEBAR_BORDER_THICKNESS;
 | 
				
			||||||
 | 
							scale_box(&box, output_scale);
 | 
				
			||||||
 | 
							render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Render decorations for a view with "border pixel".
 | 
					 * Render the top border line for a view using "border pixel".
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Care must be taken not to render over the same pixel multiple times,
 | 
					 | 
				
			||||||
 * otherwise the colors will be incorrect when using opacity.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void render_container_simple_border_pixel(struct sway_output *output,
 | 
					static void render_top_border(struct sway_output *output,
 | 
				
			||||||
		pixman_region32_t *output_damage, struct sway_container *con,
 | 
							pixman_region32_t *output_damage, struct sway_container *con,
 | 
				
			||||||
		struct border_colors *colors) {
 | 
							struct border_colors *colors) {
 | 
				
			||||||
 | 
						struct sway_view *view = con->sway_view;
 | 
				
			||||||
 | 
						if (!view->border_top) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	struct wlr_box box;
 | 
						struct wlr_box box;
 | 
				
			||||||
	float color[4];
 | 
						float color[4];
 | 
				
			||||||
	struct sway_view *view = con->sway_view;
 | 
					 | 
				
			||||||
	float output_scale = output->wlr_output->scale;
 | 
						float output_scale = output->wlr_output->scale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (view->border_left) {
 | 
						// Child border - top edge
 | 
				
			||||||
		// Child border - left edge
 | 
						memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
				
			||||||
		memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
						premultiply_alpha(color, con->alpha);
 | 
				
			||||||
		color[3] *= con->alpha;
 | 
						box.x = con->x;
 | 
				
			||||||
		box.x = con->x;
 | 
						box.y = con->y;
 | 
				
			||||||
		box.y = con->y + view->border_thickness * view->border_top;
 | 
						box.width = con->width;
 | 
				
			||||||
		box.width = view->border_thickness;
 | 
						box.height = view->border_thickness;
 | 
				
			||||||
		box.height = con->height - view->border_thickness
 | 
						scale_box(&box, output_scale);
 | 
				
			||||||
			* (view->border_top + view->border_bottom);
 | 
						render_rect(output->wlr_output, output_damage, &box, color);
 | 
				
			||||||
		scale_box(&box, output_scale);
 | 
					 | 
				
			||||||
		render_rect(output->wlr_output, output_damage, &box, color);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (view->border_right) {
 | 
					 | 
				
			||||||
		// Child border - right edge
 | 
					 | 
				
			||||||
		if (con->parent->children->length == 1
 | 
					 | 
				
			||||||
				&& con->parent->layout == L_HORIZ) {
 | 
					 | 
				
			||||||
			memcpy(&color, colors->indicator, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		color[3] *= con->alpha;
 | 
					 | 
				
			||||||
		box.x = con->x + con->width - view->border_thickness;
 | 
					 | 
				
			||||||
		box.y = con->y + view->border_thickness * view->border_top;
 | 
					 | 
				
			||||||
		box.width = view->border_thickness;
 | 
					 | 
				
			||||||
		box.height = con->height - view->border_thickness
 | 
					 | 
				
			||||||
			* (view->border_top + view->border_bottom);
 | 
					 | 
				
			||||||
		scale_box(&box, output_scale);
 | 
					 | 
				
			||||||
		render_rect(output->wlr_output, output_damage, &box, color);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (view->border_top) {
 | 
					 | 
				
			||||||
		// Child border - top edge
 | 
					 | 
				
			||||||
		memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		color[3] *= con->alpha;
 | 
					 | 
				
			||||||
		box.x = con->x;
 | 
					 | 
				
			||||||
		box.y = con->y;
 | 
					 | 
				
			||||||
		box.width = con->width;
 | 
					 | 
				
			||||||
		box.height = view->border_thickness;
 | 
					 | 
				
			||||||
		scale_box(&box, output_scale);
 | 
					 | 
				
			||||||
		render_rect(output->wlr_output, output_damage, &box, color);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (view->border_bottom) {
 | 
					 | 
				
			||||||
		// Child border - bottom edge
 | 
					 | 
				
			||||||
		if (con->parent->children->length == 1
 | 
					 | 
				
			||||||
				&& con->parent->layout == L_VERT) {
 | 
					 | 
				
			||||||
			memcpy(&color, colors->indicator, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			memcpy(&color, colors->child_border, sizeof(float) * 4);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		color[3] *= con->alpha;
 | 
					 | 
				
			||||||
		box.x = con->x;
 | 
					 | 
				
			||||||
		box.y = con->y + con->height - view->border_thickness;
 | 
					 | 
				
			||||||
		box.width = con->width;
 | 
					 | 
				
			||||||
		box.height = view->border_thickness;
 | 
					 | 
				
			||||||
		scale_box(&box, output_scale);
 | 
					 | 
				
			||||||
		render_rect(output->wlr_output, output_damage, &box, color);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void render_container(struct sway_output *output,
 | 
					static void render_container(struct sway_output *output,
 | 
				
			||||||
| 
						 | 
					@ -558,33 +592,30 @@ static void render_container_simple(struct sway_output *output,
 | 
				
			||||||
		struct sway_container *child = con->children->items[i];
 | 
							struct sway_container *child = con->children->items[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (child->type == C_VIEW) {
 | 
							if (child->type == C_VIEW) {
 | 
				
			||||||
			if (child->sway_view->border != B_NONE) {
 | 
								struct border_colors *colors;
 | 
				
			||||||
				struct border_colors *colors;
 | 
								struct wlr_texture *title_texture;
 | 
				
			||||||
				struct wlr_texture *title_texture;
 | 
								struct wlr_texture *marks_texture;
 | 
				
			||||||
				struct wlr_texture *marks_texture;
 | 
								if (focus == child || parent_focused) {
 | 
				
			||||||
				if (focus == child || parent_focused) {
 | 
									colors = &config->border_colors.focused;
 | 
				
			||||||
					colors = &config->border_colors.focused;
 | 
									title_texture = child->title_focused;
 | 
				
			||||||
					title_texture = child->title_focused;
 | 
									marks_texture = child->sway_view->marks_focused;
 | 
				
			||||||
					marks_texture = child->sway_view->marks_focused;
 | 
								} else if (seat_get_focus_inactive(seat, con) == child) {
 | 
				
			||||||
				} else if (seat_get_focus_inactive(seat, con) == child) {
 | 
									colors = &config->border_colors.focused_inactive;
 | 
				
			||||||
					colors = &config->border_colors.focused_inactive;
 | 
									title_texture = child->title_focused_inactive;
 | 
				
			||||||
					title_texture = child->title_focused_inactive;
 | 
									marks_texture = child->sway_view->marks_focused_inactive;
 | 
				
			||||||
					marks_texture = child->sway_view->marks_focused_inactive;
 | 
								} else {
 | 
				
			||||||
				} else {
 | 
									colors = &config->border_colors.unfocused;
 | 
				
			||||||
					colors = &config->border_colors.unfocused;
 | 
									title_texture = child->title_unfocused;
 | 
				
			||||||
					title_texture = child->title_unfocused;
 | 
									marks_texture = child->sway_view->marks_unfocused;
 | 
				
			||||||
					marks_texture = child->sway_view->marks_unfocused;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (child->sway_view->border == B_NORMAL) {
 | 
					 | 
				
			||||||
					render_container_simple_border_normal(output, damage,
 | 
					 | 
				
			||||||
						child, colors, title_texture, marks_texture);
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					render_container_simple_border_pixel(output, damage, child,
 | 
					 | 
				
			||||||
						colors);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			render_view(child->sway_view, output, damage);
 | 
					
 | 
				
			||||||
 | 
								if (child->sway_view->border == B_NORMAL) {
 | 
				
			||||||
 | 
									render_titlebar(output, damage, child, child->x, child->y,
 | 
				
			||||||
 | 
											child->width, colors, title_texture, marks_texture);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									render_top_border(output, damage, child, colors);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								render_view(output, damage, child, colors);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			render_container(output, damage, child,
 | 
								render_container(output, damage, child,
 | 
				
			||||||
					parent_focused || focus == child);
 | 
										parent_focused || focus == child);
 | 
				
			||||||
| 
						 | 
					@ -596,16 +627,116 @@ static void render_container_simple(struct sway_output *output,
 | 
				
			||||||
 * Render a container's children using the L_TABBED layout.
 | 
					 * Render a container's children using the L_TABBED layout.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void render_container_tabbed(struct sway_output *output,
 | 
					static void render_container_tabbed(struct sway_output *output,
 | 
				
			||||||
		pixman_region32_t *damage, struct sway_container *con) {
 | 
							pixman_region32_t *damage, struct sway_container *con,
 | 
				
			||||||
	// TODO
 | 
							bool parent_focused) {
 | 
				
			||||||
 | 
						if (!con->children->length) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *focus = seat_get_focus(seat);
 | 
				
			||||||
 | 
						struct sway_container *current = seat_get_active_child(seat, con);
 | 
				
			||||||
 | 
						struct border_colors *current_colors = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Render tabs
 | 
				
			||||||
 | 
						for (int i = 0; i < con->children->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_container *child = con->children->items[i];
 | 
				
			||||||
 | 
							struct border_colors *colors;
 | 
				
			||||||
 | 
							struct wlr_texture *title_texture;
 | 
				
			||||||
 | 
							struct wlr_texture *marks_texture;
 | 
				
			||||||
 | 
							struct sway_view *view =
 | 
				
			||||||
 | 
								child->type == C_VIEW ? child->sway_view : NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (focus == child || parent_focused) {
 | 
				
			||||||
 | 
								colors = &config->border_colors.focused;
 | 
				
			||||||
 | 
								title_texture = child->title_focused;
 | 
				
			||||||
 | 
								marks_texture = view ? view->marks_focused : NULL;
 | 
				
			||||||
 | 
							} else if (child == current) {
 | 
				
			||||||
 | 
								colors = &config->border_colors.focused_inactive;
 | 
				
			||||||
 | 
								title_texture = child->title_focused_inactive;
 | 
				
			||||||
 | 
								marks_texture = view ? view->marks_focused : NULL;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								colors = &config->border_colors.unfocused;
 | 
				
			||||||
 | 
								title_texture = child->title_unfocused;
 | 
				
			||||||
 | 
								marks_texture = view ? view->marks_unfocused : NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int tab_width = con->width / con->children->length;
 | 
				
			||||||
 | 
							int x = con->x + tab_width * i;
 | 
				
			||||||
 | 
							// Make last tab use the remaining width of the parent
 | 
				
			||||||
 | 
							if (i == con->children->length - 1) {
 | 
				
			||||||
 | 
								tab_width = con->width - tab_width * i;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							render_titlebar(output, damage, child, x, child->y, tab_width, colors,
 | 
				
			||||||
 | 
									title_texture, marks_texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (child == current) {
 | 
				
			||||||
 | 
								current_colors = colors;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Render surface and left/right/bottom borders
 | 
				
			||||||
 | 
						if (current->type == C_VIEW) {
 | 
				
			||||||
 | 
							render_view(output, damage, current, current_colors);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							render_container(output, damage, current,
 | 
				
			||||||
 | 
									parent_focused || current == focus);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Render a container's children using the L_STACKED layout.
 | 
					 * Render a container's children using the L_STACKED layout.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void render_container_stacked(struct sway_output *output,
 | 
					static void render_container_stacked(struct sway_output *output,
 | 
				
			||||||
		pixman_region32_t *damage, struct sway_container *con) {
 | 
							pixman_region32_t *damage, struct sway_container *con,
 | 
				
			||||||
	// TODO
 | 
							bool parent_focused) {
 | 
				
			||||||
 | 
						if (!con->children->length) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *focus = seat_get_focus(seat);
 | 
				
			||||||
 | 
						struct sway_container *current = seat_get_active_child(seat, con);
 | 
				
			||||||
 | 
						struct border_colors *current_colors = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Render titles
 | 
				
			||||||
 | 
						for (int i = 0; i < con->children->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_container *child = con->children->items[i];
 | 
				
			||||||
 | 
							struct border_colors *colors;
 | 
				
			||||||
 | 
							struct wlr_texture *title_texture;
 | 
				
			||||||
 | 
							struct wlr_texture *marks_texture;
 | 
				
			||||||
 | 
							struct sway_view *view =
 | 
				
			||||||
 | 
								child->type == C_VIEW ? child->sway_view : NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (focus == child || parent_focused) {
 | 
				
			||||||
 | 
								colors = &config->border_colors.focused;
 | 
				
			||||||
 | 
								title_texture = child->title_focused;
 | 
				
			||||||
 | 
								marks_texture = view ? view->marks_focused : NULL;
 | 
				
			||||||
 | 
							} else if (child == current) {
 | 
				
			||||||
 | 
								colors = &config->border_colors.focused_inactive;
 | 
				
			||||||
 | 
								title_texture = child->title_focused_inactive;
 | 
				
			||||||
 | 
								marks_texture = view ? view->marks_focused_inactive : NULL;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								colors = &config->border_colors.unfocused;
 | 
				
			||||||
 | 
								title_texture = child->title_unfocused;
 | 
				
			||||||
 | 
								marks_texture = view ? view->marks_unfocused : NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int y = con->y + container_titlebar_height() * i;
 | 
				
			||||||
 | 
							render_titlebar(output, damage, child, child->x, y, child->width,
 | 
				
			||||||
 | 
									colors, title_texture, marks_texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (child == current) {
 | 
				
			||||||
 | 
								current_colors = colors;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Render surface and left/right/bottom borders
 | 
				
			||||||
 | 
						if (current->type == C_VIEW) {
 | 
				
			||||||
 | 
							render_view(output, damage, current, current_colors);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							render_container(output, damage, current,
 | 
				
			||||||
 | 
									parent_focused || current == focus);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void render_container(struct sway_output *output,
 | 
					static void render_container(struct sway_output *output,
 | 
				
			||||||
| 
						 | 
					@ -618,10 +749,10 @@ static void render_container(struct sway_output *output,
 | 
				
			||||||
		render_container_simple(output, damage, con, parent_focused);
 | 
							render_container_simple(output, damage, con, parent_focused);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case L_STACKED:
 | 
						case L_STACKED:
 | 
				
			||||||
		render_container_stacked(output, damage, con);
 | 
							render_container_stacked(output, damage, con, parent_focused);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case L_TABBED:
 | 
						case L_TABBED:
 | 
				
			||||||
		render_container_tabbed(output, damage, con);
 | 
							render_container_tabbed(output, damage, con, parent_focused);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case L_FLOATING:
 | 
						case L_FLOATING:
 | 
				
			||||||
		// TODO
 | 
							// TODO
 | 
				
			||||||
| 
						 | 
					@ -678,7 +809,8 @@ static void render_output(struct sway_output *output, struct timespec *when,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// TODO: handle views smaller than the output
 | 
							// TODO: handle views smaller than the output
 | 
				
			||||||
		render_view(workspace->sway_workspace->fullscreen, output, damage);
 | 
							render_view_surfaces(
 | 
				
			||||||
 | 
									workspace->sway_workspace->fullscreen, output, damage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) {
 | 
							if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) {
 | 
				
			||||||
			render_unmanaged(output, damage,
 | 
								render_unmanaged(output, damage,
 | 
				
			||||||
| 
						 | 
					@ -889,9 +1021,7 @@ static void output_damage_view(struct sway_output *output,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *workspace = container_parent(view->swayc,
 | 
						if (!view_is_visible(view)) {
 | 
				
			||||||
			C_WORKSPACE);
 | 
					 | 
				
			||||||
	if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) {
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,7 +108,7 @@ static struct sway_container *container_at_coords(
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct sway_container *c;
 | 
						struct sway_container *c;
 | 
				
			||||||
	if ((c = container_at(ws, x, y, surface, sx, sy))) {
 | 
						if ((c = container_at(ws, ox, oy, surface, sx, sy))) {
 | 
				
			||||||
		return c;
 | 
							return c;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,7 +135,8 @@ static struct sway_container *container_at_coords(
 | 
				
			||||||
	return output->swayc;
 | 
						return output->swayc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec) {
 | 
					void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
				
			||||||
 | 
							bool allow_refocusing) {
 | 
				
			||||||
	if (time_msec == 0) {
 | 
						if (time_msec == 0) {
 | 
				
			||||||
		time_msec = get_current_time_msec();
 | 
							time_msec = get_current_time_msec();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -145,8 +146,24 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec)
 | 
				
			||||||
	double sx, sy;
 | 
						double sx, sy;
 | 
				
			||||||
	struct sway_container *c = container_at_coords(cursor->seat,
 | 
						struct sway_container *c = container_at_coords(cursor->seat,
 | 
				
			||||||
			cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
 | 
								cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
 | 
				
			||||||
	if (c && config->focus_follows_mouse) {
 | 
						if (c && config->focus_follows_mouse && allow_refocusing) {
 | 
				
			||||||
		seat_set_focus_warp(cursor->seat, c, false);
 | 
							struct sway_container *focus = seat_get_focus(cursor->seat);
 | 
				
			||||||
 | 
							if (focus && c->type == C_WORKSPACE) {
 | 
				
			||||||
 | 
								// Only follow the mouse if it would move to a new output
 | 
				
			||||||
 | 
								// Otherwise we'll focus the workspace, which is probably wrong
 | 
				
			||||||
 | 
								if (focus->type != C_OUTPUT) {
 | 
				
			||||||
 | 
									focus = container_parent(focus, C_OUTPUT);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								struct sway_container *output = c;
 | 
				
			||||||
 | 
								if (output->type != C_OUTPUT) {
 | 
				
			||||||
 | 
									output = container_parent(c, C_OUTPUT);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (output != focus) {
 | 
				
			||||||
 | 
									seat_set_focus_warp(cursor->seat, c, false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								seat_set_focus_warp(cursor->seat, c, false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// reset cursor if switching between clients
 | 
						// reset cursor if switching between clients
 | 
				
			||||||
| 
						 | 
					@ -177,7 +194,7 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	struct wlr_event_pointer_motion *event = data;
 | 
						struct wlr_event_pointer_motion *event = data;
 | 
				
			||||||
	wlr_cursor_move(cursor->cursor, event->device,
 | 
						wlr_cursor_move(cursor->cursor, event->device,
 | 
				
			||||||
		event->delta_x, event->delta_y);
 | 
							event->delta_x, event->delta_y);
 | 
				
			||||||
	cursor_send_pointer_motion(cursor, event->time_msec);
 | 
						cursor_send_pointer_motion(cursor, event->time_msec, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_cursor_motion_absolute(
 | 
					static void handle_cursor_motion_absolute(
 | 
				
			||||||
| 
						 | 
					@ -187,7 +204,7 @@ static void handle_cursor_motion_absolute(
 | 
				
			||||||
	wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat);
 | 
						wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat);
 | 
				
			||||||
	struct wlr_event_pointer_motion_absolute *event = data;
 | 
						struct wlr_event_pointer_motion_absolute *event = data;
 | 
				
			||||||
	wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y);
 | 
						wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y);
 | 
				
			||||||
	cursor_send_pointer_motion(cursor, event->time_msec);
 | 
						cursor_send_pointer_motion(cursor, event->time_msec, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dispatch_cursor_button(struct sway_cursor *cursor,
 | 
					void dispatch_cursor_button(struct sway_cursor *cursor,
 | 
				
			||||||
| 
						 | 
					@ -357,7 +374,7 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_cursor_warp_absolute(cursor->cursor, event->device, x, y);
 | 
						wlr_cursor_warp_absolute(cursor->cursor, event->device, x, y);
 | 
				
			||||||
	cursor_send_pointer_motion(cursor, event->time_msec);
 | 
						cursor_send_pointer_motion(cursor, event->time_msec, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_tool_tip(struct wl_listener *listener, void *data) {
 | 
					static void handle_tool_tip(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -602,7 +602,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
						wlr_output, seat->cursor->cursor->x,
 | 
											wlr_output, seat->cursor->cursor->x,
 | 
				
			||||||
						seat->cursor->cursor->y)) {
 | 
											seat->cursor->cursor->y)) {
 | 
				
			||||||
					wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);
 | 
										wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);
 | 
				
			||||||
					cursor_send_pointer_motion(seat->cursor, 0);
 | 
										cursor_send_pointer_motion(seat->cursor, 0, true);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -613,7 +613,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (last_workspace && last_workspace != new_workspace) {
 | 
						if (last_workspace && last_workspace != new_workspace) {
 | 
				
			||||||
		cursor_send_pointer_motion(seat->cursor, 0);
 | 
							cursor_send_pointer_motion(seat->cursor, 0, true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seat->has_focus = (container != NULL);
 | 
						seat->has_focus = (container != NULL);
 | 
				
			||||||
| 
						 | 
					@ -718,6 +718,18 @@ struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
 | 
				
			||||||
	return seat_get_focus_by_type(seat, container, C_TYPES);
 | 
						return seat_get_focus_by_type(seat, container, C_TYPES);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_container *seat_get_active_child(struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct sway_container *container) {
 | 
				
			||||||
 | 
						struct sway_container *focus = seat_get_focus_inactive(seat, container);
 | 
				
			||||||
 | 
						if (!focus) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						while (focus->parent != container) {
 | 
				
			||||||
 | 
							focus = focus->parent;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return focus;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *sway_seat_get_focus(struct sway_seat *seat) {
 | 
					struct sway_container *sway_seat_get_focus(struct sway_seat *seat) {
 | 
				
			||||||
	if (!seat->has_focus) {
 | 
						if (!seat->has_focus) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include "sway/server.h"
 | 
					#include "sway/server.h"
 | 
				
			||||||
#include "sway/input/input-manager.h"
 | 
					#include "sway/input/input-manager.h"
 | 
				
			||||||
#include "sway/input/seat.h"
 | 
					#include "sway/input/seat.h"
 | 
				
			||||||
 | 
					#include "sway/tree/view.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -429,6 +430,16 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
 | 
				
			||||||
			json_object_new_boolean(visible));
 | 
								json_object_new_boolean(visible));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ipc_get_marks_callback(struct sway_container *con, void *data) {
 | 
				
			||||||
 | 
						json_object *marks = (json_object *)data;
 | 
				
			||||||
 | 
						if (con->type == C_VIEW && con->sway_view->marks) {
 | 
				
			||||||
 | 
							for (int i = 0; i < con->sway_view->marks->length; ++i) {
 | 
				
			||||||
 | 
								char *mark = (char *)con->sway_view->marks->items[i];
 | 
				
			||||||
 | 
								json_object_array_add(marks, json_object_new_string(mark));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ipc_client_handle_command(struct ipc_client *client) {
 | 
					void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
	if (!sway_assert(client != NULL, "client != NULL")) {
 | 
						if (!sway_assert(client != NULL, "client != NULL")) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -569,6 +580,17 @@ void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
		goto exit_cleanup;
 | 
							goto exit_cleanup;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case IPC_GET_MARKS:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							json_object *marks = json_object_new_array();
 | 
				
			||||||
 | 
							container_descendants(&root_container, C_VIEW, ipc_get_marks_callback,
 | 
				
			||||||
 | 
									marks);
 | 
				
			||||||
 | 
							const char *json_string = json_object_to_json_string(marks);
 | 
				
			||||||
 | 
							ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
 | 
				
			||||||
 | 
							json_object_put(marks);
 | 
				
			||||||
 | 
							goto exit_cleanup;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case IPC_GET_VERSION:
 | 
						case IPC_GET_VERSION:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		json_object *version = ipc_json_get_version();
 | 
							json_object *version = ipc_json_get_version();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,6 +86,15 @@ static void apply_horiz_layout(struct sway_container *parent) {
 | 
				
			||||||
	if (!num_children) {
 | 
						if (!num_children) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						size_t parent_offset = 0;
 | 
				
			||||||
 | 
						if (parent->parent->layout == L_TABBED) {
 | 
				
			||||||
 | 
							parent_offset = container_titlebar_height();
 | 
				
			||||||
 | 
						} else if (parent->parent->layout == L_STACKED) {
 | 
				
			||||||
 | 
							parent_offset =
 | 
				
			||||||
 | 
								container_titlebar_height() * parent->parent->children->length;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						size_t parent_height = parent->height - parent_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Calculate total width of children
 | 
						// Calculate total width of children
 | 
				
			||||||
	double total_width = 0;
 | 
						double total_width = 0;
 | 
				
			||||||
	for (size_t i = 0; i < num_children; ++i) {
 | 
						for (size_t i = 0; i < num_children; ++i) {
 | 
				
			||||||
| 
						 | 
					@ -111,9 +120,9 @@ static void apply_horiz_layout(struct sway_container *parent) {
 | 
				
			||||||
				"Calculating arrangement for %p:%d (will scale %f by %f)",
 | 
									"Calculating arrangement for %p:%d (will scale %f by %f)",
 | 
				
			||||||
				child, child->type, child->width, scale);
 | 
									child, child->type, child->width, scale);
 | 
				
			||||||
		child->x = child_x;
 | 
							child->x = child_x;
 | 
				
			||||||
		child->y = parent->y;
 | 
							child->y = parent->y + parent_offset;
 | 
				
			||||||
		child->width = floor(child->width * scale);
 | 
							child->width = floor(child->width * scale);
 | 
				
			||||||
		child->height = parent->height;
 | 
							child->height = parent_height;
 | 
				
			||||||
		child_x += child->width;
 | 
							child_x += child->width;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Make last child use remaining width of parent
 | 
						// Make last child use remaining width of parent
 | 
				
			||||||
| 
						 | 
					@ -125,24 +134,33 @@ static void apply_vert_layout(struct sway_container *parent) {
 | 
				
			||||||
	if (!num_children) {
 | 
						if (!num_children) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						size_t parent_offset = 0;
 | 
				
			||||||
 | 
						if (parent->parent->layout == L_TABBED) {
 | 
				
			||||||
 | 
							parent_offset = container_titlebar_height();
 | 
				
			||||||
 | 
						} else if (parent->parent->layout == L_STACKED) {
 | 
				
			||||||
 | 
							parent_offset =
 | 
				
			||||||
 | 
								container_titlebar_height() * parent->parent->children->length;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						size_t parent_height = parent->height - parent_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Calculate total height of children
 | 
						// Calculate total height of children
 | 
				
			||||||
	double total_height = 0;
 | 
						double total_height = 0;
 | 
				
			||||||
	for (size_t i = 0; i < num_children; ++i) {
 | 
						for (size_t i = 0; i < num_children; ++i) {
 | 
				
			||||||
		struct sway_container *child = parent->children->items[i];
 | 
							struct sway_container *child = parent->children->items[i];
 | 
				
			||||||
		if (child->height <= 0) {
 | 
							if (child->height <= 0) {
 | 
				
			||||||
			if (num_children > 1) {
 | 
								if (num_children > 1) {
 | 
				
			||||||
				child->height = parent->height / (num_children - 1);
 | 
									child->height = parent_height / (num_children - 1);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				child->height = parent->height;
 | 
									child->height = parent_height;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		total_height += child->height;
 | 
							total_height += child->height;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	double scale = parent->height / total_height;
 | 
						double scale = parent_height / total_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Resize
 | 
						// Resize
 | 
				
			||||||
	wlr_log(L_DEBUG, "Arranging %p vertically", parent);
 | 
						wlr_log(L_DEBUG, "Arranging %p vertically", parent);
 | 
				
			||||||
	double child_y = parent->y;
 | 
						double child_y = parent->y + parent_offset;
 | 
				
			||||||
	struct sway_container *child;
 | 
						struct sway_container *child;
 | 
				
			||||||
	for (size_t i = 0; i < num_children; ++i) {
 | 
						for (size_t i = 0; i < num_children; ++i) {
 | 
				
			||||||
		child = parent->children->items[i];
 | 
							child = parent->children->items[i];
 | 
				
			||||||
| 
						 | 
					@ -156,7 +174,33 @@ static void apply_vert_layout(struct sway_container *parent) {
 | 
				
			||||||
		child_y += child->height;
 | 
							child_y += child->height;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Make last child use remaining height of parent
 | 
						// Make last child use remaining height of parent
 | 
				
			||||||
	child->height = parent->y + parent->height - child->y;
 | 
						child->height = parent->y + parent_offset + parent_height - child->y;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void apply_tabbed_layout(struct sway_container *parent) {
 | 
				
			||||||
 | 
						if (!parent->children->length) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (int i = 0; i < parent->children->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_container *child = parent->children->items[i];
 | 
				
			||||||
 | 
							child->x = parent->x;
 | 
				
			||||||
 | 
							child->y = parent->y;
 | 
				
			||||||
 | 
							child->width = parent->width;
 | 
				
			||||||
 | 
							child->height = parent->height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void apply_stacked_layout(struct sway_container *parent) {
 | 
				
			||||||
 | 
						if (!parent->children->length) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (int i = 0; i < parent->children->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_container *child = parent->children->items[i];
 | 
				
			||||||
 | 
							child->x = parent->x;
 | 
				
			||||||
 | 
							child->y = parent->y;
 | 
				
			||||||
 | 
							child->width = parent->width;
 | 
				
			||||||
 | 
							child->height = parent->height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arrange_children_of(struct sway_container *parent) {
 | 
					void arrange_children_of(struct sway_container *parent) {
 | 
				
			||||||
| 
						 | 
					@ -189,6 +233,12 @@ void arrange_children_of(struct sway_container *parent) {
 | 
				
			||||||
	case L_VERT:
 | 
						case L_VERT:
 | 
				
			||||||
		apply_vert_layout(parent);
 | 
							apply_vert_layout(parent);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case L_TABBED:
 | 
				
			||||||
 | 
							apply_tabbed_layout(parent);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case L_STACKED:
 | 
				
			||||||
 | 
							apply_stacked_layout(parent);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
 | 
							wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
 | 
				
			||||||
		apply_horiz_layout(parent);
 | 
							apply_horiz_layout(parent);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,6 +73,44 @@ static void container_close_notify(struct sway_container *container) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void container_update_textures_recursive(struct sway_container *con) {
 | 
				
			||||||
 | 
						container_update_title_textures(con);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (con->type == C_VIEW) {
 | 
				
			||||||
 | 
							view_update_marks_textures(con->sway_view);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							for (int i = 0; i < con->children->length; ++i) {
 | 
				
			||||||
 | 
								struct sway_container *child = con->children->items[i];
 | 
				
			||||||
 | 
								container_update_textures_recursive(child);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_reparent(struct wl_listener *listener,
 | 
				
			||||||
 | 
							void *data) {
 | 
				
			||||||
 | 
						struct sway_container *container =
 | 
				
			||||||
 | 
							wl_container_of(listener, container, reparent);
 | 
				
			||||||
 | 
						struct sway_container *old_parent = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_container *old_output = old_parent;
 | 
				
			||||||
 | 
						if (old_output != NULL && old_output->type != C_OUTPUT) {
 | 
				
			||||||
 | 
							old_output = container_parent(old_output, C_OUTPUT);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_container *new_output = container->parent;
 | 
				
			||||||
 | 
						if (new_output != NULL && new_output->type != C_OUTPUT) {
 | 
				
			||||||
 | 
							new_output = container_parent(new_output, C_OUTPUT);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (old_output && new_output) {
 | 
				
			||||||
 | 
							float old_scale = old_output->sway_output->wlr_output->scale;
 | 
				
			||||||
 | 
							float new_scale = new_output->sway_output->wlr_output->scale;
 | 
				
			||||||
 | 
							if (old_scale != new_scale) {
 | 
				
			||||||
 | 
								container_update_textures_recursive(container);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *container_create(enum sway_container_type type) {
 | 
					struct sway_container *container_create(enum sway_container_type type) {
 | 
				
			||||||
	// next id starts at 1 because 0 is assigned to root_container in layout.c
 | 
						// next id starts at 1 because 0 is assigned to root_container in layout.c
 | 
				
			||||||
	static size_t next_id = 1;
 | 
						static size_t next_id = 1;
 | 
				
			||||||
| 
						 | 
					@ -92,6 +130,9 @@ struct sway_container *container_create(enum sway_container_type type) {
 | 
				
			||||||
	wl_signal_init(&c->events.destroy);
 | 
						wl_signal_init(&c->events.destroy);
 | 
				
			||||||
	wl_signal_init(&c->events.reparent);
 | 
						wl_signal_init(&c->events.reparent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_add(&c->events.reparent, &c->reparent);
 | 
				
			||||||
 | 
						c->reparent.notify = handle_reparent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c;
 | 
						return c;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -411,79 +452,153 @@ struct sway_container *container_parent(struct sway_container *container,
 | 
				
			||||||
	return container;
 | 
						return container;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sway_container *container_at(struct sway_container *parent,
 | 
					static struct sway_container *container_at_view(struct sway_container *swayc,
 | 
				
			||||||
		double lx, double ly,
 | 
							double ox, double oy,
 | 
				
			||||||
		struct wlr_surface **surface, double *sx, double *sy) {
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
	list_t *queue = get_bfs_queue();
 | 
						if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) {
 | 
				
			||||||
	if (!queue) {
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_view *sview = swayc->sway_view;
 | 
				
			||||||
 | 
						double view_sx = ox - sview->x;
 | 
				
			||||||
 | 
						double view_sy = oy - sview->y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						double _sx, _sy;
 | 
				
			||||||
 | 
						struct wlr_surface *_surface = NULL;
 | 
				
			||||||
 | 
						switch (sview->type) {
 | 
				
			||||||
 | 
						case SWAY_VIEW_XWAYLAND:
 | 
				
			||||||
 | 
							_surface = wlr_surface_surface_at(sview->surface,
 | 
				
			||||||
 | 
									view_sx, view_sy, &_sx, &_sy);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SWAY_VIEW_XDG_SHELL_V6:
 | 
				
			||||||
 | 
							// the top left corner of the sway container is the
 | 
				
			||||||
 | 
							// coordinate of the top left corner of the window geometry
 | 
				
			||||||
 | 
							view_sx += sview->wlr_xdg_surface_v6->geometry.x;
 | 
				
			||||||
 | 
							view_sy += sview->wlr_xdg_surface_v6->geometry.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_surface = wlr_xdg_surface_v6_surface_at(
 | 
				
			||||||
 | 
									sview->wlr_xdg_surface_v6,
 | 
				
			||||||
 | 
									view_sx, view_sy, &_sx, &_sy);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SWAY_VIEW_XDG_SHELL:
 | 
				
			||||||
 | 
							// the top left corner of the sway container is the
 | 
				
			||||||
 | 
							// coordinate of the top left corner of the window geometry
 | 
				
			||||||
 | 
							view_sx += sview->wlr_xdg_surface->geometry.x;
 | 
				
			||||||
 | 
							view_sy += sview->wlr_xdg_surface->geometry.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_surface = wlr_xdg_surface_surface_at(
 | 
				
			||||||
 | 
									sview->wlr_xdg_surface,
 | 
				
			||||||
 | 
									view_sx, view_sy, &_sx, &_sy);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (_surface) {
 | 
				
			||||||
 | 
							*sx = _sx;
 | 
				
			||||||
 | 
							*sy = _sy;
 | 
				
			||||||
 | 
							*surface = _surface;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return swayc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * container_at for a container with layout L_TABBED.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct sway_container *container_at_tabbed(struct sway_container *parent,
 | 
				
			||||||
 | 
							double ox, double oy,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
 | 
						if (oy < parent->y || oy > parent->y + parent->height) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Tab titles
 | 
				
			||||||
 | 
						int title_height = container_titlebar_height();
 | 
				
			||||||
 | 
						if (oy < parent->y + title_height) {
 | 
				
			||||||
 | 
							int tab_width = parent->width / parent->children->length;
 | 
				
			||||||
 | 
							int child_index = (ox - parent->x) / tab_width;
 | 
				
			||||||
 | 
							if (child_index >= parent->children->length) {
 | 
				
			||||||
 | 
								child_index = parent->children->length - 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							struct sway_container *child = parent->children->items[child_index];
 | 
				
			||||||
 | 
							return seat_get_focus_inactive(seat, child);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Surfaces
 | 
				
			||||||
 | 
						struct sway_container *current = seat_get_active_child(seat, parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return container_at(current, ox, oy, surface, sx, sy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * container_at for a container with layout L_STACKED.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct sway_container *container_at_stacked(
 | 
				
			||||||
 | 
							struct sway_container *parent, double ox, double oy,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
 | 
						if (oy < parent->y || oy > parent->y + parent->height) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Title bars
 | 
				
			||||||
 | 
						int title_height = container_titlebar_height();
 | 
				
			||||||
 | 
						int child_index = (oy - parent->y) / title_height;
 | 
				
			||||||
 | 
						if (child_index < parent->children->length) {
 | 
				
			||||||
 | 
							struct sway_container *child = parent->children->items[child_index];
 | 
				
			||||||
 | 
							return seat_get_focus_inactive(seat, child);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Surfaces
 | 
				
			||||||
 | 
						struct sway_container *current = seat_get_active_child(seat, parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return container_at(current, ox, oy, surface, sx, sy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * container_at for a container with layout L_HORIZ or L_VERT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct sway_container *container_at_linear(struct sway_container *parent,
 | 
				
			||||||
 | 
							double ox, double oy,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
 | 
						for (int i = 0; i < parent->children->length; ++i) {
 | 
				
			||||||
 | 
							struct sway_container *child = parent->children->items[i];
 | 
				
			||||||
 | 
							struct wlr_box box = {
 | 
				
			||||||
 | 
								.x = child->x,
 | 
				
			||||||
 | 
								.y = child->y,
 | 
				
			||||||
 | 
								.width = child->width,
 | 
				
			||||||
 | 
								.height = child->height,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							if (wlr_box_contains_point(&box, ox, oy)) {
 | 
				
			||||||
 | 
								return container_at(child, ox, oy, surface, sx, sy);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_container *container_at(struct sway_container *parent,
 | 
				
			||||||
 | 
							double ox, double oy,
 | 
				
			||||||
 | 
							struct wlr_surface **surface, double *sx, double *sy) {
 | 
				
			||||||
 | 
						if (!sway_assert(parent->type >= C_WORKSPACE,
 | 
				
			||||||
 | 
									"Expected workspace or deeper")) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (parent->type == C_VIEW) {
 | 
				
			||||||
 | 
							return container_at_view(parent, ox, oy, surface, sx, sy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!parent->children->length) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_add(queue, parent);
 | 
						switch (parent->layout) {
 | 
				
			||||||
 | 
						case L_HORIZ:
 | 
				
			||||||
	struct sway_container *swayc = NULL;
 | 
						case L_VERT:
 | 
				
			||||||
	while (queue->length) {
 | 
							return container_at_linear(parent, ox, oy, surface, sx, sy);
 | 
				
			||||||
		swayc = queue->items[0];
 | 
						case L_TABBED:
 | 
				
			||||||
		list_del(queue, 0);
 | 
							return container_at_tabbed(parent, ox, oy, surface, sx, sy);
 | 
				
			||||||
		if (swayc->type == C_VIEW) {
 | 
						case L_STACKED:
 | 
				
			||||||
			struct sway_view *sview = swayc->sway_view;
 | 
							return container_at_stacked(parent, ox, oy, surface, sx, sy);
 | 
				
			||||||
			struct sway_container *soutput = container_parent(swayc, C_OUTPUT);
 | 
						case L_FLOATING:
 | 
				
			||||||
			struct wlr_box *output_box =
 | 
							return NULL; // TODO
 | 
				
			||||||
				wlr_output_layout_get_box(
 | 
						case L_NONE:
 | 
				
			||||||
					root_container.sway_root->output_layout,
 | 
							return NULL;
 | 
				
			||||||
					soutput->sway_output->wlr_output);
 | 
					 | 
				
			||||||
			double ox = lx - output_box->x;
 | 
					 | 
				
			||||||
			double oy = ly - output_box->y;
 | 
					 | 
				
			||||||
			double view_sx = ox - sview->x;
 | 
					 | 
				
			||||||
			double view_sy = oy - sview->y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			double _sx, _sy;
 | 
					 | 
				
			||||||
			struct wlr_surface *_surface;
 | 
					 | 
				
			||||||
			switch (sview->type) {
 | 
					 | 
				
			||||||
			case SWAY_VIEW_XWAYLAND:
 | 
					 | 
				
			||||||
				_surface = wlr_surface_surface_at(sview->surface,
 | 
					 | 
				
			||||||
					view_sx, view_sy, &_sx, &_sy);
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			case SWAY_VIEW_XDG_SHELL_V6:
 | 
					 | 
				
			||||||
				// the top left corner of the sway container is the
 | 
					 | 
				
			||||||
				// coordinate of the top left corner of the window geometry
 | 
					 | 
				
			||||||
				view_sx += sview->wlr_xdg_surface_v6->geometry.x;
 | 
					 | 
				
			||||||
				view_sy += sview->wlr_xdg_surface_v6->geometry.y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				_surface = wlr_xdg_surface_v6_surface_at(
 | 
					 | 
				
			||||||
					sview->wlr_xdg_surface_v6,
 | 
					 | 
				
			||||||
					view_sx, view_sy, &_sx, &_sy);
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			case SWAY_VIEW_XDG_SHELL:
 | 
					 | 
				
			||||||
				// the top left corner of the sway container is the
 | 
					 | 
				
			||||||
				// coordinate of the top left corner of the window geometry
 | 
					 | 
				
			||||||
				view_sx += sview->wlr_xdg_surface->geometry.x;
 | 
					 | 
				
			||||||
				view_sy += sview->wlr_xdg_surface->geometry.y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				_surface = wlr_xdg_surface_surface_at(
 | 
					 | 
				
			||||||
					sview->wlr_xdg_surface,
 | 
					 | 
				
			||||||
					view_sx, view_sy, &_sx, &_sy);
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (_surface) {
 | 
					 | 
				
			||||||
				*sx = _sx;
 | 
					 | 
				
			||||||
				*sy = _sy;
 | 
					 | 
				
			||||||
				*surface = _surface;
 | 
					 | 
				
			||||||
				return swayc;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			// Check the view's decorations
 | 
					 | 
				
			||||||
			struct wlr_box swayc_box = {
 | 
					 | 
				
			||||||
				.x = swayc->x,
 | 
					 | 
				
			||||||
				.y = swayc->y,
 | 
					 | 
				
			||||||
				.width = swayc->width,
 | 
					 | 
				
			||||||
				.height = swayc->height,
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			if (wlr_box_contains_point(&swayc_box, ox, oy)) {
 | 
					 | 
				
			||||||
				return swayc;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			list_cat(queue, swayc->children);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
| 
						 | 
					@ -658,19 +773,96 @@ void container_calculate_title_height(struct sway_container *container) {
 | 
				
			||||||
	container->title_height = height;
 | 
						container->title_height = height;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculate and return the length of the concatenated child titles.
 | 
				
			||||||
 | 
					 * An example concatenated title is: V[Terminal, Firefox]
 | 
				
			||||||
 | 
					 * If buffer is not NULL, also populate the buffer with the concatenated title.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static size_t concatenate_child_titles(struct sway_container *parent,
 | 
				
			||||||
 | 
							char *buffer) {
 | 
				
			||||||
 | 
						size_t len = 2; // V[
 | 
				
			||||||
 | 
						if (buffer) {
 | 
				
			||||||
 | 
							switch (parent->layout) {
 | 
				
			||||||
 | 
							case L_VERT:
 | 
				
			||||||
 | 
								strcpy(buffer, "V[");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case L_HORIZ:
 | 
				
			||||||
 | 
								strcpy(buffer, "H[");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case L_TABBED:
 | 
				
			||||||
 | 
								strcpy(buffer, "T[");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case L_STACKED:
 | 
				
			||||||
 | 
								strcpy(buffer, "S[");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case L_FLOATING:
 | 
				
			||||||
 | 
								strcpy(buffer, "F[");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case L_NONE:
 | 
				
			||||||
 | 
								strcpy(buffer, "D[");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < parent->children->length; ++i) {
 | 
				
			||||||
 | 
							if (i != 0) {
 | 
				
			||||||
 | 
								len += 1;
 | 
				
			||||||
 | 
								if (buffer) {
 | 
				
			||||||
 | 
									strcat(buffer, " ");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							struct sway_container *child = parent->children->items[i];
 | 
				
			||||||
 | 
							const char *identifier = NULL;
 | 
				
			||||||
 | 
							if (child->type == C_VIEW) {
 | 
				
			||||||
 | 
								identifier = view_get_class(child->sway_view);
 | 
				
			||||||
 | 
								if (!identifier) {
 | 
				
			||||||
 | 
									identifier = view_get_app_id(child->sway_view);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								identifier = child->name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (identifier) {
 | 
				
			||||||
 | 
								len += strlen(identifier);
 | 
				
			||||||
 | 
								if (buffer) {
 | 
				
			||||||
 | 
									strcat(buffer, identifier);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								len += 6;
 | 
				
			||||||
 | 
								if (buffer) {
 | 
				
			||||||
 | 
									strcat(buffer, "(null)");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len += 1;
 | 
				
			||||||
 | 
						if (buffer) {
 | 
				
			||||||
 | 
							strcat(buffer, "]");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void container_notify_child_title_changed(struct sway_container *container) {
 | 
					void container_notify_child_title_changed(struct sway_container *container) {
 | 
				
			||||||
	if (!container || container->type != C_CONTAINER) {
 | 
						if (!container || container->type != C_CONTAINER) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (container->layout != L_TABBED && container->layout != L_STACKED) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (container->formatted_title) {
 | 
						if (container->formatted_title) {
 | 
				
			||||||
		free(container->formatted_title);
 | 
							free(container->formatted_title);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// TODO: iterate children and concatenate their titles
 | 
					
 | 
				
			||||||
	container->formatted_title = strdup("");
 | 
						size_t len = concatenate_child_titles(container, NULL);
 | 
				
			||||||
 | 
						char *buffer = calloc(len + 1, sizeof(char));
 | 
				
			||||||
 | 
						if (!sway_assert(buffer, "Unable to allocate title string")) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						concatenate_child_titles(container, buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container->name = buffer;
 | 
				
			||||||
 | 
						container->formatted_title = buffer;
 | 
				
			||||||
	container_calculate_title_height(container);
 | 
						container_calculate_title_height(container);
 | 
				
			||||||
	container_update_title_textures(container);
 | 
						container_update_title_textures(container);
 | 
				
			||||||
	container_notify_child_title_changed(container->parent);
 | 
						container_notify_child_title_changed(container->parent);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t container_titlebar_height() {
 | 
				
			||||||
 | 
						return config->font_height + TITLEBAR_V_PADDING * 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,6 +149,8 @@ struct sway_container *container_remove_child(struct sway_container *child) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	child->parent = NULL;
 | 
						child->parent = NULL;
 | 
				
			||||||
 | 
						container_notify_child_title_changed(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return parent;
 | 
						return parent;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -182,6 +184,8 @@ void container_move_to(struct sway_container *container,
 | 
				
			||||||
		container_sort_workspaces(new_parent);
 | 
							container_sort_workspaces(new_parent);
 | 
				
			||||||
		seat_set_focus(seat, new_parent);
 | 
							seat_set_focus(seat, new_parent);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						container_notify_child_title_changed(old_parent);
 | 
				
			||||||
 | 
						container_notify_child_title_changed(new_parent);
 | 
				
			||||||
	if (old_parent) {
 | 
						if (old_parent) {
 | 
				
			||||||
		arrange_children_of(old_parent);
 | 
							arrange_children_of(old_parent);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -234,9 +238,9 @@ static bool is_parallel(enum sway_container_layout layout,
 | 
				
			||||||
		enum movement_direction dir) {
 | 
							enum movement_direction dir) {
 | 
				
			||||||
	switch (layout) {
 | 
						switch (layout) {
 | 
				
			||||||
	case L_TABBED:
 | 
						case L_TABBED:
 | 
				
			||||||
	case L_STACKED:
 | 
					 | 
				
			||||||
	case L_HORIZ:
 | 
						case L_HORIZ:
 | 
				
			||||||
		return dir == MOVE_LEFT || dir == MOVE_RIGHT;
 | 
							return dir == MOVE_LEFT || dir == MOVE_RIGHT;
 | 
				
			||||||
 | 
						case L_STACKED:
 | 
				
			||||||
	case L_VERT:
 | 
						case L_VERT:
 | 
				
			||||||
		return dir == MOVE_UP || dir == MOVE_DOWN;
 | 
							return dir == MOVE_UP || dir == MOVE_DOWN;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
| 
						 | 
					@ -485,6 +489,9 @@ void container_move(struct sway_container *container,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_notify_child_title_changed(old_parent);
 | 
				
			||||||
 | 
						container_notify_child_title_changed(container->parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (old_parent) {
 | 
						if (old_parent) {
 | 
				
			||||||
		seat_set_focus(config->handler_context.seat, old_parent);
 | 
							seat_set_focus(config->handler_context.seat, old_parent);
 | 
				
			||||||
		seat_set_focus(config->handler_context.seat, container);
 | 
							seat_set_focus(config->handler_context.seat, container);
 | 
				
			||||||
| 
						 | 
					@ -832,6 +839,8 @@ struct sway_container *container_split(struct sway_container *child,
 | 
				
			||||||
		container_add_child(cont, child);
 | 
							container_add_child(cont, child);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container_notify_child_title_changed(cont);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cont;
 | 
						return cont;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -139,10 +139,20 @@ void view_autoconfigure(struct sway_view *view) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int other_views = 1;
 | 
						struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int other_views = 0;
 | 
				
			||||||
	if (config->hide_edge_borders == E_SMART) {
 | 
						if (config->hide_edge_borders == E_SMART) {
 | 
				
			||||||
		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
							struct sway_container *con = view->swayc;
 | 
				
			||||||
		other_views = container_count_descendants_of_type(ws, C_VIEW) - 1;
 | 
							while (con != output) {
 | 
				
			||||||
 | 
								if (con->layout != L_TABBED && con->layout != L_STACKED) {
 | 
				
			||||||
 | 
									other_views += con->children ? con->children->length - 1 : 0;
 | 
				
			||||||
 | 
									if (other_views > 0) {
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								con = con->parent;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view->border_top = view->border_bottom = true;
 | 
						view->border_top = view->border_bottom = true;
 | 
				
			||||||
| 
						 | 
					@ -151,47 +161,67 @@ void view_autoconfigure(struct sway_view *view) {
 | 
				
			||||||
		if (config->hide_edge_borders == E_BOTH
 | 
							if (config->hide_edge_borders == E_BOTH
 | 
				
			||||||
				|| config->hide_edge_borders == E_VERTICAL
 | 
									|| config->hide_edge_borders == E_VERTICAL
 | 
				
			||||||
				|| (config->hide_edge_borders == E_SMART && !other_views)) {
 | 
									|| (config->hide_edge_borders == E_SMART && !other_views)) {
 | 
				
			||||||
			view->border_left = view->swayc->x != 0;
 | 
								view->border_left = view->swayc->x != ws->x;
 | 
				
			||||||
			int right_x = view->swayc->x + view->swayc->width;
 | 
								int right_x = view->swayc->x + view->swayc->width;
 | 
				
			||||||
			view->border_right = right_x != output->width;
 | 
								view->border_right = right_x != ws->x + ws->width;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (config->hide_edge_borders == E_BOTH
 | 
							if (config->hide_edge_borders == E_BOTH
 | 
				
			||||||
				|| config->hide_edge_borders == E_HORIZONTAL
 | 
									|| config->hide_edge_borders == E_HORIZONTAL
 | 
				
			||||||
				|| (config->hide_edge_borders == E_SMART && !other_views)) {
 | 
									|| (config->hide_edge_borders == E_SMART && !other_views)) {
 | 
				
			||||||
			view->border_top = view->swayc->y != 0;
 | 
								view->border_top = view->swayc->y != ws->y;
 | 
				
			||||||
			int bottom_y = view->swayc->y + view->swayc->height;
 | 
								int bottom_y = view->swayc->y + view->swayc->height;
 | 
				
			||||||
			view->border_bottom = bottom_y != output->height;
 | 
								view->border_bottom = bottom_y != ws->y + ws->height;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	double x, y, width, height;
 | 
						double x, y, width, height;
 | 
				
			||||||
	x = y = width = height = 0;
 | 
						x = y = width = height = 0;
 | 
				
			||||||
 | 
						double y_offset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// In a tabbed or stacked container, the swayc's y is the top of the title
 | 
				
			||||||
 | 
						// area. We have to offset the surface y by the height of the title bar, and
 | 
				
			||||||
 | 
						// disable any top border because we'll always have the title bar.
 | 
				
			||||||
 | 
						if (view->swayc->parent->layout == L_TABBED) {
 | 
				
			||||||
 | 
							y_offset = container_titlebar_height();
 | 
				
			||||||
 | 
							view->border_top = 0;
 | 
				
			||||||
 | 
						} else if (view->swayc->parent->layout == L_STACKED) {
 | 
				
			||||||
 | 
							y_offset = container_titlebar_height()
 | 
				
			||||||
 | 
								* view->swayc->parent->children->length;
 | 
				
			||||||
 | 
							view->border_top = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (view->border) {
 | 
						switch (view->border) {
 | 
				
			||||||
	case B_NONE:
 | 
						case B_NONE:
 | 
				
			||||||
		x = view->swayc->x;
 | 
							x = view->swayc->x;
 | 
				
			||||||
		y = view->swayc->y;
 | 
							y = view->swayc->y + y_offset;
 | 
				
			||||||
		width = view->swayc->width;
 | 
							width = view->swayc->width;
 | 
				
			||||||
		height = view->swayc->height;
 | 
							height = view->swayc->height - y_offset;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case B_PIXEL:
 | 
						case B_PIXEL:
 | 
				
			||||||
		x = view->swayc->x + view->border_thickness * view->border_left;
 | 
							x = view->swayc->x + view->border_thickness * view->border_left;
 | 
				
			||||||
		y = view->swayc->y + view->border_thickness * view->border_top;
 | 
							y = view->swayc->y + view->border_thickness * view->border_top + y_offset;
 | 
				
			||||||
		width = view->swayc->width
 | 
							width = view->swayc->width
 | 
				
			||||||
			- view->border_thickness * view->border_left
 | 
								- view->border_thickness * view->border_left
 | 
				
			||||||
			- view->border_thickness * view->border_right;
 | 
								- view->border_thickness * view->border_right;
 | 
				
			||||||
		height = view->swayc->height
 | 
							height = view->swayc->height - y_offset
 | 
				
			||||||
			- view->border_thickness * view->border_top
 | 
								- view->border_thickness * view->border_top
 | 
				
			||||||
			- view->border_thickness * view->border_bottom;
 | 
								- view->border_thickness * view->border_bottom;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case B_NORMAL:
 | 
						case B_NORMAL:
 | 
				
			||||||
		// Height is: border + title height + border + view height + border
 | 
							// Height is: 1px border + 3px pad + title height + 3px pad + 1px border
 | 
				
			||||||
		x = view->swayc->x + view->border_thickness * view->border_left;
 | 
							x = view->swayc->x + view->border_thickness * view->border_left;
 | 
				
			||||||
		y = view->swayc->y + config->font_height + view->border_thickness * 2;
 | 
					 | 
				
			||||||
		width = view->swayc->width
 | 
							width = view->swayc->width
 | 
				
			||||||
			- view->border_thickness * view->border_left
 | 
								- view->border_thickness * view->border_left
 | 
				
			||||||
			- view->border_thickness * view->border_right;
 | 
								- view->border_thickness * view->border_right;
 | 
				
			||||||
		height = view->swayc->height - config->font_height
 | 
							if (y_offset) {
 | 
				
			||||||
			- view->border_thickness * (2 + view->border_bottom);
 | 
								y = view->swayc->y + y_offset;
 | 
				
			||||||
 | 
								height = view->swayc->height - y_offset
 | 
				
			||||||
 | 
									- view->border_thickness * view->border_bottom;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								y = view->swayc->y + container_titlebar_height();
 | 
				
			||||||
 | 
								height = view->swayc->height - container_titlebar_height()
 | 
				
			||||||
 | 
									- view->border_thickness * view->border_bottom;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -440,6 +470,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
 | 
				
			||||||
	input_manager_set_focus(input_manager, cont);
 | 
						input_manager_set_focus(input_manager, cont);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	view_update_title(view, false);
 | 
						view_update_title(view, false);
 | 
				
			||||||
 | 
						container_notify_child_title_changed(view->swayc->parent);
 | 
				
			||||||
	view_execute_criteria(view);
 | 
						view_execute_criteria(view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container_damage_whole(cont);
 | 
						container_damage_whole(cont);
 | 
				
			||||||
| 
						 | 
					@ -863,3 +894,28 @@ void view_update_marks_textures(struct sway_view *view) {
 | 
				
			||||||
			&config->border_colors.urgent);
 | 
								&config->border_colors.urgent);
 | 
				
			||||||
	container_damage_whole(view->swayc);
 | 
						container_damage_whole(view->swayc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool view_is_visible(struct sway_view *view) {
 | 
				
			||||||
 | 
						if (!view->swayc) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Check view isn't in a tabbed or stacked container on an inactive tab
 | 
				
			||||||
 | 
						struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
				
			||||||
 | 
						struct sway_container *container = view->swayc;
 | 
				
			||||||
 | 
						while (container->type != C_WORKSPACE) {
 | 
				
			||||||
 | 
							if (container->parent->layout == L_TABBED ||
 | 
				
			||||||
 | 
									container->parent->layout == L_STACKED) {
 | 
				
			||||||
 | 
								if (seat_get_active_child(seat, container->parent) != container) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							container = container->parent;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Check view isn't hidden by another fullscreen view
 | 
				
			||||||
 | 
						struct sway_container *workspace = container;
 | 
				
			||||||
 | 
						if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Check the workspace is visible
 | 
				
			||||||
 | 
						return workspace_is_visible(workspace);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										158
									
								
								swaylock/main.c
									
										
									
									
									
								
							
							
						
						
									
										158
									
								
								swaylock/main.c
									
										
									
									
									
								
							| 
						 | 
					@ -13,6 +13,7 @@
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <wayland-client.h>
 | 
					#include <wayland-client.h>
 | 
				
			||||||
 | 
					#include <wordexp.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "swaylock/seat.h"
 | 
					#include "swaylock/seat.h"
 | 
				
			||||||
#include "swaylock/swaylock.h"
 | 
					#include "swaylock/swaylock.h"
 | 
				
			||||||
| 
						 | 
					@ -20,9 +21,11 @@
 | 
				
			||||||
#include "pool-buffer.h"
 | 
					#include "pool-buffer.h"
 | 
				
			||||||
#include "cairo.h"
 | 
					#include "cairo.h"
 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "stringop.h"
 | 
				
			||||||
#include "util.h"
 | 
					#include "util.h"
 | 
				
			||||||
#include "wlr-input-inhibitor-unstable-v1-client-protocol.h"
 | 
					#include "wlr-input-inhibitor-unstable-v1-client-protocol.h"
 | 
				
			||||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
 | 
					#include "wlr-layer-shell-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					#include "xdg-output-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sway_terminate(int exit_code) {
 | 
					void sway_terminate(int exit_code) {
 | 
				
			||||||
	exit(exit_code);
 | 
						exit(exit_code);
 | 
				
			||||||
| 
						 | 
					@ -77,9 +80,14 @@ static void destroy_surface(struct swaylock_surface *surface) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct zwlr_layer_surface_v1_listener layer_surface_listener;
 | 
					static const struct zwlr_layer_surface_v1_listener layer_surface_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static cairo_surface_t *select_image(struct swaylock_state *state,
 | 
				
			||||||
 | 
							struct swaylock_surface *surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void create_layer_surface(struct swaylock_surface *surface) {
 | 
					static void create_layer_surface(struct swaylock_surface *surface) {
 | 
				
			||||||
	struct swaylock_state *state = surface->state;
 | 
						struct swaylock_state *state = surface->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						surface->image = select_image(state, surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	surface->surface = wl_compositor_create_surface(state->compositor);
 | 
						surface->surface = wl_compositor_create_surface(state->compositor);
 | 
				
			||||||
	assert(surface->surface);
 | 
						assert(surface->surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,22 +131,23 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
 | 
				
			||||||
	.closed = layer_surface_closed,
 | 
						.closed = layer_surface_closed,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_geometry(void *data, struct wl_output *output, int32_t x,
 | 
					static void handle_wl_output_geometry(void *data, struct wl_output *output, int32_t x,
 | 
				
			||||||
		int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel,
 | 
							int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel,
 | 
				
			||||||
		const char *make, const char *model, int32_t transform) {
 | 
							const char *make, const char *model, int32_t transform) {
 | 
				
			||||||
	// Who cares
 | 
						// Who cares
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_mode(void *data, struct wl_output *output, uint32_t flags,
 | 
					static void handle_wl_output_mode(void *data, struct wl_output *output, uint32_t flags,
 | 
				
			||||||
		int32_t width, int32_t height, int32_t refresh) {
 | 
							int32_t width, int32_t height, int32_t refresh) {
 | 
				
			||||||
	// Who cares
 | 
						// Who cares
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_done(void *data, struct wl_output *output) {
 | 
					static void handle_wl_output_done(void *data, struct wl_output *output) {
 | 
				
			||||||
	// Who cares
 | 
						// Who cares
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_scale(void *data, struct wl_output *output, int32_t factor) {
 | 
					static void handle_wl_output_scale(void *data, struct wl_output *output,
 | 
				
			||||||
 | 
							int32_t factor) {
 | 
				
			||||||
	struct swaylock_surface *surface = data;
 | 
						struct swaylock_surface *surface = data;
 | 
				
			||||||
	surface->scale = factor;
 | 
						surface->scale = factor;
 | 
				
			||||||
	if (surface->state->run_display) {
 | 
						if (surface->state->run_display) {
 | 
				
			||||||
| 
						 | 
					@ -146,11 +155,46 @@ static void output_scale(void *data, struct wl_output *output, int32_t factor) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wl_output_listener output_listener = {
 | 
					struct wl_output_listener _wl_output_listener = {
 | 
				
			||||||
	.geometry = output_geometry,
 | 
						.geometry = handle_wl_output_geometry,
 | 
				
			||||||
	.mode = output_mode,
 | 
						.mode = handle_wl_output_mode,
 | 
				
			||||||
	.done = output_done,
 | 
						.done = handle_wl_output_done,
 | 
				
			||||||
	.scale = output_scale,
 | 
						.scale = handle_wl_output_scale,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_xdg_output_logical_size(void *data, struct zxdg_output_v1 *output,
 | 
				
			||||||
 | 
							int width, int height) {
 | 
				
			||||||
 | 
						// Who cares
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_xdg_output_logical_position(void *data,
 | 
				
			||||||
 | 
							struct zxdg_output_v1 *output, int x, int y) {
 | 
				
			||||||
 | 
						// Who cares
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output,
 | 
				
			||||||
 | 
							const char *name) {
 | 
				
			||||||
 | 
						wlr_log(L_DEBUG, "output name is %s", name);
 | 
				
			||||||
 | 
						struct swaylock_surface *surface = data;
 | 
				
			||||||
 | 
						surface->xdg_output = output;
 | 
				
			||||||
 | 
						surface->output_name = strdup(name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_xdg_output_description(void *data, struct zxdg_output_v1 *output,
 | 
				
			||||||
 | 
							const char *description) {
 | 
				
			||||||
 | 
						// Who cares
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_xdg_output_done(void *data, struct zxdg_output_v1 *output) {
 | 
				
			||||||
 | 
						// Who cares
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct zxdg_output_v1_listener _xdg_output_listener = {
 | 
				
			||||||
 | 
						.logical_position = handle_xdg_output_logical_position,
 | 
				
			||||||
 | 
						.logical_size = handle_xdg_output_logical_size,
 | 
				
			||||||
 | 
						.done = handle_xdg_output_done,
 | 
				
			||||||
 | 
						.name = handle_xdg_output_name,
 | 
				
			||||||
 | 
						.description = handle_xdg_output_description,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_global(void *data, struct wl_registry *registry,
 | 
					static void handle_global(void *data, struct wl_registry *registry,
 | 
				
			||||||
| 
						 | 
					@ -172,6 +216,9 @@ static void handle_global(void *data, struct wl_registry *registry,
 | 
				
			||||||
	} else if (strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name) == 0) {
 | 
						} else if (strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name) == 0) {
 | 
				
			||||||
		state->input_inhibit_manager = wl_registry_bind(
 | 
							state->input_inhibit_manager = wl_registry_bind(
 | 
				
			||||||
				registry, name, &zwlr_input_inhibit_manager_v1_interface, 1);
 | 
									registry, name, &zwlr_input_inhibit_manager_v1_interface, 1);
 | 
				
			||||||
 | 
						} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
 | 
				
			||||||
 | 
							state->zxdg_output_manager = wl_registry_bind(
 | 
				
			||||||
 | 
									registry, name, &zxdg_output_manager_v1_interface, 2);
 | 
				
			||||||
	} else if (strcmp(interface, wl_output_interface.name) == 0) {
 | 
						} else if (strcmp(interface, wl_output_interface.name) == 0) {
 | 
				
			||||||
		struct swaylock_surface *surface =
 | 
							struct swaylock_surface *surface =
 | 
				
			||||||
			calloc(1, sizeof(struct swaylock_surface));
 | 
								calloc(1, sizeof(struct swaylock_surface));
 | 
				
			||||||
| 
						 | 
					@ -180,7 +227,7 @@ static void handle_global(void *data, struct wl_registry *registry,
 | 
				
			||||||
				&wl_output_interface, 3);
 | 
									&wl_output_interface, 3);
 | 
				
			||||||
		surface->output_global_name = name;
 | 
							surface->output_global_name = name;
 | 
				
			||||||
		surface->image = state->background_image;
 | 
							surface->image = state->background_image;
 | 
				
			||||||
		wl_output_add_listener(surface->output, &output_listener, surface);
 | 
							wl_output_add_listener(surface->output, &_wl_output_listener, surface);
 | 
				
			||||||
		wl_list_insert(&state->surfaces, &surface->link);
 | 
							wl_list_insert(&state->surfaces, &surface->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (state->run_display) {
 | 
							if (state->run_display) {
 | 
				
			||||||
| 
						 | 
					@ -207,6 +254,70 @@ static const struct wl_registry_listener registry_listener = {
 | 
				
			||||||
	.global_remove = handle_global_remove,
 | 
						.global_remove = handle_global_remove,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static cairo_surface_t *select_image(struct swaylock_state *state,
 | 
				
			||||||
 | 
							struct swaylock_surface *surface) {
 | 
				
			||||||
 | 
						struct swaylock_image *image;
 | 
				
			||||||
 | 
						cairo_surface_t *default_image = NULL;
 | 
				
			||||||
 | 
						wl_list_for_each(image, &state->images, link) {
 | 
				
			||||||
 | 
							if (lenient_strcmp(image->output_name, surface->output_name) == 0) {
 | 
				
			||||||
 | 
								return image->cairo_surface;
 | 
				
			||||||
 | 
							} else if (!image->output_name) {
 | 
				
			||||||
 | 
								default_image = image->cairo_surface;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return default_image;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void load_image(char *arg, struct swaylock_state *state) {
 | 
				
			||||||
 | 
						// [<output>:]<path>
 | 
				
			||||||
 | 
						struct swaylock_image *image = calloc(1, sizeof(struct swaylock_image));
 | 
				
			||||||
 | 
						char *separator = strchr(arg, ':');
 | 
				
			||||||
 | 
						if (separator) {
 | 
				
			||||||
 | 
							*separator = '\0';
 | 
				
			||||||
 | 
							image->output_name = strdup(arg);
 | 
				
			||||||
 | 
							image->path = strdup(separator + 1);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							image->output_name = NULL;
 | 
				
			||||||
 | 
							image->path = strdup(arg);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool exists = false;
 | 
				
			||||||
 | 
						struct swaylock_image *iter_image;
 | 
				
			||||||
 | 
						wl_list_for_each(iter_image, &state->images, link) {
 | 
				
			||||||
 | 
							if (lenient_strcmp(iter_image->output_name, image->output_name) == 0) {
 | 
				
			||||||
 | 
								exists = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (exists) {
 | 
				
			||||||
 | 
							if (image->output_name) {
 | 
				
			||||||
 | 
								wlr_log(L_ERROR, "Multiple images defined for output %s",
 | 
				
			||||||
 | 
									image->output_name);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								wlr_log(L_ERROR, "Multiple default images defined");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Bash doesn't replace the ~ with $HOME if the output name is supplied
 | 
				
			||||||
 | 
						wordexp_t p;
 | 
				
			||||||
 | 
						if (wordexp(image->path, &p, 0) == 0) {
 | 
				
			||||||
 | 
							free(image->path);
 | 
				
			||||||
 | 
							image->path = strdup(p.we_wordv[0]);
 | 
				
			||||||
 | 
							wordfree(&p);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Load the actual image
 | 
				
			||||||
 | 
						image->cairo_surface = load_background_image(image->path);
 | 
				
			||||||
 | 
						if (!image->cairo_surface) {
 | 
				
			||||||
 | 
							free(image);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wl_list_insert(&state->images, &image->link);
 | 
				
			||||||
 | 
						state->args.mode = BACKGROUND_MODE_FILL;
 | 
				
			||||||
 | 
						wlr_log(L_DEBUG, "Loaded image %s for output %s",
 | 
				
			||||||
 | 
								image->path, image->output_name ? image->output_name : "*");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct swaylock_state state;
 | 
					static struct swaylock_state state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv) {
 | 
					int main(int argc, char **argv) {
 | 
				
			||||||
| 
						 | 
					@ -233,14 +344,14 @@ int main(int argc, char **argv) {
 | 
				
			||||||
		"  -v, --version                  Show the version number and quit.\n"
 | 
							"  -v, --version                  Show the version number and quit.\n"
 | 
				
			||||||
		"  -i, --image [<output>:]<path>  Display the given image.\n"
 | 
							"  -i, --image [<output>:]<path>  Display the given image.\n"
 | 
				
			||||||
		"  -u, --no-unlock-indicator      Disable the unlock indicator.\n"
 | 
							"  -u, --no-unlock-indicator      Disable the unlock indicator.\n"
 | 
				
			||||||
		"  -f, --daemonize                Detach from the controlling terminal.\n"
 | 
							"  -f, --daemonize                Detach from the controlling terminal.\n";
 | 
				
			||||||
		"  --socket <socket>              Use the specified socket.\n";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state.args = (struct swaylock_args){
 | 
						state.args = (struct swaylock_args){
 | 
				
			||||||
		.mode = BACKGROUND_MODE_SOLID_COLOR,
 | 
							.mode = BACKGROUND_MODE_SOLID_COLOR,
 | 
				
			||||||
		.color = 0xFFFFFFFF,
 | 
							.color = 0xFFFFFFFF,
 | 
				
			||||||
		.show_indicator = true,
 | 
							.show_indicator = true,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
						wl_list_init(&state.images);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_log_init(L_DEBUG, NULL);
 | 
						wlr_log_init(L_DEBUG, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -258,12 +369,7 @@ int main(int argc, char **argv) {
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		case 'i':
 | 
							case 'i':
 | 
				
			||||||
			// TODO: Multiple background images (bleh)
 | 
								load_image(optarg, &state);
 | 
				
			||||||
			state.background_image = load_background_image(optarg);
 | 
					 | 
				
			||||||
			if (!state.background_image) {
 | 
					 | 
				
			||||||
				return 1;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			state.args.mode = BACKGROUND_MODE_FILL;
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 's':
 | 
							case 's':
 | 
				
			||||||
			state.args.mode = parse_background_mode(optarg);
 | 
								state.args.mode = parse_background_mode(optarg);
 | 
				
			||||||
| 
						 | 
					@ -313,6 +419,7 @@ int main(int argc, char **argv) {
 | 
				
			||||||
	if (!state.input_inhibit_manager) {
 | 
						if (!state.input_inhibit_manager) {
 | 
				
			||||||
		wlr_log(L_ERROR, "Compositor does not support the input inhibitor "
 | 
							wlr_log(L_ERROR, "Compositor does not support the input inhibitor "
 | 
				
			||||||
				"protocol, refusing to run insecurely");
 | 
									"protocol, refusing to run insecurely");
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wl_list_empty(&state.surfaces)) {
 | 
						if (wl_list_empty(&state.surfaces)) {
 | 
				
			||||||
| 
						 | 
					@ -322,11 +429,24 @@ int main(int argc, char **argv) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
 | 
						zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (state.zxdg_output_manager) {
 | 
				
			||||||
 | 
							struct swaylock_surface *surface;
 | 
				
			||||||
 | 
							wl_list_for_each(surface, &state.surfaces, link) {
 | 
				
			||||||
 | 
								surface->xdg_output = zxdg_output_manager_v1_get_xdg_output(
 | 
				
			||||||
 | 
											state.zxdg_output_manager, surface->output);
 | 
				
			||||||
 | 
								zxdg_output_v1_add_listener(
 | 
				
			||||||
 | 
										surface->xdg_output, &_xdg_output_listener, surface);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							wl_display_roundtrip(state.display);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							wlr_log(L_INFO, "Compositor does not support zxdg output manager, "
 | 
				
			||||||
 | 
									"images assigned to named outputs will not work");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct swaylock_surface *surface;
 | 
						struct swaylock_surface *surface;
 | 
				
			||||||
	wl_list_for_each(surface, &state.surfaces, link) {
 | 
						wl_list_for_each(surface, &state.surfaces, link) {
 | 
				
			||||||
		create_layer_surface(surface);
 | 
							create_layer_surface(surface);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wl_display_roundtrip(state.display);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state.run_display = true;
 | 
						state.run_display = true;
 | 
				
			||||||
	while (wl_display_dispatch(state.display) != -1 && state.run_display) {
 | 
						while (wl_display_dispatch(state.display) != -1 && state.run_display) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ void render_frame(struct swaylock_surface *surface) {
 | 
				
			||||||
	cairo_t *cairo = surface->current_buffer->cairo;
 | 
						cairo_t *cairo = surface->current_buffer->cairo;
 | 
				
			||||||
	cairo_identity_matrix(cairo);
 | 
						cairo_identity_matrix(cairo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) {
 | 
						if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR || !surface->image) {
 | 
				
			||||||
		cairo_set_source_u32(cairo, state->args.color);
 | 
							cairo_set_source_u32(cairo, state->args.color);
 | 
				
			||||||
		cairo_paint(cairo);
 | 
							cairo_paint(cairo);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue