mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Merge branch 'master' into destroy-output-destroy-empty-workspaces
This commit is contained in:
		
						commit
						8ce7e3b44e
					
				
					 131 changed files with 2676 additions and 1026 deletions
				
			
		| 
						 | 
				
			
			@ -107,7 +107,7 @@ int main(int argc, const char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	int desired_output = atoi(argv[1]);
 | 
			
		||||
	sway_log(L_INFO, "Using output %d of %d", desired_output, registry->outputs->length);
 | 
			
		||||
	sway_log(WLR_INFO, "Using output %d of %d", desired_output, registry->outputs->length);
 | 
			
		||||
	int i;
 | 
			
		||||
	struct output_state *output = registry->outputs->items[desired_output];
 | 
			
		||||
	struct window *window = window_setup(registry, 100, 100, false);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,9 +3,9 @@
 | 
			
		|||
Use `sway_log(importance, fmt, ...)` to log. The following importances are
 | 
			
		||||
available:
 | 
			
		||||
 | 
			
		||||
* `L_DEBUG`: Debug messages, only shows with `sway -d`
 | 
			
		||||
* `L_INFO`: Informational messages
 | 
			
		||||
* `L_ERROR`: Error messages
 | 
			
		||||
* `WLR_DEBUG`: Debug messages, only shows with `sway -d`
 | 
			
		||||
* `WLR_INFO`: Informational messages
 | 
			
		||||
* `WLR_ERROR`: Error messages
 | 
			
		||||
 | 
			
		||||
`sway_log` is a macro that calls `_sway_log` with the current filename and line
 | 
			
		||||
number, which are written into the log with your message.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ enum background_mode parse_background_mode(const char *mode) {
 | 
			
		|||
	} else if (strcmp(mode, "solid_color") == 0) {
 | 
			
		||||
		return BACKGROUND_MODE_SOLID_COLOR;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_log(L_ERROR, "Unsupported background mode: %s", mode);
 | 
			
		||||
	wlr_log(WLR_ERROR, "Unsupported background mode: %s", mode);
 | 
			
		||||
	return BACKGROUND_MODE_INVALID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ cairo_surface_t *load_background_image(const char *path) {
 | 
			
		|||
	GError *err = NULL;
 | 
			
		||||
	GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err);
 | 
			
		||||
	if (!pixbuf) {
 | 
			
		||||
		wlr_log(L_ERROR, "Failed to load background image (%s).",
 | 
			
		||||
		wlr_log(WLR_ERROR, "Failed to load background image (%s).",
 | 
			
		||||
				err->message);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -38,11 +38,11 @@ cairo_surface_t *load_background_image(const char *path) {
 | 
			
		|||
	image = cairo_image_surface_create_from_png(path);
 | 
			
		||||
#endif //HAVE_GDK_PIXBUF
 | 
			
		||||
	if (!image) {
 | 
			
		||||
		wlr_log(L_ERROR, "Failed to read background image.");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Failed to read background image.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
 | 
			
		||||
		wlr_log(L_ERROR, "Failed to read background image: %s."
 | 
			
		||||
		wlr_log(WLR_ERROR, "Failed to read background image: %s."
 | 
			
		||||
#ifndef HAVE_GDK_PIXBUF
 | 
			
		||||
				"\nSway was compiled without gdk_pixbuf support, so only"
 | 
			
		||||
				"\nPNG images can be loaded. This is the likely cause."
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,7 +97,7 @@ struct ipc_response *ipc_recv_response(int socketfd) {
 | 
			
		|||
error_2:
 | 
			
		||||
	free(response);
 | 
			
		||||
error_1:
 | 
			
		||||
	wlr_log(L_ERROR, "Unable to allocate memory for IPC response");
 | 
			
		||||
	wlr_log(WLR_ERROR, "Unable to allocate memory for IPC response");
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
list_t *create_list(void) {
 | 
			
		||||
	list_t *list = malloc(sizeof(list_t));
 | 
			
		||||
| 
						 | 
				
			
			@ -82,6 +83,20 @@ void list_swap(list_t *list, int src, int dest) {
 | 
			
		|||
	list->items[dest] = tmp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void list_move_to_end(list_t *list, void *item) {
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < list->length; ++i) {
 | 
			
		||||
		if (list->items[i] == item) {
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!sway_assert(i < list->length, "Item not found in list")) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	list_del(list, i);
 | 
			
		||||
	list_add(list, item);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void list_rotate(list_t *list, int from, int to) {
 | 
			
		||||
	void *tmp = list->items[to];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ void sway_terminate(int code);
 | 
			
		|||
void _sway_abort(const char *format, ...) {
 | 
			
		||||
	va_list args;
 | 
			
		||||
	va_start(args, format);
 | 
			
		||||
	_wlr_vlog(L_ERROR, format, args);
 | 
			
		||||
	_wlr_vlog(WLR_ERROR, format, args);
 | 
			
		||||
	va_end(args);
 | 
			
		||||
	sway_terminate(EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ bool _sway_assert(bool condition, const char *format, ...) {
 | 
			
		|||
 | 
			
		||||
	va_list args;
 | 
			
		||||
	va_start(args, format);
 | 
			
		||||
	_wlr_vlog(L_ERROR, format, args);
 | 
			
		||||
	_wlr_vlog(WLR_ERROR, format, args);
 | 
			
		||||
	va_end(args);
 | 
			
		||||
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,7 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
 | 
			
		|||
			pango_layout_set_markup(layout, buf, -1);
 | 
			
		||||
			free(buf);
 | 
			
		||||
		} else {
 | 
			
		||||
			wlr_log(L_ERROR, "pango_parse_markup '%s' -> error %s", text,
 | 
			
		||||
			wlr_log(WLR_ERROR, "pango_parse_markup '%s' -> error %s", text,
 | 
			
		||||
					error->message);
 | 
			
		||||
			g_error_free(error);
 | 
			
		||||
			markup = false; // fallback to plain text
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ char *read_line(FILE *file) {
 | 
			
		|||
	char *string = malloc(size);
 | 
			
		||||
	char lastChar = '\0';
 | 
			
		||||
	if (!string) {
 | 
			
		||||
		wlr_log(L_ERROR, "Unable to allocate memory for read_line");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Unable to allocate memory for read_line");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	while (1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ char *read_line(FILE *file) {
 | 
			
		|||
			char *new_string = realloc(string, size *= 2);
 | 
			
		||||
			if (!new_string) {
 | 
			
		||||
				free(string);
 | 
			
		||||
				wlr_log(L_ERROR, "Unable to allocate memory for read_line");
 | 
			
		||||
				wlr_log(WLR_ERROR, "Unable to allocate memory for read_line");
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
			string = new_string;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,7 +113,7 @@ uint32_t parse_color(const char *color) {
 | 
			
		|||
 | 
			
		||||
	int len = strlen(color);
 | 
			
		||||
	if (len != 6 && len != 8) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color);
 | 
			
		||||
		return 0xFFFFFFFF;
 | 
			
		||||
	}
 | 
			
		||||
	uint32_t res = (uint32_t)strtoul(color, NULL, 16);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,6 @@ types=(
 | 
			
		|||
'get_marks'
 | 
			
		||||
'get_bar_config'
 | 
			
		||||
'get_version'
 | 
			
		||||
'get_clipboard'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
_arguments -s \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,11 +13,12 @@ enum ipc_command_type {
 | 
			
		|||
	IPC_GET_MARKS = 5,
 | 
			
		||||
	IPC_GET_BAR_CONFIG = 6,
 | 
			
		||||
	IPC_GET_VERSION = 7,
 | 
			
		||||
	IPC_GET_BINDING_MODES = 8,
 | 
			
		||||
	IPC_GET_CONFIG = 9,
 | 
			
		||||
 | 
			
		||||
	// sway-specific command types
 | 
			
		||||
	IPC_GET_INPUTS = 100,
 | 
			
		||||
	IPC_GET_CLIPBOARD = 101,
 | 
			
		||||
	IPC_GET_SEATS = 102,
 | 
			
		||||
	IPC_GET_SEATS = 101,
 | 
			
		||||
 | 
			
		||||
	// Events sent from sway to clients. Events have the highest bits set.
 | 
			
		||||
	IPC_EVENT_WORKSPACE = ((1<<31) | 0),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,4 +24,6 @@ int list_seq_find(list_t *list, int compare(const void *item, const void *cmp_to
 | 
			
		|||
void list_stable_sort(list_t *list, int compare(const void *a, const void *b));
 | 
			
		||||
// swap two elements in a list
 | 
			
		||||
void list_swap(list_t *list, int src, int dest);
 | 
			
		||||
// move item to end of list
 | 
			
		||||
void list_move_to_end(list_t *list, void *item);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,13 +3,19 @@
 | 
			
		|||
#include <stdbool.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
#define ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end)))
 | 
			
		||||
#else
 | 
			
		||||
#define ATTRIB_PRINTF(start, end)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2);
 | 
			
		||||
#define sway_abort(FMT, ...) \
 | 
			
		||||
    _sway_abort("[%s:%d] " FMT, wlr_strip_path(__FILE__), __LINE__, ##__VA_ARGS__)
 | 
			
		||||
    _sway_abort("[%s:%d] " FMT, _wlr_strip_path(__FILE__), __LINE__, ##__VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3);
 | 
			
		||||
#define sway_assert(COND, FMT, ...) \
 | 
			
		||||
	_sway_assert(COND, "[%s:%d] %s:" FMT, wlr_strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
 | 
			
		||||
	_sway_assert(COND, "[%s:%d] %s:" FMT, _wlr_strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
void error_handler(int sig);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,7 +95,6 @@ sway_cmd cmd_client_unfocused;
 | 
			
		|||
sway_cmd cmd_client_urgent;
 | 
			
		||||
sway_cmd cmd_client_placeholder;
 | 
			
		||||
sway_cmd cmd_client_background;
 | 
			
		||||
sway_cmd cmd_clipboard;
 | 
			
		||||
sway_cmd cmd_commands;
 | 
			
		||||
sway_cmd cmd_debuglog;
 | 
			
		||||
sway_cmd cmd_default_border;
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +152,7 @@ sway_cmd cmd_swaybg_command;
 | 
			
		|||
sway_cmd cmd_swap;
 | 
			
		||||
sway_cmd cmd_title_format;
 | 
			
		||||
sway_cmd cmd_unmark;
 | 
			
		||||
sway_cmd cmd_urgent;
 | 
			
		||||
sway_cmd cmd_workspace;
 | 
			
		||||
sway_cmd cmd_ws_auto_back_and_forth;
 | 
			
		||||
sway_cmd cmd_workspace_layout;
 | 
			
		||||
| 
						 | 
				
			
			@ -208,8 +208,10 @@ sway_cmd input_cmd_natural_scroll;
 | 
			
		|||
sway_cmd input_cmd_pointer_accel;
 | 
			
		||||
sway_cmd input_cmd_repeat_delay;
 | 
			
		||||
sway_cmd input_cmd_repeat_rate;
 | 
			
		||||
sway_cmd input_cmd_scroll_button;
 | 
			
		||||
sway_cmd input_cmd_scroll_method;
 | 
			
		||||
sway_cmd input_cmd_tap;
 | 
			
		||||
sway_cmd input_cmd_tap_button_map;
 | 
			
		||||
sway_cmd input_cmd_xkb_layout;
 | 
			
		||||
sway_cmd input_cmd_xkb_model;
 | 
			
		||||
sway_cmd input_cmd_xkb_options;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,9 +75,11 @@ struct input_config {
 | 
			
		|||
	float pointer_accel;
 | 
			
		||||
	int repeat_delay;
 | 
			
		||||
	int repeat_rate;
 | 
			
		||||
	int scroll_button;
 | 
			
		||||
	int scroll_method;
 | 
			
		||||
	int send_events;
 | 
			
		||||
	int tap;
 | 
			
		||||
	int tap_button_map;
 | 
			
		||||
 | 
			
		||||
	char *xkb_layout;
 | 
			
		||||
	char *xkb_model;
 | 
			
		||||
| 
						 | 
				
			
			@ -271,11 +273,10 @@ enum ipc_feature {
 | 
			
		|||
	IPC_FEATURE_EVENT_WINDOW = 2048,
 | 
			
		||||
	IPC_FEATURE_EVENT_BINDING = 4096,
 | 
			
		||||
	IPC_FEATURE_EVENT_INPUT = 8192,
 | 
			
		||||
	IPC_FEATURE_GET_CLIPBOARD = 16384,
 | 
			
		||||
	IPC_FEATURE_GET_SEATS = 32768,
 | 
			
		||||
	IPC_FEATURE_GET_SEATS = 16384,
 | 
			
		||||
 | 
			
		||||
	IPC_FEATURE_ALL_COMMANDS =
 | 
			
		||||
		1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384 | 32768,
 | 
			
		||||
		1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384,
 | 
			
		||||
	IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192,
 | 
			
		||||
 | 
			
		||||
	IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS,
 | 
			
		||||
| 
						 | 
				
			
			@ -341,6 +342,7 @@ struct sway_config {
 | 
			
		|||
	int gaps_outer;
 | 
			
		||||
 | 
			
		||||
	list_t *config_chain;
 | 
			
		||||
	const char *current_config_path;
 | 
			
		||||
	const char *current_config;
 | 
			
		||||
 | 
			
		||||
	enum sway_container_border border;
 | 
			
		||||
| 
						 | 
				
			
			@ -496,7 +498,4 @@ void config_update_font_height(bool recalculate);
 | 
			
		|||
/* Global config singleton. */
 | 
			
		||||
extern struct sway_config *config;
 | 
			
		||||
 | 
			
		||||
/* Config file currently being read */
 | 
			
		||||
extern const char *current_config_path;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ enum criteria_type {
 | 
			
		|||
	CT_COMMAND          = 1 << 0,
 | 
			
		||||
	CT_ASSIGN_OUTPUT    = 1 << 1,
 | 
			
		||||
	CT_ASSIGN_WORKSPACE = 1 << 2,
 | 
			
		||||
	CT_NO_FOCUS         = 1 << 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct criteria {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,15 @@
 | 
			
		|||
#ifndef SWAY_DEBUG_H
 | 
			
		||||
#define SWAY_DEBUG_H
 | 
			
		||||
 | 
			
		||||
// Tree
 | 
			
		||||
extern bool enable_debug_tree;
 | 
			
		||||
void update_debug_tree();
 | 
			
		||||
 | 
			
		||||
// Damage
 | 
			
		||||
extern const char *damage_debug;
 | 
			
		||||
 | 
			
		||||
// Transactions
 | 
			
		||||
extern int txn_timeout_ms;
 | 
			
		||||
extern bool txn_debug;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,8 @@
 | 
			
		|||
#include <wlr/types/wlr_surface.h>
 | 
			
		||||
 | 
			
		||||
struct sway_container;
 | 
			
		||||
 | 
			
		||||
void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
 | 
			
		||||
	bool whole);
 | 
			
		||||
 | 
			
		||||
void desktop_damage_whole_container(struct sway_container *con);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,34 +6,25 @@
 | 
			
		|||
/**
 | 
			
		||||
 * Transactions enable us to perform atomic layout updates.
 | 
			
		||||
 *
 | 
			
		||||
 * When we want to make adjustments to the layout, we create a transaction.
 | 
			
		||||
 * A transaction contains a list of affected containers and their new state.
 | 
			
		||||
 * A transaction contains a list of containers and their new state.
 | 
			
		||||
 * A state might contain a new size, or new border settings, or new parent/child
 | 
			
		||||
 * relationships.
 | 
			
		||||
 *
 | 
			
		||||
 * Calling transaction_commit() makes sway notify of all the affected clients
 | 
			
		||||
 * with their new sizes. We then wait for all the views to respond with their
 | 
			
		||||
 * new surface sizes. When all are ready, or when a timeout has passed, we apply
 | 
			
		||||
 * the updates all at the same time.
 | 
			
		||||
 * Committing a transaction makes sway notify of all the affected clients with
 | 
			
		||||
 * their new sizes. We then wait for all the views to respond with their new
 | 
			
		||||
 * surface sizes. When all are ready, or when a timeout has passed, we apply the
 | 
			
		||||
 * updates all at the same time.
 | 
			
		||||
 *
 | 
			
		||||
 * When we want to make adjustments to the layout, we change the pending state
 | 
			
		||||
 * in containers, mark them as dirty and call transaction_commit_dirty(). This
 | 
			
		||||
 * create and commits a transaction from the dirty containers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct sway_transaction;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create a new transaction.
 | 
			
		||||
 * Find all dirty containers, create and commit a transaction containing them,
 | 
			
		||||
 * and unmark them as dirty.
 | 
			
		||||
 */
 | 
			
		||||
struct sway_transaction *transaction_create(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add a container's pending state to the transaction.
 | 
			
		||||
 */
 | 
			
		||||
void transaction_add_container(struct sway_transaction *transaction,
 | 
			
		||||
		struct sway_container *container);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Submit a transaction to the client views for configuration.
 | 
			
		||||
 */
 | 
			
		||||
void transaction_commit(struct sway_transaction *transaction);
 | 
			
		||||
void transaction_commit_dirty(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Notify the transaction system that a view is ready for the new layout.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,17 +118,6 @@ struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
 | 
			
		|||
struct sway_container *seat_get_active_child(struct sway_seat *seat,
 | 
			
		||||
		struct sway_container *container);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return the immediate child of container which was most recently focused, with
 | 
			
		||||
 * fallback to selecting the child in the parent's `current` (rendered) children
 | 
			
		||||
 * list.
 | 
			
		||||
 *
 | 
			
		||||
 * This is useful for when a tabbed container and its children are destroyed but
 | 
			
		||||
 * still being rendered, and we have to render an appropriate child.
 | 
			
		||||
 */
 | 
			
		||||
struct sway_container *seat_get_active_current_child(struct sway_seat *seat,
 | 
			
		||||
		struct sway_container *container);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Iterate over the focus-inactive children of the container calling the
 | 
			
		||||
 * function on each.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,10 +47,7 @@ struct sway_server {
 | 
			
		|||
	bool debug_txn_timings;
 | 
			
		||||
 | 
			
		||||
	list_t *transactions;
 | 
			
		||||
 | 
			
		||||
	// When a view is being destroyed and is waiting for a transaction to
 | 
			
		||||
	// complete it will be stored here.
 | 
			
		||||
	list_t *destroying_containers;
 | 
			
		||||
	list_t *dirty_containers;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sway_server server;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,26 +11,8 @@ void remove_gaps(struct sway_container *c);
 | 
			
		|||
void add_gaps(struct sway_container *c);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Arrange layout for all the children of the given container, and add them to
 | 
			
		||||
 * the given transaction.
 | 
			
		||||
 *
 | 
			
		||||
 * Use this function if you need to arrange multiple sections of the tree in one
 | 
			
		||||
 * transaction.
 | 
			
		||||
 *
 | 
			
		||||
 * You must set the desired state of the container before calling
 | 
			
		||||
 * arrange_windows, then don't change any state-tracked properties in the
 | 
			
		||||
 * container until you've called transaction_commit.
 | 
			
		||||
 * Arrange layout for all the children of the given container.
 | 
			
		||||
 */
 | 
			
		||||
void arrange_windows(struct sway_container *container,
 | 
			
		||||
		struct sway_transaction *transaction);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Arrange layout for the given container and commit the transaction.
 | 
			
		||||
 *
 | 
			
		||||
 * This function is a wrapper around arrange_windows, and handles creating and
 | 
			
		||||
 * committing the transaction for you. Use this function if you're only doing
 | 
			
		||||
 * one arrange operation.
 | 
			
		||||
 */
 | 
			
		||||
void arrange_and_commit(struct sway_container *container);
 | 
			
		||||
void arrange_windows(struct sway_container *container);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,6 +68,9 @@ struct sway_container_state {
 | 
			
		|||
	struct sway_container *parent;
 | 
			
		||||
	list_t *children;
 | 
			
		||||
 | 
			
		||||
	struct sway_container *focused_inactive_child;
 | 
			
		||||
	bool focused;
 | 
			
		||||
 | 
			
		||||
	// View properties
 | 
			
		||||
	double view_x, view_y;
 | 
			
		||||
	double view_width, view_height;
 | 
			
		||||
| 
						 | 
				
			
			@ -144,6 +147,10 @@ struct sway_container {
 | 
			
		|||
 | 
			
		||||
	bool destroying;
 | 
			
		||||
 | 
			
		||||
	// If true, indicates that the container has pending state that differs from
 | 
			
		||||
	// the current.
 | 
			
		||||
	bool dirty;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
		// Raised after the tree updates, but before arrange_windows
 | 
			
		||||
| 
						 | 
				
			
			@ -297,4 +304,18 @@ bool container_is_floating(struct sway_container *container);
 | 
			
		|||
 */
 | 
			
		||||
void container_get_box(struct sway_container *container, struct wlr_box *box);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Move a floating container to a new layout-local position.
 | 
			
		||||
 */
 | 
			
		||||
void container_floating_move_to(struct sway_container *con,
 | 
			
		||||
		double lx, double ly);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mark a container as dirty if it isn't already. Dirty containers will be
 | 
			
		||||
 * included in the next transaction then unmarked as dirty.
 | 
			
		||||
 */
 | 
			
		||||
void container_set_dirty(struct sway_container *container);
 | 
			
		||||
 | 
			
		||||
bool container_has_urgent_child(struct sway_container *container);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,7 @@ struct sway_view_impl {
 | 
			
		|||
	void (*set_tiled)(struct sway_view *view, bool tiled);
 | 
			
		||||
	void (*set_fullscreen)(struct sway_view *view, bool fullscreen);
 | 
			
		||||
	bool (*wants_floating)(struct sway_view *view);
 | 
			
		||||
	bool (*has_client_side_decorations)(struct sway_view *view);
 | 
			
		||||
	void (*for_each_surface)(struct sway_view *view,
 | 
			
		||||
		wlr_surface_iterator_func_t iterator, void *user_data);
 | 
			
		||||
	void (*close)(struct sway_view *view);
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +69,11 @@ struct sway_view {
 | 
			
		|||
	bool border_bottom;
 | 
			
		||||
	bool border_left;
 | 
			
		||||
	bool border_right;
 | 
			
		||||
	bool using_csd;
 | 
			
		||||
 | 
			
		||||
	struct timespec urgent;
 | 
			
		||||
	bool allow_request_urgent;
 | 
			
		||||
	struct wl_event_source *urgent_timer;
 | 
			
		||||
 | 
			
		||||
	bool destroying;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -304,4 +310,8 @@ void view_update_marks_textures(struct sway_view *view);
 | 
			
		|||
 */
 | 
			
		||||
bool view_is_visible(struct sway_view *view);
 | 
			
		||||
 | 
			
		||||
void view_set_urgent(struct sway_view *view, bool enable);
 | 
			
		||||
 | 
			
		||||
bool view_is_urgent(struct sway_view *view);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ struct sway_workspace {
 | 
			
		|||
	struct sway_view *fullscreen;
 | 
			
		||||
	struct sway_container *floating;
 | 
			
		||||
	list_t *output_priority;
 | 
			
		||||
	bool urgent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern char *prev_workspace_name;
 | 
			
		||||
| 
						 | 
				
			
			@ -42,4 +43,7 @@ void workspace_output_add_priority(struct sway_container *workspace,
 | 
			
		|||
 | 
			
		||||
struct sway_container *workspace_output_get_highest_available(
 | 
			
		||||
		struct sway_container *ws, struct sway_container *exclude);
 | 
			
		||||
 | 
			
		||||
void workspace_detect_urgent(struct sway_container *workspace);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,11 +16,24 @@ struct swaybar_pointer {
 | 
			
		|||
	int x, y;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum x11_button {
 | 
			
		||||
	NONE,
 | 
			
		||||
	LEFT,
 | 
			
		||||
	MIDDLE,
 | 
			
		||||
	RIGHT,
 | 
			
		||||
	SCROLL_UP,
 | 
			
		||||
	SCROLL_DOWN,
 | 
			
		||||
	SCROLL_LEFT,
 | 
			
		||||
	SCROLL_RIGHT,
 | 
			
		||||
	BACK,
 | 
			
		||||
	FORWARD,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct swaybar_hotspot {
 | 
			
		||||
	struct wl_list link;
 | 
			
		||||
	int x, y, width, height;
 | 
			
		||||
	void (*callback)(struct swaybar_output *output,
 | 
			
		||||
			int x, int y, uint32_t button, void *data);
 | 
			
		||||
			int x, int y, enum x11_button button, void *data);
 | 
			
		||||
	void (*destroy)(void *data);
 | 
			
		||||
	void *data;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,9 @@ bool status_handle_readable(struct status_line *status);
 | 
			
		|||
void status_line_free(struct status_line *status);
 | 
			
		||||
bool i3bar_handle_readable(struct status_line *status);
 | 
			
		||||
void i3bar_block_send_click(struct status_line *status,
 | 
			
		||||
		struct i3bar_block *block, int x, int y, uint32_t button);
 | 
			
		||||
		struct i3bar_block *block, int x, int y, enum x11_button button);
 | 
			
		||||
void i3bar_block_free(struct i3bar_block *block);
 | 
			
		||||
enum x11_button wl_button_to_x11_button(uint32_t button);
 | 
			
		||||
enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,9 +19,31 @@ enum auth_state {
 | 
			
		|||
	AUTH_STATE_INVALID,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct swaylock_colorset {
 | 
			
		||||
	uint32_t input;
 | 
			
		||||
	uint32_t cleared;
 | 
			
		||||
	uint32_t verifying;
 | 
			
		||||
	uint32_t wrong;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct swaylock_colors {
 | 
			
		||||
	uint32_t background;
 | 
			
		||||
	uint32_t bs_highlight;
 | 
			
		||||
	uint32_t key_highlight;
 | 
			
		||||
	uint32_t separator;
 | 
			
		||||
	struct swaylock_colorset inside;
 | 
			
		||||
	struct swaylock_colorset line;
 | 
			
		||||
	struct swaylock_colorset ring;
 | 
			
		||||
	struct swaylock_colorset text;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct swaylock_args {
 | 
			
		||||
	uint32_t color;
 | 
			
		||||
	struct swaylock_colors colors;
 | 
			
		||||
	enum background_mode mode;
 | 
			
		||||
	char *font;
 | 
			
		||||
	uint32_t radius;
 | 
			
		||||
	uint32_t thickness;
 | 
			
		||||
	bool ignore_empty;
 | 
			
		||||
	bool show_indicator;
 | 
			
		||||
	bool daemonize;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,8 +98,11 @@ static struct cmd_handler handlers[] = {
 | 
			
		|||
	{ "client.unfocused", cmd_client_unfocused },
 | 
			
		||||
	{ "client.urgent", cmd_client_urgent },
 | 
			
		||||
	{ "default_border", cmd_default_border },
 | 
			
		||||
	{ "default_floating_border", cmd_default_floating_border },
 | 
			
		||||
	{ "exec", cmd_exec },
 | 
			
		||||
	{ "exec_always", cmd_exec_always },
 | 
			
		||||
	{ "floating_maximum_size", cmd_floating_maximum_size },
 | 
			
		||||
	{ "floating_minimum_size", cmd_floating_minimum_size },
 | 
			
		||||
	{ "focus_follows_mouse", cmd_focus_follows_mouse },
 | 
			
		||||
	{ "focus_wrapping", cmd_focus_wrapping },
 | 
			
		||||
	{ "font", cmd_font },
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +115,7 @@ static struct cmd_handler handlers[] = {
 | 
			
		|||
	{ "input", cmd_input },
 | 
			
		||||
	{ "mode", cmd_mode },
 | 
			
		||||
	{ "mouse_warping", cmd_mouse_warping },
 | 
			
		||||
	{ "no_focus", cmd_no_focus },
 | 
			
		||||
	{ "output", cmd_output },
 | 
			
		||||
	{ "seat", cmd_seat },
 | 
			
		||||
	{ "set", cmd_set },
 | 
			
		||||
| 
						 | 
				
			
			@ -151,6 +155,7 @@ static struct cmd_handler command_handlers[] = {
 | 
			
		|||
	{ "swap", cmd_swap },
 | 
			
		||||
	{ "title_format", cmd_title_format },
 | 
			
		||||
	{ "unmark", cmd_unmark },
 | 
			
		||||
	{ "urgent", cmd_urgent },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int handler_compare(const void *_a, const void *_b) {
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +168,7 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
 | 
			
		|||
		int handlers_size) {
 | 
			
		||||
	struct cmd_handler d = { .command=line };
 | 
			
		||||
	struct cmd_handler *res = NULL;
 | 
			
		||||
	wlr_log(L_DEBUG, "find_handler(%s)", line);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "find_handler(%s)", line);
 | 
			
		||||
 | 
			
		||||
	bool config_loading = config->reading || !config->active;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -248,10 +253,10 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
 | 
			
		|||
			cmd = argsep(&cmdlist, ",");
 | 
			
		||||
			cmd += strspn(cmd, whitespace);
 | 
			
		||||
			if (strcmp(cmd, "") == 0) {
 | 
			
		||||
				wlr_log(L_INFO, "Ignoring empty command.");
 | 
			
		||||
				wlr_log(WLR_INFO, "Ignoring empty command.");
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			wlr_log(L_INFO, "Handling command '%s'", cmd);
 | 
			
		||||
			wlr_log(WLR_INFO, "Handling command '%s'", cmd);
 | 
			
		||||
			//TODO better handling of argv
 | 
			
		||||
			int argc;
 | 
			
		||||
			char **argv = split_args(cmd, &argc);
 | 
			
		||||
| 
						 | 
				
			
			@ -355,7 +360,7 @@ struct cmd_results *config_command(char *exec) {
 | 
			
		|||
		results = cmd_results_new(CMD_BLOCK_END, NULL, NULL);
 | 
			
		||||
		goto cleanup;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_log(L_INFO, "handling config command '%s'", exec);
 | 
			
		||||
	wlr_log(WLR_INFO, "handling config command '%s'", exec);
 | 
			
		||||
	struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
 | 
			
		||||
	if (!handler) {
 | 
			
		||||
		char *input = argv[0] ? argv[0] : "(empty)";
 | 
			
		||||
| 
						 | 
				
			
			@ -388,7 +393,7 @@ cleanup:
 | 
			
		|||
struct cmd_results *config_subcommand(char **argv, int argc,
 | 
			
		||||
		struct cmd_handler *handlers, size_t handlers_size) {
 | 
			
		||||
	char *command = join_args(argv, argc);
 | 
			
		||||
	wlr_log(L_DEBUG, "Subcommand: %s", command);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Subcommand: %s", command);
 | 
			
		||||
	free(command);
 | 
			
		||||
 | 
			
		||||
	struct cmd_handler *handler = find_handler(argv[0], handlers,
 | 
			
		||||
| 
						 | 
				
			
			@ -479,7 +484,7 @@ struct cmd_results *config_commands_command(char *exec) {
 | 
			
		|||
	}
 | 
			
		||||
	policy->context = context;
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_INFO, "Set command policy for %s to %d",
 | 
			
		||||
	wlr_log(WLR_INFO, "Set command policy for %s to %d",
 | 
			
		||||
			policy->command, policy->context);
 | 
			
		||||
 | 
			
		||||
	results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -493,7 +498,7 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
 | 
			
		|||
		const char *input, const char *format, ...) {
 | 
			
		||||
	struct cmd_results *results = malloc(sizeof(struct cmd_results));
 | 
			
		||||
	if (!results) {
 | 
			
		||||
		wlr_log(L_ERROR, "Unable to allocate command results");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Unable to allocate command results");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	results->status = status;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) {
 | 
			
		|||
	criteria->target = join_args(argv, target_len);
 | 
			
		||||
 | 
			
		||||
	list_add(config->criteria, criteria);
 | 
			
		||||
	wlr_log(L_DEBUG, "assign: '%s' -> '%s' added", criteria->raw,
 | 
			
		||||
	wlr_log(WLR_DEBUG, "assign: '%s' -> '%s' added", criteria->raw,
 | 
			
		||||
			criteria->target);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,13 +63,13 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
 | 
			
		|||
			for (int i = 0; i < config->bars->length; ++i) {
 | 
			
		||||
				struct bar_config *item = config->bars->items[i];
 | 
			
		||||
				if (strcmp(item->id, argv[0]) == 0) {
 | 
			
		||||
					wlr_log(L_DEBUG, "Selecting bar: %s", argv[0]);
 | 
			
		||||
					wlr_log(WLR_DEBUG, "Selecting bar: %s", argv[0]);
 | 
			
		||||
					bar = item;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (!bar) {
 | 
			
		||||
				wlr_log(L_DEBUG, "Creating bar: %s", argv[0]);
 | 
			
		||||
				wlr_log(WLR_DEBUG, "Creating bar: %s", argv[0]);
 | 
			
		||||
				bar = default_bar_config();
 | 
			
		||||
				if (!bar) {
 | 
			
		||||
					return cmd_results_new(CMD_FAILURE, "bar",
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
		// Set current bar
 | 
			
		||||
		config->current_bar = bar;
 | 
			
		||||
		wlr_log(L_DEBUG, "Creating bar %s", bar->id);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Creating bar %s", bar->id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,11 +15,11 @@ struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	if (strcasecmp("yes", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->binding_mode_indicator = true;
 | 
			
		||||
		wlr_log(L_DEBUG, "Enabling binding mode indicator on bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Enabling binding mode indicator on bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else if (strcasecmp("no", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->binding_mode_indicator = false;
 | 
			
		||||
		wlr_log(L_DEBUG, "Disabling binding mode indicator on bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Disabling binding mode indicator on bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	}
 | 
			
		||||
	return cmd_results_new(CMD_INVALID, "binding_mode_indicator",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ struct cmd_results *bar_cmd_font(int argc, char **argv) {
 | 
			
		|||
	char *font = join_args(argv, argc);
 | 
			
		||||
	free(config->current_bar->font);
 | 
			
		||||
	config->current_bar->font = font;
 | 
			
		||||
	wlr_log(L_DEBUG, "Settings font '%s' for bar: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Settings font '%s' for bar: %s",
 | 
			
		||||
			config->current_bar->font, config->current_bar->id);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_height(int argc, char **argv) {
 | 
			
		|||
				"Invalid height value: %s", argv[0]);
 | 
			
		||||
	}
 | 
			
		||||
	config->current_bar->height = height;
 | 
			
		||||
	wlr_log(L_DEBUG, "Setting bar height to %d on bar: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Setting bar height to %d on bar: %s",
 | 
			
		||||
			height, config->current_bar->id);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ static struct cmd_results *bar_set_hidden_state(struct bar_config *bar,
 | 
			
		|||
		if (!config->reading) {
 | 
			
		||||
			ipc_event_barconfig_update(bar);
 | 
			
		||||
		}
 | 
			
		||||
		wlr_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Setting hidden_state: '%s' for bar: %s",
 | 
			
		||||
				bar->hidden_state, bar->id);
 | 
			
		||||
	}
 | 
			
		||||
	// free old mode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ struct cmd_results *bar_cmd_id(int argc, char **argv) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name);
 | 
			
		||||
 | 
			
		||||
	// free old bar id
 | 
			
		||||
	free(config->current_bar->id);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode
 | 
			
		|||
		if (!config->reading) {
 | 
			
		||||
			ipc_event_barconfig_update(bar);
 | 
			
		||||
		}
 | 
			
		||||
		wlr_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// free old mode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	free_flat_list(split);
 | 
			
		||||
	config->current_bar->modifier = mod;
 | 
			
		||||
	wlr_log(L_DEBUG,
 | 
			
		||||
	wlr_log(WLR_DEBUG,
 | 
			
		||||
			"Show/Hide the bar when pressing '%s' in hide mode.", argv[0]);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ struct cmd_results *bar_cmd_output(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	if (add_output) {
 | 
			
		||||
		list_add(outputs, strdup(output));
 | 
			
		||||
		wlr_log(L_DEBUG, "Adding bar: '%s' to output '%s'",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Adding bar: '%s' to output '%s'",
 | 
			
		||||
				config->current_bar->id, output);
 | 
			
		||||
	}
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,11 +13,11 @@ struct cmd_results *bar_cmd_pango_markup(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	if (strcasecmp("enabled", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->pango_markup = true;
 | 
			
		||||
		wlr_log(L_DEBUG, "Enabling pango markup for bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Enabling pango markup for bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else if (strcasecmp("disabled", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->pango_markup = false;
 | 
			
		||||
		wlr_log(L_DEBUG, "Disabling pango markup for bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Disabling pango markup for bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else {
 | 
			
		||||
		error = cmd_results_new(CMD_INVALID, "pango_markup",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,8 +15,9 @@ struct cmd_results *bar_cmd_position(int argc, char **argv) {
 | 
			
		|||
	char *valid[] = { "top", "bottom", "left", "right" };
 | 
			
		||||
	for (size_t i = 0; i < sizeof(valid) / sizeof(valid[0]); ++i) {
 | 
			
		||||
		if (strcasecmp(valid[i], argv[0]) == 0) {
 | 
			
		||||
			wlr_log(L_DEBUG, "Setting bar position '%s' for bar: %s",
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Setting bar position '%s' for bar: %s",
 | 
			
		||||
					argv[0], config->current_bar->id);
 | 
			
		||||
			free(config->current_bar->position);
 | 
			
		||||
			config->current_bar->position = strdup(argv[0]);
 | 
			
		||||
			return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_separator_symbol(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	free(config->current_bar->separator_symbol);
 | 
			
		||||
	config->current_bar->separator_symbol = strdup(argv[0]);
 | 
			
		||||
	wlr_log(L_DEBUG, "Settings separator_symbol '%s' for bar: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Settings separator_symbol '%s' for bar: %s",
 | 
			
		||||
			config->current_bar->separator_symbol, config->current_bar->id);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_status_command(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	free(config->current_bar->status_command);
 | 
			
		||||
	config->current_bar->status_command = join_args(argv, argc);
 | 
			
		||||
	wlr_log(L_DEBUG, "Feeding bar with status command: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Feeding bar with status command: %s",
 | 
			
		||||
			config->current_bar->status_command);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,11 +15,11 @@ struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	if (strcasecmp("yes", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->strip_workspace_numbers = true;
 | 
			
		||||
		wlr_log(L_DEBUG, "Stripping workspace numbers on bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Stripping workspace numbers on bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else if (strcasecmp("no", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->strip_workspace_numbers = false;
 | 
			
		||||
		wlr_log(L_DEBUG, "Enabling workspace numbers on bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Enabling workspace numbers on bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_swaybar_command(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	free(config->current_bar->swaybar_command);
 | 
			
		||||
	config->current_bar->swaybar_command = join_args(argv, argc);
 | 
			
		||||
	wlr_log(L_DEBUG, "Using custom swaybar command: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Using custom swaybar command: %s",
 | 
			
		||||
			config->current_bar->swaybar_command);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,11 +14,11 @@ struct cmd_results *bar_cmd_workspace_buttons(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	if (strcasecmp("yes", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->workspace_buttons = true;
 | 
			
		||||
		wlr_log(L_DEBUG, "Enabling workspace buttons on bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Enabling workspace buttons on bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else if (strcasecmp("no", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->workspace_buttons = false;
 | 
			
		||||
		wlr_log(L_DEBUG, "Disabling workspace buttons on bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Disabling workspace buttons on bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "workspace_buttons",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,11 +13,11 @@ struct cmd_results *bar_cmd_wrap_scroll(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
	if (strcasecmp("yes", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->wrap_scroll = true;
 | 
			
		||||
		wlr_log(L_DEBUG, "Enabling wrap scroll on bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Enabling wrap scroll on bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else if (strcasecmp("no", argv[0]) == 0) {
 | 
			
		||||
		config->current_bar->wrap_scroll = false;
 | 
			
		||||
		wlr_log(L_DEBUG, "Disabling wrap scroll on bar: %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Disabling wrap scroll on bar: %s",
 | 
			
		||||
				config->current_bar->id);
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -184,7 +184,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
 | 
			
		|||
	for (int i = 0; i < mode_bindings->length; ++i) {
 | 
			
		||||
		struct sway_binding *config_binding = mode_bindings->items[i];
 | 
			
		||||
		if (binding_key_compare(binding, config_binding)) {
 | 
			
		||||
			wlr_log(L_DEBUG, "overwriting old binding with command '%s'",
 | 
			
		||||
			wlr_log(WLR_DEBUG, "overwriting old binding with command '%s'",
 | 
			
		||||
				config_binding->command);
 | 
			
		||||
			free_sway_binding(config_binding);
 | 
			
		||||
			mode_bindings->items[i] = binding;
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +196,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
 | 
			
		|||
		list_add(mode_bindings, binding);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "%s - Bound %s to command %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "%s - Bound %s to command %s",
 | 
			
		||||
		bindtype, argv[0], binding->command);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ struct cmd_results *cmd_border(int argc, char **argv) {
 | 
			
		|||
		container_set_geometry_from_floating_view(view->swayc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	arrange_and_commit(view->swayc);
 | 
			
		||||
	arrange_windows(view->swayc);
 | 
			
		||||
 | 
			
		||||
	struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
			
		||||
	if (seat->cursor) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										29
									
								
								sway/commands/default_floating_border.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								sway/commands/default_floating_border.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
#include "log.h"
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/config.h"
 | 
			
		||||
#include "sway/tree/container.h"
 | 
			
		||||
 | 
			
		||||
struct cmd_results *cmd_default_floating_border(int argc, char **argv) {
 | 
			
		||||
	struct cmd_results *error = NULL;
 | 
			
		||||
	if ((error = checkarg(argc, "default_floating_border",
 | 
			
		||||
					EXPECTED_AT_LEAST, 1))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (strcmp(argv[0], "none") == 0) {
 | 
			
		||||
		config->floating_border = B_NONE;
 | 
			
		||||
	} else if (strcmp(argv[0], "normal") == 0) {
 | 
			
		||||
		config->floating_border = B_NORMAL;
 | 
			
		||||
	} else if (strcmp(argv[0], "pixel") == 0) {
 | 
			
		||||
		config->floating_border = B_PIXEL;
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "default_floating_border",
 | 
			
		||||
				"Expected 'default_floating_border <none|normal|pixel>' "
 | 
			
		||||
				"or 'default_floating_border <normal|pixel> <px>'");
 | 
			
		||||
	}
 | 
			
		||||
	if (argc == 2) {
 | 
			
		||||
		config->floating_border_thickness = atoi(argv[1]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ struct cmd_results *cmd_exec(int argc, char **argv) {
 | 
			
		|||
	if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL);
 | 
			
		||||
	if (config->reloading) {
 | 
			
		||||
		char *args = join_args(argv, argc);
 | 
			
		||||
		wlr_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Ignoring 'exec %s' due to reload", args);
 | 
			
		||||
		free(args);
 | 
			
		||||
		return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	char *tmp = NULL;
 | 
			
		||||
	if (strcmp((char*)*argv, "--no-startup-id") == 0) {
 | 
			
		||||
		wlr_log(L_INFO, "exec switch '--no-startup-id' not supported, ignored.");
 | 
			
		||||
		wlr_log(WLR_INFO, "exec switch '--no-startup-id' not supported, ignored.");
 | 
			
		||||
		if ((error = checkarg(argc - 1, "exec_always", EXPECTED_MORE_THAN, 0))) {
 | 
			
		||||
			return error;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -35,11 +35,11 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
 | 
			
		|||
	strncpy(cmd, tmp, sizeof(cmd) - 1);
 | 
			
		||||
	cmd[sizeof(cmd) - 1] = 0;
 | 
			
		||||
	free(tmp);
 | 
			
		||||
	wlr_log(L_DEBUG, "Executing %s", cmd);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Executing %s", cmd);
 | 
			
		||||
 | 
			
		||||
	int fd[2];
 | 
			
		||||
	if (pipe(fd) != 0) {
 | 
			
		||||
		wlr_log(L_ERROR, "Unable to create pipe for fork");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Unable to create pipe for fork");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pid_t pid, child;
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +73,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
 | 
			
		|||
	// cleanup child process
 | 
			
		||||
	waitpid(pid, NULL, 0);
 | 
			
		||||
	if (child > 0) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Child process created with pid %d", child);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Child process created with pid %d", child);
 | 
			
		||||
		// TODO: add PID to active workspace
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "exec_always",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
 | 
			
		|||
	container_set_floating(container, wants_floating);
 | 
			
		||||
 | 
			
		||||
	struct sway_container *workspace = container_parent(container, C_WORKSPACE);
 | 
			
		||||
	arrange_and_commit(workspace);
 | 
			
		||||
	arrange_windows(workspace);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										53
									
								
								sway/commands/floating_minmax_size.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								sway/commands/floating_minmax_size.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
#include <errno.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
static const char* min_usage =
 | 
			
		||||
	"Expected 'floating_minimum_size <width> x <height>'";
 | 
			
		||||
 | 
			
		||||
static const char* max_usage =
 | 
			
		||||
	"Expected 'floating_maximum_size <width> x <height>'";
 | 
			
		||||
 | 
			
		||||
static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
 | 
			
		||||
		const char *usage, int *config_width, int *config_height) {
 | 
			
		||||
	struct cmd_results *error;
 | 
			
		||||
	if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 3))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	char *err;
 | 
			
		||||
	int width = (int)strtol(argv[0], &err, 10);
 | 
			
		||||
	if (*err) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, cmd_name, usage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (strcmp(argv[1], "x") != 0) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, cmd_name, usage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int height = (int)strtol(argv[2], &err, 10);
 | 
			
		||||
	if (*err) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, cmd_name, usage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*config_width = width;
 | 
			
		||||
	*config_height = height;
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct cmd_results *cmd_floating_minimum_size(int argc, char **argv) {
 | 
			
		||||
	return handle_command(argc, argv, "floating_minimum_size", min_usage,
 | 
			
		||||
			&config->floating_minimum_width, &config->floating_minimum_height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct cmd_results *cmd_floating_maximum_size(int argc, char **argv) {
 | 
			
		||||
	return handle_command(argc, argv, "floating_maximum_size", max_usage,
 | 
			
		||||
			&config->floating_maximum_width, &config->floating_maximum_height);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,12 @@
 | 
			
		|||
#include <strings.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/input/input-manager.h"
 | 
			
		||||
#include "sway/input/seat.h"
 | 
			
		||||
#include "sway/tree/arrange.h"
 | 
			
		||||
#include "sway/tree/view.h"
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/tree/workspace.h"
 | 
			
		||||
 | 
			
		||||
static bool parse_movement_direction(const char *name,
 | 
			
		||||
		enum movement_direction *out) {
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +29,21 @@ static bool parse_movement_direction(const char *name,
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cmd_results *focus_mode(struct sway_container *con,
 | 
			
		||||
		struct sway_seat *seat, bool floating) {
 | 
			
		||||
	struct sway_container *ws = con->type == C_WORKSPACE ?
 | 
			
		||||
		con : container_parent(con, C_WORKSPACE);
 | 
			
		||||
	struct sway_container *new_focus = ws;
 | 
			
		||||
	if (floating) {
 | 
			
		||||
		new_focus = ws->sway_workspace->floating;
 | 
			
		||||
		if (new_focus->children->length == 0) {
 | 
			
		||||
			return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	seat_set_focus(seat, seat_get_active_child(seat, new_focus));
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct cmd_results *cmd_focus(int argc, char **argv) {
 | 
			
		||||
	struct sway_container *con = config->handler_context.current_container;
 | 
			
		||||
	struct sway_seat *seat = config->handler_context.seat;
 | 
			
		||||
| 
						 | 
				
			
			@ -40,11 +57,20 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
 | 
			
		|||
		return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO mode_toggle
 | 
			
		||||
	if (strcmp(argv[0], "floating") == 0) {
 | 
			
		||||
		return focus_mode(con, seat, true);
 | 
			
		||||
	} else if (strcmp(argv[0], "tiling") == 0) {
 | 
			
		||||
		return focus_mode(con, seat, false);
 | 
			
		||||
	} else if (strcmp(argv[0], "mode_toggle") == 0) {
 | 
			
		||||
		return focus_mode(con, seat, !container_is_floating(con));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: focus output <direction|name>
 | 
			
		||||
	enum movement_direction direction = 0;
 | 
			
		||||
	if (!parse_movement_direction(argv[0], &direction)) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "focus",
 | 
			
		||||
				"Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'");
 | 
			
		||||
			"Expected 'focus <direction|parent|child|mode_toggle|floating|tiling>' "
 | 
			
		||||
			"or 'focus output <direction|name>'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct sway_container *next_focus = container_get_in_direction(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ struct cmd_results *cmd_for_window(int argc, char **argv) {
 | 
			
		|||
	criteria->cmdlist = join_args(argv + 1, argc - 1);
 | 
			
		||||
 | 
			
		||||
	list_add(config->criteria, criteria);
 | 
			
		||||
	wlr_log(L_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
 | 
			
		|||
	view_set_fullscreen(view, wants_fullscreen);
 | 
			
		||||
 | 
			
		||||
	struct sway_container *workspace = container_parent(container, C_WORKSPACE);
 | 
			
		||||
	arrange_and_commit(workspace->parent);
 | 
			
		||||
	arrange_windows(workspace->parent);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
 | 
			
		|||
			return cmd_results_new(CMD_INVALID, "gaps",
 | 
			
		||||
				"gaps edge_gaps on|off|toggle");
 | 
			
		||||
		}
 | 
			
		||||
		arrange_and_commit(&root_container);
 | 
			
		||||
		arrange_windows(&root_container);
 | 
			
		||||
	} else {
 | 
			
		||||
		int amount_idx = 0; // the current index in argv
 | 
			
		||||
		enum gaps_op op = GAPS_OP_SET;
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +124,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
 | 
			
		|||
		if (amount_idx == 0) { // gaps <amount>
 | 
			
		||||
			config->gaps_inner = val;
 | 
			
		||||
			config->gaps_outer = val;
 | 
			
		||||
			arrange_and_commit(&root_container);
 | 
			
		||||
			arrange_windows(&root_container);
 | 
			
		||||
			return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
		}
 | 
			
		||||
		// Other variants. The middle-length variant (gaps inner|outer <amount>)
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +155,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
 | 
			
		|||
			} else {
 | 
			
		||||
				config->gaps_outer = total;
 | 
			
		||||
			}
 | 
			
		||||
			arrange_and_commit(&root_container);
 | 
			
		||||
			arrange_windows(&root_container);
 | 
			
		||||
		} else {
 | 
			
		||||
			struct sway_container *c =
 | 
			
		||||
				config->handler_context.current_container;
 | 
			
		||||
| 
						 | 
				
			
			@ -169,7 +169,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
 | 
			
		|||
				c->gaps_outer = total;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			arrange_and_commit(c->parent ? c->parent : &root_container);
 | 
			
		||||
			arrange_windows(c->parent ? c->parent : &root_container);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,8 +20,10 @@ static struct cmd_handler input_handlers[] = {
 | 
			
		|||
	{ "pointer_accel", input_cmd_pointer_accel },
 | 
			
		||||
	{ "repeat_delay", input_cmd_repeat_delay },
 | 
			
		||||
	{ "repeat_rate", input_cmd_repeat_rate },
 | 
			
		||||
	{ "scroll_button", input_cmd_scroll_button },
 | 
			
		||||
	{ "scroll_method", input_cmd_scroll_method },
 | 
			
		||||
	{ "tap", input_cmd_tap },
 | 
			
		||||
	{ "tap_button_map", input_cmd_tap_button_map },
 | 
			
		||||
	{ "xkb_layout", input_cmd_xkb_layout },
 | 
			
		||||
	{ "xkb_model", input_cmd_xkb_model },
 | 
			
		||||
	{ "xkb_options", input_cmd_xkb_options },
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +37,7 @@ struct cmd_results *cmd_input(int argc, char **argv) {
 | 
			
		|||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "entering input block: %s", argv[0]);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "entering input block: %s", argv[0]);
 | 
			
		||||
 | 
			
		||||
	config->handler_context.input_config = new_input_config(argv[0]);
 | 
			
		||||
	if (!config->handler_context.input_config) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ struct cmd_results *input_cmd_events(int argc, char **argv) {
 | 
			
		|||
		return cmd_results_new(CMD_FAILURE, "events",
 | 
			
		||||
			"No input device defined.");
 | 
			
		||||
	}
 | 
			
		||||
	wlr_log(L_DEBUG, "events for device: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "events for device: %s",
 | 
			
		||||
		current_input_config->identifier);
 | 
			
		||||
	struct input_config *new_config =
 | 
			
		||||
		new_input_config(current_input_config->identifier);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										44
									
								
								sway/commands/input/scroll_button.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								sway/commands/input/scroll_button.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
#include <string.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include "sway/config.h"
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/input/input-manager.h"
 | 
			
		||||
 | 
			
		||||
struct cmd_results *input_cmd_scroll_button(int argc, char **argv) {
 | 
			
		||||
	struct cmd_results *error = NULL;
 | 
			
		||||
	if ((error = checkarg(argc, "scroll_button", EXPECTED_AT_LEAST, 1))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
	struct input_config *current_input_config =
 | 
			
		||||
		config->handler_context.input_config;
 | 
			
		||||
	if (!current_input_config) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "scroll_button",
 | 
			
		||||
			"No input device defined.");
 | 
			
		||||
	}
 | 
			
		||||
	struct input_config *new_config =
 | 
			
		||||
		new_input_config(current_input_config->identifier);
 | 
			
		||||
 | 
			
		||||
	errno = 0;
 | 
			
		||||
	char *endptr;
 | 
			
		||||
	int scroll_button = strtol(*argv, &endptr, 10);
 | 
			
		||||
	if (endptr == *argv && scroll_button == 0) {
 | 
			
		||||
		free_input_config(new_config);
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "scroll_button",
 | 
			
		||||
				"Scroll button identifier must be an integer.");
 | 
			
		||||
	}
 | 
			
		||||
	if (errno == ERANGE) {
 | 
			
		||||
		free_input_config(new_config);
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "scroll_button",
 | 
			
		||||
				"Scroll button identifier out of range.");
 | 
			
		||||
	}
 | 
			
		||||
	if (scroll_button < 0) {
 | 
			
		||||
		free_input_config(new_config);
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "scroll_button",
 | 
			
		||||
				"Scroll button identifier cannot be negative.");
 | 
			
		||||
	}
 | 
			
		||||
	new_config->scroll_button = scroll_button;
 | 
			
		||||
 | 
			
		||||
	apply_input_config(new_config);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) {
 | 
			
		|||
			"Expected 'tap <enabled|disabled>'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "apply-tap for device: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "apply-tap for device: %s",
 | 
			
		||||
		current_input_config->identifier);
 | 
			
		||||
	apply_input_config(new_config);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										33
									
								
								sway/commands/input/tap_button_map.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								sway/commands/input/tap_button_map.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
#include <string.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
#include "sway/config.h"
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/input/input-manager.h"
 | 
			
		||||
 | 
			
		||||
struct cmd_results *input_cmd_tap_button_map(int argc, char **argv) {
 | 
			
		||||
	struct cmd_results *error = NULL;
 | 
			
		||||
	if ((error = checkarg(argc, "tap_button_map", EXPECTED_AT_LEAST, 1))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
	struct input_config *current_input_config =
 | 
			
		||||
		config->handler_context.input_config;
 | 
			
		||||
	if (!current_input_config) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "tap_button_map",
 | 
			
		||||
				"No input device defined.");
 | 
			
		||||
	}
 | 
			
		||||
	struct input_config *new_config =
 | 
			
		||||
		new_input_config(current_input_config->identifier);
 | 
			
		||||
 | 
			
		||||
	if (strcasecmp(argv[0], "lrm") == 0) {
 | 
			
		||||
		new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
 | 
			
		||||
	} else if (strcasecmp(argv[0], "lmr") == 0) {
 | 
			
		||||
		new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LMR;
 | 
			
		||||
	} else {
 | 
			
		||||
		free_input_config(new_config);
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "tap_button_map",
 | 
			
		||||
			"Expected 'tap_button_map <lrm|lmr>'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	apply_input_config(new_config);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	new_config->xkb_layout = strdup(argv[0]);
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "apply-xkb_layout for device: %s layout: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "apply-xkb_layout for device: %s layout: %s",
 | 
			
		||||
		current_input_config->identifier, new_config->xkb_layout);
 | 
			
		||||
	apply_input_config(new_config);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_model(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	new_config->xkb_model = strdup(argv[0]);
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "apply-xkb_model for device: %s model: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "apply-xkb_model for device: %s model: %s",
 | 
			
		||||
		current_input_config->identifier, new_config->xkb_model);
 | 
			
		||||
	apply_input_config(new_config);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_options(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	new_config->xkb_options = strdup(argv[0]);
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "apply-xkb_options for device: %s options: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "apply-xkb_options for device: %s options: %s",
 | 
			
		||||
		current_input_config->identifier, new_config->xkb_options);
 | 
			
		||||
	apply_input_config(new_config);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	new_config->xkb_rules = strdup(argv[0]);
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "apply-xkb_rules for device: %s rules: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "apply-xkb_rules for device: %s rules: %s",
 | 
			
		||||
		current_input_config->identifier, new_config->xkb_rules);
 | 
			
		||||
	apply_input_config(new_config);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	new_config->xkb_variant = strdup(argv[0]);
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "apply-xkb_variant for device: %s variant: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "apply-xkb_variant for device: %s variant: %s",
 | 
			
		||||
		current_input_config->identifier, new_config->xkb_variant);
 | 
			
		||||
	apply_input_config(new_config);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	container_notify_subtree_changed(parent);
 | 
			
		||||
	arrange_and_commit(parent);
 | 
			
		||||
	arrange_windows(parent);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
 | 
			
		|||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
	if ((config->reading && argc > 1) || (!config->reading && argc == 1)) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Switching to mode `%s' (pango=%d)",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Switching to mode `%s' (pango=%d)",
 | 
			
		||||
				mode->name, mode->pango);
 | 
			
		||||
	}
 | 
			
		||||
	// Set current mode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,12 @@
 | 
			
		|||
#define _XOPEN_SOURCE 500
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
#include <wlr/types/wlr_cursor.h>
 | 
			
		||||
#include <wlr/types/wlr_output.h>
 | 
			
		||||
#include <wlr/types/wlr_output_layout.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/desktop/transaction.h"
 | 
			
		||||
#include "sway/input/cursor.h"
 | 
			
		||||
#include "sway/input/seat.h"
 | 
			
		||||
#include "sway/output.h"
 | 
			
		||||
#include "sway/tree/arrange.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -103,10 +104,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
 | 
			
		|||
		// TODO: Ideally we would arrange the surviving parent after reaping,
 | 
			
		||||
		// but container_reap_empty does not return it, so we arrange the
 | 
			
		||||
		// workspace instead.
 | 
			
		||||
		struct sway_transaction *txn = transaction_create();
 | 
			
		||||
		arrange_windows(old_ws, txn);
 | 
			
		||||
		arrange_windows(destination->parent, txn);
 | 
			
		||||
		transaction_commit(txn);
 | 
			
		||||
		arrange_windows(old_ws);
 | 
			
		||||
		arrange_windows(destination->parent);
 | 
			
		||||
 | 
			
		||||
		return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
	} else if (strcasecmp(argv[1], "to") == 0
 | 
			
		||||
| 
						 | 
				
			
			@ -142,10 +141,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
 | 
			
		|||
		// TODO: Ideally we would arrange the surviving parent after reaping,
 | 
			
		||||
		// but container_reap_empty does not return it, so we arrange the
 | 
			
		||||
		// workspace instead.
 | 
			
		||||
		struct sway_transaction *txn = transaction_create();
 | 
			
		||||
		arrange_windows(old_ws, txn);
 | 
			
		||||
		arrange_windows(focus->parent, txn);
 | 
			
		||||
		transaction_commit(txn);
 | 
			
		||||
		arrange_windows(old_ws);
 | 
			
		||||
		arrange_windows(focus->parent);
 | 
			
		||||
 | 
			
		||||
		return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -175,20 +172,56 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current,
 | 
			
		|||
	}
 | 
			
		||||
	container_move_to(current, destination);
 | 
			
		||||
 | 
			
		||||
	struct sway_transaction *txn = transaction_create();
 | 
			
		||||
	arrange_windows(source, txn);
 | 
			
		||||
	arrange_windows(destination, txn);
 | 
			
		||||
	transaction_commit(txn);
 | 
			
		||||
	arrange_windows(source);
 | 
			
		||||
	arrange_windows(destination);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cmd_results *move_in_direction(struct sway_container *container,
 | 
			
		||||
		enum movement_direction direction, int move_amt) {
 | 
			
		||||
		enum movement_direction direction, int argc, char **argv) {
 | 
			
		||||
	int move_amt = 10;
 | 
			
		||||
	if (argc > 1) {
 | 
			
		||||
		char *inv;
 | 
			
		||||
		move_amt = (int)strtol(argv[1], &inv, 10);
 | 
			
		||||
		if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
 | 
			
		||||
			return cmd_results_new(CMD_FAILURE, "move",
 | 
			
		||||
					"Invalid distance specified");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (container->type == C_WORKSPACE) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move",
 | 
			
		||||
				"Cannot move workspaces in a direction");
 | 
			
		||||
	}
 | 
			
		||||
	if (container_is_floating(container)) {
 | 
			
		||||
		if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
 | 
			
		||||
			return cmd_results_new(CMD_FAILURE, "move",
 | 
			
		||||
					"Cannot move fullscreen floating container");
 | 
			
		||||
		}
 | 
			
		||||
		double lx = container->x;
 | 
			
		||||
		double ly = container->y;
 | 
			
		||||
		switch (direction) {
 | 
			
		||||
		case MOVE_LEFT:
 | 
			
		||||
			lx -= move_amt;
 | 
			
		||||
			break;
 | 
			
		||||
		case MOVE_RIGHT:
 | 
			
		||||
			lx += move_amt;
 | 
			
		||||
			break;
 | 
			
		||||
		case MOVE_UP:
 | 
			
		||||
			ly -= move_amt;
 | 
			
		||||
			break;
 | 
			
		||||
		case MOVE_DOWN:
 | 
			
		||||
			ly += move_amt;
 | 
			
		||||
			break;
 | 
			
		||||
		case MOVE_PARENT:
 | 
			
		||||
		case MOVE_CHILD:
 | 
			
		||||
			return cmd_results_new(CMD_FAILURE, "move",
 | 
			
		||||
					"Cannot move floating container to parent or child");
 | 
			
		||||
		}
 | 
			
		||||
		container_floating_move_to(container, lx, ly);
 | 
			
		||||
		return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	// For simplicity, we'll arrange the entire workspace. The reason for this
 | 
			
		||||
	// is moving the container might reap the old parent, and container_move
 | 
			
		||||
	// does not return a surviving parent.
 | 
			
		||||
| 
						 | 
				
			
			@ -198,41 +231,86 @@ static struct cmd_results *move_in_direction(struct sway_container *container,
 | 
			
		|||
	container_move(container, direction, move_amt);
 | 
			
		||||
	struct sway_container *new_ws = container_parent(container, C_WORKSPACE);
 | 
			
		||||
 | 
			
		||||
	struct sway_transaction *txn = transaction_create();
 | 
			
		||||
	arrange_windows(old_ws, txn);
 | 
			
		||||
	arrange_windows(old_ws);
 | 
			
		||||
	if (new_ws != old_ws) {
 | 
			
		||||
		arrange_windows(new_ws, txn);
 | 
			
		||||
		arrange_windows(new_ws);
 | 
			
		||||
	}
 | 
			
		||||
	transaction_commit(txn);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char* expected_position_syntax =
 | 
			
		||||
	"Expected 'move [absolute] position <x> <y>' or "
 | 
			
		||||
	"'move [absolute] position mouse'";
 | 
			
		||||
 | 
			
		||||
static struct cmd_results *move_to_position(struct sway_container *container,
 | 
			
		||||
		int argc, char **argv) {
 | 
			
		||||
	if (!container_is_floating(container)) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move",
 | 
			
		||||
				"Only floating containers "
 | 
			
		||||
				"can be moved to an absolute position");
 | 
			
		||||
	}
 | 
			
		||||
	if (!argc) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(argv[0], "absolute") == 0) {
 | 
			
		||||
		--argc;
 | 
			
		||||
		++argv;
 | 
			
		||||
	}
 | 
			
		||||
	if (!argc) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(argv[0], "position") == 0) {
 | 
			
		||||
		--argc;
 | 
			
		||||
		++argv;
 | 
			
		||||
	}
 | 
			
		||||
	if (!argc) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(argv[0], "mouse") == 0) {
 | 
			
		||||
		struct sway_seat *seat = config->handler_context.seat;
 | 
			
		||||
		if (!seat->cursor) {
 | 
			
		||||
			return cmd_results_new(CMD_FAILURE, "move", "No cursor device");
 | 
			
		||||
		}
 | 
			
		||||
		double lx = seat->cursor->cursor->x - container->width / 2;
 | 
			
		||||
		double ly = seat->cursor->cursor->y - container->height / 2;
 | 
			
		||||
		container_floating_move_to(container, lx, ly);
 | 
			
		||||
		return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if (argc != 2) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
 | 
			
		||||
	}
 | 
			
		||||
	double lx, ly;
 | 
			
		||||
	char *inv;
 | 
			
		||||
	lx = (double)strtol(argv[0], &inv, 10);
 | 
			
		||||
	if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move",
 | 
			
		||||
				"Invalid position specified");
 | 
			
		||||
	}
 | 
			
		||||
	ly = (double)strtol(argv[1], &inv, 10);
 | 
			
		||||
	if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move",
 | 
			
		||||
				"Invalid position specified");
 | 
			
		||||
	}
 | 
			
		||||
	container_floating_move_to(container, lx, ly);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct cmd_results *cmd_move(int argc, char **argv) {
 | 
			
		||||
	struct cmd_results *error = NULL;
 | 
			
		||||
	int move_amt = 10;
 | 
			
		||||
	if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
	struct sway_container *current = config->handler_context.current_container;
 | 
			
		||||
 | 
			
		||||
	if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) {
 | 
			
		||||
		char *inv;
 | 
			
		||||
		move_amt = (int)strtol(argv[1], &inv, 10);
 | 
			
		||||
		if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
 | 
			
		||||
			return cmd_results_new(CMD_FAILURE, "move",
 | 
			
		||||
					"Invalid distance specified");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (strcasecmp(argv[0], "left") == 0) {
 | 
			
		||||
		return move_in_direction(current, MOVE_LEFT, move_amt);
 | 
			
		||||
		return move_in_direction(current, MOVE_LEFT, argc, argv);
 | 
			
		||||
	} else if (strcasecmp(argv[0], "right") == 0) {
 | 
			
		||||
		return move_in_direction(current, MOVE_RIGHT, move_amt);
 | 
			
		||||
		return move_in_direction(current, MOVE_RIGHT, argc, argv);
 | 
			
		||||
	} else if (strcasecmp(argv[0], "up") == 0) {
 | 
			
		||||
		return move_in_direction(current, MOVE_UP, move_amt);
 | 
			
		||||
		return move_in_direction(current, MOVE_UP, argc, argv);
 | 
			
		||||
	} else if (strcasecmp(argv[0], "down") == 0) {
 | 
			
		||||
		return move_in_direction(current, MOVE_DOWN, move_amt);
 | 
			
		||||
		return move_in_direction(current, MOVE_DOWN, argc, argv);
 | 
			
		||||
	} else if (strcasecmp(argv[0], "container") == 0
 | 
			
		||||
			|| strcasecmp(argv[0], "window") == 0) {
 | 
			
		||||
		return cmd_move_container(current, argc, argv);
 | 
			
		||||
| 
						 | 
				
			
			@ -244,8 +322,9 @@ struct cmd_results *cmd_move(int argc, char **argv) {
 | 
			
		|||
		// TODO: scratchpad
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
 | 
			
		||||
	} else if (strcasecmp(argv[0], "position") == 0) {
 | 
			
		||||
		// TODO: floating
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
 | 
			
		||||
		return move_to_position(current, argc, argv);
 | 
			
		||||
	} else if (strcasecmp(argv[0], "absolute") == 0) {
 | 
			
		||||
		return move_to_position(current, argc, argv);
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "move", expected_syntax);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										26
									
								
								sway/commands/no_focus.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								sway/commands/no_focus.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
#define _XOPEN_SOURCE 500
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/criteria.h"
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
struct cmd_results *cmd_no_focus(int argc, char **argv) {
 | 
			
		||||
	struct cmd_results *error = NULL;
 | 
			
		||||
	if ((error = checkarg(argc, "no_focus", EXPECTED_AT_LEAST, 1))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	char *err_str = NULL;
 | 
			
		||||
	struct criteria *criteria = criteria_parse(argv[0], &err_str);
 | 
			
		||||
	if (!criteria) {
 | 
			
		||||
		error = cmd_results_new(CMD_INVALID, "no_focus", err_str);
 | 
			
		||||
		free(err_str);
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	criteria->type = CT_NO_FOCUS;
 | 
			
		||||
	list_add(config->criteria, criteria);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	struct output_config *output = new_output_config(argv[0]);
 | 
			
		||||
	if (!output) {
 | 
			
		||||
		wlr_log(L_ERROR, "Failed to allocate output config");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Failed to allocate output config");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	argc--; argv++;
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +71,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
 | 
			
		|||
		list_add(config->output_configs, output);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
 | 
			
		||||
		"position %d,%d scale %f transform %d) (bg %s %s) (dpms %d)",
 | 
			
		||||
		output->name, output->enabled, output->width, output->height,
 | 
			
		||||
		output->refresh_rate, output->x, output->y, output->scale,
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
 | 
			
		|||
	struct sway_output *sway_output;
 | 
			
		||||
	wl_list_for_each(sway_output, &root_container.sway_root->outputs, link) {
 | 
			
		||||
		output_get_identifier(identifier, sizeof(identifier), sway_output);
 | 
			
		||||
		wlr_log(L_DEBUG, "Checking identifier %s", identifier);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Checking identifier %s", identifier);
 | 
			
		||||
		if (all || strcmp(sway_output->wlr_output->name, output->name) == 0
 | 
			
		||||
				|| strcmp(identifier, output->name) == 0) {
 | 
			
		||||
			if (!sway_output->swayc) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
 | 
			
		|||
		src = strdup(p.we_wordv[0]);
 | 
			
		||||
		wordfree(&p);
 | 
			
		||||
		if (!src) {
 | 
			
		||||
			wlr_log(L_ERROR, "Failed to duplicate string");
 | 
			
		||||
			wlr_log(WLR_ERROR, "Failed to duplicate string");
 | 
			
		||||
			return cmd_results_new(CMD_FAILURE, "output",
 | 
			
		||||
				"Unable to allocate resource");
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -80,9 +80,9 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
 | 
			
		|||
		if (config->reading && *src != '/') {
 | 
			
		||||
			// src file is inside configuration dir
 | 
			
		||||
 | 
			
		||||
			char *conf = strdup(config->current_config);
 | 
			
		||||
			char *conf = strdup(config->current_config_path);
 | 
			
		||||
			if (!conf) {
 | 
			
		||||
				wlr_log(L_ERROR, "Failed to duplicate string");
 | 
			
		||||
				wlr_log(WLR_ERROR, "Failed to duplicate string");
 | 
			
		||||
				free(src);
 | 
			
		||||
				return cmd_results_new(CMD_FAILURE, "output",
 | 
			
		||||
						"Unable to allocate resources");
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +94,7 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
 | 
			
		|||
			if (!src) {
 | 
			
		||||
				free(rel_path);
 | 
			
		||||
				free(conf);
 | 
			
		||||
				wlr_log(L_ERROR, "Unable to allocate memory");
 | 
			
		||||
				wlr_log(WLR_ERROR, "Unable to allocate memory");
 | 
			
		||||
				return cmd_results_new(CMD_FAILURE, "output",
 | 
			
		||||
						"Unable to allocate resources");
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,11 +7,11 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
 | 
			
		|||
	if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
	if (!load_main_config(config->current_config, true)) {
 | 
			
		||||
	if (!load_main_config(config->current_config_path, true)) {
 | 
			
		||||
		return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	load_swaybars();
 | 
			
		||||
	arrange_and_commit(&root_container);
 | 
			
		||||
	arrange_windows(&root_container);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,7 +68,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
 | 
			
		|||
				"Workspace already exists");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
 | 
			
		||||
	free(workspace->name);
 | 
			
		||||
	workspace->name = new_name;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +8,7 @@
 | 
			
		|||
#include <wlr/util/log.h>
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/tree/arrange.h"
 | 
			
		||||
#include "sway/tree/view.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
static const int MIN_SANE_W = 100, MIN_SANE_H = 60;
 | 
			
		||||
| 
						 | 
				
			
			@ -21,9 +23,18 @@ enum resize_unit {
 | 
			
		|||
enum resize_axis {
 | 
			
		||||
	RESIZE_AXIS_HORIZONTAL,
 | 
			
		||||
	RESIZE_AXIS_VERTICAL,
 | 
			
		||||
	RESIZE_AXIS_UP,
 | 
			
		||||
	RESIZE_AXIS_DOWN,
 | 
			
		||||
	RESIZE_AXIS_LEFT,
 | 
			
		||||
	RESIZE_AXIS_RIGHT,
 | 
			
		||||
	RESIZE_AXIS_INVALID,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct resize_amount {
 | 
			
		||||
	int amount;
 | 
			
		||||
	enum resize_unit unit;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static enum resize_unit parse_resize_unit(const char *unit) {
 | 
			
		||||
	if (strcasecmp(unit, "px") == 0) {
 | 
			
		||||
		return RESIZE_UNIT_PX;
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +48,69 @@ static enum resize_unit parse_resize_unit(const char *unit) {
 | 
			
		|||
	return RESIZE_UNIT_INVALID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse arguments such as "10", "10px" or "10 px".
 | 
			
		||||
// Returns the number of arguments consumed.
 | 
			
		||||
static int parse_resize_amount(int argc, char **argv,
 | 
			
		||||
		struct resize_amount *amount) {
 | 
			
		||||
	char *err;
 | 
			
		||||
	amount->amount = (int)strtol(argv[0], &err, 10);
 | 
			
		||||
	if (*err) {
 | 
			
		||||
		// e.g. 10px
 | 
			
		||||
		amount->unit = parse_resize_unit(err);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (argc == 1) {
 | 
			
		||||
		amount->unit = RESIZE_UNIT_DEFAULT;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	// Try the second argument
 | 
			
		||||
	amount->unit = parse_resize_unit(argv[1]);
 | 
			
		||||
	if (amount->unit == RESIZE_UNIT_INVALID) {
 | 
			
		||||
		amount->unit = RESIZE_UNIT_DEFAULT;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	return 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void calculate_constraints(int *min_width, int *max_width,
 | 
			
		||||
		int *min_height, int *max_height) {
 | 
			
		||||
	struct sway_container *con = config->handler_context.current_container;
 | 
			
		||||
 | 
			
		||||
	if (config->floating_minimum_width == -1) { // no minimum
 | 
			
		||||
		*min_width = 0;
 | 
			
		||||
	} else if (config->floating_minimum_width == 0) { // automatic
 | 
			
		||||
		*min_width = 75;
 | 
			
		||||
	} else {
 | 
			
		||||
		*min_width = config->floating_minimum_width;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (config->floating_minimum_height == -1) { // no minimum
 | 
			
		||||
		*min_height = 0;
 | 
			
		||||
	} else if (config->floating_minimum_height == 0) { // automatic
 | 
			
		||||
		*min_height = 50;
 | 
			
		||||
	} else {
 | 
			
		||||
		*min_height = config->floating_minimum_height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (config->floating_maximum_width == -1) { // no maximum
 | 
			
		||||
		*max_width = INT_MAX;
 | 
			
		||||
	} else if (config->floating_maximum_width == 0) { // automatic
 | 
			
		||||
		struct sway_container *ws = container_parent(con, C_WORKSPACE);
 | 
			
		||||
		*max_width = ws->width;
 | 
			
		||||
	} else {
 | 
			
		||||
		*max_width = config->floating_maximum_width;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (config->floating_maximum_height == -1) { // no maximum
 | 
			
		||||
		*max_height = INT_MAX;
 | 
			
		||||
	} else if (config->floating_maximum_height == 0) { // automatic
 | 
			
		||||
		struct sway_container *ws = container_parent(con, C_WORKSPACE);
 | 
			
		||||
		*max_height = ws->height;
 | 
			
		||||
	} else {
 | 
			
		||||
		*max_height = config->floating_maximum_height;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum resize_axis parse_resize_axis(const char *axis) {
 | 
			
		||||
	if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) {
 | 
			
		||||
		return RESIZE_AXIS_HORIZONTAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +118,18 @@ static enum resize_axis parse_resize_axis(const char *axis) {
 | 
			
		|||
	if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) {
 | 
			
		||||
		return RESIZE_AXIS_VERTICAL;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcasecmp(axis, "up") == 0) {
 | 
			
		||||
		return RESIZE_AXIS_UP;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcasecmp(axis, "down") == 0) {
 | 
			
		||||
		return RESIZE_AXIS_DOWN;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcasecmp(axis, "left") == 0) {
 | 
			
		||||
		return RESIZE_AXIS_LEFT;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcasecmp(axis, "right") == 0) {
 | 
			
		||||
		return RESIZE_AXIS_RIGHT;
 | 
			
		||||
	}
 | 
			
		||||
	return RESIZE_AXIS_INVALID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -95,7 +181,7 @@ static void resize_tiled(int amount, enum resize_axis axis) {
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG,
 | 
			
		||||
	wlr_log(WLR_DEBUG,
 | 
			
		||||
			"Found the proper parent: %p. It has %d l conts, and %d r conts",
 | 
			
		||||
			parent->parent, minor_weight, major_weight);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -182,32 +268,286 @@ static void resize_tiled(int amount, enum resize_axis axis) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	arrange_and_commit(parent->parent);
 | 
			
		||||
	arrange_windows(parent->parent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void resize(int amount, enum resize_axis axis, enum resize_unit unit) {
 | 
			
		||||
	struct sway_container *current = config->handler_context.current_container;
 | 
			
		||||
	if (unit == RESIZE_UNIT_DEFAULT) {
 | 
			
		||||
		// Default for tiling; TODO floating should be px
 | 
			
		||||
		unit = RESIZE_UNIT_PPT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unit == RESIZE_UNIT_PPT) {
 | 
			
		||||
		float pct = amount / 100.0f;
 | 
			
		||||
/**
 | 
			
		||||
 * Implement `resize <grow|shrink>` for a floating container.
 | 
			
		||||
 */
 | 
			
		||||
static struct cmd_results *resize_adjust_floating(enum resize_axis axis,
 | 
			
		||||
		struct resize_amount *amount) {
 | 
			
		||||
	struct sway_container *con = config->handler_context.current_container;
 | 
			
		||||
	int grow_width = 0, grow_height = 0;
 | 
			
		||||
	switch (axis) {
 | 
			
		||||
	case RESIZE_AXIS_HORIZONTAL:
 | 
			
		||||
			amount = (float)current->width * pct;
 | 
			
		||||
	case RESIZE_AXIS_LEFT:
 | 
			
		||||
	case RESIZE_AXIS_RIGHT:
 | 
			
		||||
		grow_width = amount->amount;
 | 
			
		||||
		break;
 | 
			
		||||
	case RESIZE_AXIS_VERTICAL:
 | 
			
		||||
			amount = (float)current->height * pct;
 | 
			
		||||
	case RESIZE_AXIS_UP:
 | 
			
		||||
	case RESIZE_AXIS_DOWN:
 | 
			
		||||
		grow_height = amount->amount;
 | 
			
		||||
		break;
 | 
			
		||||
		default:
 | 
			
		||||
			sway_assert(0, "invalid resize axis");
 | 
			
		||||
			return;
 | 
			
		||||
	case RESIZE_AXIS_INVALID:
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction");
 | 
			
		||||
	}
 | 
			
		||||
	// Make sure we're not adjusting beyond floating min/max size
 | 
			
		||||
	int min_width, max_width, min_height, max_height;
 | 
			
		||||
	calculate_constraints(&min_width, &max_width, &min_height, &max_height);
 | 
			
		||||
	if (con->width + grow_width < min_width) {
 | 
			
		||||
		grow_width = min_width - con->width;
 | 
			
		||||
	} else if (con->width + grow_width > max_width) {
 | 
			
		||||
		grow_width = max_width - con->width;
 | 
			
		||||
	}
 | 
			
		||||
	if (con->height + grow_height < min_height) {
 | 
			
		||||
		grow_height = min_height - con->height;
 | 
			
		||||
	} else if (con->height + grow_height > max_height) {
 | 
			
		||||
		grow_height = max_height - con->height;
 | 
			
		||||
	}
 | 
			
		||||
	int grow_x = 0, grow_y = 0;
 | 
			
		||||
	switch (axis) {
 | 
			
		||||
	case RESIZE_AXIS_HORIZONTAL:
 | 
			
		||||
		grow_x = -grow_width / 2;
 | 
			
		||||
		break;
 | 
			
		||||
	case RESIZE_AXIS_VERTICAL:
 | 
			
		||||
		grow_y = -grow_height / 2;
 | 
			
		||||
		break;
 | 
			
		||||
	case RESIZE_AXIS_UP:
 | 
			
		||||
		grow_y = -grow_height;
 | 
			
		||||
		break;
 | 
			
		||||
	case RESIZE_AXIS_LEFT:
 | 
			
		||||
		grow_x = -grow_width;
 | 
			
		||||
		break;
 | 
			
		||||
	case RESIZE_AXIS_DOWN:
 | 
			
		||||
	case RESIZE_AXIS_RIGHT:
 | 
			
		||||
		break;
 | 
			
		||||
	case RESIZE_AXIS_INVALID:
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction");
 | 
			
		||||
	}
 | 
			
		||||
	con->x += grow_x;
 | 
			
		||||
	con->y += grow_y;
 | 
			
		||||
	con->width += grow_width;
 | 
			
		||||
	con->height += grow_height;
 | 
			
		||||
 | 
			
		||||
	if (con->type == C_VIEW) {
 | 
			
		||||
		struct sway_view *view = con->sway_view;
 | 
			
		||||
		view->x += grow_x;
 | 
			
		||||
		view->y += grow_y;
 | 
			
		||||
		view->width += grow_width;
 | 
			
		||||
		view->height += grow_height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	arrange_windows(con);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implement `resize <grow|shrink>` for a tiled container.
 | 
			
		||||
 */
 | 
			
		||||
static struct cmd_results *resize_adjust_tiled(enum resize_axis axis,
 | 
			
		||||
		struct resize_amount *amount) {
 | 
			
		||||
	struct sway_container *current = config->handler_context.current_container;
 | 
			
		||||
 | 
			
		||||
	if (amount->unit == RESIZE_UNIT_DEFAULT) {
 | 
			
		||||
		amount->unit = RESIZE_UNIT_PPT;
 | 
			
		||||
	}
 | 
			
		||||
	if (amount->unit == RESIZE_UNIT_PPT) {
 | 
			
		||||
		float pct = amount->amount / 100.0f;
 | 
			
		||||
		// TODO: Make left/right/up/down resize in that direction?
 | 
			
		||||
		switch (axis) {
 | 
			
		||||
		case RESIZE_AXIS_LEFT:
 | 
			
		||||
		case RESIZE_AXIS_RIGHT:
 | 
			
		||||
		case RESIZE_AXIS_HORIZONTAL:
 | 
			
		||||
			amount->amount = (float)current->width * pct;
 | 
			
		||||
			break;
 | 
			
		||||
		case RESIZE_AXIS_UP:
 | 
			
		||||
		case RESIZE_AXIS_DOWN:
 | 
			
		||||
		case RESIZE_AXIS_VERTICAL:
 | 
			
		||||
			amount->amount = (float)current->height * pct;
 | 
			
		||||
			break;
 | 
			
		||||
		case RESIZE_AXIS_INVALID:
 | 
			
		||||
			return cmd_results_new(CMD_INVALID, "resize",
 | 
			
		||||
					"Invalid resize axis/direction");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resize_tiled(amount, axis);
 | 
			
		||||
	resize_tiled(amount->amount, axis);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implement `resize set` for a tiled container.
 | 
			
		||||
 */
 | 
			
		||||
static struct cmd_results *resize_set_tiled(struct sway_container *con,
 | 
			
		||||
		struct resize_amount *width, struct resize_amount *height) {
 | 
			
		||||
	return cmd_results_new(CMD_INVALID, "resize",
 | 
			
		||||
			"'resize set' is not implemented for tiled views");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implement `resize set` for a floating container.
 | 
			
		||||
 */
 | 
			
		||||
static struct cmd_results *resize_set_floating(struct sway_container *con,
 | 
			
		||||
		struct resize_amount *width, struct resize_amount *height) {
 | 
			
		||||
	int min_width, max_width, min_height, max_height;
 | 
			
		||||
	calculate_constraints(&min_width, &max_width, &min_height, &max_height);
 | 
			
		||||
	width->amount = fmax(min_width, fmin(width->amount, max_width));
 | 
			
		||||
	height->amount = fmax(min_height, fmin(height->amount, max_height));
 | 
			
		||||
	int grow_width = width->amount - con->width;
 | 
			
		||||
	int grow_height = height->amount - con->height;
 | 
			
		||||
	con->x -= grow_width / 2;
 | 
			
		||||
	con->y -= grow_height / 2;
 | 
			
		||||
	con->width = width->amount;
 | 
			
		||||
	con->height = height->amount;
 | 
			
		||||
 | 
			
		||||
	if (con->type == C_VIEW) {
 | 
			
		||||
		struct sway_view *view = con->sway_view;
 | 
			
		||||
		view->x -= grow_width / 2;
 | 
			
		||||
		view->y -= grow_height / 2;
 | 
			
		||||
		view->width += grow_width;
 | 
			
		||||
		view->height += grow_height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	arrange_windows(con);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * resize set <args>
 | 
			
		||||
 *
 | 
			
		||||
 * args: <width> [px|ppt] <height> [px|ppt]
 | 
			
		||||
 */
 | 
			
		||||
static struct cmd_results *cmd_resize_set(int argc, char **argv) {
 | 
			
		||||
	struct cmd_results *error;
 | 
			
		||||
	if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
	const char *usage = "Expected 'resize set <width> <height>'";
 | 
			
		||||
 | 
			
		||||
	// Width
 | 
			
		||||
	struct resize_amount width;
 | 
			
		||||
	int num_consumed_args = parse_resize_amount(argc, argv, &width);
 | 
			
		||||
	argc -= num_consumed_args;
 | 
			
		||||
	argv += num_consumed_args;
 | 
			
		||||
	if (width.unit == RESIZE_UNIT_INVALID) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
	}
 | 
			
		||||
	if (!argc) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Height
 | 
			
		||||
	struct resize_amount height;
 | 
			
		||||
	num_consumed_args = parse_resize_amount(argc, argv, &height);
 | 
			
		||||
	argc -= num_consumed_args;
 | 
			
		||||
	argv += num_consumed_args;
 | 
			
		||||
	if (height.unit == RESIZE_UNIT_INVALID) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If 0, don't resize that dimension
 | 
			
		||||
	struct sway_container *con = config->handler_context.current_container;
 | 
			
		||||
	if (width.amount <= 0) {
 | 
			
		||||
		width.amount = con->width;
 | 
			
		||||
	}
 | 
			
		||||
	if (height.amount <= 0) {
 | 
			
		||||
		height.amount = con->height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (container_is_floating(con)) {
 | 
			
		||||
		return resize_set_floating(con, &width, &height);
 | 
			
		||||
	}
 | 
			
		||||
	return resize_set_tiled(con, &width, &height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * resize <grow|shrink> <args>
 | 
			
		||||
 *
 | 
			
		||||
 * args: <direction>
 | 
			
		||||
 * args: <direction> <amount> <unit>
 | 
			
		||||
 * args: <direction> <amount> <unit> or <amount> <other_unit>
 | 
			
		||||
 */
 | 
			
		||||
static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
 | 
			
		||||
		int multiplier) {
 | 
			
		||||
	const char *usage = "Expected 'resize grow|shrink <direction> "
 | 
			
		||||
		"[<amount> px|ppt [or <amount> px|ppt]]'";
 | 
			
		||||
	enum resize_axis axis = parse_resize_axis(*argv);
 | 
			
		||||
	if (axis == RESIZE_AXIS_INVALID) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
	}
 | 
			
		||||
	--argc; ++argv;
 | 
			
		||||
 | 
			
		||||
	// First amount
 | 
			
		||||
	struct resize_amount first_amount;
 | 
			
		||||
	if (argc) {
 | 
			
		||||
		int num_consumed_args = parse_resize_amount(argc, argv, &first_amount);
 | 
			
		||||
		argc -= num_consumed_args;
 | 
			
		||||
		argv += num_consumed_args;
 | 
			
		||||
		if (first_amount.unit == RESIZE_UNIT_INVALID) {
 | 
			
		||||
			return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		first_amount.amount = 10;
 | 
			
		||||
		first_amount.unit = RESIZE_UNIT_DEFAULT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// "or"
 | 
			
		||||
	if (argc) {
 | 
			
		||||
		if (strcmp(*argv, "or") != 0) {
 | 
			
		||||
			return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
		}
 | 
			
		||||
		--argc; ++argv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Second amount
 | 
			
		||||
	struct resize_amount second_amount;
 | 
			
		||||
	if (argc) {
 | 
			
		||||
		int num_consumed_args = parse_resize_amount(argc, argv, &second_amount);
 | 
			
		||||
		argc -= num_consumed_args;
 | 
			
		||||
		argv += num_consumed_args;
 | 
			
		||||
		if (second_amount.unit == RESIZE_UNIT_INVALID) {
 | 
			
		||||
			return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		second_amount.unit = RESIZE_UNIT_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	first_amount.amount *= multiplier;
 | 
			
		||||
	second_amount.amount *= multiplier;
 | 
			
		||||
 | 
			
		||||
	struct sway_container *con = config->handler_context.current_container;
 | 
			
		||||
	if (container_is_floating(con)) {
 | 
			
		||||
		// Floating containers can only resize in px. Choose an amount which
 | 
			
		||||
		// uses px, with fallback to an amount that specified no unit.
 | 
			
		||||
		if (first_amount.unit == RESIZE_UNIT_PX) {
 | 
			
		||||
			return resize_adjust_floating(axis, &first_amount);
 | 
			
		||||
		} else if (second_amount.unit == RESIZE_UNIT_PX) {
 | 
			
		||||
			return resize_adjust_floating(axis, &second_amount);
 | 
			
		||||
		} else if (first_amount.unit == RESIZE_UNIT_DEFAULT) {
 | 
			
		||||
			return resize_adjust_floating(axis, &first_amount);
 | 
			
		||||
		} else if (second_amount.unit == RESIZE_UNIT_DEFAULT) {
 | 
			
		||||
			return resize_adjust_floating(axis, &second_amount);
 | 
			
		||||
		} else {
 | 
			
		||||
			return cmd_results_new(CMD_INVALID, "resize",
 | 
			
		||||
					"Floating containers cannot use ppt measurements");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// For tiling, prefer ppt -> default -> px
 | 
			
		||||
	if (first_amount.unit == RESIZE_UNIT_PPT) {
 | 
			
		||||
		return resize_adjust_tiled(axis, &first_amount);
 | 
			
		||||
	} else if (second_amount.unit == RESIZE_UNIT_PPT) {
 | 
			
		||||
		return resize_adjust_tiled(axis, &second_amount);
 | 
			
		||||
	} else if (first_amount.unit == RESIZE_UNIT_DEFAULT) {
 | 
			
		||||
		return resize_adjust_tiled(axis, &first_amount);
 | 
			
		||||
	} else if (second_amount.unit == RESIZE_UNIT_DEFAULT) {
 | 
			
		||||
		return resize_adjust_tiled(axis, &second_amount);
 | 
			
		||||
	} else {
 | 
			
		||||
		return resize_adjust_tiled(axis, &first_amount);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct cmd_results *cmd_resize(int argc, char **argv) {
 | 
			
		||||
| 
						 | 
				
			
			@ -226,61 +566,17 @@ struct cmd_results *cmd_resize(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (strcasecmp(argv[0], "set") == 0) {
 | 
			
		||||
		// TODO
 | 
			
		||||
		//return cmd_resize_set(argc - 1, &argv[1]);
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", "resize set unimplemented");
 | 
			
		||||
		return cmd_resize_set(argc - 1, &argv[1]);
 | 
			
		||||
	}
 | 
			
		||||
	if (strcasecmp(argv[0], "grow") == 0) {
 | 
			
		||||
		return cmd_resize_adjust(argc - 1, &argv[1], 1);
 | 
			
		||||
	}
 | 
			
		||||
	if (strcasecmp(argv[0], "shrink") == 0) {
 | 
			
		||||
		return cmd_resize_adjust(argc - 1, &argv[1], -1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: resize grow|shrink left|right|up|down
 | 
			
		||||
 | 
			
		||||
	const char *usage = "Expected 'resize <shrink|grow> "
 | 
			
		||||
		"<width|height> [<amount>] [px|ppt]'";
 | 
			
		||||
		"<width|height|up|down|left|right> [<amount>] [px|ppt]'";
 | 
			
		||||
 | 
			
		||||
	int multiplier = 0;
 | 
			
		||||
	if (strcasecmp(*argv, "grow") == 0) {
 | 
			
		||||
		multiplier = 1;
 | 
			
		||||
	} else if (strcasecmp(*argv, "shrink") == 0) {
 | 
			
		||||
		multiplier = -1;
 | 
			
		||||
	} else {
 | 
			
		||||
	return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
}
 | 
			
		||||
	--argc; ++argv;
 | 
			
		||||
 | 
			
		||||
	enum resize_axis axis = parse_resize_axis(*argv);
 | 
			
		||||
	if (axis == RESIZE_AXIS_INVALID) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
	}
 | 
			
		||||
	--argc; ++argv;
 | 
			
		||||
 | 
			
		||||
	int amount = 10; // Default amount
 | 
			
		||||
	enum resize_unit unit = RESIZE_UNIT_DEFAULT;
 | 
			
		||||
 | 
			
		||||
	if (argc) {
 | 
			
		||||
		char *err;
 | 
			
		||||
		amount = (int)strtol(*argv, &err, 10);
 | 
			
		||||
		if (*err) {
 | 
			
		||||
			// e.g. `resize grow width 10px`
 | 
			
		||||
			unit = parse_resize_unit(err);
 | 
			
		||||
			if (unit == RESIZE_UNIT_INVALID) {
 | 
			
		||||
				return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		--argc; ++argv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (argc) {
 | 
			
		||||
		unit = parse_resize_unit(*argv);
 | 
			
		||||
		if (unit == RESIZE_UNIT_INVALID) {
 | 
			
		||||
			return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
		}
 | 
			
		||||
		--argc; ++argv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (argc) {
 | 
			
		||||
		// Provied too many args, the bastard
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "resize", usage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resize(amount * multiplier, axis, unit);
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ struct cmd_results *cmd_set(int argc, char **argv) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (argv[0][0] != '$') {
 | 
			
		||||
		wlr_log(L_INFO, "Warning: variable '%s' doesn't start with $", argv[0]);
 | 
			
		||||
		wlr_log(WLR_INFO, "Warning: variable '%s' doesn't start with $", argv[0]);
 | 
			
		||||
 | 
			
		||||
		size_t size = snprintf(NULL, 0, "$%s", argv[0]);
 | 
			
		||||
		tmp = malloc(size + 1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
 | 
			
		|||
			"Expected 'smart_gaps <on|off>' ");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	arrange_and_commit(&root_container);
 | 
			
		||||
	arrange_windows(&root_container);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ static struct cmd_results *do_split(int layout) {
 | 
			
		|||
	}
 | 
			
		||||
	struct sway_container *parent = container_split(con, layout);
 | 
			
		||||
	container_create_notify(parent);
 | 
			
		||||
	arrange_and_commit(parent->parent);
 | 
			
		||||
	arrange_windows(parent->parent);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
#include <strings.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/desktop/transaction.h"
 | 
			
		||||
#include "sway/tree/arrange.h"
 | 
			
		||||
#include "sway/tree/layout.h"
 | 
			
		||||
#include "sway/tree/view.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -79,14 +78,10 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
 | 
			
		|||
 | 
			
		||||
	container_swap(current, other);
 | 
			
		||||
 | 
			
		||||
	struct sway_transaction *txn = transaction_create();
 | 
			
		||||
	arrange_windows(current->parent, txn);
 | 
			
		||||
 | 
			
		||||
	arrange_windows(current->parent);
 | 
			
		||||
	if (other->parent != current->parent) {
 | 
			
		||||
		arrange_windows(other->parent, txn);
 | 
			
		||||
		arrange_windows(other->parent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	transaction_commit(txn);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ struct cmd_results *cmd_swaybg_command(int argc, char **argv) {
 | 
			
		|||
		free(config->swaybg_command);
 | 
			
		||||
	}
 | 
			
		||||
	config->swaybg_command = join_args(argv, argc);
 | 
			
		||||
	wlr_log(L_DEBUG, "Using custom swaybg command: %s",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Using custom swaybg command: %s",
 | 
			
		||||
			config->swaybg_command);
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										36
									
								
								sway/commands/urgent.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								sway/commands/urgent.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
#include "log.h"
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/config.h"
 | 
			
		||||
#include "sway/tree/arrange.h"
 | 
			
		||||
#include "sway/tree/container.h"
 | 
			
		||||
#include "sway/tree/view.h"
 | 
			
		||||
#include "sway/tree/layout.h"
 | 
			
		||||
 | 
			
		||||
struct cmd_results *cmd_urgent(int argc, char **argv) {
 | 
			
		||||
	struct cmd_results *error = NULL;
 | 
			
		||||
	if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
	struct sway_container *container =
 | 
			
		||||
		config->handler_context.current_container;
 | 
			
		||||
	if (container->type != C_VIEW) {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "urgent",
 | 
			
		||||
				"Only views can be urgent");
 | 
			
		||||
	}
 | 
			
		||||
	struct sway_view *view = container->sway_view;
 | 
			
		||||
 | 
			
		||||
	if (strcmp(argv[0], "enable") == 0) {
 | 
			
		||||
		view_set_urgent(view, true);
 | 
			
		||||
	} else if (strcmp(argv[0], "disable") == 0) {
 | 
			
		||||
		view_set_urgent(view, false);
 | 
			
		||||
	} else if (strcmp(argv[0], "allow") == 0) {
 | 
			
		||||
		view->allow_request_urgent = true;
 | 
			
		||||
	} else if (strcmp(argv[0], "deny") == 0) {
 | 
			
		||||
		view->allow_request_urgent = false;
 | 
			
		||||
	} else {
 | 
			
		||||
		return cmd_results_new(CMD_INVALID, "urgent",
 | 
			
		||||
				"Expected 'urgent <enable|disable|allow|deny>'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
 | 
			
		|||
			free(old); // workspaces can only be assigned to a single output
 | 
			
		||||
			list_del(config->workspace_outputs, i);
 | 
			
		||||
		}
 | 
			
		||||
		wlr_log(L_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output);
 | 
			
		||||
		list_add(config->workspace_outputs, wso);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (config->reading || !config->active) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										125
									
								
								sway/config.c
									
										
									
									
									
								
							
							
						
						
									
										125
									
								
								sway/config.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -24,6 +24,7 @@
 | 
			
		|||
#include "sway/input/seat.h"
 | 
			
		||||
#include "sway/commands.h"
 | 
			
		||||
#include "sway/config.h"
 | 
			
		||||
#include "sway/criteria.h"
 | 
			
		||||
#include "sway/tree/arrange.h"
 | 
			
		||||
#include "sway/tree/layout.h"
 | 
			
		||||
#include "sway/tree/workspace.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +106,12 @@ void free_config(struct sway_config *config) {
 | 
			
		|||
		}
 | 
			
		||||
		list_free(config->seat_configs);
 | 
			
		||||
	}
 | 
			
		||||
	if (config->criteria) {
 | 
			
		||||
		for (int i = 0; i < config->criteria->length; ++i) {
 | 
			
		||||
			criteria_destroy(config->criteria->items[i]);
 | 
			
		||||
		}
 | 
			
		||||
		list_free(config->criteria);
 | 
			
		||||
	}
 | 
			
		||||
	list_free(config->no_focus);
 | 
			
		||||
	list_free(config->active_bar_modifiers);
 | 
			
		||||
	list_free(config->config_chain);
 | 
			
		||||
| 
						 | 
				
			
			@ -117,6 +123,7 @@ void free_config(struct sway_config *config) {
 | 
			
		|||
	free(config->floating_scroll_left_cmd);
 | 
			
		||||
	free(config->floating_scroll_right_cmd);
 | 
			
		||||
	free(config->font);
 | 
			
		||||
	free((char *)config->current_config_path);
 | 
			
		||||
	free((char *)config->current_config);
 | 
			
		||||
	free(config);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -205,6 +212,7 @@ static void config_defaults(struct sway_config *config) {
 | 
			
		|||
	if (!(config->active_bar_modifiers = create_list())) goto cleanup;
 | 
			
		||||
 | 
			
		||||
	if (!(config->config_chain = create_list())) goto cleanup;
 | 
			
		||||
	config->current_config_path = NULL;
 | 
			
		||||
	config->current_config = NULL;
 | 
			
		||||
 | 
			
		||||
	// borders
 | 
			
		||||
| 
						 | 
				
			
			@ -276,12 +284,12 @@ static char *get_config_path(void) {
 | 
			
		|||
		char *home = getenv("HOME");
 | 
			
		||||
		char *config_home = malloc(strlen(home) + strlen("/.config") + 1);
 | 
			
		||||
		if (!config_home) {
 | 
			
		||||
			wlr_log(L_ERROR, "Unable to allocate $HOME/.config");
 | 
			
		||||
			wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config");
 | 
			
		||||
		} else {
 | 
			
		||||
			strcpy(config_home, home);
 | 
			
		||||
			strcat(config_home, "/.config");
 | 
			
		||||
			setenv("XDG_CONFIG_HOME", config_home, 1);
 | 
			
		||||
			wlr_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
 | 
			
		||||
			free(config_home);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -304,16 +312,13 @@ static char *get_config_path(void) {
 | 
			
		|||
	return NULL; // Not reached
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *current_config_path;
 | 
			
		||||
 | 
			
		||||
static bool load_config(const char *path, struct sway_config *config) {
 | 
			
		||||
	if (path == NULL) {
 | 
			
		||||
		wlr_log(L_ERROR, "Unable to find a config file!");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Unable to find a config file!");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_INFO, "Loading config from %s", path);
 | 
			
		||||
	current_config_path = path;
 | 
			
		||||
	wlr_log(WLR_INFO, "Loading config from %s", path);
 | 
			
		||||
 | 
			
		||||
	struct stat sb;
 | 
			
		||||
	if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -322,7 +327,7 @@ static bool load_config(const char *path, struct sway_config *config) {
 | 
			
		|||
 | 
			
		||||
	FILE *f = fopen(path, "r");
 | 
			
		||||
	if (!f) {
 | 
			
		||||
		wlr_log(L_ERROR, "Unable to open %s for reading", path);
 | 
			
		||||
		wlr_log(WLR_ERROR, "Unable to open %s for reading", path);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -330,10 +335,9 @@ static bool load_config(const char *path, struct sway_config *config) {
 | 
			
		|||
	fclose(f);
 | 
			
		||||
 | 
			
		||||
	if (!config_load_success) {
 | 
			
		||||
		wlr_log(L_ERROR, "Error(s) loading config!");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Error(s) loading config!");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	current_config_path = NULL;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -353,12 +357,12 @@ bool load_main_config(const char *file, bool is_active) {
 | 
			
		|||
 | 
			
		||||
	config_defaults(config);
 | 
			
		||||
	if (is_active) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Performing configuration file reload");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Performing configuration file reload");
 | 
			
		||||
		config->reloading = true;
 | 
			
		||||
		config->active = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config->current_config = path;
 | 
			
		||||
	config->current_config_path = path;
 | 
			
		||||
	list_add(config->config_chain, path);
 | 
			
		||||
 | 
			
		||||
	config->reading = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -369,7 +373,7 @@ bool load_main_config(const char *file, bool is_active) {
 | 
			
		|||
	/*
 | 
			
		||||
	DIR *dir = opendir(SYSCONFDIR "/sway/security.d");
 | 
			
		||||
	if (!dir) {
 | 
			
		||||
		wlr_log(L_ERROR,
 | 
			
		||||
		wlr_log(WLR_ERROR,
 | 
			
		||||
			"%s does not exist, sway will have no security configuration"
 | 
			
		||||
			" and will probably be broken", SYSCONFDIR "/sway/security.d");
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -398,7 +402,7 @@ bool load_main_config(const char *file, bool is_active) {
 | 
			
		|||
			if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 ||
 | 
			
		||||
					(((s.st_mode & 0777) != 0644) &&
 | 
			
		||||
					(s.st_mode & 0777) != 0444)) {
 | 
			
		||||
				wlr_log(L_ERROR,
 | 
			
		||||
				wlr_log(WLR_ERROR,
 | 
			
		||||
					"Refusing to load %s - it must be owned by root "
 | 
			
		||||
					"and mode 644 or 444", _path);
 | 
			
		||||
				success = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -428,7 +432,7 @@ bool load_main_config(const char *file, bool is_active) {
 | 
			
		|||
static bool load_include_config(const char *path, const char *parent_dir,
 | 
			
		||||
		struct sway_config *config) {
 | 
			
		||||
	// save parent config
 | 
			
		||||
	const char *parent_config = config->current_config;
 | 
			
		||||
	const char *parent_config = config->current_config_path;
 | 
			
		||||
 | 
			
		||||
	char *full_path;
 | 
			
		||||
	int len = strlen(path);
 | 
			
		||||
| 
						 | 
				
			
			@ -436,7 +440,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
 | 
			
		|||
		len = len + strlen(parent_dir) + 2;
 | 
			
		||||
		full_path = malloc(len * sizeof(char));
 | 
			
		||||
		if (!full_path) {
 | 
			
		||||
			wlr_log(L_ERROR,
 | 
			
		||||
			wlr_log(WLR_ERROR,
 | 
			
		||||
				"Unable to allocate full path to included config");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -449,7 +453,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
 | 
			
		|||
	free(full_path);
 | 
			
		||||
 | 
			
		||||
	if (real_path == NULL) {
 | 
			
		||||
		wlr_log(L_DEBUG, "%s not found.", path);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "%s not found.", path);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -458,7 +462,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
 | 
			
		|||
	for (j = 0; j < config->config_chain->length; ++j) {
 | 
			
		||||
		char *old_path = config->config_chain->items[j];
 | 
			
		||||
		if (strcmp(real_path, old_path) == 0) {
 | 
			
		||||
			wlr_log(L_DEBUG,
 | 
			
		||||
			wlr_log(WLR_DEBUG,
 | 
			
		||||
				"%s already included once, won't be included again.",
 | 
			
		||||
				real_path);
 | 
			
		||||
			free(real_path);
 | 
			
		||||
| 
						 | 
				
			
			@ -466,25 +470,25 @@ static bool load_include_config(const char *path, const char *parent_dir,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config->current_config = real_path;
 | 
			
		||||
	config->current_config_path = real_path;
 | 
			
		||||
	list_add(config->config_chain, real_path);
 | 
			
		||||
	int index = config->config_chain->length - 1;
 | 
			
		||||
 | 
			
		||||
	if (!load_config(real_path, config)) {
 | 
			
		||||
		free(real_path);
 | 
			
		||||
		config->current_config = parent_config;
 | 
			
		||||
		config->current_config_path = parent_config;
 | 
			
		||||
		list_del(config->config_chain, index);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// restore current_config
 | 
			
		||||
	config->current_config = parent_config;
 | 
			
		||||
	// restore current_config_path
 | 
			
		||||
	config->current_config_path = parent_config;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool load_include_configs(const char *path, struct sway_config *config) {
 | 
			
		||||
	char *wd = getcwd(NULL, 0);
 | 
			
		||||
	char *parent_path = strdup(config->current_config);
 | 
			
		||||
	char *parent_path = strdup(config->current_config_path);
 | 
			
		||||
	const char *parent_dir = dirname(parent_path);
 | 
			
		||||
 | 
			
		||||
	if (chdir(parent_dir) < 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +516,7 @@ bool load_include_configs(const char *path, struct sway_config *config) {
 | 
			
		|||
	// restore wd
 | 
			
		||||
	if (chdir(wd) < 0) {
 | 
			
		||||
		free(wd);
 | 
			
		||||
		wlr_log(L_ERROR, "failed to restore working directory");
 | 
			
		||||
		wlr_log(WLR_ERROR, "failed to restore working directory");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -527,13 +531,13 @@ static int detect_brace_on_following_line(FILE *file, char *line,
 | 
			
		|||
		char *peeked = NULL;
 | 
			
		||||
		long position = 0;
 | 
			
		||||
		do {
 | 
			
		||||
			wlr_log(L_DEBUG, "Peeking line %d", line_number + lines + 1);
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Peeking line %d", line_number + lines + 1);
 | 
			
		||||
			free(peeked);
 | 
			
		||||
			peeked = peek_line(file, lines, &position);
 | 
			
		||||
			if (peeked) {
 | 
			
		||||
				peeked = strip_whitespace(peeked);
 | 
			
		||||
			}
 | 
			
		||||
			wlr_log(L_DEBUG, "Peeked line: `%s`", peeked);
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Peeked line: `%s`", peeked);
 | 
			
		||||
			lines++;
 | 
			
		||||
		} while (peeked && strlen(peeked) == 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -552,7 +556,7 @@ static char *expand_line(const char *block, const char *line, bool add_brace) {
 | 
			
		|||
		+ (add_brace ? 2 : 0) + 1;
 | 
			
		||||
	char *expanded = calloc(1, size);
 | 
			
		||||
	if (!expanded) {
 | 
			
		||||
		wlr_log(L_ERROR, "Cannot allocate expanded line buffer");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Cannot allocate expanded line buffer");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	snprintf(expanded, size, "%s%s%s%s", block ? block : "",
 | 
			
		||||
| 
						 | 
				
			
			@ -561,10 +565,33 @@ static char *expand_line(const char *block, const char *line, bool add_brace) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool read_config(FILE *file, struct sway_config *config) {
 | 
			
		||||
	bool reading_main_config = false;
 | 
			
		||||
	char *this_config = NULL;
 | 
			
		||||
	size_t config_size = 0;
 | 
			
		||||
	if (config->current_config == NULL) {
 | 
			
		||||
		reading_main_config = true;
 | 
			
		||||
 | 
			
		||||
		int ret_seek = fseek(file, 0, SEEK_END);
 | 
			
		||||
		long ret_tell = ftell(file);
 | 
			
		||||
		if (ret_seek == -1 || ret_tell == -1) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "Unable to get size of config file");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		config_size = ret_tell;
 | 
			
		||||
		rewind(file);
 | 
			
		||||
 | 
			
		||||
		config->current_config = this_config = calloc(1, config_size + 1);
 | 
			
		||||
		if (this_config == NULL) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "Unable to allocate buffer for config contents");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool success = true;
 | 
			
		||||
	int line_number = 0;
 | 
			
		||||
	char *line;
 | 
			
		||||
	list_t *stack = create_list();
 | 
			
		||||
	size_t read = 0;
 | 
			
		||||
	while (!feof(file)) {
 | 
			
		||||
		char *block = stack->length ? stack->items[0] : NULL;
 | 
			
		||||
		line = read_line(file);
 | 
			
		||||
| 
						 | 
				
			
			@ -572,7 +599,26 @@ bool read_config(FILE *file, struct sway_config *config) {
 | 
			
		|||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		line_number++;
 | 
			
		||||
		wlr_log(L_DEBUG, "Read line %d: %s", line_number, line);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Read line %d: %s", line_number, line);
 | 
			
		||||
 | 
			
		||||
		if (reading_main_config) {
 | 
			
		||||
			size_t length = strlen(line);
 | 
			
		||||
 | 
			
		||||
			if (read + length > config_size) {
 | 
			
		||||
				wlr_log(WLR_ERROR, "Config file changed during reading");
 | 
			
		||||
				list_foreach(stack, free);
 | 
			
		||||
				list_free(stack);
 | 
			
		||||
				free(line);
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			strcpy(this_config + read, line);
 | 
			
		||||
			if (line_number != 1) {
 | 
			
		||||
				this_config[read - 1] = '\n';
 | 
			
		||||
			}
 | 
			
		||||
			read += length + 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		line = strip_whitespace(line);
 | 
			
		||||
		if (line[0] == '#') {
 | 
			
		||||
			free(line);
 | 
			
		||||
| 
						 | 
				
			
			@ -586,15 +632,16 @@ bool read_config(FILE *file, struct sway_config *config) {
 | 
			
		|||
				line_number);
 | 
			
		||||
		if (brace_detected > 0) {
 | 
			
		||||
			line_number += brace_detected;
 | 
			
		||||
			wlr_log(L_DEBUG, "Detected open brace on line %d", line_number);
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Detected open brace on line %d", line_number);
 | 
			
		||||
		}
 | 
			
		||||
		char *expanded = expand_line(block, line, brace_detected > 0);
 | 
			
		||||
		if (!expanded) {
 | 
			
		||||
			list_foreach(stack, free);
 | 
			
		||||
			list_free(stack);
 | 
			
		||||
			free(line);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		wlr_log(L_DEBUG, "Expanded line: %s", expanded);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Expanded line: %s", expanded);
 | 
			
		||||
		struct cmd_results *res;
 | 
			
		||||
		if (block && strcmp(block, "<commands>") == 0) {
 | 
			
		||||
			// Special case
 | 
			
		||||
| 
						 | 
				
			
			@ -606,23 +653,23 @@ bool read_config(FILE *file, struct sway_config *config) {
 | 
			
		|||
		switch(res->status) {
 | 
			
		||||
		case CMD_FAILURE:
 | 
			
		||||
		case CMD_INVALID:
 | 
			
		||||
			wlr_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number,
 | 
			
		||||
				line, res->error, config->current_config);
 | 
			
		||||
			wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number,
 | 
			
		||||
				line, res->error, config->current_config_path);
 | 
			
		||||
			success = false;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case CMD_DEFER:
 | 
			
		||||
			wlr_log(L_DEBUG, "Deferring command `%s'", line);
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Deferring command `%s'", line);
 | 
			
		||||
			list_add(config->cmd_queue, strdup(line));
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case CMD_BLOCK_COMMANDS:
 | 
			
		||||
			wlr_log(L_DEBUG, "Entering commands block");
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Entering commands block");
 | 
			
		||||
			list_insert(stack, 0, "<commands>");
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case CMD_BLOCK:
 | 
			
		||||
			wlr_log(L_DEBUG, "Entering block '%s'", res->input);
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Entering block '%s'", res->input);
 | 
			
		||||
			list_insert(stack, 0, strdup(res->input));
 | 
			
		||||
			if (strcmp(res->input, "bar") == 0) {
 | 
			
		||||
				config->current_bar = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -631,7 +678,7 @@ bool read_config(FILE *file, struct sway_config *config) {
 | 
			
		|||
 | 
			
		||||
		case CMD_BLOCK_END:
 | 
			
		||||
			if (!block) {
 | 
			
		||||
				wlr_log(L_DEBUG, "Unmatched '}' on line %i", line_number);
 | 
			
		||||
				wlr_log(WLR_DEBUG, "Unmatched '}' on line %i", line_number);
 | 
			
		||||
				success = false;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -639,7 +686,7 @@ bool read_config(FILE *file, struct sway_config *config) {
 | 
			
		|||
				config->current_bar = NULL;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			wlr_log(L_DEBUG, "Exiting block '%s'", block);
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Exiting block '%s'", block);
 | 
			
		||||
			list_del(stack, 0);
 | 
			
		||||
			free(block);
 | 
			
		||||
			memset(&config->handler_context, 0,
 | 
			
		||||
| 
						 | 
				
			
			@ -682,7 +729,7 @@ char *do_var_replacement(char *str) {
 | 
			
		|||
				int vvlen = strlen(var->value);
 | 
			
		||||
				char *newstr = malloc(strlen(str) - vnlen + vvlen + 1);
 | 
			
		||||
				if (!newstr) {
 | 
			
		||||
					wlr_log(L_ERROR,
 | 
			
		||||
					wlr_log(WLR_ERROR,
 | 
			
		||||
						"Unable to allocate replacement "
 | 
			
		||||
						"during variable expansion");
 | 
			
		||||
					break;
 | 
			
		||||
| 
						 | 
				
			
			@ -744,6 +791,6 @@ void config_update_font_height(bool recalculate) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (config->font_height != prev_max_height) {
 | 
			
		||||
		arrange_and_commit(&root_container);
 | 
			
		||||
		arrange_windows(&root_container);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,10 +16,10 @@
 | 
			
		|||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
static void terminate_swaybar(pid_t pid) {
 | 
			
		||||
	wlr_log(L_DEBUG, "Terminating swaybar %d", pid);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid);
 | 
			
		||||
	int ret = kill(-pid, SIGTERM);
 | 
			
		||||
	if (ret != 0) {
 | 
			
		||||
		wlr_log_errno(L_ERROR, "Unable to terminate swaybar %d", pid);
 | 
			
		||||
		wlr_log_errno(WLR_ERROR, "Unable to terminate swaybar %d", pid);
 | 
			
		||||
	} else {
 | 
			
		||||
		int status;
 | 
			
		||||
		waitpid(pid, &status, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +167,7 @@ void invoke_swaybar(struct bar_config *bar) {
 | 
			
		|||
	// Pipe to communicate errors
 | 
			
		||||
	int filedes[2];
 | 
			
		||||
	if (pipe(filedes) == -1) {
 | 
			
		||||
		wlr_log(L_ERROR, "Pipe setup failed! Cannot fork into bar");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Pipe setup failed! Cannot fork into bar");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -197,17 +197,17 @@ void invoke_swaybar(struct bar_config *bar) {
 | 
			
		|||
		execvp(cmd[0], cmd);
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	wlr_log(L_DEBUG, "Spawned swaybar %d", bar->pid);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Spawned swaybar %d", bar->pid);
 | 
			
		||||
	close(filedes[0]);
 | 
			
		||||
	size_t len;
 | 
			
		||||
	if (read(filedes[1], &len, sizeof(size_t)) == sizeof(size_t)) {
 | 
			
		||||
		char *buf = malloc(len);
 | 
			
		||||
		if(!buf) {
 | 
			
		||||
			wlr_log(L_ERROR, "Cannot allocate error string");
 | 
			
		||||
			wlr_log(WLR_ERROR, "Cannot allocate error string");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (read(filedes[1], buf, len)) {
 | 
			
		||||
			wlr_log(L_ERROR, "%s", buf);
 | 
			
		||||
			wlr_log(WLR_ERROR, "%s", buf);
 | 
			
		||||
		}
 | 
			
		||||
		free(buf);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -244,7 +244,7 @@ void load_swaybars() {
 | 
			
		|||
			if (bar->pid != 0) {
 | 
			
		||||
				terminate_swaybar(bar->pid);
 | 
			
		||||
			}
 | 
			
		||||
			wlr_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
 | 
			
		||||
			invoke_swaybar(bar);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,17 +8,18 @@
 | 
			
		|||
struct input_config *new_input_config(const char* identifier) {
 | 
			
		||||
	struct input_config *input = calloc(1, sizeof(struct input_config));
 | 
			
		||||
	if (!input) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Unable to allocate input config");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Unable to allocate input config");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_log(L_DEBUG, "new_input_config(%s)", identifier);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "new_input_config(%s)", identifier);
 | 
			
		||||
	if (!(input->identifier = strdup(identifier))) {
 | 
			
		||||
		free(input);
 | 
			
		||||
		wlr_log(L_DEBUG, "Unable to allocate input config");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Unable to allocate input config");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input->tap = INT_MIN;
 | 
			
		||||
	input->tap_button_map = INT_MIN;
 | 
			
		||||
	input->drag_lock = INT_MIN;
 | 
			
		||||
	input->dwt = INT_MIN;
 | 
			
		||||
	input->send_events = INT_MIN;
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +28,7 @@ struct input_config *new_input_config(const char* identifier) {
 | 
			
		|||
	input->natural_scroll = INT_MIN;
 | 
			
		||||
	input->accel_profile = INT_MIN;
 | 
			
		||||
	input->pointer_accel = FLT_MIN;
 | 
			
		||||
	input->scroll_button = INT_MIN;
 | 
			
		||||
	input->scroll_method = INT_MIN;
 | 
			
		||||
	input->left_handed = INT_MIN;
 | 
			
		||||
	input->repeat_delay = INT_MIN;
 | 
			
		||||
| 
						 | 
				
			
			@ -70,12 +72,18 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
 | 
			
		|||
	if (src->scroll_method != INT_MIN) {
 | 
			
		||||
		dst->scroll_method = src->scroll_method;
 | 
			
		||||
	}
 | 
			
		||||
	if (src->scroll_button != INT_MIN) {
 | 
			
		||||
		dst->scroll_button = src->scroll_button;
 | 
			
		||||
	}
 | 
			
		||||
	if (src->send_events != INT_MIN) {
 | 
			
		||||
		dst->send_events = src->send_events;
 | 
			
		||||
	}
 | 
			
		||||
	if (src->tap != INT_MIN) {
 | 
			
		||||
		dst->tap = src->tap;
 | 
			
		||||
	}
 | 
			
		||||
	if (src->tap_button_map != INT_MIN) {
 | 
			
		||||
		dst->tap_button_map = src->tap_button_map;
 | 
			
		||||
	}
 | 
			
		||||
	if (src->xkb_layout) {
 | 
			
		||||
		free(dst->xkb_layout);
 | 
			
		||||
		dst->xkb_layout = strdup(src->xkb_layout);
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +120,7 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
 | 
			
		|||
struct input_config *copy_input_config(struct input_config *ic) {
 | 
			
		||||
	struct input_config *copy = calloc(1, sizeof(struct input_config));
 | 
			
		||||
	if (copy == NULL) {
 | 
			
		||||
		wlr_log(L_ERROR, "could not allocate input config");
 | 
			
		||||
		wlr_log(WLR_ERROR, "could not allocate input config");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	merge_input_config(copy, ic);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ static void set_mode(struct wlr_output *output, int width, int height,
 | 
			
		|||
		float refresh_rate) {
 | 
			
		||||
	int mhz = (int)(refresh_rate * 1000);
 | 
			
		||||
	if (wl_list_empty(&output->modes)) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Assigning custom mode to %s", output->name);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Assigning custom mode to %s", output->name);
 | 
			
		||||
		wlr_output_set_custom_mode(output, width, height, mhz);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -106,9 +106,9 @@ static void set_mode(struct wlr_output *output, int width, int height,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!best) {
 | 
			
		||||
		wlr_log(L_ERROR, "Configured mode for %s not available", output->name);
 | 
			
		||||
		wlr_log(WLR_ERROR, "Configured mode for %s not available", output->name);
 | 
			
		||||
	} else {
 | 
			
		||||
		wlr_log(L_DEBUG, "Assigning configured mode to %s", output->name);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Assigning configured mode to %s", output->name);
 | 
			
		||||
		wlr_output_set_mode(output, best);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +116,7 @@ static void set_mode(struct wlr_output *output, int width, int height,
 | 
			
		|||
void terminate_swaybg(pid_t pid) {
 | 
			
		||||
	int ret = kill(pid, SIGTERM);
 | 
			
		||||
	if (ret != 0) {
 | 
			
		||||
		wlr_log(L_ERROR, "Unable to terminate swaybg [pid: %d]", pid);
 | 
			
		||||
		wlr_log(WLR_ERROR, "Unable to terminate swaybg [pid: %d]", pid);
 | 
			
		||||
	} else {
 | 
			
		||||
		int status;
 | 
			
		||||
		waitpid(pid, &status, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -144,22 +144,22 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (oc && oc->width > 0 && oc->height > 0) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width,
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width,
 | 
			
		||||
			oc->height, oc->refresh_rate);
 | 
			
		||||
		set_mode(wlr_output, oc->width, oc->height, oc->refresh_rate);
 | 
			
		||||
	}
 | 
			
		||||
	if (oc && oc->scale > 0) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
 | 
			
		||||
		wlr_output_set_scale(wlr_output, oc->scale);
 | 
			
		||||
	}
 | 
			
		||||
	if (oc && oc->transform >= 0) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
 | 
			
		||||
		wlr_output_set_transform(wlr_output, oc->transform);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Find position for it
 | 
			
		||||
	if (oc && (oc->x != -1 || oc->y != -1)) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y);
 | 
			
		||||
		wlr_output_layout_add(output_layout, wlr_output, oc->x, oc->y);
 | 
			
		||||
	} else {
 | 
			
		||||
		wlr_output_layout_add_auto(output_layout, wlr_output);
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
 | 
			
		|||
			terminate_swaybg(output->sway_output->bg_pid);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wlr_log(L_DEBUG, "Setting background for output %d to %s",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Setting background for output %d to %s",
 | 
			
		||||
				output_i, oc->background);
 | 
			
		||||
 | 
			
		||||
		size_t len = snprintf(NULL, 0, "%s %d %s %s",
 | 
			
		||||
| 
						 | 
				
			
			@ -195,28 +195,30 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
 | 
			
		|||
				output_i, oc->background, oc->background_option);
 | 
			
		||||
		char *command = malloc(len + 1);
 | 
			
		||||
		if (!command) {
 | 
			
		||||
			wlr_log(L_DEBUG, "Unable to allocate swaybg command");
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Unable to allocate swaybg command");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		snprintf(command, len + 1, "%s %d %s %s",
 | 
			
		||||
				config->swaybg_command ? config->swaybg_command : "swaybg",
 | 
			
		||||
				output_i, oc->background, oc->background_option);
 | 
			
		||||
		wlr_log(L_DEBUG, "-> %s", command);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "-> %s", command);
 | 
			
		||||
 | 
			
		||||
		char *const cmd[] = { "sh", "-c", command, NULL };
 | 
			
		||||
		output->sway_output->bg_pid = fork();
 | 
			
		||||
		if (output->sway_output->bg_pid == 0) {
 | 
			
		||||
			execvp(cmd[0], cmd);
 | 
			
		||||
		} else {
 | 
			
		||||
			free(command);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (oc && oc->dpms_state != DPMS_IGNORE) {
 | 
			
		||||
		switch (oc->dpms_state) {
 | 
			
		||||
		case DPMS_ON:
 | 
			
		||||
			wlr_log(L_DEBUG, "Turning on screen");
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Turning on screen");
 | 
			
		||||
			wlr_output_enable(wlr_output, true);
 | 
			
		||||
			break;
 | 
			
		||||
		case DPMS_OFF:
 | 
			
		||||
			wlr_log(L_DEBUG, "Turning off screen");
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Turning off screen");
 | 
			
		||||
			wlr_output_enable(wlr_output, false);
 | 
			
		||||
			break;
 | 
			
		||||
		case DPMS_IGNORE:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,11 +7,11 @@
 | 
			
		|||
struct seat_config *new_seat_config(const char* name) {
 | 
			
		||||
	struct seat_config *seat = calloc(1, sizeof(struct seat_config));
 | 
			
		||||
	if (!seat) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Unable to allocate seat config");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Unable to allocate seat config");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "new_seat_config(%s)", name);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "new_seat_config(%s)", name);
 | 
			
		||||
	seat->name = strdup(name);
 | 
			
		||||
	if (!sway_assert(seat->name, "could not allocate name for seat")) {
 | 
			
		||||
		free(seat);
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ struct seat_attachment_config *seat_attachment_config_new() {
 | 
			
		|||
	struct seat_attachment_config *attachment =
 | 
			
		||||
		calloc(1, sizeof(struct seat_attachment_config));
 | 
			
		||||
	if (!attachment) {
 | 
			
		||||
		wlr_log(L_DEBUG, "cannot allocate attachment config");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "cannot allocate attachment config");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return attachment;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ void criteria_destroy(struct criteria *criteria) {
 | 
			
		|||
	pcre_free(criteria->con_mark);
 | 
			
		||||
	pcre_free(criteria->window_role);
 | 
			
		||||
	free(criteria->workspace);
 | 
			
		||||
 | 
			
		||||
	free(criteria->cmdlist);
 | 
			
		||||
	free(criteria->raw);
 | 
			
		||||
	free(criteria);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +46,31 @@ static int regex_cmp(const char *item, const pcre *regex) {
 | 
			
		|||
	return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cmp_urgent(const void *_a, const void *_b) {
 | 
			
		||||
	struct sway_view *a = *(void **)_a;
 | 
			
		||||
	struct sway_view *b = *(void **)_b;
 | 
			
		||||
 | 
			
		||||
	if (a->urgent.tv_sec < b->urgent.tv_sec) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	} else if (a->urgent.tv_sec > b->urgent.tv_sec) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (a->urgent.tv_nsec < b->urgent.tv_nsec) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	} else if (a->urgent.tv_nsec > b->urgent.tv_nsec) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void find_urgent_iterator(struct sway_container *swayc, void *data) {
 | 
			
		||||
	if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	list_t *urgent_views = data;
 | 
			
		||||
	list_add(urgent_views, swayc->sway_view);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool criteria_matches_view(struct criteria *criteria,
 | 
			
		||||
		struct sway_view *view) {
 | 
			
		||||
	if (criteria->title) {
 | 
			
		||||
| 
						 | 
				
			
			@ -133,9 +158,24 @@ static bool criteria_matches_view(struct criteria *criteria,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (criteria->urgent) {
 | 
			
		||||
		// TODO
 | 
			
		||||
		if (!view_is_urgent(view)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		list_t *urgent_views = create_list();
 | 
			
		||||
		container_for_each_descendant_dfs(&root_container,
 | 
			
		||||
				find_urgent_iterator, urgent_views);
 | 
			
		||||
		list_stable_sort(urgent_views, cmp_urgent);
 | 
			
		||||
		struct sway_view *target;
 | 
			
		||||
		if (criteria->urgent == 'o') { // oldest
 | 
			
		||||
			target = urgent_views->items[0];
 | 
			
		||||
		} else { // latest
 | 
			
		||||
			target = urgent_views->items[urgent_views->length - 1];
 | 
			
		||||
		}
 | 
			
		||||
		list_free(urgent_views);
 | 
			
		||||
		if (view != target) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (criteria->workspace) {
 | 
			
		||||
		if (!view->swayc) {
 | 
			
		||||
| 
						 | 
				
			
			@ -507,7 +547,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
 | 
			
		|||
			}
 | 
			
		||||
			unescape(value);
 | 
			
		||||
		}
 | 
			
		||||
		wlr_log(L_DEBUG, "Found pair: %s=%s", name, value);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Found pair: %s=%s", name, value);
 | 
			
		||||
		if (!parse_token(criteria, name, value)) {
 | 
			
		||||
			*error_arg = error;
 | 
			
		||||
			goto cleanup;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,3 +13,12 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void desktop_damage_whole_container(struct sway_container *con) {
 | 
			
		||||
	for (int i = 0; i < root_container.children->length; ++i) {
 | 
			
		||||
		struct sway_container *cont = root_container.children->items[i];
 | 
			
		||||
		if (cont->type == C_OUTPUT) {
 | 
			
		||||
			output_damage_whole_container(cont->sway_output, con);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@
 | 
			
		|||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct sway_idle_inhibitor_v1 *inhibitor =
 | 
			
		||||
		wl_container_of(listener, inhibitor, destroy);
 | 
			
		||||
	wlr_log(L_DEBUG, "Sway idle inhibitor destroyed");
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Sway idle inhibitor destroyed");
 | 
			
		||||
	wl_list_remove(&inhibitor->link);
 | 
			
		||||
	wl_list_remove(&inhibitor->destroy.link);
 | 
			
		||||
	idle_inhibit_v1_check_active(inhibitor->manager);
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
 | 
			
		|||
	struct wlr_idle_inhibitor_v1 *wlr_inhibitor = data;
 | 
			
		||||
	struct sway_idle_inhibit_manager_v1 *manager =
 | 
			
		||||
		wl_container_of(listener, manager, new_idle_inhibitor_v1);
 | 
			
		||||
	wlr_log(L_DEBUG, "New sway idle inhibitor");
 | 
			
		||||
	wlr_log(WLR_DEBUG, "New sway idle inhibitor");
 | 
			
		||||
 | 
			
		||||
	struct sway_idle_inhibitor_v1 *inhibitor =
 | 
			
		||||
		calloc(1, sizeof(struct sway_idle_inhibitor_v1));
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +67,7 @@ struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
 | 
			
		|||
 | 
			
		||||
	manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display);
 | 
			
		||||
	if (!manager->wlr_manager) {
 | 
			
		||||
		free(manager);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	manager->idle = idle;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,6 @@
 | 
			
		|||
#include "sway/layers.h"
 | 
			
		||||
#include "sway/output.h"
 | 
			
		||||
#include "sway/server.h"
 | 
			
		||||
#include "sway/tree/arrange.h"
 | 
			
		||||
#include "sway/tree/layout.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -174,9 +173,9 @@ void arrange_layers(struct sway_output *output) {
 | 
			
		|||
 | 
			
		||||
	if (memcmp(&usable_area, &output->usable_area,
 | 
			
		||||
				sizeof(struct wlr_box)) != 0) {
 | 
			
		||||
		wlr_log(L_DEBUG, "Usable area changed, rearranging output");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Usable area changed, rearranging output");
 | 
			
		||||
		memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
 | 
			
		||||
		arrange_and_commit(output->swayc);
 | 
			
		||||
		container_set_dirty(output->swayc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Arrange non-exlusive surfaces from top->bottom
 | 
			
		||||
| 
						 | 
				
			
			@ -269,7 +268,7 @@ static void unmap(struct sway_layer_surface *sway_layer) {
 | 
			
		|||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct sway_layer_surface *sway_layer =
 | 
			
		||||
		wl_container_of(listener, sway_layer, destroy);
 | 
			
		||||
	wlr_log(L_DEBUG, "Layer surface destroyed (%s)",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Layer surface destroyed (%s)",
 | 
			
		||||
		sway_layer->layer_surface->namespace);
 | 
			
		||||
	if (sway_layer->layer_surface->mapped) {
 | 
			
		||||
		unmap(sway_layer);
 | 
			
		||||
| 
						 | 
				
			
			@ -316,7 +315,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
	struct wlr_layer_surface *layer_surface = data;
 | 
			
		||||
	struct sway_server *server =
 | 
			
		||||
		wl_container_of(listener, server, layer_shell_surface);
 | 
			
		||||
	wlr_log(L_DEBUG, "new layer surface: namespace %s layer %d anchor %d "
 | 
			
		||||
	wlr_log(WLR_DEBUG, "new layer surface: namespace %s layer %d anchor %d "
 | 
			
		||||
			"size %dx%d margin %d,%d,%d,%d",
 | 
			
		||||
		layer_surface->namespace, layer_surface->layer, layer_surface->layer,
 | 
			
		||||
		layer_surface->client_pending.desired_width,
 | 
			
		||||
| 
						 | 
				
			
			@ -326,12 +325,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
		layer_surface->client_pending.margin.bottom,
 | 
			
		||||
		layer_surface->client_pending.margin.left);
 | 
			
		||||
 | 
			
		||||
	struct sway_layer_surface *sway_layer =
 | 
			
		||||
		calloc(1, sizeof(struct sway_layer_surface));
 | 
			
		||||
	if (!sway_layer) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!layer_surface->output) {
 | 
			
		||||
		// Assign last active output
 | 
			
		||||
		struct sway_container *output = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -353,6 +346,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
		layer_surface->output = output->sway_output->wlr_output;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct sway_layer_surface *sway_layer =
 | 
			
		||||
		calloc(1, sizeof(struct sway_layer_surface));
 | 
			
		||||
	if (!sway_layer) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sway_layer->surface_commit.notify = handle_surface_commit;
 | 
			
		||||
	wl_signal_add(&layer_surface->surface->events.commit,
 | 
			
		||||
		&sway_layer->surface_commit);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -204,11 +204,11 @@ bool output_has_opaque_lockscreen(struct sway_output *output,
 | 
			
		|||
		};
 | 
			
		||||
		pixman_region32_t surface_opaque_box;
 | 
			
		||||
		pixman_region32_init(&surface_opaque_box);
 | 
			
		||||
		pixman_region32_copy(&surface_opaque_box, &wlr_surface->current.opaque);
 | 
			
		||||
		pixman_region32_copy(&surface_opaque_box, &wlr_surface->opaque_region);
 | 
			
		||||
		pixman_region32_translate(&surface_opaque_box,
 | 
			
		||||
			sway_layer_surface->geo.x, sway_layer_surface->geo.y);
 | 
			
		||||
		bool contains = pixman_region32_contains_rectangle(
 | 
			
		||||
				&wlr_surface->current.opaque, &output_box);
 | 
			
		||||
		bool contains = pixman_region32_contains_rectangle(&surface_opaque_box,
 | 
			
		||||
			&output_box);
 | 
			
		||||
		pixman_region32_fini(&surface_opaque_box);
 | 
			
		||||
		if (contains) {
 | 
			
		||||
			return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -492,19 +492,21 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
			
		|||
	output->wlr_output->data = NULL;
 | 
			
		||||
	free(output);
 | 
			
		||||
 | 
			
		||||
	arrange_and_commit(&root_container);
 | 
			
		||||
	arrange_windows(&root_container);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_mode(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct sway_output *output = wl_container_of(listener, output, mode);
 | 
			
		||||
	arrange_layers(output);
 | 
			
		||||
	arrange_and_commit(output->swayc);
 | 
			
		||||
	arrange_windows(output->swayc);
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_transform(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct sway_output *output = wl_container_of(listener, output, transform);
 | 
			
		||||
	arrange_layers(output);
 | 
			
		||||
	arrange_and_commit(output->swayc);
 | 
			
		||||
	arrange_windows(output->swayc);
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_scale_iterator(struct sway_container *view, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -515,7 +517,8 @@ static void handle_scale(struct wl_listener *listener, void *data) {
 | 
			
		|||
	struct sway_output *output = wl_container_of(listener, output, scale);
 | 
			
		||||
	arrange_layers(output);
 | 
			
		||||
	container_descendants(output->swayc, C_VIEW, handle_scale_iterator, NULL);
 | 
			
		||||
	arrange_and_commit(output->swayc);
 | 
			
		||||
	arrange_windows(output->swayc);
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) {
 | 
			
		||||
| 
						 | 
				
			
			@ -525,7 +528,7 @@ struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) {
 | 
			
		|||
void handle_new_output(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct sway_server *server = wl_container_of(listener, server, new_output);
 | 
			
		||||
	struct wlr_output *wlr_output = data;
 | 
			
		||||
	wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
 | 
			
		||||
 | 
			
		||||
	struct sway_output *output = calloc(1, sizeof(struct sway_output));
 | 
			
		||||
	if (!output) {
 | 
			
		||||
| 
						 | 
				
			
			@ -584,5 +587,6 @@ void output_enable(struct sway_output *output) {
 | 
			
		|||
	output->damage_destroy.notify = damage_handle_destroy;
 | 
			
		||||
 | 
			
		||||
	arrange_layers(output);
 | 
			
		||||
	arrange_and_commit(&root_container);
 | 
			
		||||
	arrange_windows(&root_container);
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
#include <wlr/util/region.h>
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "sway/config.h"
 | 
			
		||||
#include "sway/debug.h"
 | 
			
		||||
#include "sway/input/input-manager.h"
 | 
			
		||||
#include "sway/input/seat.h"
 | 
			
		||||
#include "sway/layers.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -255,6 +256,10 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
 | 
			
		|||
		render_view_surfaces(view, output, damage, view->swayc->alpha);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (view->using_csd) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_box box;
 | 
			
		||||
	float output_scale = output->wlr_output->scale;
 | 
			
		||||
	float color[4];
 | 
			
		||||
| 
						 | 
				
			
			@ -542,9 +547,6 @@ static void render_container(struct sway_output *output,
 | 
			
		|||
static void render_container_simple(struct sway_output *output,
 | 
			
		||||
		pixman_region32_t *damage, struct sway_container *con,
 | 
			
		||||
		bool parent_focused) {
 | 
			
		||||
	struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
			
		||||
	struct sway_container *focus = seat_get_focus(seat);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < con->current.children->length; ++i) {
 | 
			
		||||
		struct sway_container *child = con->current.children->items[i];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -555,11 +557,15 @@ static void render_container_simple(struct sway_output *output,
 | 
			
		|||
			struct wlr_texture *marks_texture;
 | 
			
		||||
			struct sway_container_state *state = &child->current;
 | 
			
		||||
 | 
			
		||||
			if (focus == child || parent_focused) {
 | 
			
		||||
			if (view_is_urgent(view)) {
 | 
			
		||||
				colors = &config->border_colors.urgent;
 | 
			
		||||
				title_texture = child->title_urgent;
 | 
			
		||||
				marks_texture = view->marks_urgent;
 | 
			
		||||
			} else if (state->focused || parent_focused) {
 | 
			
		||||
				colors = &config->border_colors.focused;
 | 
			
		||||
				title_texture = child->title_focused;
 | 
			
		||||
				marks_texture = view->marks_focused;
 | 
			
		||||
			} else if (seat_get_focus_inactive(seat, con) == child) {
 | 
			
		||||
			} else if (con->current.focused_inactive_child == child) {
 | 
			
		||||
				colors = &config->border_colors.focused_inactive;
 | 
			
		||||
				title_texture = child->title_focused_inactive;
 | 
			
		||||
				marks_texture = view->marks_focused_inactive;
 | 
			
		||||
| 
						 | 
				
			
			@ -569,6 +575,7 @@ static void render_container_simple(struct sway_output *output,
 | 
			
		|||
				marks_texture = view->marks_unfocused;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!view->using_csd) {
 | 
			
		||||
				if (state->border == B_NORMAL) {
 | 
			
		||||
					render_titlebar(output, damage, child, state->swayc_x,
 | 
			
		||||
							state->swayc_y, state->swayc_width, colors,
 | 
			
		||||
| 
						 | 
				
			
			@ -576,10 +583,11 @@ static void render_container_simple(struct sway_output *output,
 | 
			
		|||
				} else {
 | 
			
		||||
					render_top_border(output, damage, child, colors);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			render_view(output, damage, child, colors);
 | 
			
		||||
		} else {
 | 
			
		||||
			render_container(output, damage, child,
 | 
			
		||||
					parent_focused || focus == child);
 | 
			
		||||
					parent_focused || child->current.focused);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -593,26 +601,34 @@ static void render_container_tabbed(struct sway_output *output,
 | 
			
		|||
	if (!con->current.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_current_child(seat, con);
 | 
			
		||||
	struct border_colors *current_colors = &config->border_colors.unfocused;
 | 
			
		||||
	struct sway_container_state *pstate = &con->current;
 | 
			
		||||
	struct sway_container *current = pstate->focused_inactive_child;
 | 
			
		||||
	struct border_colors *current_colors = &config->border_colors.unfocused;
 | 
			
		||||
 | 
			
		||||
	double width_gap_adjustment = 2 * pstate->current_gaps;
 | 
			
		||||
	int tab_width =
 | 
			
		||||
		(pstate->swayc_width - width_gap_adjustment) / pstate->children->length;
 | 
			
		||||
 | 
			
		||||
	// Render tabs
 | 
			
		||||
	for (int i = 0; i < con->current.children->length; ++i) {
 | 
			
		||||
		struct sway_container *child = con->current.children->items[i];
 | 
			
		||||
	for (int i = 0; i < pstate->children->length; ++i) {
 | 
			
		||||
		struct sway_container *child = pstate->children->items[i];
 | 
			
		||||
		struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL;
 | 
			
		||||
		struct sway_container_state *cstate = &child->current;
 | 
			
		||||
		struct border_colors *colors;
 | 
			
		||||
		struct wlr_texture *title_texture;
 | 
			
		||||
		struct wlr_texture *marks_texture;
 | 
			
		||||
		bool urgent = view ?
 | 
			
		||||
			view_is_urgent(view) : container_has_urgent_child(child);
 | 
			
		||||
 | 
			
		||||
		if (focus == child || parent_focused) {
 | 
			
		||||
		if (urgent) {
 | 
			
		||||
			colors = &config->border_colors.urgent;
 | 
			
		||||
			title_texture = child->title_urgent;
 | 
			
		||||
			marks_texture = view ? view->marks_urgent : NULL;
 | 
			
		||||
		} else if (cstate->focused || parent_focused) {
 | 
			
		||||
			colors = &config->border_colors.focused;
 | 
			
		||||
			title_texture = child->title_focused;
 | 
			
		||||
			marks_texture = view ? view->marks_focused : NULL;
 | 
			
		||||
		} else if (child == current) {
 | 
			
		||||
		} else if (child == pstate->focused_inactive_child) {
 | 
			
		||||
			colors = &config->border_colors.focused_inactive;
 | 
			
		||||
			title_texture = child->title_focused_inactive;
 | 
			
		||||
			marks_texture = view ? view->marks_focused_inactive : NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -622,11 +638,12 @@ static void render_container_tabbed(struct sway_output *output,
 | 
			
		|||
			marks_texture = view ? view->marks_unfocused : NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int tab_width = pstate->swayc_width / pstate->children->length;
 | 
			
		||||
		int x = pstate->swayc_x + tab_width * i;
 | 
			
		||||
		int x = cstate->swayc_x + tab_width * i;
 | 
			
		||||
 | 
			
		||||
		// Make last tab use the remaining width of the parent
 | 
			
		||||
		if (i == pstate->children->length - 1) {
 | 
			
		||||
			tab_width = pstate->swayc_width - tab_width * i;
 | 
			
		||||
			tab_width =
 | 
			
		||||
				pstate->swayc_width - width_gap_adjustment - tab_width * i;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width,
 | 
			
		||||
| 
						 | 
				
			
			@ -638,13 +655,11 @@ static void render_container_tabbed(struct sway_output *output,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Render surface and left/right/bottom borders
 | 
			
		||||
	if (current) {
 | 
			
		||||
	if (current->type == C_VIEW) {
 | 
			
		||||
		render_view(output, damage, current, current_colors);
 | 
			
		||||
	} else {
 | 
			
		||||
		render_container(output, damage, current,
 | 
			
		||||
					parent_focused || current == focus);
 | 
			
		||||
		}
 | 
			
		||||
				parent_focused || current->current.focused);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -657,26 +672,32 @@ static void render_container_stacked(struct sway_output *output,
 | 
			
		|||
	if (!con->current.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_current_child(seat, con);
 | 
			
		||||
	struct border_colors *current_colors = &config->border_colors.unfocused;
 | 
			
		||||
	struct sway_container_state *pstate = &con->current;
 | 
			
		||||
	struct sway_container *current = pstate->focused_inactive_child;
 | 
			
		||||
	struct border_colors *current_colors = &config->border_colors.unfocused;
 | 
			
		||||
 | 
			
		||||
	size_t titlebar_height = container_titlebar_height();
 | 
			
		||||
 | 
			
		||||
	// Render titles
 | 
			
		||||
	for (int i = 0; i < con->current.children->length; ++i) {
 | 
			
		||||
		struct sway_container *child = con->current.children->items[i];
 | 
			
		||||
	for (int i = 0; i < pstate->children->length; ++i) {
 | 
			
		||||
		struct sway_container *child = pstate->children->items[i];
 | 
			
		||||
		struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL;
 | 
			
		||||
		struct sway_container_state *cstate = &child->current;
 | 
			
		||||
		struct border_colors *colors;
 | 
			
		||||
		struct wlr_texture *title_texture;
 | 
			
		||||
		struct wlr_texture *marks_texture;
 | 
			
		||||
		bool urgent = view ?
 | 
			
		||||
			view_is_urgent(view) : container_has_urgent_child(child);
 | 
			
		||||
 | 
			
		||||
		if (focus == child || parent_focused) {
 | 
			
		||||
		if (urgent) {
 | 
			
		||||
			colors = &config->border_colors.urgent;
 | 
			
		||||
			title_texture = child->title_urgent;
 | 
			
		||||
			marks_texture = view ? view->marks_urgent : NULL;
 | 
			
		||||
		} else if (cstate->focused || parent_focused) {
 | 
			
		||||
			colors = &config->border_colors.focused;
 | 
			
		||||
			title_texture = child->title_focused;
 | 
			
		||||
			marks_texture = view ? view->marks_focused : NULL;
 | 
			
		||||
		} else if (child == current) {
 | 
			
		||||
		} else if (child == pstate->focused_inactive_child) {
 | 
			
		||||
			colors = &config->border_colors.focused_inactive;
 | 
			
		||||
			title_texture = child->title_focused_inactive;
 | 
			
		||||
			marks_texture = view ? view->marks_focused_inactive : NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -686,7 +707,7 @@ static void render_container_stacked(struct sway_output *output,
 | 
			
		|||
			marks_texture = view ? view->marks_unfocused : NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int y = pstate->swayc_y + container_titlebar_height() * i;
 | 
			
		||||
		int y = cstate->swayc_y + titlebar_height * i;
 | 
			
		||||
		render_titlebar(output, damage, child, cstate->swayc_x, y,
 | 
			
		||||
				cstate->swayc_width, colors, title_texture, marks_texture);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -696,13 +717,11 @@ static void render_container_stacked(struct sway_output *output,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Render surface and left/right/bottom borders
 | 
			
		||||
	if (current) {
 | 
			
		||||
	if (current->type == C_VIEW) {
 | 
			
		||||
		render_view(output, damage, current, current_colors);
 | 
			
		||||
	} else {
 | 
			
		||||
		render_container(output, damage, current,
 | 
			
		||||
					parent_focused || current == focus);
 | 
			
		||||
		}
 | 
			
		||||
				parent_focused || current->current.focused);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -730,13 +749,15 @@ static void render_floating_container(struct sway_output *soutput,
 | 
			
		|||
		pixman_region32_t *damage, struct sway_container *con) {
 | 
			
		||||
	if (con->type == C_VIEW) {
 | 
			
		||||
		struct sway_view *view = con->sway_view;
 | 
			
		||||
		struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
			
		||||
		struct sway_container *focus = seat_get_focus(seat);
 | 
			
		||||
		struct border_colors *colors;
 | 
			
		||||
		struct wlr_texture *title_texture;
 | 
			
		||||
		struct wlr_texture *marks_texture;
 | 
			
		||||
 | 
			
		||||
		if (focus == con) {
 | 
			
		||||
		if (view_is_urgent(view)) {
 | 
			
		||||
			colors = &config->border_colors.urgent;
 | 
			
		||||
			title_texture = con->title_urgent;
 | 
			
		||||
			marks_texture = view->marks_urgent;
 | 
			
		||||
		} else if (con->current.focused) {
 | 
			
		||||
			colors = &config->border_colors.focused;
 | 
			
		||||
			title_texture = con->title_focused;
 | 
			
		||||
			marks_texture = view->marks_focused;
 | 
			
		||||
| 
						 | 
				
			
			@ -746,6 +767,7 @@ static void render_floating_container(struct sway_output *soutput,
 | 
			
		|||
			marks_texture = view->marks_unfocused;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!view->using_csd) {
 | 
			
		||||
			if (con->current.border == B_NORMAL) {
 | 
			
		||||
				render_titlebar(soutput, damage, con, con->current.swayc_x,
 | 
			
		||||
						con->current.swayc_y, con->current.swayc_width, colors,
 | 
			
		||||
| 
						 | 
				
			
			@ -753,6 +775,7 @@ static void render_floating_container(struct sway_output *soutput,
 | 
			
		|||
			} else if (con->current.border != B_NONE) {
 | 
			
		||||
				render_top_border(soutput, damage, con, colors);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		render_view(soutput, damage, con, colors);
 | 
			
		||||
	} else {
 | 
			
		||||
		render_container(soutput, damage, con, false);
 | 
			
		||||
| 
						 | 
				
			
			@ -779,6 +802,8 @@ static void render_floating(struct sway_output *soutput,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *damage_debug = NULL;
 | 
			
		||||
 | 
			
		||||
void output_render(struct sway_output *output, struct timespec *when,
 | 
			
		||||
		pixman_region32_t *damage) {
 | 
			
		||||
	struct wlr_output *wlr_output = output->wlr_output;
 | 
			
		||||
| 
						 | 
				
			
			@ -798,7 +823,6 @@ void output_render(struct sway_output *output, struct timespec *when,
 | 
			
		|||
		goto renderer_end;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG");
 | 
			
		||||
	if (damage_debug != NULL) {
 | 
			
		||||
		if (strcmp(damage_debug, "highlight") == 0) {
 | 
			
		||||
			wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
 | 
			
		||||
| 
						 | 
				
			
			@ -837,7 +861,11 @@ void output_render(struct sway_output *output, struct timespec *when,
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: handle views smaller than the output
 | 
			
		||||
		if (fullscreen_view->swayc->instructions->length) {
 | 
			
		||||
			render_saved_view(fullscreen_view, output, damage, 1.0f);
 | 
			
		||||
		} else {
 | 
			
		||||
			render_view_surfaces(fullscreen_view, output, damage, 1.0f);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) {
 | 
			
		||||
			render_unmanaged(output, damage,
 | 
			
		||||
| 
						 | 
				
			
			@ -858,9 +886,7 @@ void output_render(struct sway_output *output, struct timespec *when,
 | 
			
		|||
		render_layer(output, damage,
 | 
			
		||||
			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
 | 
			
		||||
 | 
			
		||||
		struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
			
		||||
		struct sway_container *focus = seat_get_focus(seat);
 | 
			
		||||
		render_container(output, damage, workspace, focus == workspace);
 | 
			
		||||
		render_container(output, damage, workspace, workspace->current.focused);
 | 
			
		||||
		render_floating(output, damage);
 | 
			
		||||
 | 
			
		||||
		render_unmanaged(output, damage,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,14 +19,14 @@
 | 
			
		|||
 * How long we should wait for views to respond to the configure before giving
 | 
			
		||||
 * up and applying the transaction anyway.
 | 
			
		||||
 */
 | 
			
		||||
#define TIMEOUT_MS 200
 | 
			
		||||
int txn_timeout_ms = 200;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * If enabled, sway will always wait for the transaction timeout before
 | 
			
		||||
 * applying it, rather than applying it when the views are ready. This allows us
 | 
			
		||||
 * to observe the rendered state while a transaction is in progress.
 | 
			
		||||
 */
 | 
			
		||||
#define TRANSACTION_DEBUG false
 | 
			
		||||
bool txn_debug = false;
 | 
			
		||||
 | 
			
		||||
struct sway_transaction {
 | 
			
		||||
	struct wl_event_source *timer;
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +47,7 @@ struct sway_transaction_instruction {
 | 
			
		|||
	bool ready;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sway_transaction *transaction_create() {
 | 
			
		||||
static struct sway_transaction *transaction_create() {
 | 
			
		||||
	struct sway_transaction *transaction =
 | 
			
		||||
		calloc(1, sizeof(struct sway_transaction));
 | 
			
		||||
	transaction->instructions = create_list();
 | 
			
		||||
| 
						 | 
				
			
			@ -139,25 +139,18 @@ static void copy_pending_state(struct sway_container *container,
 | 
			
		|||
		state->children = create_list();
 | 
			
		||||
		list_cat(state->children, container->children);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
			
		||||
	state->focused = seat_get_focus(seat) == container;
 | 
			
		||||
 | 
			
		||||
	if (container->type != C_VIEW) {
 | 
			
		||||
		state->focused_inactive_child =
 | 
			
		||||
			seat_get_active_child(seat, container);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool transaction_has_container(struct sway_transaction *transaction,
 | 
			
		||||
static void transaction_add_container(struct sway_transaction *transaction,
 | 
			
		||||
		struct sway_container *container) {
 | 
			
		||||
	for (int i = 0; i < transaction->instructions->length; ++i) {
 | 
			
		||||
		struct sway_transaction_instruction *instruction =
 | 
			
		||||
			transaction->instructions->items[i];
 | 
			
		||||
		if (instruction->container == container) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void transaction_add_container(struct sway_transaction *transaction,
 | 
			
		||||
		struct sway_container *container) {
 | 
			
		||||
	if (transaction_has_container(transaction, container)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	struct sway_transaction_instruction *instruction =
 | 
			
		||||
		calloc(1, sizeof(struct sway_transaction_instruction));
 | 
			
		||||
	instruction->transaction = transaction;
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +168,7 @@ void transaction_add_container(struct sway_transaction *transaction,
 | 
			
		|||
 * Apply a transaction to the "current" state of the tree.
 | 
			
		||||
 */
 | 
			
		||||
static void transaction_apply(struct sway_transaction *transaction) {
 | 
			
		||||
	wlr_log(L_DEBUG, "Applying transaction %p", transaction);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Applying transaction %p", transaction);
 | 
			
		||||
	if (server.debug_txn_timings) {
 | 
			
		||||
		struct timespec now;
 | 
			
		||||
		clock_gettime(CLOCK_MONOTONIC, &now);
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +179,7 @@ static void transaction_apply(struct sway_transaction *transaction) {
 | 
			
		|||
		float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 +
 | 
			
		||||
			(now.tv_nsec - commit->tv_nsec) / 1000000.0;
 | 
			
		||||
		float ms_total = ms_arranging + ms_waiting;
 | 
			
		||||
		wlr_log(L_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, "
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, "
 | 
			
		||||
			"%.1fms total (%.1f frames if 60Hz)", transaction,
 | 
			
		||||
			ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -210,11 +203,13 @@ static void transaction_apply(struct sway_transaction *transaction) {
 | 
			
		|||
			.width = instruction->state.swayc_width,
 | 
			
		||||
			.height = instruction->state.swayc_height,
 | 
			
		||||
		};
 | 
			
		||||
		for (int j = 0; j < root_container.children->length; ++j) {
 | 
			
		||||
			struct sway_container *output = root_container.children->items[j];
 | 
			
		||||
		for (int j = 0; j < root_container.current.children->length; ++j) {
 | 
			
		||||
			struct sway_container *output = root_container.current.children->items[j];
 | 
			
		||||
			if (output->sway_output) {
 | 
			
		||||
				output_damage_box(output->sway_output, &old_box);
 | 
			
		||||
				output_damage_box(output->sway_output, &new_box);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// There are separate children lists for each instruction state, the
 | 
			
		||||
		// container's current state and the container's pending state
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +246,7 @@ static void transaction_progress_queue() {
 | 
			
		|||
 | 
			
		||||
static int handle_timeout(void *data) {
 | 
			
		||||
	struct sway_transaction *transaction = data;
 | 
			
		||||
	wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting)",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Transaction %p timed out (%li waiting)",
 | 
			
		||||
			transaction, transaction->num_waiting);
 | 
			
		||||
	transaction->num_waiting = 0;
 | 
			
		||||
	transaction_progress_queue();
 | 
			
		||||
| 
						 | 
				
			
			@ -285,8 +280,8 @@ static bool should_configure(struct sway_container *con,
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void transaction_commit(struct sway_transaction *transaction) {
 | 
			
		||||
	wlr_log(L_DEBUG, "Transaction %p committing with %i instructions",
 | 
			
		||||
static void transaction_commit(struct sway_transaction *transaction) {
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Transaction %p committing with %i instructions",
 | 
			
		||||
			transaction, transaction->instructions->length);
 | 
			
		||||
	transaction->num_waiting = 0;
 | 
			
		||||
	for (int i = 0; i < transaction->instructions->length; ++i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -319,7 +314,7 @@ void transaction_commit(struct sway_transaction *transaction) {
 | 
			
		|||
	} else {
 | 
			
		||||
		// There are no other transactions in progress, and this one has nothing
 | 
			
		||||
		// to wait for, so we can skip the queue.
 | 
			
		||||
		wlr_log(L_DEBUG, "Transaction %p has nothing to wait for", transaction);
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Transaction %p has nothing to wait for", transaction);
 | 
			
		||||
		transaction_apply(transaction);
 | 
			
		||||
		transaction_destroy(transaction);
 | 
			
		||||
		idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
 | 
			
		||||
| 
						 | 
				
			
			@ -330,7 +325,7 @@ void transaction_commit(struct sway_transaction *transaction) {
 | 
			
		|||
		// Set up a timer which the views must respond within
 | 
			
		||||
		transaction->timer = wl_event_loop_add_timer(server.wl_event_loop,
 | 
			
		||||
				handle_timeout, transaction);
 | 
			
		||||
		wl_event_source_timer_update(transaction->timer, TIMEOUT_MS);
 | 
			
		||||
		wl_event_source_timer_update(transaction->timer, txn_timeout_ms);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The debug tree shows the pending/live tree. Here is a good place to
 | 
			
		||||
| 
						 | 
				
			
			@ -350,7 +345,7 @@ static void set_instruction_ready(
 | 
			
		|||
		struct timespec *start = &transaction->commit_time;
 | 
			
		||||
		float ms = (now.tv_sec - start->tv_sec) * 1000 +
 | 
			
		||||
			(now.tv_nsec - start->tv_nsec) / 1000000.0;
 | 
			
		||||
		wlr_log(L_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)",
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)",
 | 
			
		||||
				transaction,
 | 
			
		||||
				transaction->num_configures - transaction->num_waiting + 1,
 | 
			
		||||
				transaction->num_configures, ms,
 | 
			
		||||
| 
						 | 
				
			
			@ -361,11 +356,11 @@ static void set_instruction_ready(
 | 
			
		|||
	// If all views are ready, apply the transaction.
 | 
			
		||||
	// If the transaction has timed out then its num_waiting will be 0 already.
 | 
			
		||||
	if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) {
 | 
			
		||||
#if !TRANSACTION_DEBUG
 | 
			
		||||
		wlr_log(L_DEBUG, "Transaction %p is ready", transaction);
 | 
			
		||||
		if (!txn_debug) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction);
 | 
			
		||||
			wl_event_source_timer_update(transaction->timer, 0);
 | 
			
		||||
			transaction_progress_queue();
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -418,3 +413,17 @@ struct wlr_texture *transaction_get_saved_texture(struct sway_view *view,
 | 
			
		|||
	*height = instruction->saved_buffer_height;
 | 
			
		||||
	return instruction->saved_buffer->texture;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void transaction_commit_dirty(void) {
 | 
			
		||||
	if (!server.dirty_containers->length) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	struct sway_transaction *transaction = transaction_create();
 | 
			
		||||
	for (int i = 0; i < server.dirty_containers->length; ++i) {
 | 
			
		||||
		struct sway_container *container = server.dirty_containers->items[i];
 | 
			
		||||
		transaction_add_container(transaction, container);
 | 
			
		||||
		container->dirty = false;
 | 
			
		||||
	}
 | 
			
		||||
	server.dirty_containers->length = 0;
 | 
			
		||||
	transaction_commit(transaction);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,24 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
 | 
			
		|||
	view_child_destroy(&popup->child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void popup_unconstrain(struct sway_xdg_popup *popup) {
 | 
			
		||||
	struct sway_view *view = popup->child.view;
 | 
			
		||||
	struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup;
 | 
			
		||||
 | 
			
		||||
	struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
			
		||||
 | 
			
		||||
	// the output box expressed in the coordinate system of the toplevel parent
 | 
			
		||||
	// of the popup
 | 
			
		||||
	struct wlr_box output_toplevel_sx_box = {
 | 
			
		||||
		.x = output->x - view->x,
 | 
			
		||||
		.y = output->y - view->y,
 | 
			
		||||
		.width = output->width,
 | 
			
		||||
		.height = output->height,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct sway_xdg_popup *popup_create(
 | 
			
		||||
		struct wlr_xdg_popup *wlr_popup, struct sway_view *view) {
 | 
			
		||||
	struct wlr_xdg_surface *xdg_surface = wlr_popup->base;
 | 
			
		||||
| 
						 | 
				
			
			@ -55,12 +73,15 @@ static struct sway_xdg_popup *popup_create(
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
 | 
			
		||||
	popup->wlr_xdg_surface = xdg_surface;
 | 
			
		||||
 | 
			
		||||
	wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
 | 
			
		||||
	popup->new_popup.notify = popup_handle_new_popup;
 | 
			
		||||
	wl_signal_add(&xdg_surface->events.destroy, &popup->destroy);
 | 
			
		||||
	popup->destroy.notify = popup_handle_destroy;
 | 
			
		||||
 | 
			
		||||
	popup_unconstrain(popup);
 | 
			
		||||
 | 
			
		||||
	return popup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +244,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
 | 
			
		|||
	view_set_fullscreen(view, e->fullscreen);
 | 
			
		||||
 | 
			
		||||
	struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
			
		||||
	arrange_and_commit(output);
 | 
			
		||||
	arrange_windows(output);
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -260,10 +282,11 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
			
		|||
	if (xdg_surface->toplevel->client_pending.fullscreen) {
 | 
			
		||||
		view_set_fullscreen(view, true);
 | 
			
		||||
		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
			
		||||
		arrange_and_commit(ws);
 | 
			
		||||
		arrange_windows(ws);
 | 
			
		||||
	} else {
 | 
			
		||||
		arrange_and_commit(view->swayc->parent);
 | 
			
		||||
		arrange_windows(view->swayc->parent);
 | 
			
		||||
	}
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
 | 
			
		||||
	xdg_shell_view->commit.notify = handle_commit;
 | 
			
		||||
	wl_signal_add(&xdg_surface->surface->events.commit,
 | 
			
		||||
| 
						 | 
				
			
			@ -304,11 +327,11 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
	struct wlr_xdg_surface *xdg_surface = data;
 | 
			
		||||
 | 
			
		||||
	if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
 | 
			
		||||
		wlr_log(L_DEBUG, "New xdg_shell popup");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "New xdg_shell popup");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'",
 | 
			
		||||
		xdg_surface->toplevel->title, xdg_surface->toplevel->app_id);
 | 
			
		||||
	wlr_xdg_surface_ping(xdg_surface);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,24 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
 | 
			
		|||
	view_child_destroy(&popup->child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) {
 | 
			
		||||
	struct sway_view *view = popup->child.view;
 | 
			
		||||
	struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup;
 | 
			
		||||
 | 
			
		||||
	struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
			
		||||
 | 
			
		||||
	// the output box expressed in the coordinate system of the toplevel parent
 | 
			
		||||
	// of the popup
 | 
			
		||||
	struct wlr_box output_toplevel_sx_box = {
 | 
			
		||||
		.x = output->x - view->x,
 | 
			
		||||
		.y = output->y - view->y,
 | 
			
		||||
		.width = output->width,
 | 
			
		||||
		.height = output->height,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct sway_xdg_popup_v6 *popup_create(
 | 
			
		||||
		struct wlr_xdg_popup_v6 *wlr_popup, struct sway_view *view) {
 | 
			
		||||
	struct wlr_xdg_surface_v6 *xdg_surface = wlr_popup->base;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,12 +72,15 @@ static struct sway_xdg_popup_v6 *popup_create(
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
 | 
			
		||||
	popup->wlr_xdg_surface_v6 = xdg_surface;
 | 
			
		||||
 | 
			
		||||
	wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
 | 
			
		||||
	popup->new_popup.notify = popup_handle_new_popup;
 | 
			
		||||
	wl_signal_add(&xdg_surface->events.destroy, &popup->destroy);
 | 
			
		||||
	popup->destroy.notify = popup_handle_destroy;
 | 
			
		||||
 | 
			
		||||
	popup_unconstrain(popup);
 | 
			
		||||
 | 
			
		||||
	return popup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +239,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
 | 
			
		|||
	view_set_fullscreen(view, e->fullscreen);
 | 
			
		||||
 | 
			
		||||
	struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
			
		||||
	arrange_and_commit(output);
 | 
			
		||||
	arrange_windows(output);
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -255,10 +277,11 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
			
		|||
	if (xdg_surface->toplevel->client_pending.fullscreen) {
 | 
			
		||||
		view_set_fullscreen(view, true);
 | 
			
		||||
		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
			
		||||
		arrange_and_commit(ws);
 | 
			
		||||
		arrange_windows(ws);
 | 
			
		||||
	} else {
 | 
			
		||||
		arrange_and_commit(view->swayc->parent);
 | 
			
		||||
		arrange_windows(view->swayc->parent);
 | 
			
		||||
	}
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
 | 
			
		||||
	xdg_shell_v6_view->commit.notify = handle_commit;
 | 
			
		||||
	wl_signal_add(&xdg_surface->surface->events.commit,
 | 
			
		||||
| 
						 | 
				
			
			@ -295,11 +318,11 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
	struct wlr_xdg_surface_v6 *xdg_surface = data;
 | 
			
		||||
 | 
			
		||||
	if (xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) {
 | 
			
		||||
		wlr_log(L_DEBUG, "New xdg_shell_v6 popup");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "New xdg_shell_v6 popup");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'",
 | 
			
		||||
		xdg_surface->toplevel->title, xdg_surface->toplevel->app_id);
 | 
			
		||||
	wlr_xdg_surface_v6_ping(xdg_surface);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,7 +119,7 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
 | 
			
		|||
	struct sway_xwayland_unmanaged *surface =
 | 
			
		||||
		calloc(1, sizeof(struct sway_xwayland_unmanaged));
 | 
			
		||||
	if (surface == NULL) {
 | 
			
		||||
		wlr_log(L_ERROR, "Allocation failed");
 | 
			
		||||
		wlr_log(WLR_ERROR, "Allocation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -246,6 +246,14 @@ static bool wants_floating(struct sway_view *view) {
 | 
			
		|||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool has_client_side_decorations(struct sway_view *view) {
 | 
			
		||||
	if (xwayland_view_from_view(view) == NULL) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
 | 
			
		||||
	return surface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _close(struct sway_view *view) {
 | 
			
		||||
	if (xwayland_view_from_view(view) == NULL) {
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -269,6 +277,7 @@ static const struct sway_view_impl view_impl = {
 | 
			
		|||
	.set_tiled = set_tiled,
 | 
			
		||||
	.set_fullscreen = set_fullscreen,
 | 
			
		||||
	.wants_floating = wants_floating,
 | 
			
		||||
	.has_client_side_decorations = has_client_side_decorations,
 | 
			
		||||
	.close = _close,
 | 
			
		||||
	.destroy = destroy,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -288,6 +297,10 @@ static void handle_commit(struct wl_listener *listener, void *data) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	view_damage_from(view);
 | 
			
		||||
 | 
			
		||||
	if (view->allow_request_urgent) {
 | 
			
		||||
		view_set_urgent(view, (bool)xsurface->hints_urgency);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_unmap(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -324,10 +337,11 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
			
		|||
	if (xsurface->fullscreen) {
 | 
			
		||||
		view_set_fullscreen(view, true);
 | 
			
		||||
		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
 | 
			
		||||
		arrange_and_commit(ws);
 | 
			
		||||
		arrange_windows(ws);
 | 
			
		||||
	} else {
 | 
			
		||||
		arrange_and_commit(view->swayc->parent);
 | 
			
		||||
		arrange_windows(view->swayc->parent);
 | 
			
		||||
	}
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -383,7 +397,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
 | 
			
		|||
	view_set_fullscreen(view, xsurface->fullscreen);
 | 
			
		||||
 | 
			
		||||
	struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
 | 
			
		||||
	arrange_and_commit(output);
 | 
			
		||||
	arrange_windows(output);
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_set_title(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -432,12 +447,12 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 | 
			
		|||
 | 
			
		||||
	if (wlr_xwayland_surface_is_unmanaged(xsurface) ||
 | 
			
		||||
			xsurface->override_redirect) {
 | 
			
		||||
		wlr_log(L_DEBUG, "New xwayland unmanaged surface");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "New xwayland unmanaged surface");
 | 
			
		||||
		create_unmanaged(xsurface);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'",
 | 
			
		||||
	wlr_log(WLR_DEBUG, "New xwayland surface title='%s' class='%s'",
 | 
			
		||||
		xsurface->title, xsurface->class);
 | 
			
		||||
 | 
			
		||||
	struct sway_xwayland_view *xwayland_view =
 | 
			
		||||
| 
						 | 
				
			
			@ -490,7 +505,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) {
 | 
			
		|||
	xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL);
 | 
			
		||||
	int err = xcb_connection_has_error(xcb_conn);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		wlr_log(L_ERROR, "XCB connect failed: %d", err);
 | 
			
		||||
		wlr_log(WLR_ERROR, "XCB connect failed: %d", err);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -509,7 +524,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) {
 | 
			
		|||
		free(reply);
 | 
			
		||||
 | 
			
		||||
		if (error != NULL) {
 | 
			
		||||
			wlr_log(L_ERROR, "could not resolve atom %s, X11 error code %d",
 | 
			
		||||
			wlr_log(WLR_ERROR, "could not resolve atom %s, X11 error code %d",
 | 
			
		||||
				atom_map[i], error->error_code);
 | 
			
		||||
			free(error);
 | 
			
		||||
			break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@
 | 
			
		|||
#include <wlr/types/wlr_idle.h>
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "sway/desktop/transaction.h"
 | 
			
		||||
#include "sway/input/cursor.h"
 | 
			
		||||
#include "sway/layers.h"
 | 
			
		||||
#include "sway/output.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -219,6 +220,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 | 
			
		|||
		struct sway_drag_icon *drag_icon = wlr_drag_icon->data;
 | 
			
		||||
		drag_icon_update_position(drag_icon);
 | 
			
		||||
	}
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_cursor_motion(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -278,6 +280,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
 | 
			
		|||
 | 
			
		||||
	wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
 | 
			
		||||
			time_msec, button, state);
 | 
			
		||||
	transaction_commit_dirty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_cursor_button(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -474,7 +477,7 @@ static void handle_request_set_cursor(struct wl_listener *listener,
 | 
			
		|||
	// TODO: check cursor mode
 | 
			
		||||
	if (focused_client == NULL ||
 | 
			
		||||
			event->seat_client->client != focused_client) {
 | 
			
		||||
		wlr_log(L_DEBUG, "denying request to set cursor from unfocused client");
 | 
			
		||||
		wlr_log(WLR_DEBUG, "denying request to set cursor from unfocused client");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue