mirror of
https://github.com/swaywm/sway.git
synced 2025-11-19 06:59:52 -05:00
Merge branch 'master' into pid-workspaces
This commit is contained in:
commit
f4b882475e
156 changed files with 5391 additions and 2147 deletions
|
|
@ -98,12 +98,18 @@ 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 },
|
||||
{ "floating_modifier", cmd_floating_modifier },
|
||||
{ "focus", cmd_focus },
|
||||
{ "focus_follows_mouse", cmd_focus_follows_mouse },
|
||||
{ "focus_wrapping", cmd_focus_wrapping },
|
||||
{ "font", cmd_font },
|
||||
{ "for_window", cmd_for_window },
|
||||
{ "force_display_urgency_hint", cmd_force_display_urgency_hint },
|
||||
{ "force_focus_wrapping", cmd_force_focus_wrapping },
|
||||
{ "fullscreen", cmd_fullscreen },
|
||||
{ "gaps", cmd_gaps },
|
||||
|
|
@ -112,6 +118,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 },
|
||||
|
|
@ -133,7 +140,6 @@ static struct cmd_handler command_handlers[] = {
|
|||
{ "border", cmd_border },
|
||||
{ "exit", cmd_exit },
|
||||
{ "floating", cmd_floating },
|
||||
{ "focus", cmd_focus },
|
||||
{ "fullscreen", cmd_fullscreen },
|
||||
{ "kill", cmd_kill },
|
||||
{ "layout", cmd_layout },
|
||||
|
|
@ -143,6 +149,7 @@ static struct cmd_handler command_handlers[] = {
|
|||
{ "reload", cmd_reload },
|
||||
{ "rename", cmd_rename },
|
||||
{ "resize", cmd_resize },
|
||||
{ "scratchpad", cmd_scratchpad },
|
||||
{ "split", cmd_split },
|
||||
{ "splith", cmd_splith },
|
||||
{ "splitt", cmd_splitt },
|
||||
|
|
@ -151,6 +158,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 +171,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 +256,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);
|
||||
|
|
@ -319,7 +327,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
|||
} while(head);
|
||||
cleanup:
|
||||
free(exec);
|
||||
free(views);
|
||||
list_free(views);
|
||||
if (!results) {
|
||||
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
|
@ -344,7 +352,7 @@ struct cmd_results *config_command(char *exec) {
|
|||
|
||||
// Start block
|
||||
if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) {
|
||||
char *block = join_args(argv, argc - 1);
|
||||
char *block = join_args(argv, argc - 1);
|
||||
results = cmd_results_new(CMD_BLOCK, block, NULL);
|
||||
free(block);
|
||||
goto cleanup;
|
||||
|
|
@ -355,7 +363,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 +396,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,
|
||||
|
|
@ -428,8 +436,7 @@ struct cmd_results *config_commands_command(char *exec) {
|
|||
|
||||
struct cmd_handler *handler = find_handler(cmd, NULL, 0);
|
||||
if (!handler && strcmp(cmd, "*") != 0) {
|
||||
char *input = cmd ? cmd : "(empty)";
|
||||
results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
|
||||
results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -471,14 +478,16 @@ struct cmd_results *config_commands_command(char *exec) {
|
|||
}
|
||||
if (!policy) {
|
||||
policy = alloc_command_policy(cmd);
|
||||
sway_assert(policy, "Unable to allocate security policy");
|
||||
if (policy) {
|
||||
list_add(config->command_policies, policy);
|
||||
if (!sway_assert(policy, "Unable to allocate security policy")) {
|
||||
results = cmd_results_new(CMD_INVALID, cmd,
|
||||
"Unable to allocate memory");
|
||||
goto cleanup;
|
||||
}
|
||||
list_add(config->command_policies, policy);
|
||||
}
|
||||
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);
|
||||
|
|
@ -492,7 +501,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;
|
||||
|
|
@ -526,7 +535,7 @@ void free_cmd_results(struct cmd_results *results) {
|
|||
free(results);
|
||||
}
|
||||
|
||||
const char *cmd_results_to_json(struct cmd_results *results) {
|
||||
char *cmd_results_to_json(struct cmd_results *results) {
|
||||
json_object *result_array = json_object_new_array();
|
||||
json_object *root = json_object_new_object();
|
||||
json_object_object_add(root, "success",
|
||||
|
|
@ -541,9 +550,9 @@ const char *cmd_results_to_json(struct cmd_results *results) {
|
|||
}
|
||||
json_object_array_add(result_array, root);
|
||||
const char *json = json_object_to_json_string(result_array);
|
||||
free(result_array);
|
||||
free(root);
|
||||
return json;
|
||||
char *res = strdup(json);
|
||||
json_object_put(result_array);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) {
|
|||
|
||||
if (strncmp(*argv, "→", strlen("→")) == 0) {
|
||||
if (argc < 3) {
|
||||
free(criteria);
|
||||
return cmd_results_new(CMD_INVALID, "assign", "Missing workspace");
|
||||
}
|
||||
++argv;
|
||||
|
|
@ -44,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",
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ 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 = strdup(font);
|
||||
wlr_log(L_DEBUG, "Settings font '%s' for bar: %s",
|
||||
config->current_bar->font = font;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -22,14 +22,15 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) {
|
|||
mod |= tmp_mod;
|
||||
continue;
|
||||
} else {
|
||||
error = cmd_results_new(CMD_INVALID, "modifier",
|
||||
"Unknown modifier '%s'", split->items[i]);
|
||||
free_flat_list(split);
|
||||
return cmd_results_new(CMD_INVALID, "modifier",
|
||||
"Unknown modifier '%s'", split->items[i]);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
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,50 +35,49 @@ 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;
|
||||
pid_t *child = malloc(sizeof(pid_t)); // malloc'd so that Linux can avoid copying the process space
|
||||
if (!child) {
|
||||
return cmd_results_new(CMD_FAILURE, "exec_always", "Unable to allocate child pid");
|
||||
}
|
||||
pid_t pid, child;
|
||||
// Fork process
|
||||
if ((pid = fork()) == 0) {
|
||||
// Fork child process again
|
||||
setsid();
|
||||
if ((*child = fork()) == 0) {
|
||||
execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL);
|
||||
// Not reached
|
||||
}
|
||||
close(fd[0]);
|
||||
if ((child = fork()) == 0) {
|
||||
close(fd[1]);
|
||||
execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL);
|
||||
_exit(0);
|
||||
}
|
||||
ssize_t s = 0;
|
||||
while ((size_t)s < sizeof(pid_t)) {
|
||||
s += write(fd[1], ((uint8_t *)child) + s, sizeof(pid_t) - s);
|
||||
s += write(fd[1], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
|
||||
}
|
||||
close(fd[1]);
|
||||
_exit(0); // Close child process
|
||||
} else if (pid < 0) {
|
||||
free(child);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
return cmd_results_new(CMD_FAILURE, "exec_always", "fork() failed");
|
||||
}
|
||||
close(fd[1]); // close write
|
||||
ssize_t s = 0;
|
||||
while ((size_t)s < sizeof(pid_t)) {
|
||||
s += read(fd[0], ((uint8_t *)child) + s, sizeof(pid_t) - s);
|
||||
s += read(fd[0], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
|
||||
}
|
||||
close(fd[0]);
|
||||
// cleanup child process
|
||||
waitpid(pid, NULL, 0);
|
||||
if (*child > 0) {
|
||||
wlr_log(L_DEBUG, "Child process created with pid %d", *child);
|
||||
workspace_record_pid(*child);
|
||||
if (child > 0) {
|
||||
wlr_log(WLR_DEBUG, "Child process created with pid %d", child);
|
||||
workspace_record_pid(child);
|
||||
} else {
|
||||
free(child);
|
||||
return cmd_results_new(CMD_FAILURE, "exec_always",
|
||||
"Second fork() failed");
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
20
sway/commands/floating_modifier.c
Normal file
20
sway/commands/floating_modifier.c
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "util.h"
|
||||
|
||||
struct cmd_results *cmd_floating_modifier(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
uint32_t mod = get_modifier_mask_by_name(argv[0]);
|
||||
if (!mod) {
|
||||
return cmd_results_new(CMD_INVALID, "floating_modifier",
|
||||
"Invalid modifier");
|
||||
}
|
||||
|
||||
config->floating_mod = mod;
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
#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/output.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "stringop.h"
|
||||
|
||||
static bool parse_movement_direction(const char *name,
|
||||
enum movement_direction *out) {
|
||||
|
|
@ -27,7 +31,55 @@ 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);
|
||||
}
|
||||
|
||||
static struct cmd_results *focus_output(struct sway_container *con,
|
||||
struct sway_seat *seat, int argc, char **argv) {
|
||||
if (!argc) {
|
||||
return cmd_results_new(CMD_INVALID, "focus",
|
||||
"Expected 'focus output <direction|name>'");
|
||||
}
|
||||
char *identifier = join_args(argv, argc);
|
||||
struct sway_container *output = output_by_name(identifier);
|
||||
|
||||
if (!output) {
|
||||
enum movement_direction direction;
|
||||
if (!parse_movement_direction(identifier, &direction) ||
|
||||
direction == MOVE_PARENT || direction == MOVE_CHILD) {
|
||||
free(identifier);
|
||||
return cmd_results_new(CMD_INVALID, "focus",
|
||||
"There is no output with that name");
|
||||
}
|
||||
struct sway_container *focus = seat_get_focus(seat);
|
||||
focus = container_parent(focus, C_OUTPUT);
|
||||
output = container_get_in_direction(focus, seat, direction);
|
||||
}
|
||||
|
||||
free(identifier);
|
||||
if (output) {
|
||||
seat_set_focus(seat, seat_get_focus_inactive(seat, output));
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_focus(int argc, char **argv) {
|
||||
if (config->reading || !config->active) {
|
||||
return cmd_results_new(CMD_DEFER, NULL, NULL);
|
||||
}
|
||||
struct sway_container *con = config->handler_context.current_container;
|
||||
struct sway_seat *seat = config->handler_context.seat;
|
||||
if (con->type < C_WORKSPACE) {
|
||||
|
|
@ -40,11 +92,24 @@ 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));
|
||||
}
|
||||
|
||||
if (strcmp(argv[0], "output") == 0) {
|
||||
argc--; argv++;
|
||||
return focus_output(con, seat, argc, argv);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
23
sway/commands/force_display_urgency_hint.c
Normal file
23
sway/commands/force_display_urgency_hint.c
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
|
||||
struct cmd_results *cmd_force_display_urgency_hint(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "force_display_urgency_hint",
|
||||
EXPECTED_AT_LEAST, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
char *err;
|
||||
int timeout = (int)strtol(argv[0], &err, 10);
|
||||
if (*err) {
|
||||
if (strcmp(err, "ms") != 0) {
|
||||
return cmd_results_new(CMD_INVALID, "force_display_urgency_hint",
|
||||
"Expected 'force_display_urgency_hint <timeout> ms'");
|
||||
}
|
||||
}
|
||||
|
||||
config->urgent_timeout = timeout > 0 ? timeout : 0;
|
||||
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ struct cmd_results *input_cmd_accel_profile(int argc, char **argv) {
|
|||
} else if (strcasecmp(argv[0], "flat") == 0) {
|
||||
new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "accel_profile",
|
||||
"Expected 'accel_profile <adaptive|flat>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ struct cmd_results *input_cmd_click_method(int argc, char **argv) {
|
|||
} else if (strcasecmp(argv[0], "clickfinger") == 0) {
|
||||
new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "click_method",
|
||||
"Expected 'click_method <none|button_areas|clickfinger'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
|
|||
} else if (strcasecmp(argv[0], "disabled") == 0) {
|
||||
new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "drag_lock",
|
||||
"Expected 'drag_lock <enabled|disabled>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) {
|
|||
} else if (strcasecmp(argv[0], "disabled") == 0) {
|
||||
new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "dwt",
|
||||
"Expected 'dwt <enabled|disabled>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -29,6 +29,7 @@ struct cmd_results *input_cmd_events(int argc, char **argv) {
|
|||
new_config->send_events =
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "events",
|
||||
"Expected 'events <enabled|disabled|disabled_on_external_mouse>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
|
|||
} else if (strcasecmp(argv[0], "disabled") == 0) {
|
||||
new_config->left_handed = 0;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "left_handed",
|
||||
"Expected 'left_handed <enabled|disabled>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,20 +54,28 @@ struct cmd_results *input_cmd_map_from_region(int argc, char **argv) {
|
|||
bool mm1, mm2;
|
||||
if (!parse_coords(argv[0], &new_config->mapped_from_region->x1,
|
||||
&new_config->mapped_from_region->y1, &mm1)) {
|
||||
free(new_config->mapped_from_region);
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_FAILURE, "map_from_region",
|
||||
"Invalid top-left coordinates");
|
||||
}
|
||||
if (!parse_coords(argv[1], &new_config->mapped_from_region->x2,
|
||||
&new_config->mapped_from_region->y2, &mm2)) {
|
||||
free(new_config->mapped_from_region);
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_FAILURE, "map_from_region",
|
||||
"Invalid bottom-right coordinates");
|
||||
}
|
||||
if (new_config->mapped_from_region->x1 > new_config->mapped_from_region->x2 ||
|
||||
new_config->mapped_from_region->y1 > new_config->mapped_from_region->y2) {
|
||||
free(new_config->mapped_from_region);
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_FAILURE, "map_from_region",
|
||||
"Invalid rectangle");
|
||||
}
|
||||
if (mm1 != mm2) {
|
||||
free(new_config->mapped_from_region);
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_FAILURE, "map_from_region",
|
||||
"Both coordinates must be in the same unit");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
|
|||
new_config->middle_emulation =
|
||||
LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "middle_emulation",
|
||||
"Expected 'middle_emulation <enabled|disabled>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
|
|||
} else if (strcasecmp(argv[0], "disabled") == 0) {
|
||||
new_config->natural_scroll = 0;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "natural_scroll",
|
||||
"Expected 'natural_scroll <enabled|disabled>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) {
|
|||
|
||||
float pointer_accel = atof(argv[0]);
|
||||
if (pointer_accel < -1 || pointer_accel > 1) {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "pointer_accel",
|
||||
"Input out of range [-1, 1]");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ struct cmd_results *input_cmd_repeat_delay(int argc, char **argv) {
|
|||
|
||||
int repeat_delay = atoi(argv[0]);
|
||||
if (repeat_delay < 0) {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "repeat_delay",
|
||||
"Repeat delay cannot be negative");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ struct cmd_results *input_cmd_repeat_rate(int argc, char **argv) {
|
|||
|
||||
int repeat_rate = atoi(argv[0]);
|
||||
if (repeat_rate < 0) {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "repeat_rate",
|
||||
"Repeat rate cannot be negative");
|
||||
}
|
||||
|
|
|
|||
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);
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ struct cmd_results *input_cmd_scroll_method(int argc, char **argv) {
|
|||
} else if (strcasecmp(argv[0], "on_button_down") == 0) {
|
||||
new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "scroll_method",
|
||||
"Expected 'scroll_method <none|two_finger|edge|on_button_down>'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,12 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) {
|
|||
} else if (strcasecmp(argv[0], "disabled") == 0) {
|
||||
new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
|
||||
} else {
|
||||
free_input_config(new_config);
|
||||
return cmd_results_new(CMD_INVALID, "tap",
|
||||
"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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,17 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
|
|||
"mode", "Can only be used in config file.");
|
||||
}
|
||||
|
||||
const char *mode_name = argv[0];
|
||||
bool pango = strcmp(*argv, "--pango_markup") == 0;
|
||||
if (pango) {
|
||||
argc--; argv++;
|
||||
if (argc == 0) {
|
||||
return cmd_results_new(CMD_FAILURE, "mode",
|
||||
"Mode name is missing");
|
||||
}
|
||||
}
|
||||
|
||||
char *mode_name = *argv;
|
||||
strip_quotes(mode_name);
|
||||
struct sway_mode *mode = NULL;
|
||||
// Find mode
|
||||
for (int i = 0; i < config->modes->length; ++i) {
|
||||
|
|
@ -46,6 +56,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
|
|||
mode->name = strdup(mode_name);
|
||||
mode->keysym_bindings = create_list();
|
||||
mode->keycode_bindings = create_list();
|
||||
mode->pango = pango;
|
||||
list_add(config->modes, mode);
|
||||
}
|
||||
if (!mode) {
|
||||
|
|
@ -54,13 +65,15 @@ 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'",mode->name);
|
||||
wlr_log(WLR_DEBUG, "Switching to mode `%s' (pango=%d)",
|
||||
mode->name, mode->pango);
|
||||
}
|
||||
// Set current mode
|
||||
config->current_mode = mode;
|
||||
if (argc == 1) {
|
||||
// trigger IPC mode event
|
||||
ipc_event_mode(config->current_mode->name);
|
||||
ipc_event_mode(config->current_mode->name,
|
||||
config->current_mode->pango);
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
#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/scratchpad.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/layout.h"
|
||||
|
|
@ -103,10 +105,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 +142,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 +173,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,54 +232,112 @@ 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);
|
||||
}
|
||||
|
||||
static struct cmd_results *move_to_scratchpad(struct sway_container *con) {
|
||||
if (con->type != C_CONTAINER && con->type != C_VIEW) {
|
||||
return cmd_results_new(CMD_INVALID, "move",
|
||||
"Only views and containers can be moved to the scratchpad");
|
||||
}
|
||||
if (con->scratchpad) {
|
||||
return cmd_results_new(CMD_INVALID, "move",
|
||||
"Container is already in the scratchpad");
|
||||
}
|
||||
scratchpad_add_container(con);
|
||||
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);
|
||||
} else if (strcasecmp(argv[0], "workspace") == 0) {
|
||||
return cmd_move_workspace(current, argc, argv);
|
||||
} else if (strcasecmp(argv[0], "scratchpad") == 0
|
||||
|| (strcasecmp(argv[0], "to") == 0
|
||||
|| (strcasecmp(argv[0], "to") == 0 && argc == 2
|
||||
&& strcasecmp(argv[1], "scratchpad") == 0)) {
|
||||
// TODO: scratchpad
|
||||
return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
|
||||
return move_to_scratchpad(current);
|
||||
} 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++;
|
||||
|
|
@ -60,53 +60,13 @@ struct cmd_results *cmd_output(int argc, char **argv) {
|
|||
config->handler_context.leftovers.argc = 0;
|
||||
config->handler_context.leftovers.argv = NULL;
|
||||
|
||||
int i = list_seq_find(config->output_configs, output_name_cmp, output->name);
|
||||
if (i >= 0) {
|
||||
// Merge existing config
|
||||
struct output_config *current = config->output_configs->items[i];
|
||||
merge_output_config(current, output);
|
||||
free_output_config(output);
|
||||
output = current;
|
||||
} else {
|
||||
list_add(config->output_configs, output);
|
||||
}
|
||||
output = store_output_config(output);
|
||||
|
||||
wlr_log(L_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,
|
||||
output->transform, output->background, output->background_option, output->dpms_state);
|
||||
|
||||
// Try to find the output container and apply configuration now. If
|
||||
// this is during startup then there will be no container and config
|
||||
// will be applied during normal "new output" event from wlroots.
|
||||
char identifier[128];
|
||||
bool all = strcmp(output->name, "*") == 0;
|
||||
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);
|
||||
if (all || strcmp(sway_output->wlr_output->name, output->name) == 0
|
||||
|| strcmp(identifier, output->name) == 0) {
|
||||
if (!sway_output->swayc) {
|
||||
if (!output->enabled) {
|
||||
if (!all) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
output_enable(sway_output);
|
||||
}
|
||||
|
||||
apply_output_config(output, sway_output->swayc);
|
||||
|
||||
if (!all) {
|
||||
// Stop looking if the output config isn't applicable to all
|
||||
// outputs
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If reloading, the output configs will be applied after reading the
|
||||
// entire config and before the deferred commands so that an auto generated
|
||||
// workspace name is not given to re-enabled outputs.
|
||||
if (!config->reloading) {
|
||||
apply_output_config_to_outputs(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
|
|
|
|||
|
|
@ -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,10 @@ 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);
|
||||
if(!conf) {
|
||||
wlr_log(L_ERROR, "Failed to duplicate string");
|
||||
char *conf = strdup(config->current_config_path);
|
||||
if (!conf) {
|
||||
wlr_log(WLR_ERROR, "Failed to duplicate string");
|
||||
free(src);
|
||||
return cmd_results_new(CMD_FAILURE, "output",
|
||||
"Unable to allocate resources");
|
||||
}
|
||||
|
|
@ -93,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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,11 +36,11 @@ struct cmd_results *output_cmd_mode(int argc, char **argv) {
|
|||
}
|
||||
} else {
|
||||
// Format is 1234 4321
|
||||
argc--; argv++;
|
||||
if (!argc) {
|
||||
return cmd_results_new(CMD_INVALID, "output",
|
||||
"Missing mode argument (height).");
|
||||
}
|
||||
argc--; argv++;
|
||||
output->height = strtol(*argv, &end, 10);
|
||||
if (*end) {
|
||||
return cmd_results_new(CMD_INVALID, "output",
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ struct cmd_results *output_cmd_position(int argc, char **argv) {
|
|||
}
|
||||
} else {
|
||||
// Format is 1234 4321 (legacy)
|
||||
argc--; argv++;
|
||||
if (!argc) {
|
||||
return cmd_results_new(CMD_INVALID, "output",
|
||||
"Missing position argument (y).");
|
||||
}
|
||||
argc--; argv++;
|
||||
config->handler_context.output_config->y = strtol(*argv, &end, 10);
|
||||
if (*end) {
|
||||
return cmd_results_new(CMD_INVALID, "output",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
/**
|
||||
* 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:
|
||||
case RESIZE_AXIS_LEFT:
|
||||
case RESIZE_AXIS_RIGHT:
|
||||
grow_width = amount->amount;
|
||||
break;
|
||||
case RESIZE_AXIS_VERTICAL:
|
||||
case RESIZE_AXIS_UP:
|
||||
case RESIZE_AXIS_DOWN:
|
||||
grow_height = amount->amount;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
if (unit == RESIZE_UNIT_PPT) {
|
||||
float pct = amount / 100.0f;
|
||||
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 = (float)current->width * pct;
|
||||
amount->amount = (float)current->width * pct;
|
||||
break;
|
||||
case RESIZE_AXIS_UP:
|
||||
case RESIZE_AXIS_DOWN:
|
||||
case RESIZE_AXIS_VERTICAL:
|
||||
amount = (float)current->height * pct;
|
||||
amount->amount = (float)current->height * pct;
|
||||
break;
|
||||
default:
|
||||
sway_assert(0, "invalid resize axis");
|
||||
return;
|
||||
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);
|
||||
return cmd_results_new(CMD_INVALID, "resize", usage);
|
||||
}
|
||||
|
|
|
|||
36
sway/commands/scratchpad.c
Normal file
36
sway/commands/scratchpad.c
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "log.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/scratchpad.h"
|
||||
#include "sway/tree/container.h"
|
||||
|
||||
struct cmd_results *cmd_scratchpad(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1))) {
|
||||
return error;
|
||||
}
|
||||
if (strcmp(argv[0], "show") != 0) {
|
||||
return cmd_results_new(CMD_INVALID, "scratchpad",
|
||||
"Expected 'scratchpad show'");
|
||||
}
|
||||
if (!root_container.sway_root->scratchpad->length) {
|
||||
return cmd_results_new(CMD_INVALID, "scratchpad",
|
||||
"Scratchpad is empty");
|
||||
}
|
||||
|
||||
if (config->handler_context.using_criteria) {
|
||||
// If using criteria, this command is executed for every container which
|
||||
// matches the criteria. If this container isn't in the scratchpad,
|
||||
// we'll just silently return a success.
|
||||
struct sway_container *con = config->handler_context.current_container;
|
||||
wlr_log(WLR_INFO, "cmd_scratchpad(%s)", con->name);
|
||||
if (!con->scratchpad) {
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
scratchpad_toggle_container(con);
|
||||
} else {
|
||||
scratchpad_toggle_auto();
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
|||
157
sway/config.c
157
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"
|
||||
|
|
@ -86,7 +87,12 @@ void free_config(struct sway_config *config) {
|
|||
}
|
||||
list_free(config->cmd_queue);
|
||||
list_free(config->workspace_outputs);
|
||||
list_free(config->output_configs);
|
||||
if (config->output_configs) {
|
||||
for (int i = 0; i < config->output_configs->length; i++) {
|
||||
free_output_config(config->output_configs->items[i]);
|
||||
}
|
||||
list_free(config->output_configs);
|
||||
}
|
||||
if (config->input_configs) {
|
||||
for (int i = 0; i < config->input_configs->length; i++) {
|
||||
free_input_config(config->input_configs->items[i]);
|
||||
|
|
@ -99,7 +105,12 @@ void free_config(struct sway_config *config) {
|
|||
}
|
||||
list_free(config->seat_configs);
|
||||
}
|
||||
list_free(config->criteria);
|
||||
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);
|
||||
|
|
@ -111,6 +122,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);
|
||||
}
|
||||
|
|
@ -172,6 +184,7 @@ static void config_defaults(struct sway_config *config) {
|
|||
config->default_orientation = L_NONE;
|
||||
if (!(config->font = strdup("monospace 10"))) goto cleanup;
|
||||
config->font_height = 17; // height of monospace 10
|
||||
config->urgent_timeout = 500;
|
||||
|
||||
// floating view
|
||||
config->floating_maximum_width = 0;
|
||||
|
|
@ -198,6 +211,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
|
||||
|
|
@ -269,12 +283,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);
|
||||
}
|
||||
}
|
||||
|
|
@ -297,25 +311,22 @@ 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) {
|
||||
wlr_log(L_INFO, "Loading config from %s", path);
|
||||
current_config_path = path;
|
||||
if (path == NULL) {
|
||||
wlr_log(WLR_ERROR, "Unable to find a config file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_log(WLR_INFO, "Loading config from %s", path);
|
||||
|
||||
struct stat sb;
|
||||
if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (path == NULL) {
|
||||
wlr_log(L_ERROR, "Unable to find a config file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -323,10 +334,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;
|
||||
}
|
||||
|
||||
|
|
@ -346,12 +356,13 @@ 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;
|
||||
create_default_output_configs();
|
||||
}
|
||||
|
||||
config->current_config = path;
|
||||
config->current_config_path = path;
|
||||
list_add(config->config_chain, path);
|
||||
|
||||
config->reading = true;
|
||||
|
|
@ -362,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 {
|
||||
|
|
@ -391,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;
|
||||
|
|
@ -407,6 +418,9 @@ bool load_main_config(const char *file, bool is_active) {
|
|||
success = success && load_config(path, config);
|
||||
|
||||
if (is_active) {
|
||||
for (int i = 0; i < config->output_configs->length; i++) {
|
||||
apply_output_config_to_outputs(config->output_configs->items[i]);
|
||||
}
|
||||
config->reloading = false;
|
||||
}
|
||||
|
||||
|
|
@ -421,26 +435,28 @@ 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 = strdup(path);
|
||||
char *full_path;
|
||||
int len = strlen(path);
|
||||
if (len >= 1 && path[0] != '/') {
|
||||
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;
|
||||
}
|
||||
snprintf(full_path, len, "%s/%s", parent_dir, path);
|
||||
} else {
|
||||
full_path = strdup(path);
|
||||
}
|
||||
|
||||
char *real_path = realpath(full_path, NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +465,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);
|
||||
|
|
@ -457,25 +473,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) {
|
||||
|
|
@ -503,7 +519,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;
|
||||
}
|
||||
|
||||
|
|
@ -518,13 +534,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);
|
||||
|
||||
|
|
@ -543,7 +559,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 : "",
|
||||
|
|
@ -552,10 +568,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);
|
||||
|
|
@ -563,7 +602,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);
|
||||
|
|
@ -577,13 +635,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
|
||||
|
|
@ -591,27 +652,26 @@ bool read_config(FILE *file, struct sway_config *config) {
|
|||
} else {
|
||||
res = config_command(expanded);
|
||||
}
|
||||
free(expanded);
|
||||
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);
|
||||
list_add(config->cmd_queue, strdup(line));
|
||||
wlr_log(WLR_DEBUG, "Deferring command `%s'", line);
|
||||
list_add(config->cmd_queue, strdup(expanded));
|
||||
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;
|
||||
|
|
@ -620,7 +680,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;
|
||||
}
|
||||
|
|
@ -628,13 +688,14 @@ 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,
|
||||
sizeof(config->handler_context));
|
||||
default:;
|
||||
}
|
||||
free(expanded);
|
||||
free(line);
|
||||
free_cmd_results(res);
|
||||
}
|
||||
|
|
@ -671,7 +732,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;
|
||||
|
|
@ -733,6 +794,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);
|
||||
|
|
@ -30,6 +30,7 @@ void free_bar_config(struct bar_config *bar) {
|
|||
if (!bar) {
|
||||
return;
|
||||
}
|
||||
free(bar->id);
|
||||
free(bar->mode);
|
||||
free(bar->position);
|
||||
free(bar->hidden_state);
|
||||
|
|
@ -70,16 +71,12 @@ void free_bar_config(struct bar_config *bar) {
|
|||
|
||||
struct bar_config *default_bar_config(void) {
|
||||
struct bar_config *bar = NULL;
|
||||
bar = malloc(sizeof(struct bar_config));
|
||||
bar = calloc(1, sizeof(struct bar_config));
|
||||
if (!bar) {
|
||||
return NULL;
|
||||
}
|
||||
if (!(bar->mode = strdup("dock"))) goto cleanup;
|
||||
if (!(bar->hidden_state = strdup("hide"))) goto cleanup;
|
||||
bar->outputs = NULL;
|
||||
bar->position = strdup("bottom");
|
||||
if (!(bar->bindings = create_list())) goto cleanup;
|
||||
if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup;
|
||||
bar->pango_markup = false;
|
||||
bar->swaybar_command = NULL;
|
||||
bar->font = NULL;
|
||||
|
|
@ -91,6 +88,19 @@ struct bar_config *default_bar_config(void) {
|
|||
bar->binding_mode_indicator = true;
|
||||
bar->verbose = false;
|
||||
bar->pid = 0;
|
||||
if (!(bar->mode = strdup("dock"))) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (!(bar->hidden_state = strdup("hide"))) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (!(bar->bindings = create_list())) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (!(bar->status_command =
|
||||
strdup("while date +'%Y-%m-%d %l:%M:%S %p'; do sleep 1; done"))) {
|
||||
goto cleanup;
|
||||
}
|
||||
// set default colors
|
||||
if (!(bar->colors.background = strndup("#000000ff", 9))) {
|
||||
goto cleanup;
|
||||
|
|
@ -157,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;
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +184,7 @@ void invoke_swaybar(struct bar_config *bar) {
|
|||
if (!command) {
|
||||
const char msg[] = "Unable to allocate swaybar command string";
|
||||
size_t msg_len = sizeof(msg);
|
||||
if (write(filedes[1], &msg_len, sizeof(int))) {};
|
||||
if (write(filedes[1], &msg_len, sizeof(size_t))) {};
|
||||
if (write(filedes[1], msg, msg_len)) {};
|
||||
close(filedes[1]);
|
||||
exit(1);
|
||||
|
|
@ -187,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]);
|
||||
ssize_t len;
|
||||
if (read(filedes[1], &len, sizeof(int)) == sizeof(int)) {
|
||||
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);
|
||||
}
|
||||
|
|
@ -234,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);
|
||||
|
|
|
|||
|
|
@ -45,10 +45,6 @@ struct output_config *new_output_config(const char *name) {
|
|||
}
|
||||
|
||||
void merge_output_config(struct output_config *dst, struct output_config *src) {
|
||||
if (src->name) {
|
||||
free(dst->name);
|
||||
dst->name = strdup(src->name);
|
||||
}
|
||||
if (src->enabled != -1) {
|
||||
dst->enabled = src->enabled;
|
||||
}
|
||||
|
|
@ -86,11 +82,61 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
|
|||
}
|
||||
}
|
||||
|
||||
static void merge_wildcard_on_all(struct output_config *wildcard) {
|
||||
for (int i = 0; i < config->output_configs->length; i++) {
|
||||
struct output_config *oc = config->output_configs->items[i];
|
||||
if (strcmp(wildcard->name, oc->name) != 0) {
|
||||
wlr_log(WLR_DEBUG, "Merging output * config on %s", oc->name);
|
||||
merge_output_config(oc, wildcard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct output_config *store_output_config(struct output_config *oc) {
|
||||
bool wildcard = strcmp(oc->name, "*") == 0;
|
||||
if (wildcard) {
|
||||
merge_wildcard_on_all(oc);
|
||||
}
|
||||
|
||||
int i = list_seq_find(config->output_configs, output_name_cmp, oc->name);
|
||||
if (i >= 0) {
|
||||
wlr_log(WLR_DEBUG, "Merging on top of existing output config");
|
||||
struct output_config *current = config->output_configs->items[i];
|
||||
merge_output_config(current, oc);
|
||||
free_output_config(oc);
|
||||
oc = current;
|
||||
} else if (!wildcard) {
|
||||
wlr_log(WLR_DEBUG, "Adding non-wildcard output config");
|
||||
i = list_seq_find(config->output_configs, output_name_cmp, "*");
|
||||
if (i >= 0) {
|
||||
wlr_log(WLR_DEBUG, "Merging on top of output * config");
|
||||
struct output_config *current = new_output_config(oc->name);
|
||||
merge_output_config(current, config->output_configs->items[i]);
|
||||
merge_output_config(current, oc);
|
||||
free_output_config(oc);
|
||||
oc = current;
|
||||
}
|
||||
list_add(config->output_configs, oc);
|
||||
} else {
|
||||
// New wildcard config. Just add it
|
||||
wlr_log(WLR_DEBUG, "Adding output * config");
|
||||
list_add(config->output_configs, oc);
|
||||
}
|
||||
|
||||
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)",
|
||||
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
|
||||
oc->x, oc->y, oc->scale, oc->transform, oc->background,
|
||||
oc->background_option, oc->dpms_state);
|
||||
|
||||
return oc;
|
||||
}
|
||||
|
||||
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 +152,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 +162,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,37 +190,27 @@ 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);
|
||||
}
|
||||
|
||||
if (!oc || !oc->background) {
|
||||
// Look for a * config for background
|
||||
int i = list_seq_find(config->output_configs, output_name_cmp, "*");
|
||||
if (i >= 0) {
|
||||
oc = config->output_configs->items[i];
|
||||
} else {
|
||||
oc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int output_i;
|
||||
for (output_i = 0; output_i < root_container.children->length; ++output_i) {
|
||||
if (root_container.children->items[output_i] == output) {
|
||||
|
|
@ -187,7 +223,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 +231,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:
|
||||
|
|
@ -225,6 +263,60 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
|
|||
}
|
||||
}
|
||||
|
||||
static struct output_config *get_output_config(char *name, char *identifier) {
|
||||
int i = list_seq_find(config->output_configs, output_name_cmp, name);
|
||||
if (i >= 0) {
|
||||
return config->output_configs->items[i];
|
||||
}
|
||||
|
||||
i = list_seq_find(config->output_configs, output_name_cmp, identifier);
|
||||
if (i >= 0) {
|
||||
return config->output_configs->items[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void apply_output_config_to_outputs(struct output_config *oc) {
|
||||
// Try to find the output container and apply configuration now. If
|
||||
// this is during startup then there will be no container and config
|
||||
// will be applied during normal "new output" event from wlroots.
|
||||
bool wildcard = strcmp(oc->name, "*") == 0;
|
||||
char id[128];
|
||||
struct sway_output *sway_output;
|
||||
wl_list_for_each(sway_output, &root_container.sway_root->outputs, link) {
|
||||
char *name = sway_output->wlr_output->name;
|
||||
output_get_identifier(id, sizeof(id), sway_output);
|
||||
if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) {
|
||||
if (!sway_output->swayc) {
|
||||
if (!oc->enabled) {
|
||||
if (!wildcard) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
output_enable(sway_output);
|
||||
}
|
||||
|
||||
struct output_config *current = oc;
|
||||
if (wildcard) {
|
||||
struct output_config *tmp = get_output_config(name, id);
|
||||
if (tmp) {
|
||||
current = tmp;
|
||||
}
|
||||
}
|
||||
apply_output_config(current, sway_output->swayc);
|
||||
|
||||
if (!wildcard) {
|
||||
// Stop looking if the output config isn't applicable to all
|
||||
// outputs
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void free_output_config(struct output_config *oc) {
|
||||
if (!oc) {
|
||||
return;
|
||||
|
|
@ -234,3 +326,29 @@ void free_output_config(struct output_config *oc) {
|
|||
free(oc->background_option);
|
||||
free(oc);
|
||||
}
|
||||
|
||||
static void default_output_config(struct output_config *oc,
|
||||
struct wlr_output *wlr_output) {
|
||||
oc->enabled = 1;
|
||||
if (!wl_list_empty(&wlr_output->modes)) {
|
||||
struct wlr_output_mode *mode =
|
||||
wl_container_of(wlr_output->modes.prev, mode, link);
|
||||
oc->width = mode->width;
|
||||
oc->height = mode->height;
|
||||
oc->refresh_rate = mode->refresh;
|
||||
}
|
||||
oc->x = oc->y = -1;
|
||||
oc->scale = 1;
|
||||
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
}
|
||||
|
||||
void create_default_output_configs(void) {
|
||||
struct sway_output *sway_output;
|
||||
wl_list_for_each(sway_output, &root_container.sway_root->outputs, link) {
|
||||
char *name = sway_output->wlr_output->name;
|
||||
struct output_config *oc = new_output_config(name);
|
||||
default_output_config(oc, sway_output->wlr_output);
|
||||
list_add(config->output_configs, oc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,8 +158,23 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
}
|
||||
|
||||
if (criteria->urgent) {
|
||||
// TODO
|
||||
return false;
|
||||
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) {
|
||||
|
|
@ -185,6 +225,15 @@ list_t *criteria_get_views(struct criteria *criteria) {
|
|||
};
|
||||
container_for_each_descendant_dfs(&root_container,
|
||||
criteria_get_views_iterator, &data);
|
||||
|
||||
// Scratchpad items which are hidden are not in the tree.
|
||||
for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
|
||||
struct sway_container *con =
|
||||
root_container.sway_root->scratchpad->items[i];
|
||||
if (!con->parent) {
|
||||
criteria_get_views_iterator(con, &data);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
|
|
@ -507,7 +556,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
80
sway/desktop/idle_inhibit_v1.c
Normal file
80
sway/desktop/idle_inhibit_v1.c
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#include <stdlib.h>
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include "log.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/server.h"
|
||||
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_idle_inhibitor_v1 *inhibitor =
|
||||
wl_container_of(listener, inhibitor, destroy);
|
||||
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);
|
||||
free(inhibitor);
|
||||
}
|
||||
|
||||
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(WLR_DEBUG, "New sway idle inhibitor");
|
||||
|
||||
struct sway_idle_inhibitor_v1 *inhibitor =
|
||||
calloc(1, sizeof(struct sway_idle_inhibitor_v1));
|
||||
if (!inhibitor) {
|
||||
return;
|
||||
}
|
||||
|
||||
inhibitor->manager = manager;
|
||||
inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface);
|
||||
wl_list_insert(&manager->inhibitors, &inhibitor->link);
|
||||
|
||||
|
||||
inhibitor->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy);
|
||||
|
||||
idle_inhibit_v1_check_active(manager);
|
||||
}
|
||||
|
||||
void idle_inhibit_v1_check_active(
|
||||
struct sway_idle_inhibit_manager_v1 *manager) {
|
||||
struct sway_idle_inhibitor_v1 *inhibitor;
|
||||
bool inhibited = false;
|
||||
wl_list_for_each(inhibitor, &manager->inhibitors, link) {
|
||||
if (!inhibitor->view) {
|
||||
/* Cannot guess if view is visible so assume it is */
|
||||
inhibited = true;
|
||||
break;
|
||||
}
|
||||
if (view_is_visible(inhibitor->view)) {
|
||||
inhibited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
wlr_idle_set_enabled(manager->idle, NULL, !inhibited);
|
||||
}
|
||||
|
||||
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
|
||||
struct wl_display *wl_display, struct wlr_idle *idle) {
|
||||
struct sway_idle_inhibit_manager_v1 *manager =
|
||||
calloc(1, sizeof(struct sway_idle_inhibit_manager_v1));
|
||||
if (!manager) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display);
|
||||
if (!manager->wlr_manager) {
|
||||
free(manager);
|
||||
return NULL;
|
||||
}
|
||||
manager->idle = idle;
|
||||
wl_signal_add(&manager->wlr_manager->events.new_inhibitor,
|
||||
&manager->new_idle_inhibitor_v1);
|
||||
manager->new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1;
|
||||
wl_list_init(&manager->inhibitors);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
919
sway/desktop/render.c
Normal file
919
sway/desktop/render.c
Normal file
|
|
@ -0,0 +1,919 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <wayland-server.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_output_damage.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#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"
|
||||
#include "sway/output.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/layout.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
|
||||
struct render_data {
|
||||
struct root_geometry root_geo;
|
||||
struct sway_output *output;
|
||||
pixman_region32_t *damage;
|
||||
struct sway_view *view;
|
||||
float alpha;
|
||||
};
|
||||
|
||||
static void scale_box(struct wlr_box *box, float scale) {
|
||||
box->x *= scale;
|
||||
box->y *= scale;
|
||||
box->width *= scale;
|
||||
box->height *= scale;
|
||||
}
|
||||
|
||||
static void scissor_output(struct wlr_output *wlr_output,
|
||||
pixman_box32_t *rect) {
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
|
||||
assert(renderer);
|
||||
|
||||
struct wlr_box box = {
|
||||
.x = rect->x1,
|
||||
.y = rect->y1,
|
||||
.width = rect->x2 - rect->x1,
|
||||
.height = rect->y2 - rect->y1,
|
||||
};
|
||||
|
||||
int ow, oh;
|
||||
wlr_output_transformed_resolution(wlr_output, &ow, &oh);
|
||||
|
||||
enum wl_output_transform transform =
|
||||
wlr_output_transform_invert(wlr_output->transform);
|
||||
wlr_box_transform(&box, transform, ow, oh, &box);
|
||||
|
||||
wlr_renderer_scissor(renderer, &box);
|
||||
}
|
||||
|
||||
static void render_texture(struct wlr_output *wlr_output,
|
||||
pixman_region32_t *output_damage, struct wlr_texture *texture,
|
||||
const struct wlr_box *box, const float matrix[static 9], float alpha) {
|
||||
struct wlr_renderer *renderer =
|
||||
wlr_backend_get_renderer(wlr_output->backend);
|
||||
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
pixman_region32_union_rect(&damage, &damage, box->x, box->y,
|
||||
box->width, box->height);
|
||||
pixman_region32_intersect(&damage, &damage, output_damage);
|
||||
bool damaged = pixman_region32_not_empty(&damage);
|
||||
if (!damaged) {
|
||||
goto damage_finish;
|
||||
}
|
||||
|
||||
int nrects;
|
||||
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
|
||||
for (int i = 0; i < nrects; ++i) {
|
||||
scissor_output(wlr_output, &rects[i]);
|
||||
wlr_render_texture_with_matrix(renderer, texture, matrix, alpha);
|
||||
}
|
||||
|
||||
damage_finish:
|
||||
pixman_region32_fini(&damage);
|
||||
}
|
||||
|
||||
static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
|
||||
void *_data) {
|
||||
struct render_data *data = _data;
|
||||
struct wlr_output *wlr_output = data->output->wlr_output;
|
||||
float rotation = data->root_geo.rotation;
|
||||
pixman_region32_t *output_damage = data->damage;
|
||||
float alpha = data->alpha;
|
||||
|
||||
struct wlr_texture *texture = wlr_surface_get_texture(surface);
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_box box;
|
||||
bool intersects = output_get_surface_box(&data->root_geo, data->output,
|
||||
surface, sx, sy, &box);
|
||||
if (!intersects) {
|
||||
return;
|
||||
}
|
||||
|
||||
scale_box(&box, wlr_output->scale);
|
||||
|
||||
float matrix[9];
|
||||
enum wl_output_transform transform =
|
||||
wlr_output_transform_invert(surface->current.transform);
|
||||
wlr_matrix_project_box(matrix, &box, transform, rotation,
|
||||
wlr_output->transform_matrix);
|
||||
|
||||
render_texture(wlr_output, output_damage, texture, &box, matrix, alpha);
|
||||
}
|
||||
|
||||
static void render_layer(struct sway_output *output,
|
||||
pixman_region32_t *damage, struct wl_list *layer_surfaces) {
|
||||
struct render_data data = {
|
||||
.output = output,
|
||||
.damage = damage,
|
||||
.alpha = 1.0f,
|
||||
};
|
||||
output_layer_for_each_surface(layer_surfaces, &data.root_geo,
|
||||
render_surface_iterator, &data);
|
||||
}
|
||||
|
||||
static void render_unmanaged(struct sway_output *output,
|
||||
pixman_region32_t *damage, struct wl_list *unmanaged) {
|
||||
struct render_data data = {
|
||||
.output = output,
|
||||
.damage = damage,
|
||||
.alpha = 1.0f,
|
||||
};
|
||||
output_unmanaged_for_each_surface(unmanaged, output, &data.root_geo,
|
||||
render_surface_iterator, &data);
|
||||
}
|
||||
|
||||
static void render_drag_icons(struct sway_output *output,
|
||||
pixman_region32_t *damage, struct wl_list *drag_icons) {
|
||||
struct render_data data = {
|
||||
.output = output,
|
||||
.damage = damage,
|
||||
.alpha = 1.0f,
|
||||
};
|
||||
output_drag_icons_for_each_surface(drag_icons, output, &data.root_geo,
|
||||
render_surface_iterator, &data);
|
||||
}
|
||||
|
||||
static void render_rect(struct wlr_output *wlr_output,
|
||||
pixman_region32_t *output_damage, const struct wlr_box *_box,
|
||||
float color[static 4]) {
|
||||
struct wlr_renderer *renderer =
|
||||
wlr_backend_get_renderer(wlr_output->backend);
|
||||
|
||||
struct wlr_box box;
|
||||
memcpy(&box, _box, sizeof(struct wlr_box));
|
||||
box.x -= wlr_output->lx * wlr_output->scale;
|
||||
box.y -= wlr_output->ly * wlr_output->scale;
|
||||
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
pixman_region32_union_rect(&damage, &damage, box.x, box.y,
|
||||
box.width, box.height);
|
||||
pixman_region32_intersect(&damage, &damage, output_damage);
|
||||
bool damaged = pixman_region32_not_empty(&damage);
|
||||
if (!damaged) {
|
||||
goto damage_finish;
|
||||
}
|
||||
|
||||
int nrects;
|
||||
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
|
||||
for (int i = 0; i < nrects; ++i) {
|
||||
scissor_output(wlr_output, &rects[i]);
|
||||
wlr_render_rect(renderer, &box, color,
|
||||
wlr_output->transform_matrix);
|
||||
}
|
||||
|
||||
damage_finish:
|
||||
pixman_region32_fini(&damage);
|
||||
}
|
||||
|
||||
static void premultiply_alpha(float color[4], float opacity) {
|
||||
color[3] *= opacity;
|
||||
color[0] *= color[3];
|
||||
color[1] *= color[3];
|
||||
color[2] *= color[3];
|
||||
}
|
||||
|
||||
static void render_view_surfaces(struct sway_view *view,
|
||||
struct sway_output *output, pixman_region32_t *damage, float alpha) {
|
||||
struct render_data data = {
|
||||
.output = output,
|
||||
.damage = damage,
|
||||
.view = view,
|
||||
.alpha = alpha,
|
||||
};
|
||||
output_view_for_each_surface(view, output, &data.root_geo,
|
||||
render_surface_iterator, &data);
|
||||
}
|
||||
|
||||
static void render_saved_view(struct sway_view *view,
|
||||
struct sway_output *output, pixman_region32_t *damage, float alpha) {
|
||||
struct wlr_output *wlr_output = output->wlr_output;
|
||||
|
||||
int width, height;
|
||||
struct wlr_texture *texture =
|
||||
transaction_get_saved_texture(view, &width, &height);
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
struct wlr_box box = {
|
||||
.x = view->swayc->current.view_x - output->swayc->current.swayc_x,
|
||||
.y = view->swayc->current.view_y - output->swayc->current.swayc_y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
struct wlr_box output_box = {
|
||||
.width = output->swayc->current.swayc_width,
|
||||
.height = output->swayc->current.swayc_height,
|
||||
};
|
||||
|
||||
struct wlr_box intersection;
|
||||
bool intersects = wlr_box_intersection(&output_box, &box, &intersection);
|
||||
if (!intersects) {
|
||||
return;
|
||||
}
|
||||
|
||||
scale_box(&box, wlr_output->scale);
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
|
||||
wlr_output->transform_matrix);
|
||||
|
||||
render_texture(wlr_output, damage, texture, &box, matrix, alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a view's surface and left/bottom/right borders.
|
||||
*/
|
||||
static void render_view(struct sway_output *output, pixman_region32_t *damage,
|
||||
struct sway_container *con, struct border_colors *colors) {
|
||||
struct sway_view *view = con->sway_view;
|
||||
if (view->swayc->instructions->length) {
|
||||
render_saved_view(view, output, damage, view->swayc->alpha);
|
||||
} else {
|
||||
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];
|
||||
struct sway_container_state *state = &con->current;
|
||||
|
||||
if (state->border != B_NONE) {
|
||||
if (state->border_left) {
|
||||
memcpy(&color, colors->child_border, sizeof(float) * 4);
|
||||
premultiply_alpha(color, con->alpha);
|
||||
box.x = state->swayc_x;
|
||||
box.y = state->view_y;
|
||||
box.width = state->border_thickness;
|
||||
box.height = state->view_height;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, damage, &box, color);
|
||||
}
|
||||
|
||||
if (state->border_right) {
|
||||
if (state->parent->current.children->length == 1
|
||||
&& state->parent->current.layout == L_HORIZ) {
|
||||
memcpy(&color, colors->indicator, sizeof(float) * 4);
|
||||
} else {
|
||||
memcpy(&color, colors->child_border, sizeof(float) * 4);
|
||||
}
|
||||
premultiply_alpha(color, con->alpha);
|
||||
box.x = state->view_x + state->view_width;
|
||||
box.y = state->view_y;
|
||||
box.width = state->border_thickness;
|
||||
box.height = state->view_height;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, damage, &box, color);
|
||||
}
|
||||
|
||||
if (state->border_bottom) {
|
||||
if (state->parent->current.children->length == 1
|
||||
&& con->current.parent->current.layout == L_VERT) {
|
||||
memcpy(&color, colors->indicator, sizeof(float) * 4);
|
||||
} else {
|
||||
memcpy(&color, colors->child_border, sizeof(float) * 4);
|
||||
}
|
||||
premultiply_alpha(color, con->alpha);
|
||||
box.x = state->swayc_x;
|
||||
box.y = state->view_y + state->view_height;
|
||||
box.width = state->swayc_width;
|
||||
box.height = state->border_thickness;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, damage, &box, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a titlebar.
|
||||
*
|
||||
* Care must be taken not to render over the same pixel multiple times,
|
||||
* otherwise the colors will be incorrect when using opacity.
|
||||
*
|
||||
* The height is: 1px border, 3px padding, font height, 3px padding, 1px border
|
||||
* The left side for L_TABBED is: 1px border, 2px padding, title
|
||||
* The left side for other layouts is: 3px padding, title
|
||||
*/
|
||||
static void render_titlebar(struct sway_output *output,
|
||||
pixman_region32_t *output_damage, struct sway_container *con,
|
||||
int x, int y, int width,
|
||||
struct border_colors *colors, struct wlr_texture *title_texture,
|
||||
struct wlr_texture *marks_texture) {
|
||||
struct wlr_box box;
|
||||
float color[4];
|
||||
struct sway_container_state *state = &con->current;
|
||||
float output_scale = output->wlr_output->scale;
|
||||
enum sway_container_layout layout = state->parent->current.layout;
|
||||
list_t *children = state->parent->current.children;
|
||||
bool is_last_child = children->items[children->length - 1] == con;
|
||||
double output_x = output->swayc->current.swayc_x;
|
||||
double output_y = output->swayc->current.swayc_y;
|
||||
|
||||
// Single pixel bar above title
|
||||
memcpy(&color, colors->border, sizeof(float) * 4);
|
||||
premultiply_alpha(color, con->alpha);
|
||||
box.x = x;
|
||||
box.y = y;
|
||||
box.width = width;
|
||||
box.height = TITLEBAR_BORDER_THICKNESS;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
|
||||
// Single pixel bar below title
|
||||
size_t left_offset = 0, right_offset = 0;
|
||||
bool connects_sides = false;
|
||||
if (layout == L_HORIZ || layout == L_VERT ||
|
||||
(layout == L_STACKED && is_last_child)) {
|
||||
if (con->type == C_VIEW) {
|
||||
left_offset = state->border_left * state->border_thickness;
|
||||
right_offset = state->border_right * state->border_thickness;
|
||||
connects_sides = true;
|
||||
}
|
||||
}
|
||||
box.x = x + left_offset;
|
||||
box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
|
||||
box.width = width - left_offset - right_offset;
|
||||
box.height = TITLEBAR_BORDER_THICKNESS;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
|
||||
if (layout == L_TABBED) {
|
||||
// Single pixel left edge
|
||||
box.x = x;
|
||||
box.y = y + TITLEBAR_BORDER_THICKNESS;
|
||||
box.width = TITLEBAR_BORDER_THICKNESS;
|
||||
box.height =
|
||||
container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
|
||||
// Single pixel right edge
|
||||
box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale;
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
}
|
||||
|
||||
size_t inner_width = width - TITLEBAR_H_PADDING * 2;
|
||||
|
||||
// Marks
|
||||
size_t marks_ob_width = 0; // output-buffer-local
|
||||
if (config->show_marks && marks_texture) {
|
||||
struct wlr_box texture_box;
|
||||
wlr_texture_get_size(marks_texture,
|
||||
&texture_box.width, &texture_box.height);
|
||||
texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING)
|
||||
* output_scale - texture_box.width;
|
||||
texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale;
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, &texture_box,
|
||||
WL_OUTPUT_TRANSFORM_NORMAL,
|
||||
0.0, output->wlr_output->transform_matrix);
|
||||
|
||||
if (inner_width * output_scale < texture_box.width) {
|
||||
texture_box.width = inner_width * output_scale;
|
||||
}
|
||||
render_texture(output->wlr_output, output_damage, marks_texture,
|
||||
&texture_box, matrix, con->alpha);
|
||||
marks_ob_width = texture_box.width;
|
||||
|
||||
// Gap between the marks and bottom padding, for when the marks texture
|
||||
// height is smaller than the config's font height
|
||||
memcpy(&color, colors->background, sizeof(float) * 4);
|
||||
premultiply_alpha(color, con->alpha);
|
||||
box.x = texture_box.x;
|
||||
box.y = texture_box.y + texture_box.height;
|
||||
box.width = texture_box.width;
|
||||
box.height = config->font_height * output_scale - texture_box.height;
|
||||
if (box.height > 0) {
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
}
|
||||
}
|
||||
|
||||
// Title text
|
||||
size_t title_ob_width = 0; // output-buffer-local
|
||||
if (title_texture) {
|
||||
struct wlr_box texture_box;
|
||||
wlr_texture_get_size(title_texture,
|
||||
&texture_box.width, &texture_box.height);
|
||||
texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale;
|
||||
texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale;
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, &texture_box,
|
||||
WL_OUTPUT_TRANSFORM_NORMAL,
|
||||
0.0, output->wlr_output->transform_matrix);
|
||||
|
||||
if (inner_width * output_scale - marks_ob_width < texture_box.width) {
|
||||
texture_box.width = inner_width * output_scale - marks_ob_width;
|
||||
}
|
||||
render_texture(output->wlr_output, output_damage, title_texture,
|
||||
&texture_box, matrix, con->alpha);
|
||||
title_ob_width = texture_box.width;
|
||||
|
||||
// Gap between the title and bottom padding, for when the title texture
|
||||
// height is smaller than the config's font height
|
||||
memcpy(&color, colors->background, sizeof(float) * 4);
|
||||
premultiply_alpha(color, con->alpha);
|
||||
box.x = texture_box.x;
|
||||
box.y = texture_box.y + texture_box.height;
|
||||
box.width = texture_box.width;
|
||||
box.height = config->font_height * output_scale - texture_box.height;
|
||||
if (box.height > 0) {
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
}
|
||||
}
|
||||
|
||||
// Padding above title
|
||||
memcpy(&color, colors->background, sizeof(float) * 4);
|
||||
premultiply_alpha(color, con->alpha);
|
||||
box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
|
||||
box.y = y + TITLEBAR_BORDER_THICKNESS;
|
||||
box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2;
|
||||
box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
|
||||
// Padding below title
|
||||
box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale;
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
|
||||
// Filler between title and marks
|
||||
box.width = inner_width * output_scale - title_ob_width - marks_ob_width;
|
||||
if (box.width > 0) {
|
||||
box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_ob_width;
|
||||
box.y = (y + TITLEBAR_V_PADDING) * output_scale;
|
||||
box.height = config->font_height * output_scale;
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
}
|
||||
|
||||
// Padding left of title
|
||||
left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
|
||||
box.x = x + left_offset;
|
||||
box.y = y + TITLEBAR_V_PADDING;
|
||||
box.width = TITLEBAR_H_PADDING - left_offset;
|
||||
box.height = config->font_height;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
|
||||
// Padding right of marks
|
||||
right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
|
||||
box.x = x + width - TITLEBAR_H_PADDING;
|
||||
box.y = y + TITLEBAR_V_PADDING;
|
||||
box.width = TITLEBAR_H_PADDING - right_offset;
|
||||
box.height = config->font_height;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
|
||||
if (connects_sides) {
|
||||
// Left pixel in line with bottom bar
|
||||
box.x = x;
|
||||
box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
|
||||
box.width = state->border_thickness * state->border_left;
|
||||
box.height = TITLEBAR_BORDER_THICKNESS;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
|
||||
// Right pixel in line with bottom bar
|
||||
box.x = x + width - state->border_thickness * state->border_right;
|
||||
box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
|
||||
box.width = state->border_thickness * state->border_right;
|
||||
box.height = TITLEBAR_BORDER_THICKNESS;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the top border line for a view using "border pixel".
|
||||
*/
|
||||
static void render_top_border(struct sway_output *output,
|
||||
pixman_region32_t *output_damage, struct sway_container *con,
|
||||
struct border_colors *colors) {
|
||||
struct sway_container_state *state = &con->current;
|
||||
if (!state->border_top) {
|
||||
return;
|
||||
}
|
||||
struct wlr_box box;
|
||||
float color[4];
|
||||
float output_scale = output->wlr_output->scale;
|
||||
|
||||
// Child border - top edge
|
||||
memcpy(&color, colors->child_border, sizeof(float) * 4);
|
||||
premultiply_alpha(color, con->alpha);
|
||||
box.x = state->swayc_x;
|
||||
box.y = state->swayc_y;
|
||||
box.width = state->swayc_width;
|
||||
box.height = state->border_thickness;
|
||||
scale_box(&box, output_scale);
|
||||
render_rect(output->wlr_output, output_damage, &box, color);
|
||||
}
|
||||
|
||||
static void render_container(struct sway_output *output,
|
||||
pixman_region32_t *damage, struct sway_container *con, bool parent_focused);
|
||||
|
||||
/**
|
||||
* Render a container's children using a L_HORIZ or L_VERT layout.
|
||||
*
|
||||
* Wrap child views in borders and leave child containers borderless because
|
||||
* they'll apply their own borders to their children.
|
||||
*/
|
||||
static void render_container_simple(struct sway_output *output,
|
||||
pixman_region32_t *damage, struct sway_container *con,
|
||||
bool parent_focused) {
|
||||
for (int i = 0; i < con->current.children->length; ++i) {
|
||||
struct sway_container *child = con->current.children->items[i];
|
||||
|
||||
if (child->type == C_VIEW) {
|
||||
struct sway_view *view = child->sway_view;
|
||||
struct border_colors *colors;
|
||||
struct wlr_texture *title_texture;
|
||||
struct wlr_texture *marks_texture;
|
||||
struct sway_container_state *state = &child->current;
|
||||
|
||||
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 (con->current.focused_inactive_child == child) {
|
||||
colors = &config->border_colors.focused_inactive;
|
||||
title_texture = child->title_focused_inactive;
|
||||
marks_texture = view->marks_focused_inactive;
|
||||
} else {
|
||||
colors = &config->border_colors.unfocused;
|
||||
title_texture = child->title_unfocused;
|
||||
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,
|
||||
title_texture, marks_texture);
|
||||
} else {
|
||||
render_top_border(output, damage, child, colors);
|
||||
}
|
||||
}
|
||||
render_view(output, damage, child, colors);
|
||||
} else {
|
||||
render_container(output, damage, child,
|
||||
parent_focused || child->current.focused);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a container's children using the L_TABBED layout.
|
||||
*/
|
||||
static void render_container_tabbed(struct sway_output *output,
|
||||
pixman_region32_t *damage, struct sway_container *con,
|
||||
bool parent_focused) {
|
||||
if (!con->current.children->length) {
|
||||
return;
|
||||
}
|
||||
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 < 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 (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 == pstate->focused_inactive_child) {
|
||||
colors = &config->border_colors.focused_inactive;
|
||||
title_texture = child->title_focused_inactive;
|
||||
marks_texture = view ? view->marks_focused_inactive : NULL;
|
||||
} else {
|
||||
colors = &config->border_colors.unfocused;
|
||||
title_texture = child->title_unfocused;
|
||||
marks_texture = view ? view->marks_unfocused : NULL;
|
||||
}
|
||||
|
||||
int 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 - width_gap_adjustment - tab_width * i;
|
||||
}
|
||||
|
||||
render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width,
|
||||
colors, title_texture, marks_texture);
|
||||
|
||||
if (child == current) {
|
||||
current_colors = colors;
|
||||
}
|
||||
}
|
||||
|
||||
// Render surface and left/right/bottom borders
|
||||
if (current->type == C_VIEW) {
|
||||
render_view(output, damage, current, current_colors);
|
||||
} else {
|
||||
render_container(output, damage, current,
|
||||
parent_focused || current->current.focused);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a container's children using the L_STACKED layout.
|
||||
*/
|
||||
static void render_container_stacked(struct sway_output *output,
|
||||
pixman_region32_t *damage, struct sway_container *con,
|
||||
bool parent_focused) {
|
||||
if (!con->current.children->length) {
|
||||
return;
|
||||
}
|
||||
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 < 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 (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 == pstate->focused_inactive_child) {
|
||||
colors = &config->border_colors.focused_inactive;
|
||||
title_texture = child->title_focused_inactive;
|
||||
marks_texture = view ? view->marks_focused_inactive : NULL;
|
||||
} else {
|
||||
colors = &config->border_colors.unfocused;
|
||||
title_texture = child->title_unfocused;
|
||||
marks_texture = view ? view->marks_unfocused : NULL;
|
||||
}
|
||||
|
||||
int y = cstate->swayc_y + titlebar_height * i;
|
||||
render_titlebar(output, damage, child, cstate->swayc_x, y,
|
||||
cstate->swayc_width, colors, title_texture, marks_texture);
|
||||
|
||||
if (child == current) {
|
||||
current_colors = colors;
|
||||
}
|
||||
}
|
||||
|
||||
// Render surface and left/right/bottom borders
|
||||
if (current->type == C_VIEW) {
|
||||
render_view(output, damage, current, current_colors);
|
||||
} else {
|
||||
render_container(output, damage, current,
|
||||
parent_focused || current->current.focused);
|
||||
}
|
||||
}
|
||||
|
||||
static void render_container(struct sway_output *output,
|
||||
pixman_region32_t *damage, struct sway_container *con,
|
||||
bool parent_focused) {
|
||||
switch (con->current.layout) {
|
||||
case L_NONE:
|
||||
case L_HORIZ:
|
||||
case L_VERT:
|
||||
render_container_simple(output, damage, con, parent_focused);
|
||||
break;
|
||||
case L_STACKED:
|
||||
render_container_stacked(output, damage, con, parent_focused);
|
||||
break;
|
||||
case L_TABBED:
|
||||
render_container_tabbed(output, damage, con, parent_focused);
|
||||
break;
|
||||
case L_FLOATING:
|
||||
sway_assert(false, "Didn't expect to see floating here");
|
||||
}
|
||||
}
|
||||
|
||||
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 border_colors *colors;
|
||||
struct wlr_texture *title_texture;
|
||||
struct wlr_texture *marks_texture;
|
||||
|
||||
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;
|
||||
} else {
|
||||
colors = &config->border_colors.unfocused;
|
||||
title_texture = con->title_unfocused;
|
||||
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,
|
||||
title_texture, marks_texture);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void render_floating(struct sway_output *soutput,
|
||||
pixman_region32_t *damage) {
|
||||
for (int i = 0; i < root_container.current.children->length; ++i) {
|
||||
struct sway_container *output =
|
||||
root_container.current.children->items[i];
|
||||
for (int j = 0; j < output->current.children->length; ++j) {
|
||||
struct sway_container *ws = output->current.children->items[j];
|
||||
if (!workspace_is_visible(ws)) {
|
||||
continue;
|
||||
}
|
||||
list_t *floating =
|
||||
ws->current.ws_floating->current.children;
|
||||
for (int k = 0; k < floating->length; ++k) {
|
||||
struct sway_container *floater = floating->items[k];
|
||||
render_floating_container(soutput, damage, floater);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
struct wlr_renderer *renderer =
|
||||
wlr_backend_get_renderer(wlr_output->backend);
|
||||
if (!sway_assert(renderer != NULL,
|
||||
"expected the output backend to have a renderer")) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
|
||||
|
||||
bool damage_whole_before_swap = false;
|
||||
if (!pixman_region32_not_empty(damage)) {
|
||||
// Output isn't damaged but needs buffer swap
|
||||
goto renderer_end;
|
||||
}
|
||||
|
||||
if (damage_debug != NULL) {
|
||||
if (strcmp(damage_debug, "highlight") == 0) {
|
||||
wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
|
||||
damage_whole_before_swap = true;
|
||||
} else if (strcmp(damage_debug, "rerender") == 0) {
|
||||
int width, height;
|
||||
wlr_output_transformed_resolution(wlr_output, &width, &height);
|
||||
pixman_region32_union_rect(damage, damage, 0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
struct sway_container *workspace = output_get_active_workspace(output);
|
||||
struct sway_view *fullscreen_view = workspace->current.ws_fullscreen;
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
|
||||
if (output_has_opaque_lockscreen(output, seat) && seat->focused_layer) {
|
||||
struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer;
|
||||
struct sway_layer_surface *sway_layer_surface =
|
||||
layer_from_wlr_layer_surface(seat->focused_layer);
|
||||
struct render_data data = {
|
||||
.output = output,
|
||||
.damage = damage,
|
||||
.alpha = 1.0f,
|
||||
};
|
||||
output_surface_for_each_surface(wlr_layer_surface->surface,
|
||||
sway_layer_surface->geo.x, sway_layer_surface->geo.y,
|
||||
&data.root_geo, render_surface_iterator, &data);
|
||||
} else if (fullscreen_view) {
|
||||
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
int nrects;
|
||||
pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
|
||||
for (int i = 0; i < nrects; ++i) {
|
||||
scissor_output(wlr_output, &rects[i]);
|
||||
wlr_renderer_clear(renderer, clear_color);
|
||||
}
|
||||
|
||||
// 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,
|
||||
&root_container.sway_root->xwayland_unmanaged);
|
||||
}
|
||||
} else {
|
||||
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
|
||||
|
||||
int nrects;
|
||||
pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
|
||||
for (int i = 0; i < nrects; ++i) {
|
||||
scissor_output(wlr_output, &rects[i]);
|
||||
wlr_renderer_clear(renderer, clear_color);
|
||||
}
|
||||
|
||||
render_layer(output, damage,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
|
||||
render_layer(output, damage,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
||||
|
||||
render_container(output, damage, workspace, workspace->current.focused);
|
||||
render_floating(output, damage);
|
||||
|
||||
render_unmanaged(output, damage,
|
||||
&root_container.sway_root->xwayland_unmanaged);
|
||||
render_layer(output, damage,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
|
||||
}
|
||||
render_layer(output, damage,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
|
||||
render_drag_icons(output, damage, &root_container.sway_root->drag_icons);
|
||||
|
||||
renderer_end:
|
||||
if (root_container.sway_root->debug_tree) {
|
||||
wlr_render_texture(renderer, root_container.sway_root->debug_tree,
|
||||
wlr_output->transform_matrix, 0, 0, 1);
|
||||
}
|
||||
|
||||
if (damage_whole_before_swap || root_container.sway_root->debug_tree) {
|
||||
int width, height;
|
||||
wlr_output_transformed_resolution(wlr_output, &width, &height);
|
||||
pixman_region32_union_rect(damage, damage, 0, 0, width, height);
|
||||
}
|
||||
|
||||
wlr_renderer_scissor(renderer, NULL);
|
||||
wlr_renderer_end(renderer);
|
||||
if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) {
|
||||
return;
|
||||
}
|
||||
output->last_frame = *when;
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf.h>
|
||||
#include "sway/debug.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/tree/container.h"
|
||||
|
|
@ -18,14 +18,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;
|
||||
|
|
@ -46,7 +46,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();
|
||||
|
|
@ -72,8 +72,8 @@ static void save_view_buffer(struct sway_view *view,
|
|||
}
|
||||
if (view->surface && wlr_surface_has_buffer(view->surface)) {
|
||||
instruction->saved_buffer = wlr_buffer_ref(view->surface->buffer);
|
||||
instruction->saved_buffer_width = view->surface->current->width;
|
||||
instruction->saved_buffer_height = view->surface->current->height;
|
||||
instruction->saved_buffer_width = view->surface->current.width;
|
||||
instruction->saved_buffer_height = view->surface->current.height;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,25 +138,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;
|
||||
|
|
@ -174,7 +167,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);
|
||||
|
|
@ -185,9 +178,9 @@ 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, "
|
||||
"%.1fms total (%.1f frames if 60Hz)", transaction,
|
||||
ms_arranging, ms_waiting, ms_total, ms_total / (1000 / 60));
|
||||
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));
|
||||
}
|
||||
|
||||
// Apply the instruction state to the container's current state
|
||||
|
|
@ -209,10 +202,12 @@ 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];
|
||||
output_damage_box(output->sway_output, &old_box);
|
||||
output_damage_box(output->sway_output, &new_box);
|
||||
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
|
||||
|
|
@ -227,29 +222,22 @@ static void transaction_apply(struct sway_transaction *transaction) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For simplicity, we only progress the queue if it can be completely flushed.
|
||||
*/
|
||||
static void transaction_progress_queue() {
|
||||
// We iterate this list in reverse because we're more likely to find a
|
||||
// waiting transactions at the end of the list.
|
||||
for (int i = server.transactions->length - 1; i >= 0; --i) {
|
||||
struct sway_transaction *transaction = server.transactions->items[i];
|
||||
while (server.transactions->length) {
|
||||
struct sway_transaction *transaction = server.transactions->items[0];
|
||||
if (transaction->num_waiting) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < server.transactions->length; ++i) {
|
||||
struct sway_transaction *transaction = server.transactions->items[i];
|
||||
transaction_apply(transaction);
|
||||
transaction_destroy(transaction);
|
||||
list_del(server.transactions, 0);
|
||||
}
|
||||
server.transactions->length = 0;
|
||||
idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
@ -283,8 +271,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) {
|
||||
|
|
@ -317,9 +305,10 @@ 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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +316,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
|
||||
|
|
@ -347,7 +336,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,
|
||||
|
|
@ -358,11 +347,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);
|
||||
wl_event_source_timer_update(transaction->timer, 0);
|
||||
transaction_progress_queue();
|
||||
#endif
|
||||
if (!txn_debug) {
|
||||
wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction);
|
||||
wl_event_source_timer_update(transaction->timer, 0);
|
||||
transaction_progress_queue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +363,9 @@ static void set_instructions_ready(struct sway_view *view, int index) {
|
|||
for (int i = 0; i <= index; ++i) {
|
||||
struct sway_transaction_instruction *instruction =
|
||||
view->swayc->instructions->items[i];
|
||||
set_instruction_ready(instruction);
|
||||
if (!instruction->ready) {
|
||||
set_instruction_ready(instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -413,3 +404,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#define _POSIX_C_SOURCE 199309L
|
||||
#include <float.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-server.h>
|
||||
|
|
@ -45,6 +46,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 +74,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;
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +96,16 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view(
|
|||
return (struct sway_xdg_shell_view *)view;
|
||||
}
|
||||
|
||||
static void get_constraints(struct sway_view *view, double *min_width,
|
||||
double *max_width, double *min_height, double *max_height) {
|
||||
struct wlr_xdg_toplevel_state *state =
|
||||
&view->wlr_xdg_surface->toplevel->current;
|
||||
*min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
|
||||
*max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
|
||||
*min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
|
||||
*max_height = state->max_height > 0 ? state->max_height : DBL_MAX;
|
||||
}
|
||||
|
||||
static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
|
||||
if (xdg_shell_view_from_view(view) == NULL) {
|
||||
return NULL;
|
||||
|
|
@ -167,6 +199,7 @@ static void destroy(struct sway_view *view) {
|
|||
}
|
||||
|
||||
static const struct sway_view_impl view_impl = {
|
||||
.get_constraints = get_constraints,
|
||||
.get_string_prop = get_string_prop,
|
||||
.configure = configure,
|
||||
.set_activated = set_activated,
|
||||
|
|
@ -192,10 +225,24 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
transaction_notify_view_ready(view, xdg_surface->configure_serial);
|
||||
}
|
||||
|
||||
view_update_title(view, false);
|
||||
view_damage_from(view);
|
||||
}
|
||||
|
||||
static void handle_set_title(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_view *xdg_shell_view =
|
||||
wl_container_of(listener, xdg_shell_view, set_title);
|
||||
struct sway_view *view = &xdg_shell_view->view;
|
||||
view_update_title(view, false);
|
||||
view_execute_criteria(view);
|
||||
}
|
||||
|
||||
static void handle_set_app_id(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_view *xdg_shell_view =
|
||||
wl_container_of(listener, xdg_shell_view, set_app_id);
|
||||
struct sway_view *view = &xdg_shell_view->view;
|
||||
view_execute_criteria(view);
|
||||
}
|
||||
|
||||
static void handle_new_popup(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_view *xdg_shell_view =
|
||||
wl_container_of(listener, xdg_shell_view, new_popup);
|
||||
|
|
@ -222,8 +269,37 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
|
|||
|
||||
view_set_fullscreen(view, e->fullscreen);
|
||||
|
||||
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
|
||||
arrange_and_commit(ws);
|
||||
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
|
||||
arrange_windows(output);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
static void handle_request_move(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_view *xdg_shell_view =
|
||||
wl_container_of(listener, xdg_shell_view, request_move);
|
||||
struct sway_view *view = &xdg_shell_view->view;
|
||||
if (!container_is_floating(view->swayc)) {
|
||||
return;
|
||||
}
|
||||
struct wlr_xdg_toplevel_move_event *e = data;
|
||||
struct sway_seat *seat = e->seat->seat->data;
|
||||
if (e->serial == seat->last_button_serial) {
|
||||
seat_begin_move(seat, view->swayc, seat->last_button);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_request_resize(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_view *xdg_shell_view =
|
||||
wl_container_of(listener, xdg_shell_view, request_resize);
|
||||
struct sway_view *view = &xdg_shell_view->view;
|
||||
if (!container_is_floating(view->swayc)) {
|
||||
return;
|
||||
}
|
||||
struct wlr_xdg_toplevel_resize_event *e = data;
|
||||
struct sway_seat *seat = e->seat->seat->data;
|
||||
if (e->serial == seat->last_button_serial) {
|
||||
seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_unmap(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -240,6 +316,10 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
|
|||
wl_list_remove(&xdg_shell_view->commit.link);
|
||||
wl_list_remove(&xdg_shell_view->new_popup.link);
|
||||
wl_list_remove(&xdg_shell_view->request_fullscreen.link);
|
||||
wl_list_remove(&xdg_shell_view->request_move.link);
|
||||
wl_list_remove(&xdg_shell_view->request_resize.link);
|
||||
wl_list_remove(&xdg_shell_view->set_title.link);
|
||||
wl_list_remove(&xdg_shell_view->set_app_id.link);
|
||||
}
|
||||
|
||||
static void handle_map(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -251,8 +331,8 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
|||
view->natural_width = view->wlr_xdg_surface->geometry.width;
|
||||
view->natural_height = view->wlr_xdg_surface->geometry.height;
|
||||
if (!view->natural_width && !view->natural_height) {
|
||||
view->natural_width = view->wlr_xdg_surface->surface->current->width;
|
||||
view->natural_height = view->wlr_xdg_surface->surface->current->height;
|
||||
view->natural_width = view->wlr_xdg_surface->surface->current.width;
|
||||
view->natural_height = view->wlr_xdg_surface->surface->current.height;
|
||||
}
|
||||
|
||||
view_map(view, view->wlr_xdg_surface->surface);
|
||||
|
|
@ -260,10 +340,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,
|
||||
|
|
@ -276,6 +357,22 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
|||
xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
|
||||
&xdg_shell_view->request_fullscreen);
|
||||
|
||||
xdg_shell_view->request_move.notify = handle_request_move;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.request_move,
|
||||
&xdg_shell_view->request_move);
|
||||
|
||||
xdg_shell_view->request_resize.notify = handle_request_resize;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.request_resize,
|
||||
&xdg_shell_view->request_resize);
|
||||
|
||||
xdg_shell_view->set_title.notify = handle_set_title;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.set_title,
|
||||
&xdg_shell_view->set_title);
|
||||
|
||||
xdg_shell_view->set_app_id.notify = handle_set_app_id;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.set_app_id,
|
||||
&xdg_shell_view->set_app_id);
|
||||
}
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -304,11 +401,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#define _POSIX_C_SOURCE 199309L
|
||||
#include <float.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-server.h>
|
||||
|
|
@ -44,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_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 +73,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;
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +95,16 @@ static struct sway_xdg_shell_v6_view *xdg_shell_v6_view_from_view(
|
|||
return (struct sway_xdg_shell_v6_view *)view;
|
||||
}
|
||||
|
||||
static void get_constraints(struct sway_view *view, double *min_width,
|
||||
double *max_width, double *min_height, double *max_height) {
|
||||
struct wlr_xdg_toplevel_v6_state *state =
|
||||
&view->wlr_xdg_surface_v6->toplevel->current;
|
||||
*min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
|
||||
*max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
|
||||
*min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
|
||||
*max_height = state->max_height > 0 ? state->max_height : DBL_MAX;
|
||||
}
|
||||
|
||||
static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
|
||||
if (xdg_shell_v6_view_from_view(view) == NULL) {
|
||||
return NULL;
|
||||
|
|
@ -163,6 +195,7 @@ static void destroy(struct sway_view *view) {
|
|||
}
|
||||
|
||||
static const struct sway_view_impl view_impl = {
|
||||
.get_constraints = get_constraints,
|
||||
.get_string_prop = get_string_prop,
|
||||
.configure = configure,
|
||||
.set_activated = set_activated,
|
||||
|
|
@ -187,10 +220,24 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
transaction_notify_view_ready(view, xdg_surface_v6->configure_serial);
|
||||
}
|
||||
|
||||
view_update_title(view, false);
|
||||
view_damage_from(view);
|
||||
}
|
||||
|
||||
static void handle_set_title(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
|
||||
wl_container_of(listener, xdg_shell_v6_view, set_title);
|
||||
struct sway_view *view = &xdg_shell_v6_view->view;
|
||||
view_update_title(view, false);
|
||||
view_execute_criteria(view);
|
||||
}
|
||||
|
||||
static void handle_set_app_id(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
|
||||
wl_container_of(listener, xdg_shell_v6_view, set_app_id);
|
||||
struct sway_view *view = &xdg_shell_v6_view->view;
|
||||
view_execute_criteria(view);
|
||||
}
|
||||
|
||||
static void handle_new_popup(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
|
||||
wl_container_of(listener, xdg_shell_v6_view, new_popup);
|
||||
|
|
@ -217,8 +264,37 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
|
|||
|
||||
view_set_fullscreen(view, e->fullscreen);
|
||||
|
||||
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
|
||||
arrange_and_commit(ws);
|
||||
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
|
||||
arrange_windows(output);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
static void handle_request_move(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
|
||||
wl_container_of(listener, xdg_shell_v6_view, request_move);
|
||||
struct sway_view *view = &xdg_shell_v6_view->view;
|
||||
if (!container_is_floating(view->swayc)) {
|
||||
return;
|
||||
}
|
||||
struct wlr_xdg_toplevel_v6_move_event *e = data;
|
||||
struct sway_seat *seat = e->seat->seat->data;
|
||||
if (e->serial == seat->last_button_serial) {
|
||||
seat_begin_move(seat, view->swayc, seat->last_button);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_request_resize(struct wl_listener *listener, void *data) {
|
||||
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
|
||||
wl_container_of(listener, xdg_shell_v6_view, request_resize);
|
||||
struct sway_view *view = &xdg_shell_v6_view->view;
|
||||
if (!container_is_floating(view->swayc)) {
|
||||
return;
|
||||
}
|
||||
struct wlr_xdg_toplevel_v6_resize_event *e = data;
|
||||
struct sway_seat *seat = e->seat->seat->data;
|
||||
if (e->serial == seat->last_button_serial) {
|
||||
seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_unmap(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -235,6 +311,10 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
|
|||
wl_list_remove(&xdg_shell_v6_view->commit.link);
|
||||
wl_list_remove(&xdg_shell_v6_view->new_popup.link);
|
||||
wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link);
|
||||
wl_list_remove(&xdg_shell_v6_view->request_move.link);
|
||||
wl_list_remove(&xdg_shell_v6_view->request_resize.link);
|
||||
wl_list_remove(&xdg_shell_v6_view->set_title.link);
|
||||
wl_list_remove(&xdg_shell_v6_view->set_app_id.link);
|
||||
}
|
||||
|
||||
static void handle_map(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -246,8 +326,8 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
|||
view->natural_width = view->wlr_xdg_surface_v6->geometry.width;
|
||||
view->natural_height = view->wlr_xdg_surface_v6->geometry.height;
|
||||
if (!view->natural_width && !view->natural_height) {
|
||||
view->natural_width = view->wlr_xdg_surface_v6->surface->current->width;
|
||||
view->natural_height = view->wlr_xdg_surface_v6->surface->current->height;
|
||||
view->natural_width = view->wlr_xdg_surface_v6->surface->current.width;
|
||||
view->natural_height = view->wlr_xdg_surface_v6->surface->current.height;
|
||||
}
|
||||
|
||||
view_map(view, view->wlr_xdg_surface_v6->surface);
|
||||
|
|
@ -255,10 +335,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,
|
||||
|
|
@ -271,6 +352,22 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
|||
xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
|
||||
&xdg_shell_v6_view->request_fullscreen);
|
||||
|
||||
xdg_shell_v6_view->request_move.notify = handle_request_move;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.request_move,
|
||||
&xdg_shell_v6_view->request_move);
|
||||
|
||||
xdg_shell_v6_view->request_resize.notify = handle_request_resize;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.request_resize,
|
||||
&xdg_shell_v6_view->request_resize);
|
||||
|
||||
xdg_shell_v6_view->set_title.notify = handle_set_title;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.set_title,
|
||||
&xdg_shell_v6_view->set_title);
|
||||
|
||||
xdg_shell_v6_view->set_app_id.notify = handle_set_app_id;
|
||||
wl_signal_add(&xdg_surface->toplevel->events.set_app_id,
|
||||
&xdg_shell_v6_view->set_app_id);
|
||||
}
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -295,11 +392,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -69,16 +69,11 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
|
|||
surface->ly = xsurface->y;
|
||||
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true);
|
||||
|
||||
if (!wlr_xwayland_surface_is_unmanaged(xsurface)) {
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
struct wlr_xwayland *xwayland =
|
||||
seat->input->server->xwayland.wlr_xwayland;
|
||||
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
|
||||
seat_set_focus_surface(seat, xsurface->surface);
|
||||
}
|
||||
|
||||
// TODO: we don't send surface enter/leave events to xwayland unmanaged
|
||||
// surfaces, but xwayland doesn't support HiDPI anyway
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
struct wlr_xwayland *xwayland =
|
||||
seat->input->server->xwayland.wlr_xwayland;
|
||||
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
|
||||
seat_set_focus_surface(seat, xsurface->surface, false);
|
||||
}
|
||||
|
||||
static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -89,18 +84,16 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
|
|||
wl_list_remove(&surface->link);
|
||||
wl_list_remove(&surface->commit.link);
|
||||
|
||||
if (!wlr_xwayland_surface_is_unmanaged(xsurface)) {
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
if (seat->wlr_seat->keyboard_state.focused_surface ==
|
||||
xsurface->surface) {
|
||||
// Restore focus
|
||||
struct sway_container *previous =
|
||||
seat_get_focus_inactive(seat, &root_container);
|
||||
if (previous) {
|
||||
// Hack to get seat to re-focus the return value of get_focus
|
||||
seat_set_focus(seat, previous->parent);
|
||||
seat_set_focus(seat, previous);
|
||||
}
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
if (seat->wlr_seat->keyboard_state.focused_surface ==
|
||||
xsurface->surface) {
|
||||
// Restore focus
|
||||
struct sway_container *previous =
|
||||
seat_get_focus_inactive(seat, &root_container);
|
||||
if (previous) {
|
||||
// Hack to get seat to re-focus the return value of get_focus
|
||||
seat_set_focus(seat, previous->parent);
|
||||
seat_set_focus(seat, previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -119,7 +112,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 +239,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 +270,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,
|
||||
};
|
||||
|
|
@ -278,15 +280,42 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
wl_container_of(listener, xwayland_view, commit);
|
||||
struct sway_view *view = &xwayland_view->view;
|
||||
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
|
||||
struct wlr_surface_state *surface_state = xsurface->surface->current;
|
||||
struct wlr_surface_state *surface_state = &xsurface->surface->current;
|
||||
|
||||
if (view->swayc->instructions->length) {
|
||||
transaction_notify_view_ready_by_size(view,
|
||||
surface_state->width, surface_state->height);
|
||||
} else if (container_is_floating(view->swayc)) {
|
||||
view_update_size(view, surface_state->width, surface_state->height);
|
||||
}
|
||||
|
||||
view_damage_from(view);
|
||||
}
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_view *xwayland_view =
|
||||
wl_container_of(listener, xwayland_view, destroy);
|
||||
struct sway_view *view = &xwayland_view->view;
|
||||
|
||||
if (view->surface) {
|
||||
view_unmap(view);
|
||||
wl_list_remove(&xwayland_view->commit.link);
|
||||
}
|
||||
|
||||
wl_list_remove(&xwayland_view->destroy.link);
|
||||
wl_list_remove(&xwayland_view->request_configure.link);
|
||||
wl_list_remove(&xwayland_view->request_fullscreen.link);
|
||||
wl_list_remove(&xwayland_view->request_move.link);
|
||||
wl_list_remove(&xwayland_view->request_resize.link);
|
||||
wl_list_remove(&xwayland_view->set_title.link);
|
||||
wl_list_remove(&xwayland_view->set_class.link);
|
||||
wl_list_remove(&xwayland_view->set_window_type.link);
|
||||
wl_list_remove(&xwayland_view->set_hints.link);
|
||||
wl_list_remove(&xwayland_view->map.link);
|
||||
wl_list_remove(&xwayland_view->unmap.link);
|
||||
view_destroy(&xwayland_view->view);
|
||||
}
|
||||
|
||||
static void handle_unmap(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_view *xwayland_view =
|
||||
wl_container_of(listener, xwayland_view, unmap);
|
||||
|
|
@ -307,6 +336,15 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
|||
struct wlr_xwayland_surface *xsurface = data;
|
||||
struct sway_view *view = &xwayland_view->view;
|
||||
|
||||
if (xsurface->override_redirect) {
|
||||
// This window used not to have the override redirect flag and has it
|
||||
// now. Switch to unmanaged.
|
||||
handle_destroy(&xwayland_view->destroy, view);
|
||||
struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface);
|
||||
unmanaged_handle_map(&unmanaged->map, xsurface);
|
||||
return;
|
||||
}
|
||||
|
||||
view->natural_width = xsurface->width;
|
||||
view->natural_height = xsurface->height;
|
||||
|
||||
|
|
@ -321,31 +359,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);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_view *xwayland_view =
|
||||
wl_container_of(listener, xwayland_view, destroy);
|
||||
struct sway_view *view = &xwayland_view->view;
|
||||
|
||||
if (view->surface) {
|
||||
view_unmap(view);
|
||||
wl_list_remove(&xwayland_view->commit.link);
|
||||
}
|
||||
|
||||
wl_list_remove(&xwayland_view->destroy.link);
|
||||
wl_list_remove(&xwayland_view->request_configure.link);
|
||||
wl_list_remove(&xwayland_view->request_fullscreen.link);
|
||||
wl_list_remove(&xwayland_view->set_title.link);
|
||||
wl_list_remove(&xwayland_view->set_class.link);
|
||||
wl_list_remove(&xwayland_view->set_window_type.link);
|
||||
wl_list_remove(&xwayland_view->map.link);
|
||||
wl_list_remove(&xwayland_view->unmap.link);
|
||||
view_destroy(&xwayland_view->view);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
static void handle_request_configure(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -379,8 +397,40 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
|
|||
}
|
||||
view_set_fullscreen(view, xsurface->fullscreen);
|
||||
|
||||
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
|
||||
arrange_and_commit(ws);
|
||||
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
|
||||
arrange_windows(output);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
static void handle_request_move(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_view *xwayland_view =
|
||||
wl_container_of(listener, xwayland_view, request_move);
|
||||
struct sway_view *view = &xwayland_view->view;
|
||||
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
|
||||
if (!xsurface->mapped) {
|
||||
return;
|
||||
}
|
||||
if (!container_is_floating(view->swayc)) {
|
||||
return;
|
||||
}
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
seat_begin_move(seat, view->swayc, seat->last_button);
|
||||
}
|
||||
|
||||
static void handle_request_resize(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_view *xwayland_view =
|
||||
wl_container_of(listener, xwayland_view, request_resize);
|
||||
struct sway_view *view = &xwayland_view->view;
|
||||
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
|
||||
if (!xsurface->mapped) {
|
||||
return;
|
||||
}
|
||||
if (!container_is_floating(view->swayc)) {
|
||||
return;
|
||||
}
|
||||
struct wlr_xwayland_resize_event *e = data;
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
|
||||
}
|
||||
|
||||
static void handle_set_title(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -417,6 +467,25 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) {
|
|||
view_execute_criteria(view);
|
||||
}
|
||||
|
||||
static void handle_set_hints(struct wl_listener *listener, void *data) {
|
||||
struct sway_xwayland_view *xwayland_view =
|
||||
wl_container_of(listener, xwayland_view, set_hints);
|
||||
struct sway_view *view = &xwayland_view->view;
|
||||
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
|
||||
if (!xsurface->mapped) {
|
||||
return;
|
||||
}
|
||||
if (!xsurface->hints_urgency && view->urgent_timer) {
|
||||
// The view is is in the timeout period. We'll ignore the request to
|
||||
// unset urgency so that the view remains urgent until the timer clears
|
||||
// it.
|
||||
return;
|
||||
}
|
||||
if (view->allow_request_urgent) {
|
||||
view_set_urgent(view, (bool)xsurface->hints_urgency);
|
||||
}
|
||||
}
|
||||
|
||||
struct sway_view *view_from_wlr_xwayland_surface(
|
||||
struct wlr_xwayland_surface *xsurface) {
|
||||
return xsurface->data;
|
||||
|
|
@ -427,14 +496,13 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
|
|||
xwayland_surface);
|
||||
struct wlr_xwayland_surface *xsurface = data;
|
||||
|
||||
if (wlr_xwayland_surface_is_unmanaged(xsurface) ||
|
||||
xsurface->override_redirect) {
|
||||
wlr_log(L_DEBUG, "New xwayland unmanaged surface");
|
||||
if (xsurface->override_redirect) {
|
||||
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 =
|
||||
|
|
@ -457,6 +525,14 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
|
|||
&xwayland_view->request_fullscreen);
|
||||
xwayland_view->request_fullscreen.notify = handle_request_fullscreen;
|
||||
|
||||
wl_signal_add(&xsurface->events.request_move,
|
||||
&xwayland_view->request_move);
|
||||
xwayland_view->request_move.notify = handle_request_move;
|
||||
|
||||
wl_signal_add(&xsurface->events.request_resize,
|
||||
&xwayland_view->request_resize);
|
||||
xwayland_view->request_resize.notify = handle_request_resize;
|
||||
|
||||
wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title);
|
||||
xwayland_view->set_title.notify = handle_set_title;
|
||||
|
||||
|
|
@ -467,6 +543,9 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
|
|||
&xwayland_view->set_window_type);
|
||||
xwayland_view->set_window_type.notify = handle_set_window_type;
|
||||
|
||||
wl_signal_add(&xsurface->events.set_hints, &xwayland_view->set_hints);
|
||||
xwayland_view->set_hints.notify = handle_set_hints;
|
||||
|
||||
wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap);
|
||||
xwayland_view->unmap.notify = handle_unmap;
|
||||
|
||||
|
|
@ -484,7 +563,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;
|
||||
}
|
||||
|
||||
|
|
@ -503,7 +582,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;
|
||||
|
|
|
|||
|
|
@ -5,14 +5,19 @@
|
|||
#elif __FreeBSD__
|
||||
#include <dev/evdev/input-event-codes.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "sway/desktop.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/keyboard.h"
|
||||
#include "sway/layers.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "wlr-layer-shell-unstable-v1-protocol.h"
|
||||
|
|
@ -126,7 +131,7 @@ static struct sway_container *container_at_coords(
|
|||
return ws;
|
||||
}
|
||||
|
||||
c = seat_get_focus_inactive(seat, output->swayc);
|
||||
c = seat_get_active_child(seat, output->swayc);
|
||||
if (c) {
|
||||
return c;
|
||||
}
|
||||
|
|
@ -138,6 +143,171 @@ static struct sway_container *container_at_coords(
|
|||
return output->swayc;
|
||||
}
|
||||
|
||||
static enum wlr_edges find_resize_edge(struct sway_container *cont,
|
||||
struct sway_cursor *cursor) {
|
||||
if (cont->type != C_VIEW) {
|
||||
return WLR_EDGE_NONE;
|
||||
}
|
||||
struct sway_view *view = cont->sway_view;
|
||||
if (view->border == B_NONE || !view->border_thickness || view->using_csd) {
|
||||
return WLR_EDGE_NONE;
|
||||
}
|
||||
|
||||
enum wlr_edges edge = 0;
|
||||
if (cursor->cursor->x < cont->x + view->border_thickness) {
|
||||
edge |= WLR_EDGE_LEFT;
|
||||
}
|
||||
if (cursor->cursor->y < cont->y + view->border_thickness) {
|
||||
edge |= WLR_EDGE_TOP;
|
||||
}
|
||||
if (cursor->cursor->x >= cont->x + cont->width - view->border_thickness) {
|
||||
edge |= WLR_EDGE_RIGHT;
|
||||
}
|
||||
if (cursor->cursor->y >= cont->y + cont->height - view->border_thickness) {
|
||||
edge |= WLR_EDGE_BOTTOM;
|
||||
}
|
||||
return edge;
|
||||
}
|
||||
|
||||
static void handle_move_motion(struct sway_seat *seat,
|
||||
struct sway_cursor *cursor) {
|
||||
struct sway_container *con = seat->op_container;
|
||||
desktop_damage_whole_container(con);
|
||||
container_floating_translate(con,
|
||||
cursor->cursor->x - cursor->previous.x,
|
||||
cursor->cursor->y - cursor->previous.y);
|
||||
desktop_damage_whole_container(con);
|
||||
}
|
||||
|
||||
static void calculate_floating_constraints(struct sway_container *con,
|
||||
int *min_width, int *max_width, int *min_height, int *max_height) {
|
||||
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 void handle_resize_motion(struct sway_seat *seat,
|
||||
struct sway_cursor *cursor) {
|
||||
struct sway_container *con = seat->op_container;
|
||||
enum wlr_edges edge = seat->op_resize_edge;
|
||||
|
||||
// The amount the mouse has moved since the start of the resize operation
|
||||
// Positive is down/right
|
||||
double mouse_move_x = cursor->cursor->x - seat->op_ref_lx;
|
||||
double mouse_move_y = cursor->cursor->y - seat->op_ref_ly;
|
||||
|
||||
if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) {
|
||||
mouse_move_x = 0;
|
||||
}
|
||||
if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) {
|
||||
mouse_move_y = 0;
|
||||
}
|
||||
|
||||
double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x;
|
||||
double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y;
|
||||
|
||||
if (seat->op_resize_preserve_ratio) {
|
||||
double x_multiplier = grow_width / seat->op_ref_width;
|
||||
double y_multiplier = grow_height / seat->op_ref_height;
|
||||
double max_multiplier = fmax(x_multiplier, y_multiplier);
|
||||
grow_width = seat->op_ref_width * max_multiplier;
|
||||
grow_height = seat->op_ref_height * max_multiplier;
|
||||
}
|
||||
|
||||
// Determine new width/height, and accommodate for floating min/max values
|
||||
double width = seat->op_ref_width + grow_width;
|
||||
double height = seat->op_ref_height + grow_height;
|
||||
int min_width, max_width, min_height, max_height;
|
||||
calculate_floating_constraints(con, &min_width, &max_width,
|
||||
&min_height, &max_height);
|
||||
width = fmax(min_width, fmin(width, max_width));
|
||||
height = fmax(min_height, fmin(height, max_height));
|
||||
|
||||
// Apply the view's min/max size
|
||||
if (con->type == C_VIEW) {
|
||||
double view_min_width, view_max_width, view_min_height, view_max_height;
|
||||
view_get_constraints(con->sway_view, &view_min_width, &view_max_width,
|
||||
&view_min_height, &view_max_height);
|
||||
width = fmax(view_min_width, fmin(width, view_max_width));
|
||||
height = fmax(view_min_height, fmin(height, view_max_height));
|
||||
}
|
||||
|
||||
// Recalculate these, in case we hit a min/max limit
|
||||
grow_width = width - seat->op_ref_width;
|
||||
grow_height = height - seat->op_ref_height;
|
||||
|
||||
// Determine grow x/y values - these are relative to the container's x/y at
|
||||
// the start of the resize operation.
|
||||
double grow_x = 0, grow_y = 0;
|
||||
if (edge & WLR_EDGE_LEFT) {
|
||||
grow_x = -grow_width;
|
||||
} else if (edge & WLR_EDGE_RIGHT) {
|
||||
grow_x = 0;
|
||||
} else {
|
||||
grow_x = -grow_width / 2;
|
||||
}
|
||||
if (edge & WLR_EDGE_TOP) {
|
||||
grow_y = -grow_height;
|
||||
} else if (edge & WLR_EDGE_BOTTOM) {
|
||||
grow_y = 0;
|
||||
} else {
|
||||
grow_y = -grow_height / 2;
|
||||
}
|
||||
|
||||
// Determine the amounts we need to bump everything relative to the current
|
||||
// size.
|
||||
int relative_grow_width = width - con->width;
|
||||
int relative_grow_height = height - con->height;
|
||||
int relative_grow_x = (seat->op_ref_con_lx + grow_x) - con->x;
|
||||
int relative_grow_y = (seat->op_ref_con_ly + grow_y) - con->y;
|
||||
|
||||
// Actually resize stuff
|
||||
con->x += relative_grow_x;
|
||||
con->y += relative_grow_y;
|
||||
con->width += relative_grow_width;
|
||||
con->height += relative_grow_height;
|
||||
|
||||
if (con->type == C_VIEW) {
|
||||
struct sway_view *view = con->sway_view;
|
||||
view->x += relative_grow_x;
|
||||
view->y += relative_grow_y;
|
||||
view->width += relative_grow_width;
|
||||
view->height += relative_grow_height;
|
||||
}
|
||||
|
||||
arrange_windows(con);
|
||||
}
|
||||
|
||||
void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
|
||||
bool allow_refocusing) {
|
||||
if (time_msec == 0) {
|
||||
|
|
@ -145,6 +315,18 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
|
|||
}
|
||||
|
||||
struct sway_seat *seat = cursor->seat;
|
||||
|
||||
if (seat->operation != OP_NONE) {
|
||||
if (seat->operation == OP_MOVE) {
|
||||
handle_move_motion(seat, cursor);
|
||||
} else {
|
||||
handle_resize_motion(seat, cursor);
|
||||
}
|
||||
cursor->previous.x = cursor->cursor->x;
|
||||
cursor->previous.y = cursor->cursor->y;
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_seat *wlr_seat = seat->wlr_seat;
|
||||
struct wlr_surface *surface = NULL;
|
||||
double sx, sy;
|
||||
|
|
@ -193,15 +375,21 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
|
|||
}
|
||||
}
|
||||
|
||||
// reset cursor if switching between clients
|
||||
struct wl_client *client = NULL;
|
||||
if (surface != NULL) {
|
||||
client = wl_resource_get_client(surface->resource);
|
||||
}
|
||||
if (client != cursor->image_client) {
|
||||
wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
|
||||
"left_ptr", cursor->cursor);
|
||||
cursor->image_client = client;
|
||||
// Handle cursor image
|
||||
if (surface) {
|
||||
// Reset cursor if switching between clients
|
||||
struct wl_client *client = wl_resource_get_client(surface->resource);
|
||||
if (client != cursor->image_client) {
|
||||
cursor_set_image(cursor, "left_ptr", client);
|
||||
}
|
||||
} else if (c && container_is_floating(c)) {
|
||||
// Try a floating container's resize edge
|
||||
enum wlr_edges edge = find_resize_edge(c, cursor);
|
||||
const char *image = edge == WLR_EDGE_NONE ?
|
||||
"left_ptr" : wlr_xcursor_get_resize_name(edge);
|
||||
cursor_set_image(cursor, image, NULL);
|
||||
} else {
|
||||
cursor_set_image(cursor, "left_ptr", NULL);
|
||||
}
|
||||
|
||||
// send pointer enter/leave
|
||||
|
|
@ -228,6 +416,7 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
|
|||
wlr_cursor_move(cursor->cursor, event->device,
|
||||
event->delta_x, event->delta_y);
|
||||
cursor_send_pointer_motion(cursor, event->time_msec, true);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
static void handle_cursor_motion_absolute(
|
||||
|
|
@ -238,10 +427,56 @@ static void handle_cursor_motion_absolute(
|
|||
struct wlr_event_pointer_motion_absolute *event = data;
|
||||
wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y);
|
||||
cursor_send_pointer_motion(cursor, event->time_msec, true);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
static void dispatch_cursor_button_floating(struct sway_cursor *cursor,
|
||||
uint32_t time_msec, uint32_t button, enum wlr_button_state state,
|
||||
struct wlr_surface *surface, double sx, double sy,
|
||||
struct sway_container *cont) {
|
||||
struct sway_seat *seat = cursor->seat;
|
||||
|
||||
// Deny moving or resizing a fullscreen view
|
||||
if (cont->type == C_VIEW && cont->sway_view->is_fullscreen) {
|
||||
seat_pointer_notify_button(seat, time_msec, button, state);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
||||
bool mod_pressed = keyboard &&
|
||||
(wlr_keyboard_get_modifiers(keyboard) & config->floating_mod);
|
||||
enum wlr_edges edge = find_resize_edge(cont, cursor);
|
||||
bool over_title = edge == WLR_EDGE_NONE && !surface;
|
||||
|
||||
// Check for beginning move
|
||||
if (button == BTN_LEFT && state == WLR_BUTTON_PRESSED &&
|
||||
(mod_pressed || over_title)) {
|
||||
seat_begin_move(seat, cont, BTN_LEFT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for beginning resize
|
||||
bool resizing_via_border = button == BTN_LEFT && edge != WLR_EDGE_NONE;
|
||||
bool resizing_via_mod = button == BTN_RIGHT && mod_pressed;
|
||||
if ((resizing_via_border || resizing_via_mod) &&
|
||||
state == WLR_BUTTON_PRESSED) {
|
||||
seat_begin_resize(seat, cont, button, edge);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send event to surface
|
||||
seat_set_focus(seat, cont);
|
||||
seat_pointer_notify_button(seat, time_msec, button, state);
|
||||
}
|
||||
|
||||
void dispatch_cursor_button(struct sway_cursor *cursor,
|
||||
uint32_t time_msec, uint32_t button, enum wlr_button_state state) {
|
||||
if (cursor->seat->operation != OP_NONE &&
|
||||
button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) {
|
||||
seat_end_mouse_operation(cursor->seat);
|
||||
seat_pointer_notify_button(cursor->seat, time_msec, button, state);
|
||||
return;
|
||||
}
|
||||
if (time_msec == 0) {
|
||||
time_msec = get_current_time_msec();
|
||||
}
|
||||
|
|
@ -255,14 +490,16 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
|
|||
wlr_layer_surface_from_wlr_surface(surface);
|
||||
if (layer->current.keyboard_interactive) {
|
||||
seat_set_focus_layer(cursor->seat, layer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Avoid moving keyboard focus from a surface that accepts it to one
|
||||
// that does not unless the change would move us to a new workspace.
|
||||
//
|
||||
// This prevents, for example, losing focus when clicking on swaybar.
|
||||
if (surface && cont && cont->type != C_VIEW) {
|
||||
seat_pointer_notify_button(cursor->seat, time_msec, button, state);
|
||||
} else if (cont && container_is_floating(cont)) {
|
||||
dispatch_cursor_button_floating(cursor, time_msec, button, state,
|
||||
surface, sx, sy, cont);
|
||||
} else if (surface && cont && cont->type != C_VIEW) {
|
||||
// Avoid moving keyboard focus from a surface that accepts it to one
|
||||
// that does not unless the change would move us to a new workspace.
|
||||
//
|
||||
// This prevents, for example, losing focus when clicking on swaybar.
|
||||
struct sway_container *new_ws = cont;
|
||||
if (new_ws && new_ws->type != C_WORKSPACE) {
|
||||
new_ws = container_parent(new_ws, C_WORKSPACE);
|
||||
|
|
@ -274,12 +511,15 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
|
|||
if (new_ws != old_ws) {
|
||||
seat_set_focus(cursor->seat, cont);
|
||||
}
|
||||
seat_pointer_notify_button(cursor->seat, time_msec, button, state);
|
||||
} else if (cont) {
|
||||
seat_set_focus(cursor->seat, cont);
|
||||
seat_pointer_notify_button(cursor->seat, time_msec, button, state);
|
||||
} else {
|
||||
seat_pointer_notify_button(cursor->seat, time_msec, button, state);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
@ -425,6 +665,7 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
|
|||
|
||||
wlr_cursor_warp_absolute(cursor->cursor, event->device, x, y);
|
||||
cursor_send_pointer_motion(cursor, event->time_msec, true);
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
static void handle_tool_tip(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -464,6 +705,9 @@ static void handle_request_set_cursor(struct wl_listener *listener,
|
|||
void *data) {
|
||||
struct sway_cursor *cursor =
|
||||
wl_container_of(listener, cursor, request_set_cursor);
|
||||
if (cursor->seat->operation != OP_NONE) {
|
||||
return;
|
||||
}
|
||||
struct wlr_seat_pointer_request_set_cursor_event *event = data;
|
||||
|
||||
struct wl_client *focused_client = NULL;
|
||||
|
|
@ -476,15 +720,26 @@ 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;
|
||||
}
|
||||
|
||||
wlr_cursor_set_surface(cursor->cursor, event->surface, event->hotspot_x,
|
||||
event->hotspot_y);
|
||||
cursor->image = NULL;
|
||||
cursor->image_client = focused_client;
|
||||
}
|
||||
|
||||
void cursor_set_image(struct sway_cursor *cursor, const char *image,
|
||||
struct wl_client *client) {
|
||||
if (!cursor->image || strcmp(cursor->image, image) != 0) {
|
||||
wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image,
|
||||
cursor->cursor);
|
||||
cursor->image = image;
|
||||
}
|
||||
cursor->image_client = client;
|
||||
}
|
||||
|
||||
void sway_cursor_destroy(struct sway_cursor *cursor) {
|
||||
if (!cursor) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ static char *get_device_identifier(struct wlr_input_device *device) {
|
|||
int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1;
|
||||
char *identifier = malloc(len);
|
||||
if (!identifier) {
|
||||
wlr_log(L_ERROR, "Unable to allocate unique input device name");
|
||||
wlr_log(WLR_ERROR, "Unable to allocate unique input device name");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -104,77 +104,89 @@ static void input_manager_libinput_config_pointer(
|
|||
}
|
||||
|
||||
libinput_device = wlr_libinput_get_device_handle(wlr_device);
|
||||
wlr_log(L_DEBUG, "input_manager_libinput_config_pointer(%s)",
|
||||
wlr_log(WLR_DEBUG, "input_manager_libinput_config_pointer(%s)",
|
||||
ic->identifier);
|
||||
|
||||
if (ic->accel_profile != INT_MIN) {
|
||||
wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)",
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)",
|
||||
ic->identifier, ic->accel_profile);
|
||||
libinput_device_config_accel_set_profile(libinput_device,
|
||||
ic->accel_profile);
|
||||
}
|
||||
if (ic->click_method != INT_MIN) {
|
||||
wlr_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)",
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)",
|
||||
ic->identifier, ic->click_method);
|
||||
libinput_device_config_click_set_method(libinput_device,
|
||||
ic->click_method);
|
||||
}
|
||||
if (ic->drag_lock != INT_MIN) {
|
||||
wlr_log(L_DEBUG,
|
||||
wlr_log(WLR_DEBUG,
|
||||
"libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
|
||||
ic->identifier, ic->click_method);
|
||||
libinput_device_config_tap_set_drag_lock_enabled(libinput_device,
|
||||
ic->drag_lock);
|
||||
}
|
||||
if (ic->dwt != INT_MIN) {
|
||||
wlr_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)",
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)",
|
||||
ic->identifier, ic->dwt);
|
||||
libinput_device_config_dwt_set_enabled(libinput_device, ic->dwt);
|
||||
}
|
||||
if (ic->left_handed != INT_MIN) {
|
||||
wlr_log(L_DEBUG,
|
||||
wlr_log(WLR_DEBUG,
|
||||
"libinput_config_pointer(%s) left_handed_set_enabled(%d)",
|
||||
ic->identifier, ic->left_handed);
|
||||
libinput_device_config_left_handed_set(libinput_device,
|
||||
ic->left_handed);
|
||||
}
|
||||
if (ic->middle_emulation != INT_MIN) {
|
||||
wlr_log(L_DEBUG,
|
||||
wlr_log(WLR_DEBUG,
|
||||
"libinput_config_pointer(%s) middle_emulation_set_enabled(%d)",
|
||||
ic->identifier, ic->middle_emulation);
|
||||
libinput_device_config_middle_emulation_set_enabled(libinput_device,
|
||||
ic->middle_emulation);
|
||||
}
|
||||
if (ic->natural_scroll != INT_MIN) {
|
||||
wlr_log(L_DEBUG,
|
||||
wlr_log(WLR_DEBUG,
|
||||
"libinput_config_pointer(%s) natural_scroll_set_enabled(%d)",
|
||||
ic->identifier, ic->natural_scroll);
|
||||
libinput_device_config_scroll_set_natural_scroll_enabled(
|
||||
libinput_device, ic->natural_scroll);
|
||||
}
|
||||
if (ic->pointer_accel != FLT_MIN) {
|
||||
wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)",
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)",
|
||||
ic->identifier, ic->pointer_accel);
|
||||
libinput_device_config_accel_set_speed(libinput_device,
|
||||
ic->pointer_accel);
|
||||
}
|
||||
if (ic->scroll_button != INT_MIN) {
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) scroll_set_button(%d)",
|
||||
ic->identifier, ic->scroll_button);
|
||||
libinput_device_config_scroll_set_button(libinput_device,
|
||||
ic->scroll_button);
|
||||
}
|
||||
if (ic->scroll_method != INT_MIN) {
|
||||
wlr_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)",
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)",
|
||||
ic->identifier, ic->scroll_method);
|
||||
libinput_device_config_scroll_set_method(libinput_device,
|
||||
ic->scroll_method);
|
||||
}
|
||||
if (ic->send_events != INT_MIN) {
|
||||
wlr_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)",
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)",
|
||||
ic->identifier, ic->send_events);
|
||||
libinput_device_config_send_events_set_mode(libinput_device,
|
||||
ic->send_events);
|
||||
}
|
||||
if (ic->tap != INT_MIN) {
|
||||
wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)",
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)",
|
||||
ic->identifier, ic->tap);
|
||||
libinput_device_config_tap_set_enabled(libinput_device, ic->tap);
|
||||
}
|
||||
if (ic->tap_button_map != INT_MIN) {
|
||||
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_button_map(%d)",
|
||||
ic->identifier, ic->tap);
|
||||
libinput_device_config_tap_set_button_map(libinput_device,
|
||||
ic->tap_button_map);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_device_destroy(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -187,7 +199,7 @@ static void handle_device_destroy(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "removing device: '%s'",
|
||||
wlr_log(WLR_DEBUG, "removing device: '%s'",
|
||||
input_device->identifier);
|
||||
|
||||
struct sway_seat *seat = NULL;
|
||||
|
|
@ -217,16 +229,19 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
|
|||
input_device->identifier = get_device_identifier(device);
|
||||
wl_list_insert(&input->devices, &input_device->link);
|
||||
|
||||
wlr_log(L_DEBUG, "adding device: '%s'",
|
||||
wlr_log(WLR_DEBUG, "adding device: '%s'",
|
||||
input_device->identifier);
|
||||
|
||||
if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
|
||||
input_manager_libinput_config_pointer(input_device);
|
||||
}
|
||||
|
||||
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
|
||||
input_device->device_destroy.notify = handle_device_destroy;
|
||||
|
||||
struct sway_seat *seat = NULL;
|
||||
if (!input_has_seat_configuration(input)) {
|
||||
wlr_log(L_DEBUG, "no seat configuration, using default seat");
|
||||
wlr_log(WLR_DEBUG, "no seat configuration, using default seat");
|
||||
seat = input_manager_get_seat(input, default_seat);
|
||||
seat_add_device(seat, input_device);
|
||||
return;
|
||||
|
|
@ -256,13 +271,10 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
|
||||
if (!added) {
|
||||
wlr_log(L_DEBUG,
|
||||
wlr_log(WLR_DEBUG,
|
||||
"device '%s' is not configured on any seats",
|
||||
input_device->identifier);
|
||||
}
|
||||
|
||||
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
|
||||
input_device->device_destroy.notify = handle_device_destroy;
|
||||
}
|
||||
|
||||
static void handle_inhibit_activate(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -282,7 +294,7 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
|
|||
seat_set_exclusive_client(seat, NULL);
|
||||
struct sway_container *previous = seat_get_focus(seat);
|
||||
if (previous) {
|
||||
wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous,
|
||||
wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous,
|
||||
container_type_to_str(previous->type), previous->name);
|
||||
// Hack to get seat to re-focus the return value of get_focus
|
||||
seat_set_focus(seat, previous->parent);
|
||||
|
|
@ -359,7 +371,7 @@ void input_manager_apply_input_config(struct sway_input_manager *input,
|
|||
|
||||
void input_manager_apply_seat_config(struct sway_input_manager *input,
|
||||
struct seat_config *seat_config) {
|
||||
wlr_log(L_DEBUG, "applying new seat config for seat %s",
|
||||
wlr_log(WLR_DEBUG, "applying new seat config for seat %s",
|
||||
seat_config->name);
|
||||
struct sway_seat *seat = input_manager_get_seat(input, seat_config->name);
|
||||
if (!seat) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <wlr/backend/multi.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/input/keyboard.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
|
|
@ -108,7 +109,7 @@ static void get_active_binding(const struct sway_shortcut_state *state,
|
|||
}
|
||||
|
||||
if (*current_binding && *current_binding != binding) {
|
||||
wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d",
|
||||
wlr_log(WLR_DEBUG, "encountered duplicate bindings %d and %d",
|
||||
(*current_binding)->order, binding->order);
|
||||
} else {
|
||||
*current_binding = binding;
|
||||
|
|
@ -122,12 +123,13 @@ static void get_active_binding(const struct sway_shortcut_state *state,
|
|||
*/
|
||||
static void keyboard_execute_command(struct sway_keyboard *keyboard,
|
||||
struct sway_binding *binding) {
|
||||
wlr_log(L_DEBUG, "running command for binding: %s",
|
||||
wlr_log(WLR_DEBUG, "running command for binding: %s",
|
||||
binding->command);
|
||||
config->handler_context.seat = keyboard->seat_device->sway_seat;
|
||||
struct cmd_results *results = execute_command(binding->command, NULL);
|
||||
transaction_commit_dirty();
|
||||
if (results->status != CMD_SUCCESS) {
|
||||
wlr_log(L_DEBUG, "could not run command for binding: %s (%s)",
|
||||
wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
|
||||
binding->command, results->error);
|
||||
}
|
||||
free_cmd_results(results);
|
||||
|
|
@ -386,7 +388,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
|
|||
xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
if (!keymap) {
|
||||
wlr_log(L_DEBUG, "cannot configure keyboard: keymap does not exist");
|
||||
wlr_log(WLR_DEBUG, "cannot configure keyboard: keymap does not exist");
|
||||
xkb_context_unref(context);
|
||||
return;
|
||||
}
|
||||
|
|
@ -420,6 +422,9 @@ void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
|
|||
if (!keyboard) {
|
||||
return;
|
||||
}
|
||||
if (keyboard->keymap) {
|
||||
xkb_keymap_unref(keyboard->keymap);
|
||||
}
|
||||
wl_list_remove(&keyboard->keyboard_key.link);
|
||||
wl_list_remove(&keyboard->keyboard_modifiers.link);
|
||||
free(keyboard);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
#define _XOPEN_SOURCE 700
|
||||
#define _POSIX_C_SOURCE 199309L
|
||||
#include <assert.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/input-event-codes.h>
|
||||
#elif __FreeBSD__
|
||||
#include <dev/evdev/input-event-codes.h>
|
||||
#endif
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
|
|
@ -75,7 +80,7 @@ static void seat_send_activate(struct sway_container *con,
|
|||
struct sway_seat *seat) {
|
||||
if (con->type == C_VIEW) {
|
||||
if (!seat_is_input_allowed(seat, con->sway_view->surface)) {
|
||||
wlr_log(L_DEBUG, "Refusing to set focus, input is inhibited");
|
||||
wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited");
|
||||
return;
|
||||
}
|
||||
view_set_activated(con->sway_view, true);
|
||||
|
|
@ -219,7 +224,7 @@ static struct sway_seat_container *seat_container_from_container(
|
|||
|
||||
seat_con = calloc(1, sizeof(struct sway_seat_container));
|
||||
if (seat_con == NULL) {
|
||||
wlr_log(L_ERROR, "could not allocate seat container");
|
||||
wlr_log(WLR_ERROR, "could not allocate seat container");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -301,7 +306,7 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct sway_drag_icon *icon = calloc(1, sizeof(struct sway_drag_icon));
|
||||
if (icon == NULL) {
|
||||
wlr_log(L_ERROR, "Allocation failed");
|
||||
wlr_log(WLR_ERROR, "Allocation failed");
|
||||
return;
|
||||
}
|
||||
icon->seat = seat;
|
||||
|
|
@ -348,6 +353,7 @@ struct sway_seat *seat_create(struct sway_input_manager *input,
|
|||
free(seat);
|
||||
return NULL;
|
||||
}
|
||||
seat->wlr_seat->data = seat;
|
||||
|
||||
seat->cursor = sway_cursor_create(seat);
|
||||
if (!seat->cursor) {
|
||||
|
|
@ -391,7 +397,7 @@ static void seat_apply_input_config(struct sway_seat *seat,
|
|||
struct input_config *ic = input_device_get_config(
|
||||
sway_device->input_device);
|
||||
if (ic != NULL) {
|
||||
wlr_log(L_DEBUG, "Applying input config to %s",
|
||||
wlr_log(WLR_DEBUG, "Applying input config to %s",
|
||||
sway_device->input_device->identifier);
|
||||
|
||||
mapped_to_output = ic->mapped_to_output;
|
||||
|
|
@ -401,7 +407,7 @@ static void seat_apply_input_config(struct sway_seat *seat,
|
|||
mapped_to_output = sway_device->input_device->wlr_device->output_name;
|
||||
}
|
||||
if (mapped_to_output != NULL) {
|
||||
wlr_log(L_DEBUG, "Mapping input device %s to output %s",
|
||||
wlr_log(WLR_DEBUG, "Mapping input device %s to output %s",
|
||||
sway_device->input_device->identifier, mapped_to_output);
|
||||
struct sway_container *output = NULL;
|
||||
for (int i = 0; i < root_container.children->length; ++i) {
|
||||
|
|
@ -415,7 +421,7 @@ static void seat_apply_input_config(struct sway_seat *seat,
|
|||
wlr_cursor_map_input_to_output(seat->cursor->cursor,
|
||||
sway_device->input_device->wlr_device,
|
||||
output->sway_output->wlr_output);
|
||||
wlr_log(L_DEBUG, "Mapped to output %s", output->name);
|
||||
wlr_log(WLR_DEBUG, "Mapped to output %s", output->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -495,7 +501,7 @@ void seat_configure_device(struct sway_seat *seat,
|
|||
seat_configure_tablet_tool(seat, seat_device);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_PAD:
|
||||
wlr_log(L_DEBUG, "TODO: configure tablet pad");
|
||||
wlr_log(WLR_DEBUG, "TODO: configure tablet pad");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -510,11 +516,11 @@ void seat_add_device(struct sway_seat *seat,
|
|||
struct sway_seat_device *seat_device =
|
||||
calloc(1, sizeof(struct sway_seat_device));
|
||||
if (!seat_device) {
|
||||
wlr_log(L_DEBUG, "could not allocate seat device");
|
||||
wlr_log(WLR_DEBUG, "could not allocate seat device");
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "adding device %s to seat %s",
|
||||
wlr_log(WLR_DEBUG, "adding device %s to seat %s",
|
||||
input_device->identifier, seat->wlr_seat->name);
|
||||
|
||||
seat_device->sway_seat = seat;
|
||||
|
|
@ -533,7 +539,7 @@ void seat_remove_device(struct sway_seat *seat,
|
|||
return;
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "removing device %s from seat %s",
|
||||
wlr_log(WLR_DEBUG, "removing device %s from seat %s",
|
||||
input_device->identifier, seat->wlr_seat->name);
|
||||
|
||||
seat_device_destroy(seat_device);
|
||||
|
|
@ -594,6 +600,12 @@ static void seat_send_unfocus(struct sway_container *container,
|
|||
}
|
||||
}
|
||||
|
||||
static int handle_urgent_timeout(void *data) {
|
||||
struct sway_view *view = data;
|
||||
view_set_urgent(view, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void seat_set_focus_warp(struct sway_seat *seat,
|
||||
struct sway_container *container, bool warp) {
|
||||
if (seat->focused_layer) {
|
||||
|
|
@ -616,6 +628,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
|
|||
|
||||
if (last_workspace && last_workspace == new_workspace
|
||||
&& last_workspace->sway_workspace->fullscreen
|
||||
&& container && container->type == C_VIEW
|
||||
&& !container->sway_view->is_fullscreen) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -649,6 +662,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
|
|||
while (parent) {
|
||||
wl_list_remove(&parent->link);
|
||||
wl_list_insert(&seat->focus_stack, &parent->link);
|
||||
container_set_dirty(parent->container);
|
||||
|
||||
parent =
|
||||
seat_container_from_container(seat,
|
||||
|
|
@ -661,9 +675,39 @@ void seat_set_focus_warp(struct sway_seat *seat,
|
|||
if (last_focus) {
|
||||
seat_send_unfocus(last_focus, seat);
|
||||
}
|
||||
|
||||
seat_send_focus(container, seat);
|
||||
container_damage_whole(container);
|
||||
|
||||
container_set_dirty(container);
|
||||
container_set_dirty(container->parent); // for focused_inactive_child
|
||||
if (last_focus) {
|
||||
container_set_dirty(last_focus);
|
||||
}
|
||||
}
|
||||
|
||||
// If urgent, either unset the urgency or start a timer to unset it
|
||||
if (container && container->type == C_VIEW &&
|
||||
view_is_urgent(container->sway_view) &&
|
||||
!container->sway_view->urgent_timer) {
|
||||
struct sway_view *view = container->sway_view;
|
||||
if (last_workspace && last_workspace != new_workspace &&
|
||||
config->urgent_timeout > 0) {
|
||||
view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop,
|
||||
handle_urgent_timeout, view);
|
||||
wl_event_source_timer_update(view->urgent_timer,
|
||||
config->urgent_timeout);
|
||||
} else {
|
||||
view_set_urgent(view, false);
|
||||
}
|
||||
}
|
||||
|
||||
// If we've focused a floating container, bring it to the front.
|
||||
// We do this by putting it at the end of the floating list.
|
||||
// This must happen for both the pending and current children lists.
|
||||
if (container && container_is_floating(container)) {
|
||||
list_move_to_end(container->parent->children, container);
|
||||
if (container_has_ancestor(container, container->current.parent)) {
|
||||
list_move_to_end(container->parent->current.children, container);
|
||||
}
|
||||
}
|
||||
|
||||
// clean up unfocused empty workspace on new output
|
||||
|
|
@ -707,11 +751,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
|
|||
}
|
||||
}
|
||||
|
||||
if (last_focus) {
|
||||
container_damage_whole(last_focus);
|
||||
}
|
||||
|
||||
if (last_workspace && last_workspace != new_workspace) {
|
||||
if (last_focus != NULL) {
|
||||
cursor_send_pointer_motion(seat->cursor, 0, true);
|
||||
}
|
||||
|
||||
|
|
@ -726,11 +766,11 @@ void seat_set_focus(struct sway_seat *seat,
|
|||
}
|
||||
|
||||
void seat_set_focus_surface(struct sway_seat *seat,
|
||||
struct wlr_surface *surface) {
|
||||
struct wlr_surface *surface, bool unfocus) {
|
||||
if (seat->focused_layer != NULL) {
|
||||
return;
|
||||
}
|
||||
if (seat->has_focus) {
|
||||
if (seat->has_focus && unfocus) {
|
||||
struct sway_container *focus = seat_get_focus(seat);
|
||||
seat_send_unfocus(focus, seat);
|
||||
seat->has_focus = false;
|
||||
|
|
@ -752,7 +792,7 @@ void seat_set_focus_layer(struct sway_seat *seat,
|
|||
struct sway_container *previous =
|
||||
seat_get_focus_inactive(seat, &root_container);
|
||||
if (previous) {
|
||||
wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous,
|
||||
wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous,
|
||||
container_type_to_str(previous->type), previous->name);
|
||||
// Hack to get seat to re-focus the return value of get_focus
|
||||
seat_set_focus(seat, previous->parent);
|
||||
|
|
@ -762,7 +802,7 @@ void seat_set_focus_layer(struct sway_seat *seat,
|
|||
} else if (!layer || seat->focused_layer == layer) {
|
||||
return;
|
||||
}
|
||||
seat_set_focus_surface(seat, layer->surface);
|
||||
seat_set_focus_surface(seat, layer->surface, true);
|
||||
if (layer->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
|
||||
seat->focused_layer = layer;
|
||||
}
|
||||
|
|
@ -830,18 +870,6 @@ struct sway_container *seat_get_active_child(struct sway_seat *seat,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_container *seat_get_active_current_child(struct sway_seat *seat,
|
||||
struct sway_container *container) {
|
||||
struct sway_container *child = seat_get_active_child(seat, container);
|
||||
if (child) {
|
||||
return child;
|
||||
}
|
||||
if (container->current.children->length == 1) {
|
||||
return container->current.children->items[0];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_container *seat_get_focus(struct sway_seat *seat) {
|
||||
if (!seat->has_focus) {
|
||||
return NULL;
|
||||
|
|
@ -873,3 +901,68 @@ struct seat_config *seat_get_config(struct sway_seat *seat) {
|
|||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
|
||||
uint32_t button) {
|
||||
if (!seat->cursor) {
|
||||
wlr_log(WLR_DEBUG, "Ignoring move request due to no cursor device");
|
||||
return;
|
||||
}
|
||||
seat->operation = OP_MOVE;
|
||||
seat->op_container = con;
|
||||
seat->op_button = button;
|
||||
cursor_set_image(seat->cursor, "grab", NULL);
|
||||
}
|
||||
|
||||
void seat_begin_resize(struct sway_seat *seat, struct sway_container *con,
|
||||
uint32_t button, enum wlr_edges edge) {
|
||||
if (!seat->cursor) {
|
||||
wlr_log(WLR_DEBUG, "Ignoring resize request due to no cursor device");
|
||||
return;
|
||||
}
|
||||
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
||||
seat->operation = OP_RESIZE;
|
||||
seat->op_container = con;
|
||||
seat->op_resize_preserve_ratio = keyboard &&
|
||||
(wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT);
|
||||
seat->op_resize_edge = edge == WLR_EDGE_NONE ?
|
||||
RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT : edge;
|
||||
seat->op_button = button;
|
||||
seat->op_ref_lx = seat->cursor->cursor->x;
|
||||
seat->op_ref_ly = seat->cursor->cursor->y;
|
||||
seat->op_ref_con_lx = con->x;
|
||||
seat->op_ref_con_ly = con->y;
|
||||
seat->op_ref_width = con->width;
|
||||
seat->op_ref_height = con->height;
|
||||
|
||||
const char *image = edge == WLR_EDGE_NONE ?
|
||||
"se-resize" : wlr_xcursor_get_resize_name(edge);
|
||||
cursor_set_image(seat->cursor, image, NULL);
|
||||
}
|
||||
|
||||
void seat_end_mouse_operation(struct sway_seat *seat) {
|
||||
switch (seat->operation) {
|
||||
case OP_MOVE:
|
||||
{
|
||||
// We "move" the container to its own location so it discovers its
|
||||
// output again.
|
||||
struct sway_container *con = seat->op_container;
|
||||
container_floating_move_to(con, con->x, con->y);
|
||||
}
|
||||
case OP_RESIZE:
|
||||
// Don't need to do anything here.
|
||||
break;
|
||||
case OP_NONE:
|
||||
break;
|
||||
}
|
||||
seat->operation = OP_NONE;
|
||||
seat->op_container = NULL;
|
||||
cursor_set_image(seat->cursor, "left_ptr", NULL);
|
||||
}
|
||||
|
||||
void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
|
||||
uint32_t button, enum wlr_button_state state) {
|
||||
seat->last_button = button;
|
||||
seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat,
|
||||
time_msec, button, state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "log.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/ipc-json.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
|
|
@ -41,6 +42,7 @@ json_object *ipc_json_get_version() {
|
|||
json_object_object_add(version, "major", json_object_new_int(major));
|
||||
json_object_object_add(version, "minor", json_object_new_int(minor));
|
||||
json_object_object_add(version, "patch", json_object_new_int(patch));
|
||||
json_object_object_add(version, "loaded_config_file_name", json_object_new_string(config->current_config_path));
|
||||
|
||||
return version;
|
||||
}
|
||||
|
|
@ -168,7 +170,8 @@ static void ipc_json_describe_workspace(struct sway_container *workspace,
|
|||
json_object_object_add(object, "output", workspace->parent ?
|
||||
json_object_new_string(workspace->parent->name) : NULL);
|
||||
json_object_object_add(object, "type", json_object_new_string("workspace"));
|
||||
json_object_object_add(object, "urgent", json_object_new_boolean(false));
|
||||
json_object_object_add(object, "urgent",
|
||||
json_object_new_boolean(workspace->sway_workspace->urgent));
|
||||
json_object_object_add(object, "representation", workspace->formatted_title ?
|
||||
json_object_new_string(workspace->formatted_title) : NULL);
|
||||
|
||||
|
|
@ -194,6 +197,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
|
|||
json_object_object_add(object, "layout",
|
||||
json_object_new_string(ipc_json_layout_description(c->layout)));
|
||||
}
|
||||
|
||||
bool urgent = c->type == C_VIEW ?
|
||||
view_is_urgent(c->sway_view) : container_has_urgent_child(c);
|
||||
json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
|
||||
}
|
||||
|
||||
static void focus_inactive_children_iterator(struct sway_container *c, void *data) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
#include <unistd.h>
|
||||
#include <wayland-server.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/ipc-json.h"
|
||||
#include "sway/ipc-server.h"
|
||||
#include "sway/output.h"
|
||||
|
|
@ -31,6 +33,7 @@ static int ipc_socket = -1;
|
|||
static struct wl_event_source *ipc_event_source = NULL;
|
||||
static struct sockaddr_un *ipc_sockaddr = NULL;
|
||||
static list_t *ipc_client_list = NULL;
|
||||
static struct wl_listener ipc_display_destroy;
|
||||
|
||||
static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
|
||||
|
||||
|
|
@ -56,6 +59,26 @@ void ipc_client_disconnect(struct ipc_client *client);
|
|||
void ipc_client_handle_command(struct ipc_client *client);
|
||||
bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
|
||||
|
||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
if (ipc_event_source) {
|
||||
wl_event_source_remove(ipc_event_source);
|
||||
}
|
||||
close(ipc_socket);
|
||||
unlink(ipc_sockaddr->sun_path);
|
||||
|
||||
while (ipc_client_list->length) {
|
||||
struct ipc_client *client = ipc_client_list->items[0];
|
||||
ipc_client_disconnect(client);
|
||||
}
|
||||
list_free(ipc_client_list);
|
||||
|
||||
if (ipc_sockaddr) {
|
||||
free(ipc_sockaddr);
|
||||
}
|
||||
|
||||
wl_list_remove(&ipc_display_destroy.link);
|
||||
}
|
||||
|
||||
void ipc_init(struct sway_server *server) {
|
||||
ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
|
||||
if (ipc_socket == -1) {
|
||||
|
|
@ -85,24 +108,13 @@ void ipc_init(struct sway_server *server) {
|
|||
|
||||
ipc_client_list = create_list();
|
||||
|
||||
ipc_display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(server->wl_display, &ipc_display_destroy);
|
||||
|
||||
ipc_event_source = wl_event_loop_add_fd(server->wl_event_loop, ipc_socket,
|
||||
WL_EVENT_READABLE, ipc_handle_connection, server);
|
||||
}
|
||||
|
||||
void ipc_terminate(void) {
|
||||
if (ipc_event_source) {
|
||||
wl_event_source_remove(ipc_event_source);
|
||||
}
|
||||
close(ipc_socket);
|
||||
unlink(ipc_sockaddr->sun_path);
|
||||
|
||||
list_free(ipc_client_list);
|
||||
|
||||
if (ipc_sockaddr) {
|
||||
free(ipc_sockaddr);
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_un *ipc_user_sockaddr(void) {
|
||||
struct sockaddr_un *ipc_sockaddr = malloc(sizeof(struct sockaddr_un));
|
||||
if (ipc_sockaddr == NULL) {
|
||||
|
|
@ -128,32 +140,32 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
|
|||
int ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
||||
(void) fd;
|
||||
struct sway_server *server = data;
|
||||
wlr_log(L_DEBUG, "Event on IPC listening socket");
|
||||
wlr_log(WLR_DEBUG, "Event on IPC listening socket");
|
||||
assert(mask == WL_EVENT_READABLE);
|
||||
|
||||
int client_fd = accept(ipc_socket, NULL, NULL);
|
||||
if (client_fd == -1) {
|
||||
wlr_log_errno(L_ERROR, "Unable to accept IPC client connection");
|
||||
wlr_log_errno(WLR_ERROR, "Unable to accept IPC client connection");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flags;
|
||||
if ((flags = fcntl(client_fd, F_GETFD)) == -1
|
||||
|| fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
|
||||
wlr_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket");
|
||||
wlr_log_errno(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
if ((flags = fcntl(client_fd, F_GETFL)) == -1
|
||||
|| fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) {
|
||||
wlr_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket");
|
||||
wlr_log_errno(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ipc_client *client = malloc(sizeof(struct ipc_client));
|
||||
if (!client) {
|
||||
wlr_log(L_ERROR, "Unable to allocate ipc client");
|
||||
wlr_log(WLR_ERROR, "Unable to allocate ipc client");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -169,12 +181,12 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
|||
client->write_buffer_len = 0;
|
||||
client->write_buffer = malloc(client->write_buffer_size);
|
||||
if (!client->write_buffer) {
|
||||
wlr_log(L_ERROR, "Unable to allocate ipc client write buffer");
|
||||
wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "New client: fd %d", client_fd);
|
||||
wlr_log(WLR_DEBUG, "New client: fd %d", client_fd);
|
||||
list_add(ipc_client_list, client);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -185,22 +197,22 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
|
|||
struct ipc_client *client = data;
|
||||
|
||||
if (mask & WL_EVENT_ERROR) {
|
||||
wlr_log(L_ERROR, "IPC Client socket error, removing client");
|
||||
wlr_log(WLR_ERROR, "IPC Client socket error, removing client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mask & WL_EVENT_HANGUP) {
|
||||
wlr_log(L_DEBUG, "Client %d hung up", client->fd);
|
||||
wlr_log(WLR_DEBUG, "Client %d hung up", client->fd);
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "Client %d readable", client->fd);
|
||||
wlr_log(WLR_DEBUG, "Client %d readable", client->fd);
|
||||
|
||||
int read_available;
|
||||
if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
|
||||
wlr_log_errno(L_INFO, "Unable to read IPC socket buffer size");
|
||||
wlr_log_errno(WLR_INFO, "Unable to read IPC socket buffer size");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -222,13 +234,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
|
|||
// Should be fully available, because read_available >= ipc_header_size
|
||||
ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
|
||||
if (received == -1) {
|
||||
wlr_log_errno(L_INFO, "Unable to receive header from IPC client");
|
||||
wlr_log_errno(WLR_INFO, "Unable to receive header from IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) {
|
||||
wlr_log(L_DEBUG, "IPC header check failed");
|
||||
wlr_log(WLR_DEBUG, "IPC header check failed");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -262,8 +274,11 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event)
|
|||
}
|
||||
client->current_command = event;
|
||||
if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) {
|
||||
wlr_log_errno(L_INFO, "Unable to send reply to IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
wlr_log_errno(WLR_INFO, "Unable to send reply to IPC client");
|
||||
/* ipc_send_reply destroys client on error, which also
|
||||
* removes it from the list, so we need to process
|
||||
* current index again */
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -273,7 +288,7 @@ void ipc_event_workspace(struct sway_container *old,
|
|||
if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) {
|
||||
return;
|
||||
}
|
||||
wlr_log(L_DEBUG, "Sending workspace::%s event", change);
|
||||
wlr_log(WLR_DEBUG, "Sending workspace::%s event", change);
|
||||
json_object *obj = json_object_new_object();
|
||||
json_object_object_add(obj, "change", json_object_new_string(change));
|
||||
if (strcmp("focus", change) == 0) {
|
||||
|
|
@ -301,7 +316,7 @@ void ipc_event_window(struct sway_container *window, const char *change) {
|
|||
if (!ipc_has_event_listeners(IPC_EVENT_WINDOW)) {
|
||||
return;
|
||||
}
|
||||
wlr_log(L_DEBUG, "Sending window::%s event", change);
|
||||
wlr_log(WLR_DEBUG, "Sending window::%s event", change);
|
||||
json_object *obj = json_object_new_object();
|
||||
json_object_object_add(obj, "change", json_object_new_string(change));
|
||||
json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window));
|
||||
|
|
@ -315,7 +330,7 @@ void ipc_event_barconfig_update(struct bar_config *bar) {
|
|||
if (!ipc_has_event_listeners(IPC_EVENT_BARCONFIG_UPDATE)) {
|
||||
return;
|
||||
}
|
||||
wlr_log(L_DEBUG, "Sending barconfig_update event");
|
||||
wlr_log(WLR_DEBUG, "Sending barconfig_update event");
|
||||
json_object *json = ipc_json_describe_bar_config(bar);
|
||||
|
||||
const char *json_string = json_object_to_json_string(json);
|
||||
|
|
@ -323,13 +338,15 @@ void ipc_event_barconfig_update(struct bar_config *bar) {
|
|||
json_object_put(json);
|
||||
}
|
||||
|
||||
void ipc_event_mode(const char *mode) {
|
||||
void ipc_event_mode(const char *mode, bool pango) {
|
||||
if (!ipc_has_event_listeners(IPC_EVENT_MODE)) {
|
||||
return;
|
||||
}
|
||||
wlr_log(L_DEBUG, "Sending mode::%s event", mode);
|
||||
wlr_log(WLR_DEBUG, "Sending mode::%s event", mode);
|
||||
json_object *obj = json_object_new_object();
|
||||
json_object_object_add(obj, "change", json_object_new_string(mode));
|
||||
json_object_object_add(obj, "pango_markup",
|
||||
json_object_new_boolean(pango));
|
||||
|
||||
const char *json_string = json_object_to_json_string(obj);
|
||||
ipc_send_event(json_string, IPC_EVENT_MODE);
|
||||
|
|
@ -340,13 +357,13 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
|
|||
struct ipc_client *client = data;
|
||||
|
||||
if (mask & WL_EVENT_ERROR) {
|
||||
wlr_log(L_ERROR, "IPC Client socket error, removing client");
|
||||
wlr_log(WLR_ERROR, "IPC Client socket error, removing client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mask & WL_EVENT_HANGUP) {
|
||||
wlr_log(L_DEBUG, "Client %d hung up", client->fd);
|
||||
wlr_log(WLR_DEBUG, "Client %d hung up", client->fd);
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -355,14 +372,14 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "Client %d writable", client->fd);
|
||||
wlr_log(WLR_DEBUG, "Client %d writable", client->fd);
|
||||
|
||||
ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
|
||||
|
||||
if (written == -1 && errno == EAGAIN) {
|
||||
return 0;
|
||||
} else if (written == -1) {
|
||||
wlr_log_errno(L_INFO, "Unable to send data from queue to IPC client");
|
||||
wlr_log_errno(WLR_INFO, "Unable to send data from queue to IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -383,11 +400,9 @@ void ipc_client_disconnect(struct ipc_client *client) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (client->fd != -1) {
|
||||
shutdown(client->fd, SHUT_RDWR);
|
||||
}
|
||||
shutdown(client->fd, SHUT_RDWR);
|
||||
|
||||
wlr_log(L_INFO, "IPC Client %d disconnected", client->fd);
|
||||
wlr_log(WLR_INFO, "IPC Client %d disconnected", client->fd);
|
||||
wl_event_source_remove(client->event_source);
|
||||
if (client->writable_event_source) {
|
||||
wl_event_source_remove(client->writable_event_source);
|
||||
|
|
@ -448,7 +463,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
|
||||
char *buf = malloc(client->payload_length + 1);
|
||||
if (!buf) {
|
||||
wlr_log_errno(L_INFO, "Unable to allocate IPC payload");
|
||||
wlr_log_errno(WLR_INFO, "Unable to allocate IPC payload");
|
||||
ipc_client_disconnect(client);
|
||||
return;
|
||||
}
|
||||
|
|
@ -457,7 +472,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
ssize_t received = recv(client->fd, buf, client->payload_length, 0);
|
||||
if (received == -1)
|
||||
{
|
||||
wlr_log_errno(L_INFO, "Unable to receive payload from IPC client");
|
||||
wlr_log_errno(WLR_INFO, "Unable to receive payload from IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
free(buf);
|
||||
return;
|
||||
|
|
@ -465,16 +480,16 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
}
|
||||
buf[client->payload_length] = '\0';
|
||||
|
||||
const char *error_denied = "{ \"success\": false, \"error\": \"Permission denied\" }";
|
||||
|
||||
bool client_valid = true;
|
||||
switch (client->current_command) {
|
||||
case IPC_COMMAND:
|
||||
{
|
||||
struct cmd_results *results = execute_command(buf, NULL);
|
||||
const char *json = cmd_results_to_json(results);
|
||||
char reply[256];
|
||||
int length = snprintf(reply, sizeof(reply), "%s", json);
|
||||
ipc_send_reply(client, reply, (uint32_t) length);
|
||||
transaction_commit_dirty();
|
||||
char *json = cmd_results_to_json(results);
|
||||
int length = strlen(json);
|
||||
client_valid = ipc_send_reply(client, json, (uint32_t)length);
|
||||
free(json);
|
||||
free_cmd_results(results);
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
|
@ -497,7 +512,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
}
|
||||
}
|
||||
const char *json_string = json_object_to_json_string(outputs);
|
||||
ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
json_object_put(outputs); // free
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
|
@ -508,7 +524,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
container_for_each_descendant_dfs(&root_container,
|
||||
ipc_get_workspaces_callback, workspaces);
|
||||
const char *json_string = json_object_to_json_string(workspaces);
|
||||
ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
json_object_put(workspaces); // free
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
|
@ -518,8 +535,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
// TODO: Check if they're permitted to use these events
|
||||
struct json_object *request = json_tokener_parse(buf);
|
||||
if (request == NULL) {
|
||||
ipc_send_reply(client, "{\"success\": false}", 18);
|
||||
wlr_log_errno(L_INFO, "Failed to read request");
|
||||
client_valid = ipc_send_reply(client, "{\"success\": false}", 18);
|
||||
wlr_log_errno(WLR_INFO, "Failed to read request");
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -539,15 +556,16 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
} else if (strcmp(event_type, "binding") == 0) {
|
||||
client->subscribed_events |= event_mask(IPC_EVENT_BINDING);
|
||||
} else {
|
||||
ipc_send_reply(client, "{\"success\": false}", 18);
|
||||
client_valid =
|
||||
ipc_send_reply(client, "{\"success\": false}", 18);
|
||||
json_object_put(request);
|
||||
wlr_log_errno(L_INFO, "Failed to parse request");
|
||||
wlr_log_errno(WLR_INFO, "Failed to parse request");
|
||||
goto exit_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
json_object_put(request);
|
||||
ipc_send_reply(client, "{\"success\": true}", 17);
|
||||
client_valid = ipc_send_reply(client, "{\"success\": true}", 17);
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +577,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
json_object_array_add(inputs, ipc_json_describe_input(device));
|
||||
}
|
||||
const char *json_string = json_object_to_json_string(inputs);
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
json_object_put(inputs); // free
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
|
@ -572,7 +591,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
json_object_array_add(seats, ipc_json_describe_seat(seat));
|
||||
}
|
||||
const char *json_string = json_object_to_json_string(seats);
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
json_object_put(seats); // free
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
|
@ -582,7 +602,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
json_object *tree =
|
||||
ipc_json_describe_container_recursive(&root_container);
|
||||
const char *json_string = json_object_to_json_string(tree);
|
||||
ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
|
||||
json_object_put(tree);
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
|
@ -593,7 +614,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
container_descendants(&root_container, C_VIEW, ipc_get_marks_callback,
|
||||
marks);
|
||||
const char *json_string = json_object_to_json_string(marks);
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
json_object_put(marks);
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
|
@ -602,7 +624,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
{
|
||||
json_object *version = ipc_json_get_version();
|
||||
const char *json_string = json_object_to_json_string(version);
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
json_object_put(version); // free
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
|
@ -617,7 +640,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
json_object_array_add(bars, json_object_new_string(bar->id));
|
||||
}
|
||||
const char *json_string = json_object_to_json_string(bars);
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(bars); // free
|
||||
} else {
|
||||
// Send particular bar's details
|
||||
|
|
@ -631,27 +656,54 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
}
|
||||
if (!bar) {
|
||||
const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }";
|
||||
ipc_send_reply(client, error, (uint32_t)strlen(error));
|
||||
client_valid =
|
||||
ipc_send_reply(client, error, (uint32_t)strlen(error));
|
||||
goto exit_cleanup;
|
||||
}
|
||||
json_object *json = ipc_json_describe_bar_config(bar);
|
||||
const char *json_string = json_object_to_json_string(json);
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(json); // free
|
||||
}
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
||||
default:
|
||||
wlr_log(L_INFO, "Unknown IPC command type %i", client->current_command);
|
||||
case IPC_GET_BINDING_MODES:
|
||||
{
|
||||
json_object *modes = json_object_new_array();
|
||||
for (int i = 0; i < config->modes->length; i++) {
|
||||
struct sway_mode *mode = config->modes->items[i];
|
||||
json_object_array_add(modes, json_object_new_string(mode->name));
|
||||
}
|
||||
const char *json_string = json_object_to_json_string(modes);
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
json_object_put(modes); // free
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
||||
ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied));
|
||||
wlr_log(L_DEBUG, "Denied IPC client access to %i", client->current_command);
|
||||
case IPC_GET_CONFIG:
|
||||
{
|
||||
json_object *json = json_object_new_object();
|
||||
json_object_object_add(json, "config", json_object_new_string(config->current_config));
|
||||
const char *json_string = json_object_to_json_string(json);
|
||||
client_valid =
|
||||
ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
|
||||
json_object_put(json); // free
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
||||
default:
|
||||
wlr_log(WLR_INFO, "Unknown IPC command type %i", client->current_command);
|
||||
goto exit_cleanup;
|
||||
}
|
||||
|
||||
exit_cleanup:
|
||||
client->payload_length = 0;
|
||||
if (client_valid) {
|
||||
client->payload_length = 0;
|
||||
}
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
|
@ -672,14 +724,14 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
|
|||
}
|
||||
|
||||
if (client->write_buffer_size > 4e6) { // 4 MB
|
||||
wlr_log(L_ERROR, "Client write buffer too big, disconnecting client");
|
||||
wlr_log(WLR_ERROR, "Client write buffer too big, disconnecting client");
|
||||
ipc_client_disconnect(client);
|
||||
return false;
|
||||
}
|
||||
|
||||
char *new_buffer = realloc(client->write_buffer, client->write_buffer_size);
|
||||
if (!new_buffer) {
|
||||
wlr_log(L_ERROR, "Unable to reallocate ipc client write buffer");
|
||||
wlr_log(WLR_ERROR, "Unable to reallocate ipc client write buffer");
|
||||
ipc_client_disconnect(client);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -696,6 +748,6 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
|
|||
ipc_client_handle_writable, client);
|
||||
}
|
||||
|
||||
wlr_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
|
||||
wlr_log(WLR_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
83
sway/main.c
83
sway/main.c
|
|
@ -1,6 +1,7 @@
|
|||
#define _XOPEN_SOURCE 700
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <getopt.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/debug.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/tree/layout.h"
|
||||
#include "sway/ipc-server.h"
|
||||
|
|
@ -128,7 +130,7 @@ static void log_env() {
|
|||
"SWAYSOCK"
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) {
|
||||
wlr_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
|
||||
wlr_log(WLR_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,14 +145,14 @@ static void log_distro() {
|
|||
for (size_t i = 0; i < sizeof(paths) / sizeof(char *); ++i) {
|
||||
FILE *f = fopen(paths[i], "r");
|
||||
if (f) {
|
||||
wlr_log(L_INFO, "Contents of %s:", paths[i]);
|
||||
wlr_log(WLR_INFO, "Contents of %s:", paths[i]);
|
||||
while (!feof(f)) {
|
||||
char *line;
|
||||
if (!(line = read_line(f))) {
|
||||
break;
|
||||
}
|
||||
if (*line) {
|
||||
wlr_log(L_INFO, "%s", line);
|
||||
wlr_log(WLR_INFO, "%s", line);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
|
|
@ -162,7 +164,7 @@ static void log_distro() {
|
|||
static void log_kernel() {
|
||||
FILE *f = popen("uname -a", "r");
|
||||
if (!f) {
|
||||
wlr_log(L_INFO, "Unable to determine kernel version");
|
||||
wlr_log(WLR_INFO, "Unable to determine kernel version");
|
||||
return;
|
||||
}
|
||||
while (!feof(f)) {
|
||||
|
|
@ -171,25 +173,25 @@ static void log_kernel() {
|
|||
break;
|
||||
}
|
||||
if (*line) {
|
||||
wlr_log(L_INFO, "%s", line);
|
||||
wlr_log(WLR_INFO, "%s", line);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
fclose(f);
|
||||
pclose(f);
|
||||
}
|
||||
|
||||
static void security_sanity_check() {
|
||||
// TODO: Notify users visually if this has issues
|
||||
struct stat s;
|
||||
if (stat("/proc", &s)) {
|
||||
wlr_log(L_ERROR,
|
||||
wlr_log(WLR_ERROR,
|
||||
"!! DANGER !! /proc is not available - sway CANNOT enforce security rules!");
|
||||
}
|
||||
#ifdef __linux__
|
||||
cap_flag_value_t v;
|
||||
cap_t cap = cap_get_proc();
|
||||
if (!cap || cap_get_flag(cap, CAP_SYS_PTRACE, CAP_PERMITTED, &v) != 0 || v != CAP_SET) {
|
||||
wlr_log(L_ERROR,
|
||||
wlr_log(WLR_ERROR,
|
||||
"!! DANGER !! Sway does not have CAP_SYS_PTRACE and cannot enforce security rules for processes running as other users.");
|
||||
}
|
||||
if (cap) {
|
||||
|
|
@ -205,13 +207,13 @@ static void executable_sanity_check() {
|
|||
stat(exe, &sb);
|
||||
// We assume that cap_get_file returning NULL implies ENODATA
|
||||
if (sb.st_mode & (S_ISUID|S_ISGID) && cap_get_file(exe)) {
|
||||
wlr_log(L_ERROR,
|
||||
wlr_log(WLR_ERROR,
|
||||
"sway executable has both the s(g)uid bit AND file caps set.");
|
||||
wlr_log(L_ERROR,
|
||||
wlr_log(WLR_ERROR,
|
||||
"This is strongly discouraged (and completely broken).");
|
||||
wlr_log(L_ERROR,
|
||||
wlr_log(WLR_ERROR,
|
||||
"Please clear one of them (either the suid bit, or the file caps).");
|
||||
wlr_log(L_ERROR,
|
||||
wlr_log(WLR_ERROR,
|
||||
"If unsure, strip the file caps.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
@ -222,16 +224,16 @@ static void executable_sanity_check() {
|
|||
static void drop_permissions(bool keep_caps) {
|
||||
if (getuid() != geteuid() || getgid() != getegid()) {
|
||||
if (setgid(getgid()) != 0) {
|
||||
wlr_log(L_ERROR, "Unable to drop root");
|
||||
wlr_log(WLR_ERROR, "Unable to drop root");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (setuid(getuid()) != 0) {
|
||||
wlr_log(L_ERROR, "Unable to drop root");
|
||||
wlr_log(WLR_ERROR, "Unable to drop root");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (setuid(0) != -1) {
|
||||
wlr_log(L_ERROR, "Root privileges can be restored.");
|
||||
wlr_log(WLR_ERROR, "Root privileges can be restored.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#ifdef __linux__
|
||||
|
|
@ -239,17 +241,29 @@ static void drop_permissions(bool keep_caps) {
|
|||
// Drop every cap except CAP_SYS_PTRACE
|
||||
cap_t caps = cap_init();
|
||||
cap_value_t keep = CAP_SYS_PTRACE;
|
||||
wlr_log(L_INFO, "Dropping extra capabilities");
|
||||
wlr_log(WLR_INFO, "Dropping extra capabilities");
|
||||
if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) ||
|
||||
cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) ||
|
||||
cap_set_proc(caps)) {
|
||||
wlr_log(L_ERROR, "Failed to drop extra capabilities");
|
||||
wlr_log(WLR_ERROR, "Failed to drop extra capabilities");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void enable_debug_flag(const char *flag) {
|
||||
if (strcmp(flag, "render-tree") == 0) {
|
||||
enable_debug_tree = true;
|
||||
} else if (strncmp(flag, "damage=", 7) == 0) {
|
||||
damage_debug = &flag[7];
|
||||
} else if (strcmp(flag, "txn-debug") == 0) {
|
||||
txn_debug = true;
|
||||
} else if (strncmp(flag, "txn-timeout=", 12) == 0) {
|
||||
txn_timeout_ms = atoi(&flag[12]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
static int verbose = 0, debug = 0, validate = 0;
|
||||
|
||||
|
|
@ -289,7 +303,7 @@ int main(int argc, char **argv) {
|
|||
int c;
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
c = getopt_long(argc, argv, "hCdDvVc:", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "hCdD:vVc:", long_options, &option_index);
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -308,7 +322,7 @@ int main(int argc, char **argv) {
|
|||
debug = 1;
|
||||
break;
|
||||
case 'D': // extended debug options
|
||||
enable_debug_tree = true;
|
||||
enable_debug_flag(optarg);
|
||||
break;
|
||||
case 'v': // version
|
||||
fprintf(stdout, "sway version " SWAY_VERSION "\n");
|
||||
|
|
@ -334,22 +348,22 @@ int main(int argc, char **argv) {
|
|||
|
||||
// TODO: switch logging over to wlroots?
|
||||
if (debug) {
|
||||
wlr_log_init(L_DEBUG, NULL);
|
||||
wlr_log_init(WLR_DEBUG, NULL);
|
||||
} else if (verbose || validate) {
|
||||
wlr_log_init(L_INFO, NULL);
|
||||
wlr_log_init(WLR_INFO, NULL);
|
||||
} else {
|
||||
wlr_log_init(L_ERROR, NULL);
|
||||
wlr_log_init(WLR_ERROR, NULL);
|
||||
}
|
||||
|
||||
if (optind < argc) { // Behave as IPC client
|
||||
if(optind != 1) {
|
||||
wlr_log(L_ERROR, "Don't use options with the IPC client");
|
||||
wlr_log(WLR_ERROR, "Don't use options with the IPC client");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
drop_permissions(false);
|
||||
char *socket_path = getenv("SWAYSOCK");
|
||||
if (!socket_path) {
|
||||
wlr_log(L_ERROR, "Unable to retrieve socket path");
|
||||
wlr_log(WLR_ERROR, "Unable to retrieve socket path");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
char *command = join_args(argv + optind, argc - optind);
|
||||
|
|
@ -368,7 +382,7 @@ int main(int argc, char **argv) {
|
|||
if (getuid() != geteuid() || getgid() != getegid()) {
|
||||
// Retain capabilities after setuid()
|
||||
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
|
||||
wlr_log(L_ERROR, "Cannot keep caps after setuid()");
|
||||
wlr_log(WLR_ERROR, "Cannot keep caps after setuid()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
suid = true;
|
||||
|
|
@ -389,7 +403,7 @@ int main(int argc, char **argv) {
|
|||
// prevent ipc from crashing sway
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
wlr_log(L_INFO, "Starting sway version " SWAY_VERSION);
|
||||
wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION);
|
||||
|
||||
layout_init();
|
||||
|
||||
|
|
@ -415,32 +429,41 @@ int main(int argc, char **argv) {
|
|||
|
||||
security_sanity_check();
|
||||
|
||||
setenv("WAYLAND_DISPLAY", server.socket, true);
|
||||
if (!terminate_request) {
|
||||
if (!server_start_backend(&server)) {
|
||||
sway_terminate(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
config->active = true;
|
||||
// Execute commands until there are none left
|
||||
wlr_log(WLR_DEBUG, "Running deferred commands");
|
||||
while (config->cmd_queue->length) {
|
||||
char *line = config->cmd_queue->items[0];
|
||||
struct cmd_results *res = execute_command(line, NULL);
|
||||
if (res->status != CMD_SUCCESS) {
|
||||
wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error);
|
||||
wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
|
||||
}
|
||||
free_cmd_results(res);
|
||||
free(line);
|
||||
list_del(config->cmd_queue, 0);
|
||||
}
|
||||
transaction_commit_dirty();
|
||||
|
||||
if (!terminate_request) {
|
||||
server_run(&server);
|
||||
}
|
||||
|
||||
wlr_log(L_INFO, "Shutting down sway");
|
||||
wlr_log(WLR_INFO, "Shutting down sway");
|
||||
|
||||
server_fini(&server);
|
||||
|
||||
ipc_terminate();
|
||||
|
||||
if (config) {
|
||||
free_config(config);
|
||||
}
|
||||
|
||||
pango_cairo_font_map_set_default(NULL);
|
||||
|
||||
return exit_value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,14 @@ sway_sources = files(
|
|||
'debug-tree.c',
|
||||
'ipc-json.c',
|
||||
'ipc-server.c',
|
||||
'scratchpad.c',
|
||||
'security.c',
|
||||
|
||||
'desktop/desktop.c',
|
||||
'desktop/idle_inhibit_v1.c',
|
||||
'desktop/layer_shell.c',
|
||||
'desktop/output.c',
|
||||
'desktop/render.c',
|
||||
'desktop/transaction.c',
|
||||
'desktop/xdg_shell_v6.c',
|
||||
'desktop/xdg_shell.c',
|
||||
|
|
@ -33,16 +36,20 @@ sway_sources = files(
|
|||
'commands/border.c',
|
||||
'commands/client.c',
|
||||
'commands/default_border.c',
|
||||
'commands/default_floating_border.c',
|
||||
'commands/default_orientation.c',
|
||||
'commands/exit.c',
|
||||
'commands/exec.c',
|
||||
'commands/exec_always.c',
|
||||
'commands/floating.c',
|
||||
'commands/floating_minmax_size.c',
|
||||
'commands/floating_modifier.c',
|
||||
'commands/focus.c',
|
||||
'commands/focus_follows_mouse.c',
|
||||
'commands/focus_wrapping.c',
|
||||
'commands/font.c',
|
||||
'commands/for_window.c',
|
||||
'commands/force_display_urgency_hint.c',
|
||||
'commands/force_focus_wrapping.c',
|
||||
'commands/fullscreen.c',
|
||||
'commands/gaps.c',
|
||||
|
|
@ -56,10 +63,12 @@ sway_sources = files(
|
|||
'commands/mode.c',
|
||||
'commands/mouse_warping.c',
|
||||
'commands/move.c',
|
||||
'commands/no_focus.c',
|
||||
'commands/output.c',
|
||||
'commands/reload.c',
|
||||
'commands/rename.c',
|
||||
'commands/resize.c',
|
||||
'commands/scratchpad.c',
|
||||
'commands/seat.c',
|
||||
'commands/seat/attach.c',
|
||||
'commands/seat/cursor.c',
|
||||
|
|
@ -73,6 +82,7 @@ sway_sources = files(
|
|||
'commands/swap.c',
|
||||
'commands/title_format.c',
|
||||
'commands/unmark.c',
|
||||
'commands/urgent.c',
|
||||
'commands/workspace.c',
|
||||
'commands/workspace_layout.c',
|
||||
'commands/ws_auto_back_and_forth.c',
|
||||
|
|
@ -115,8 +125,10 @@ sway_sources = files(
|
|||
'commands/input/pointer_accel.c',
|
||||
'commands/input/repeat_delay.c',
|
||||
'commands/input/repeat_rate.c',
|
||||
'commands/input/scroll_button.c',
|
||||
'commands/input/scroll_method.c',
|
||||
'commands/input/tap.c',
|
||||
'commands/input/tap_button_map.c',
|
||||
'commands/input/xkb_layout.c',
|
||||
'commands/input/xkb_model.c',
|
||||
'commands/input/xkb_options.c',
|
||||
|
|
|
|||
175
sway/scratchpad.c
Normal file
175
sway/scratchpad.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
#define _XOPEN_SOURCE 700
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "sway/scratchpad.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
void scratchpad_add_container(struct sway_container *con) {
|
||||
if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
|
||||
return;
|
||||
}
|
||||
con->scratchpad = true;
|
||||
list_add(root_container.sway_root->scratchpad, con);
|
||||
|
||||
struct sway_container *parent = con->parent;
|
||||
container_set_floating(con, true);
|
||||
container_remove_child(con);
|
||||
arrange_windows(parent);
|
||||
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
seat_set_focus(seat, seat_get_focus_inactive(seat, parent));
|
||||
}
|
||||
|
||||
void scratchpad_remove_container(struct sway_container *con) {
|
||||
if (!sway_assert(con->scratchpad, "Container is not in scratchpad")) {
|
||||
return;
|
||||
}
|
||||
con->scratchpad = false;
|
||||
for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
|
||||
if (root_container.sway_root->scratchpad->items[i] == con) {
|
||||
list_del(root_container.sway_root->scratchpad, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a single scratchpad container.
|
||||
* The container might be visible on another workspace already.
|
||||
*/
|
||||
static void scratchpad_show(struct sway_container *con) {
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
struct sway_container *ws = seat_get_focus(seat);
|
||||
if (ws->type != C_WORKSPACE) {
|
||||
ws = container_parent(ws, C_WORKSPACE);
|
||||
}
|
||||
|
||||
// If the current con or any of its parents are in fullscreen mode, we
|
||||
// first need to disable it before showing the scratchpad con.
|
||||
if (ws->sway_workspace->fullscreen) {
|
||||
view_set_fullscreen(ws->sway_workspace->fullscreen, false);
|
||||
}
|
||||
|
||||
// Show the container
|
||||
if (con->parent) {
|
||||
container_remove_child(con);
|
||||
}
|
||||
container_add_child(ws->sway_workspace->floating, con);
|
||||
|
||||
// Make sure the container's center point overlaps this workspace
|
||||
double center_lx = con->x + con->width / 2;
|
||||
double center_ly = con->y + con->height / 2;
|
||||
|
||||
struct wlr_box workspace_box;
|
||||
container_get_box(ws, &workspace_box);
|
||||
if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
|
||||
// Maybe resize it
|
||||
if (con->width > ws->width || con->height > ws->height) {
|
||||
// TODO: Do this properly once we can float C_CONTAINERs
|
||||
if (con->type == C_VIEW) {
|
||||
view_init_floating(con->sway_view);
|
||||
arrange_windows(con);
|
||||
}
|
||||
}
|
||||
|
||||
// Center it
|
||||
double new_lx = ws->x + (ws->width - con->width) / 2;
|
||||
double new_ly = ws->y + (ws->height - con->height) / 2;
|
||||
container_floating_move_to(con, new_lx, new_ly);
|
||||
}
|
||||
|
||||
seat_set_focus(seat, con);
|
||||
|
||||
container_set_dirty(con->parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide a single scratchpad container.
|
||||
* The container might not be the focused container (eg. when using criteria).
|
||||
*/
|
||||
static void scratchpad_hide(struct sway_container *con) {
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
struct sway_container *focus = seat_get_focus(seat);
|
||||
struct sway_container *ws = container_parent(con, C_WORKSPACE);
|
||||
|
||||
container_remove_child(con);
|
||||
arrange_windows(ws);
|
||||
if (con == focus) {
|
||||
seat_set_focus(seat, seat_get_focus_inactive(seat, ws));
|
||||
}
|
||||
list_move_to_end(root_container.sway_root->scratchpad, con);
|
||||
}
|
||||
|
||||
void scratchpad_toggle_auto(void) {
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
struct sway_container *focus = seat_get_focus(seat);
|
||||
struct sway_container *ws = focus->type == C_WORKSPACE ?
|
||||
focus : container_parent(focus, C_WORKSPACE);
|
||||
|
||||
// Check if the currently focused window is a scratchpad window and should
|
||||
// be hidden again.
|
||||
if (focus->scratchpad) {
|
||||
wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s",
|
||||
focus->name);
|
||||
scratchpad_hide(focus);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there is an unfocused scratchpad window on the current workspace
|
||||
// and focus it.
|
||||
for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) {
|
||||
struct sway_container *floater =
|
||||
ws->sway_workspace->floating->children->items[i];
|
||||
if (floater->scratchpad && focus != floater) {
|
||||
wlr_log(WLR_DEBUG,
|
||||
"Focusing other scratchpad window (%s) in this workspace",
|
||||
floater->name);
|
||||
scratchpad_show(floater);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is a visible scratchpad window on another workspace.
|
||||
// In this case we move it to the current workspace.
|
||||
for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
|
||||
struct sway_container *con =
|
||||
root_container.sway_root->scratchpad->items[i];
|
||||
if (con->parent) {
|
||||
wlr_log(WLR_DEBUG,
|
||||
"Moving a visible scratchpad window (%s) to this workspace",
|
||||
con->name);
|
||||
scratchpad_show(con);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Take the container at the bottom of the scratchpad list
|
||||
if (!sway_assert(root_container.sway_root->scratchpad->length,
|
||||
"Scratchpad is empty")) {
|
||||
return;
|
||||
}
|
||||
struct sway_container *con = root_container.sway_root->scratchpad->items[0];
|
||||
wlr_log(WLR_DEBUG, "Showing %s from list", con->name);
|
||||
scratchpad_show(con);
|
||||
}
|
||||
|
||||
void scratchpad_toggle_container(struct sway_container *con) {
|
||||
if (!sway_assert(con->scratchpad, "Container isn't in the scratchpad")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it matches a currently visible scratchpad window and hide it.
|
||||
if (con->parent) {
|
||||
scratchpad_hide(con);
|
||||
return;
|
||||
}
|
||||
|
||||
scratchpad_show(con);
|
||||
}
|
||||
|
|
@ -7,13 +7,13 @@
|
|||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_gamma_control.h>
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include <wlr/types/wlr_layer_shell.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_primary_selection.h>
|
||||
#include <wlr/types/wlr_screenshooter.h>
|
||||
#include <wlr/types/wlr_screencopy_v1.h>
|
||||
#include <wlr/types/wlr_server_decoration.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/types/wlr_xdg_output.h>
|
||||
|
|
@ -21,26 +21,27 @@
|
|||
// TODO WLR: make Xwayland optional
|
||||
#include "list.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/tree/layout.h"
|
||||
#include "sway/xwayland.h"
|
||||
|
||||
bool server_privileged_prepare(struct sway_server *server) {
|
||||
wlr_log(L_DEBUG, "Preparing Wayland server initialization");
|
||||
wlr_log(WLR_DEBUG, "Preparing Wayland server initialization");
|
||||
server->wl_display = wl_display_create();
|
||||
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
|
||||
server->backend = wlr_backend_autocreate(server->wl_display, NULL);
|
||||
|
||||
if (!server->backend) {
|
||||
wlr_log(L_ERROR, "Unable to create backend");
|
||||
wlr_log(WLR_ERROR, "Unable to create backend");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool server_init(struct sway_server *server) {
|
||||
wlr_log(L_DEBUG, "Initializing Wayland server");
|
||||
wlr_log(WLR_DEBUG, "Initializing Wayland server");
|
||||
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend);
|
||||
assert(renderer);
|
||||
|
|
@ -51,8 +52,6 @@ bool server_init(struct sway_server *server) {
|
|||
server->data_device_manager =
|
||||
wlr_data_device_manager_create(server->wl_display);
|
||||
|
||||
server->idle = wlr_idle_create(server->wl_display);
|
||||
wlr_screenshooter_create(server->wl_display);
|
||||
wlr_gamma_control_manager_create(server->wl_display);
|
||||
wlr_primary_selection_device_manager_create(server->wl_display);
|
||||
|
||||
|
|
@ -62,6 +61,10 @@ bool server_init(struct sway_server *server) {
|
|||
wlr_xdg_output_manager_create(server->wl_display,
|
||||
root_container.sway_root->output_layout);
|
||||
|
||||
server->idle = wlr_idle_create(server->wl_display);
|
||||
server->idle_inhibit_manager_v1 =
|
||||
sway_idle_inhibit_manager_v1_create(server->wl_display, server->idle);
|
||||
|
||||
server->layer_shell = wlr_layer_shell_create(server->wl_display);
|
||||
wl_signal_add(&server->layer_shell->events.new_surface,
|
||||
&server->layer_shell_surface);
|
||||
|
|
@ -105,12 +108,13 @@ bool server_init(struct sway_server *server) {
|
|||
wlr_server_decoration_manager_set_default_mode(
|
||||
deco_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
|
||||
|
||||
wlr_linux_dmabuf_create(server->wl_display, renderer);
|
||||
wlr_linux_dmabuf_v1_create(server->wl_display, renderer);
|
||||
wlr_export_dmabuf_manager_v1_create(server->wl_display);
|
||||
wlr_screencopy_manager_v1_create(server->wl_display);
|
||||
|
||||
server->socket = wl_display_add_socket_auto(server->wl_display);
|
||||
if (!server->socket) {
|
||||
wlr_log(L_ERROR, "Unable to open wayland socket");
|
||||
wlr_log(WLR_ERROR, "Unable to open wayland socket");
|
||||
wlr_backend_destroy(server->backend);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -119,8 +123,7 @@ bool server_init(struct sway_server *server) {
|
|||
if (debug != NULL && strcmp(debug, "txn_timings") == 0) {
|
||||
server->debug_txn_timings = true;
|
||||
}
|
||||
server->destroying_containers = create_list();
|
||||
|
||||
server->dirty_containers = create_list();
|
||||
server->transactions = create_list();
|
||||
|
||||
input_manager = input_manager_create(server);
|
||||
|
|
@ -130,18 +133,23 @@ bool server_init(struct sway_server *server) {
|
|||
void server_fini(struct sway_server *server) {
|
||||
// TODO: free sway-specific resources
|
||||
wl_display_destroy(server->wl_display);
|
||||
list_free(server->destroying_containers);
|
||||
list_free(server->dirty_containers);
|
||||
list_free(server->transactions);
|
||||
}
|
||||
|
||||
void server_run(struct sway_server *server) {
|
||||
wlr_log(L_INFO, "Running compositor on wayland display '%s'",
|
||||
bool server_start_backend(struct sway_server *server) {
|
||||
wlr_log(WLR_INFO, "Starting backend on wayland display '%s'",
|
||||
server->socket);
|
||||
setenv("WAYLAND_DISPLAY", server->socket, true);
|
||||
if (!wlr_backend_start(server->backend)) {
|
||||
wlr_log(L_ERROR, "Failed to start backend");
|
||||
wlr_log(WLR_ERROR, "Failed to start backend");
|
||||
wlr_backend_destroy(server->backend);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void server_run(struct sway_server *server) {
|
||||
wlr_log(WLR_INFO, "Running compositor on wayland display '%s'",
|
||||
server->socket);
|
||||
wl_display_run(server->wl_display);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ For more information on these xkb configuration options, see
|
|||
Enables or disables disable-while-typing for the specified input device.
|
||||
|
||||
*input* <identifier> events enabled|disabled|disabled\_on\_external\_mouse
|
||||
Enables or disables send_events for specified input device. (Disabling
|
||||
send_events disables the input device)
|
||||
Enables or disables send\_events for specified input device. (Disabling
|
||||
send\_events disables the input device)
|
||||
|
||||
*input* <identifier> left\_handed enabled|disabled
|
||||
Enables or disables left handed mode for specified input device.
|
||||
|
|
@ -92,9 +92,20 @@ For more information on these xkb configuration options, see
|
|||
*input* <identifier> scroll\_method none|two\_finger|edge|on\_button\_down
|
||||
Changes the scroll method for the specified input device.
|
||||
|
||||
*input* <identifier> scroll\_button <button\_identifier>
|
||||
Sets button used for scroll\_method on\_button\_down. The button identifier
|
||||
can be obtained from `libinput debug-events`.
|
||||
If set to 0, it disables the scroll\_button on\_button\_down.
|
||||
|
||||
*input* <identifier> tap enabled|disabled
|
||||
Enables or disables tap for specified input device.
|
||||
|
||||
*input* <identifier> tap_button_map lrm|lmr
|
||||
Specifies which button mapping to use for tapping. _lrm_ treats 1 finger as
|
||||
left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_
|
||||
treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as
|
||||
right click.
|
||||
|
||||
## SEAT CONFIGURATION
|
||||
|
||||
Configure options for multiseat mode. sway-seat commands must be used inside a
|
||||
|
|
|
|||
|
|
@ -92,6 +92,12 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
|
|||
*focus* output <name>
|
||||
Moves focus to the named output.
|
||||
|
||||
*focus tiling*
|
||||
Sets focus to the last focused tiling container.
|
||||
|
||||
*focus floating*
|
||||
Sets focus to the last focused floating container.
|
||||
|
||||
*focus* mode\_toggle
|
||||
Moves focus between the floating and tiled layers.
|
||||
|
||||
|
|
@ -413,10 +419,12 @@ The default colors are:
|
|||
*mode* <mode>
|
||||
Switches to the specified mode. The default mode _default_.
|
||||
|
||||
*mode* <mode> *{* <commands...> *}*
|
||||
*mode* [--pango\_markup] <mode> *{* <commands...> *}*
|
||||
_commands..._ after *{* will be added to the specified mode. A newline is
|
||||
required between *{* and the first command, and *}* must be alone on a
|
||||
line. Only *bindsym* and *bindcode* commands are permitted in mode blocks.
|
||||
If _--pango\_markup_ is given, then _mode_ will be interpreted as pango
|
||||
markup.
|
||||
|
||||
*mouse\_warping* output|none
|
||||
If _output_ is specified, the mouse will be moved to new outputs as you
|
||||
|
|
@ -491,6 +499,11 @@ config after the others, or it will be matched instead of the others.
|
|||
*unmark* will remove _identifier_ from the list of current marks on a
|
||||
window. If _identifier_ is omitted, all marks are removed.
|
||||
|
||||
*urgent* enable|disable|allow|deny
|
||||
Using _enable_ or _disable_ manually sets or unsets the window's urgent
|
||||
state. Using _allow_ or _deny_ controls the window's ability to set itself
|
||||
as urgent. By default, windows are allowed to set their own urgency.
|
||||
|
||||
*workspace* [number] <name>
|
||||
Switches to the specified workspace. The string "number" is optional and is
|
||||
used to sort workspaces.
|
||||
|
|
|
|||
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