1
1
Fork 0
mirror of https://github.com/swaywm/sway synced 2024-05-09 11:46:03 +02:00

Compare commits

...

20 Commits

Author SHA1 Message Date
Pontus Andersson 07a9f4f1f8 output: Fallback to sorting workspaces alphabetically
Currently the order of unnumbered workspaces is the order they were
created. This is a bit unintuitive for workflows where workspaces are
created and named dynamically.

Instead of treating all unnumbered workspaces equal, fallback to sorting
them alphabetically based on the name of the workspace. This will make
the ordering more deterministic regardless of the order they were
created.
2024-04-24 19:10:58 +02:00
Kenny Levinsen 646019cad9 desktop/output: Fix check if config should be stored
We want to check if a config_head existed for the current
matched_output_config, so we should check cfg->output. sway_output is a
temporary variable from a previous wl_list_for_each, and does not
contain anything useful to us.

Fixes: https://github.com/swaywm/sway/issues/8128
2024-04-23 13:31:30 +02:00
Kenny Levinsen ffcde7a70c server: Use wlr_renderer_get_texture_formats
wlr_renderer_get_{dmabuf|shm}_texture_formats have been replaced by a
unified wlr_renderer_get_texture_formats interface using buffer caps.

References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4644
2024-04-21 17:19:33 +02:00
Simon Ser 087226d997 config/output: drop fast path in store_output_config()
If there is no output currently connected, we still want to merge
to any existing config.

It shouldn't matter to iterate over the list of outputs to do
nothing anwyays.
2024-04-13 00:55:28 +02:00
Simon Ser f11c5d562e config/output: fix NULL derefs in store_output_config()
../sway/config/output.c:33:21: runtime error: member access within null pointer of type 'struct sway_output'
    AddressSanitizer:DEADLYSIGNAL
    =================================================================
    ==7856==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000080 (pc 0x63da8558205c bp 0x7ffdc35881a0 sp 0x7ffdc3588160 T0)
    ==7856==The signal is caused by a READ memory access.
    ==7856==Hint: address points to the zero page.
        #0 0x63da8558205c in output_get_identifier ../sway/config/output.c:33
        #1 0x63da855865c3 in store_output_config ../sway/config/output.c:220
        #2 0x63da855d4066 in cmd_output ../sway/commands/output.c:106
        #3 0x63da8547f2e3 in config_command ../sway/commands.c:425
        #4 0x63da8548f3fc in read_config ../sway/config.c:822
        #5 0x63da8548a224 in load_config ../sway/config.c:435
        #6 0x63da8548b065 in load_main_config ../sway/config.c:507
        #7 0x63da854bee8d in main ../sway/main.c:351
        #8 0x77e2ea643ccf  (/usr/lib/libc.so.6+0x25ccf) (BuildId: c0caa0b7709d3369ee575fcd7d7d0b0fc48733af)
        #9 0x77e2ea643d89 in __libc_start_main (/usr/lib/libc.so.6+0x25d89) (BuildId: c0caa0b7709d3369ee575fcd7d7d0b0fc48733af)
        #10 0x63da8547ad64 in _start (/home/simon/src/sway/build/sway/sway+0x372d64) (BuildId: 3fa2e8838c1c32713b40aec6b1e84bbe4db5bde8)

Fixes: 1267e47de9 ("config/output: Refactor handling of tiered configs")
2024-04-13 00:55:28 +02:00
Kenny Levinsen 1267e47de9 config/output: Refactor handling of tiered configs
Output configuration can be applied to a particular output in three
ways: As a wildcard, by connector name and by identifier. This in turn
means that three different configurations must be handled at any given
time.

In the current model, this is managed by merging new configuration into
every other matching configuration. At the same time, an additional
synthetic configuration is made which matchehes both identifier and name
at the same time, further complicating logic.

Instead, manage and store each configuration independently and merge
them in order when retrieving configuration for an output. When changes
are made to a less specific configuration, clear these fields from more
specific configurations to allow the change to take effect regardless of
precedence.

Fixes: https://github.com/swaywm/sway/issues/8048
2024-04-12 17:32:26 +02:00
Ferdinand Bachmann bc258a3be2
input: add Super as alternative for Mod4
This PR implements alternative human-readable names for the logo key
(Mod4) as proposed in #8084.
2024-04-05 16:40:28 +02:00
Daniel Kahn Gillmor dcb142bf5e sway-ipc(7): Escape backslashes correctly in GET_CONFIG output
Without this change, i see the following in the sway-ipc manpage:

```

   9. GET_CONFIG
       MESSAGE
       Retrieve the contents of the config that was last loaded

       REPLY
       An object with a single string property containing the contents of  the
       config

       Example Reply:
           {
                "config": "set $mod Mod4nbindsym $mod+q exitn"
           }
```
2024-03-30 01:16:22 +01:00
Simon Ser 9e14651077 input: pass wlr_seat_client to wlr_seat_touch_notify_cancel()
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4613
2024-03-28 11:49:20 +01:00
Kenny Levinsen a4ef37752f commands/output/toggle: Use free_output_config 2024-03-28 10:45:20 +01:00
Kenny Levinsen 26a9a6b479 output/config: Remove unused test_output_config 2024-03-28 10:45:20 +01:00
Kenny Levinsen c3fca26d30 config/output: Make merge_output_config static 2024-03-28 10:45:20 +01:00
Kenny Levinsen 9becff0ba5 output/config: Remove reset_outputs and co.
apply_output_config_to_outputs uses the specified output config to check
which outputs to apply to, and to use as backup when no config is found.
If any config matches the output, the specified config will be
disregarded.

The only remaining user of apply_output_config_to_outputs is
reset_outputs, which called apply_output_config_to_outputs with either
the first stored wildcard config, or a new empty wildcard config.

Providing a stored or empty wildcard config is practically the same as
calling `apply_all_output_configs`. Replace uses of `reset_outputs` with
`apply_all_output_configs` and remove the now unused functions.
2024-03-28 10:45:20 +01:00
Kenny Levinsen 56e97b7d60 config/output: Remove apply_output_config 2024-03-28 10:45:20 +01:00
Kenny Levinsen 3b419020a3 desktop/output: Use apply_output_configs for output mgmt 2024-03-28 10:45:20 +01:00
Kenny Levinsen 98be797356 Use apply_all_output_configs to light up outputs
This allows us to test and if necessary degrade the entire backend
configuration to light everything up.
2024-03-28 10:45:20 +01:00
Kenny Levinsen 923f642b70 output/config: Add apply_all_output_configs
Apply all output configs as they are. This differs from
apply_output_config_to_outputs, which tries to apply a specific output
config.
2024-03-28 10:45:20 +01:00
Kenny Levinsen 3e03eb3a01 config/output: Introduce apply_output_configs
Introduce apply_output_configs, which applies the specified matched
output configs as a single backend commit.

Reimplement apply_output_config_to_outputs using apply_output_configs.
2024-03-28 10:45:20 +01:00
Kenny Levinsen e2f3ebad8c config/output: Split apply_output_config
Applying an output config has two stages: Atomic application of
wlr_output_state, and applicaiton of non-atomic state like output
layout.

Split the latter out into finalize_output_config for use in a later
commit.
2024-03-28 10:45:20 +01:00
Ferdinand Bachmann 125c74338a man: document supported modifier names 2024-03-28 10:26:34 +01:00
12 changed files with 357 additions and 295 deletions

View File

@ -291,6 +291,14 @@ struct output_config {
char *background_fallback;
};
/**
* An output config pre-matched to an output
*/
struct matched_output_config {
struct sway_output *output;
struct output_config *config;
};
/**
* Stores size of gaps for each side
*/
@ -680,20 +688,22 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt
struct output_config *new_output_config(const char *name);
void merge_output_config(struct output_config *dst, struct output_config *src);
bool apply_output_configs(struct matched_output_config *configs,
size_t configs_len, bool test_only);
bool apply_output_config(struct output_config *oc, struct sway_output *output);
void apply_all_output_configs(void);
bool test_output_config(struct output_config *oc, struct sway_output *output);
struct output_config *store_output_config(struct output_config *oc);
/**
* store_output_config stores a new output config. An output may be matched by
* three different config types, in order of precedence: Identifier, name and
* wildcard. When storing a config type of lower precedence, assume that the
* user wants the config to take immediate effect by superseding (clearing) the
* same values from higher presedence configuration.
*/
void store_output_config(struct output_config *oc);
struct output_config *find_output_config(struct sway_output *output);
void apply_output_config_to_outputs(struct output_config *oc);
void reset_outputs(void);
void free_output_config(struct output_config *oc);
bool spawn_swaybg(void);

View File

@ -103,13 +103,13 @@ struct cmd_results *cmd_output(int argc, char **argv) {
bool background = output->background;
output = store_output_config(output);
store_output_config(output);
// 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 && !config->validating) {
apply_output_config_to_outputs(output);
apply_all_output_configs();
if (background) {
if (!spawn_swaybg()) {
return cmd_results_new(CMD_FAILURE,

View File

@ -29,7 +29,7 @@ struct cmd_results *output_cmd_toggle(int argc, char **argv) {
config->handler_context.output_config->enabled = 1;
}
free(oc);
free_output_config(oc);
config->handler_context.leftovers.argc = argc;
config->handler_context.leftovers.argv = argv;
return NULL;

View File

@ -532,7 +532,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
}
sway_switch_retrigger_bindings_for_all();
reset_outputs();
apply_all_output_configs();
spawn_swaybg();
config->reloading = false;

View File

@ -9,6 +9,7 @@
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_swapchain_manager.h>
#include "sway/config.h"
#include "sway/input/cursor.h"
#include "sway/output.h"
@ -78,7 +79,72 @@ struct output_config *new_output_config(const char *name) {
return oc;
}
void merge_output_config(struct output_config *dst, struct output_config *src) {
// supersede_output_config clears all fields in dst that were set in src
static void supersede_output_config(struct output_config *dst, struct output_config *src) {
if (src->enabled != -1) {
dst->enabled = -1;
}
if (src->width != -1) {
dst->width = -1;
}
if (src->height != -1) {
dst->height = -1;
}
if (src->x != -1) {
dst->x = -1;
}
if (src->y != -1) {
dst->y = -1;
}
if (src->scale != -1) {
dst->scale = -1;
}
if (src->scale_filter != SCALE_FILTER_DEFAULT) {
dst->scale_filter = SCALE_FILTER_DEFAULT;
}
if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
dst->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
}
if (src->refresh_rate != -1) {
dst->refresh_rate = -1;
}
if (src->custom_mode != -1) {
dst->custom_mode = -1;
}
if (src->drm_mode.type != (uint32_t) -1) {
dst->drm_mode.type = -1;
}
if (src->transform != -1) {
dst->transform = -1;
}
if (src->max_render_time != -1) {
dst->max_render_time = -1;
}
if (src->adaptive_sync != -1) {
dst->adaptive_sync = -1;
}
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
}
if (src->background) {
free(dst->background);
dst->background = NULL;
}
if (src->background_option) {
free(dst->background_option);
dst->background_option = NULL;
}
if (src->background_fallback) {
free(dst->background_fallback);
dst->background_fallback = NULL;
}
if (src->power != -1) {
dst->power = -1;
}
}
// merge_output_config sets all fields in dst that were set in src
static void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->enabled != -1) {
dst->enabled = src->enabled;
}
@ -141,94 +207,42 @@ 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) {
sway_log(SWAY_DEBUG, "Merging output * config on %s", oc->name);
merge_output_config(oc, wildcard);
}
}
}
static void merge_id_on_name(struct output_config *oc) {
struct sway_output *output = all_output_by_name_or_id(oc->name);
if (output == NULL) {
return;
}
const char *name = output->wlr_output->name;
char id[128];
output_get_identifier(id, sizeof(id), output);
char *id_on_name = format_str("%s on %s", id, name);
if (!id_on_name) {
return;
}
int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name);
if (i >= 0) {
sway_log(SWAY_DEBUG, "Merging on top of existing id on name config");
merge_output_config(config->output_configs->items[i], oc);
} else {
// If both a name and identifier config, exist generate an id on name
int ni = list_seq_find(config->output_configs, output_name_cmp, name);
int ii = list_seq_find(config->output_configs, output_name_cmp, id);
if ((ni >= 0 && ii >= 0) || (ni >= 0 && strcmp(oc->name, id) == 0)
|| (ii >= 0 && strcmp(oc->name, name) == 0)) {
struct output_config *ion_oc = new_output_config(id_on_name);
if (ni >= 0) {
merge_output_config(ion_oc, config->output_configs->items[ni]);
}
if (ii >= 0) {
merge_output_config(ion_oc, config->output_configs->items[ii]);
}
merge_output_config(ion_oc, oc);
list_add(config->output_configs, ion_oc);
sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\""
" (enabled: %d) (%dx%d@%fHz position %d,%d scale %f "
"transform %d) (bg %s %s) (power %d) (max render time: %d)",
ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height,
ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale,
ion_oc->transform, ion_oc->background,
ion_oc->background_option, ion_oc->power,
ion_oc->max_render_time);
}
}
free(id_on_name);
}
struct output_config *store_output_config(struct output_config *oc) {
void store_output_config(struct output_config *oc) {
bool merged = false;
bool wildcard = strcmp(oc->name, "*") == 0;
if (wildcard) {
merge_wildcard_on_all(oc);
} else {
merge_id_on_name(oc);
struct sway_output *output = wildcard ? NULL : output_by_name_or_id(oc->name);
char id[128];
if (output) {
output_get_identifier(id, sizeof(id), output);
}
int i = list_seq_find(config->output_configs, output_name_cmp, oc->name);
if (i >= 0) {
sway_log(SWAY_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) {
sway_log(SWAY_DEBUG, "Adding non-wildcard output config");
i = list_seq_find(config->output_configs, output_name_cmp, "*");
if (i >= 0) {
sway_log(SWAY_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;
for (int i = 0; i < config->output_configs->length; i++) {
struct output_config *old = config->output_configs->items[i];
// If the old config matches the new config's name, regardless of
// whether it was name or identifier, merge on top of the existing
// config. If the new config is a wildcard, this also merges on top of
// old wildcard configs.
if (strcmp(old->name, oc->name) == 0) {
merge_output_config(old, oc);
merged = true;
continue;
}
// If the new config is a wildcard config we supersede all non-wildcard
// configs. Old wildcard configs have already been handled above.
if (wildcard) {
supersede_output_config(old, oc);
continue;
}
// If the new config matches an output's name, and the old config
// matches on that output's identifier, supersede it.
if (output && strcmp(old->name, id) == 0 &&
strcmp(oc->name, output->wlr_output->name) == 0) {
supersede_output_config(old, oc);
}
list_add(config->output_configs, oc);
} else {
// New wildcard config. Just add it
sway_log(SWAY_DEBUG, "Adding output * config");
list_add(config->output_configs, oc);
}
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
@ -239,7 +253,13 @@ struct output_config *store_output_config(struct output_config *oc) {
oc->transform, oc->background, oc->background_option, oc->power,
oc->max_render_time);
return oc;
// If the configuration was not merged into an existing configuration, add
// it to the list. Otherwise we're done with it and can free it.
if (!merged) {
list_add(config->output_configs, oc);
} else {
free_output_config(oc);
}
}
static void set_mode(struct wlr_output *output, struct wlr_output_state *pending,
@ -503,25 +523,12 @@ static void queue_output_config(struct output_config *oc,
}
}
bool apply_output_config(struct output_config *oc, struct sway_output *output) {
static bool finalize_output_config(struct output_config *oc, struct sway_output *output) {
if (output == root->fallback_output) {
return false;
}
struct wlr_output *wlr_output = output->wlr_output;
struct wlr_output_state pending = {0};
queue_output_config(oc, output, &pending);
sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name);
if (!wlr_output_commit_state(wlr_output, &pending)) {
// Failed to commit output changes, maybe the output is missing a CRTC.
// Leave the output disabled for now and try again when the output gets
// the mode we asked for.
sway_log(SWAY_ERROR, "Failed to commit output %s", wlr_output->name);
return false;
}
if (oc && !oc->enabled) {
sway_log(SWAY_DEBUG, "Disabling output %s", oc->name);
if (output->enabled) {
@ -577,25 +584,9 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
output->max_render_time = oc->max_render_time;
}
// Reconfigure all devices, since input config may have been applied before
// this output came online, and some config items (like map_to_output) are
// dependent on an output being present.
input_manager_configure_all_input_mappings();
// Reconfigure the cursor images, since the scale may have changed.
input_manager_configure_xcursor();
return true;
}
bool test_output_config(struct output_config *oc, struct sway_output *output) {
if (output == root->fallback_output) {
return false;
}
struct wlr_output_state pending = {0};
queue_output_config(oc, output, &pending);
return wlr_output_test_state(output->wlr_output, &pending);
}
static void default_output_config(struct output_config *oc,
struct wlr_output *wlr_output) {
oc->enabled = 1;
@ -615,140 +606,167 @@ static void default_output_config(struct output_config *oc,
oc->max_render_time = 0;
}
static struct output_config *get_output_config(char *identifier,
struct sway_output *sway_output) {
// find_output_config returns a merged output_config containing all stored
// configuration that applies to the specified output.
struct output_config *find_output_config(struct sway_output *sway_output) {
const char *name = sway_output->wlr_output->name;
struct output_config *oc = NULL;
struct output_config *oc_id_on_name = NULL;
struct output_config *oc_name = NULL;
struct output_config *oc_id = NULL;
char *id_on_name = format_str("%s on %s", identifier, name);
int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name);
if (i >= 0) {
oc_id_on_name = config->output_configs->items[i];
} else {
i = list_seq_find(config->output_configs, output_name_cmp, name);
if (i >= 0) {
oc_name = config->output_configs->items[i];
}
i = list_seq_find(config->output_configs, output_name_cmp, identifier);
if (i >= 0) {
oc_id = config->output_configs->items[i];
}
}
struct output_config *result = new_output_config("temp");
struct output_config *result = new_output_config(name);
if (config->reloading) {
default_output_config(result, sway_output->wlr_output);
}
if (oc_id_on_name) {
// Already have an identifier on name config, use that
free(result->name);
result->name = strdup(id_on_name);
merge_output_config(result, oc_id_on_name);
} else if (oc_name && oc_id) {
// Generate a config named `<identifier> on <name>` which contains a
// merged copy of the identifier on name. This will make sure that both
// identifier and name configs are respected, with identifier getting
// priority
struct output_config *temp = new_output_config(id_on_name);
merge_output_config(temp, oc_name);
merge_output_config(temp, oc_id);
list_add(config->output_configs, temp);
free(result->name);
result->name = strdup(id_on_name);
merge_output_config(result, temp);
char id[128];
output_get_identifier(id, sizeof(id), sway_output);
sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)"
" (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)"
" (power %d) (max render time: %d)", result->name, result->enabled,
result->width, result->height, result->refresh_rate,
result->x, result->y, result->scale, result->transform,
result->background, result->background_option, result->power,
result->max_render_time);
} else if (oc_name) {
// No identifier config, just return a copy of the name config
free(result->name);
result->name = strdup(name);
merge_output_config(result, oc_name);
} else if (oc_id) {
// No name config, just return a copy of the identifier config
free(result->name);
result->name = strdup(identifier);
merge_output_config(result, oc_id);
} else {
i = list_seq_find(config->output_configs, output_name_cmp, "*");
if (i >= 0) {
// No name or identifier config, but there is a wildcard config
free(result->name);
result->name = strdup("*");
merge_output_config(result, config->output_configs->items[i]);
} else if (!config->reloading) {
// No name, identifier, or wildcard config. Since we are not
// reloading with defaults, the output config will be empty, so
// just return NULL
free_output_config(result);
result = NULL;
}
int i;
bool match = false;
if ((i = list_seq_find(config->output_configs, output_name_cmp, "*")) >= 0) {
match = true;
oc = config->output_configs->items[i];
merge_output_config(result, oc);
}
if ((i = list_seq_find(config->output_configs, output_name_cmp, name)) >= 0) {
match = true;
oc = config->output_configs->items[i];
merge_output_config(result, oc);
}
if ((i = list_seq_find(config->output_configs, output_name_cmp, id)) >= 0) {
match = true;
oc = config->output_configs->items[i];
merge_output_config(result, oc);
}
if (!match && !config->reloading) {
// No name, identifier, or wildcard config. Since we are not
// reloading with defaults, the output config will be empty, so
// just return NULL
free_output_config(result);
return NULL;
}
free(id_on_name);
return result;
}
struct output_config *find_output_config(struct sway_output *output) {
char id[128];
output_get_identifier(id, sizeof(id), output);
return get_output_config(id, output);
}
bool apply_output_configs(struct matched_output_config *configs,
size_t configs_len, bool test_only) {
struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
if (!states) {
return false;
}
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;
struct sway_output *sway_output, *tmp;
wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) {
if (output_match_name_or_id(sway_output, oc->name)) {
char id[128];
output_get_identifier(id, sizeof(id), sway_output);
struct output_config *current = get_output_config(id, sway_output);
if (!current) {
// No stored output config matched, apply oc directly
sway_log(SWAY_DEBUG, "Applying oc directly");
current = new_output_config(oc->name);
merge_output_config(current, oc);
}
apply_output_config(current, sway_output);
free_output_config(current);
sway_log(SWAY_DEBUG, "Committing %zd outputs", configs_len);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
struct wlr_backend_output_state *backend_state = &states[idx];
if (!wildcard) {
// Stop looking if the output config isn't applicable to all
// outputs
break;
}
backend_state->output = cfg->output->wlr_output;
wlr_output_state_init(&backend_state->base);
sway_log(SWAY_DEBUG, "Preparing config for %s",
cfg->output->wlr_output->name);
queue_output_config(cfg->config, cfg->output, &backend_state->base);
}
struct wlr_output_swapchain_manager swapchain_mgr;
wlr_output_swapchain_manager_init(&swapchain_mgr, server.backend);
bool ok = wlr_output_swapchain_manager_prepare(&swapchain_mgr, states, configs_len);
if (!ok) {
sway_log(SWAY_ERROR, "Swapchain prepare failed");
goto out;
}
if (test_only) {
// The swapchain manager already did a test for us
goto out;
}
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
struct wlr_backend_output_state *backend_state = &states[idx];
struct wlr_scene_output_state_options opts = {
.swapchain = wlr_output_swapchain_manager_get_swapchain(
&swapchain_mgr, backend_state->output),
};
struct wlr_scene_output *scene_output = cfg->output->scene_output;
struct wlr_output_state *state = &backend_state->base;
if (!wlr_scene_output_build_state(scene_output, state, &opts)) {
sway_log(SWAY_ERROR, "Building output state for '%s' failed",
backend_state->output->name);
goto out;
}
}
ok = wlr_backend_commit(server.backend, states, configs_len);
if (!ok) {
sway_log(SWAY_ERROR, "Backend commit failed");
goto out;
}
sway_log(SWAY_DEBUG, "Commit of %zd outputs succeeded", configs_len);
wlr_output_swapchain_manager_apply(&swapchain_mgr);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
sway_log(SWAY_DEBUG, "Finalizing config for %s",
cfg->output->wlr_output->name);
finalize_output_config(cfg->config, cfg->output);
}
out:
wlr_output_swapchain_manager_finish(&swapchain_mgr);
for (size_t idx = 0; idx < configs_len; idx++) {
struct wlr_backend_output_state *backend_state = &states[idx];
wlr_output_state_finish(&backend_state->base);
}
free(states);
// Reconfigure all devices, since input config may have been applied before
// this output came online, and some config items (like map_to_output) are
// dependent on an output being present.
input_manager_configure_all_input_mappings();
// Reconfigure the cursor images, since the scale may have changed.
input_manager_configure_xcursor();
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
cursor_rebase(seat->cursor);
}
return ok;
}
void reset_outputs(void) {
struct output_config *oc = NULL;
int i = list_seq_find(config->output_configs, output_name_cmp, "*");
if (i >= 0) {
oc = config->output_configs->items[i];
} else {
oc = store_output_config(new_output_config("*"));
void apply_all_output_configs(void) {
size_t configs_len = wl_list_length(&root->all_outputs);
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
if (!configs) {
return;
}
apply_output_config_to_outputs(oc);
int config_idx = 0;
struct sway_output *sway_output;
wl_list_for_each(sway_output, &root->all_outputs, link) {
if (sway_output == root->fallback_output) {
configs_len--;
continue;
}
struct matched_output_config *config = &configs[config_idx++];
config->output = sway_output;
config->config = find_output_config(sway_output);
}
apply_output_configs(configs, configs_len, false);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
free_output_config(cfg->config);
}
free(configs);
}
void free_output_config(struct output_config *oc) {

View File

@ -521,9 +521,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
sway_session_lock_add_output(server->session_lock.lock, output);
}
struct output_config *oc = find_output_config(output);
apply_output_config(oc, output);
free_output_config(oc);
apply_all_output_configs();
transaction_commit_dirty();
@ -552,63 +550,88 @@ void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) {
wlr_output_schedule_frame(output->wlr_output);
}
static struct output_config *output_config_for_config_head(
struct wlr_output_configuration_head_v1 *config_head,
struct sway_output *output) {
struct output_config *oc = new_output_config(output->wlr_output->name);
oc->enabled = config_head->state.enabled;
if (!oc->enabled) {
return oc;
}
if (config_head->state.mode != NULL) {
struct wlr_output_mode *mode = config_head->state.mode;
oc->width = mode->width;
oc->height = mode->height;
oc->refresh_rate = mode->refresh / 1000.f;
} else {
oc->width = config_head->state.custom_mode.width;
oc->height = config_head->state.custom_mode.height;
oc->refresh_rate =
config_head->state.custom_mode.refresh / 1000.f;
}
oc->x = config_head->state.x;
oc->y = config_head->state.y;
oc->transform = config_head->state.transform;
oc->scale = config_head->state.scale;
oc->adaptive_sync = config_head->state.adaptive_sync_enabled;
return oc;
}
static void output_manager_apply(struct sway_server *server,
struct wlr_output_configuration_v1 *config, bool test_only) {
// TODO: perform atomic tests on the whole backend atomically
size_t configs_len = wl_list_length(&root->all_outputs);
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
if (!configs) {
return;
}
struct wlr_output_configuration_head_v1 *config_head;
// First disable outputs we need to disable
bool ok = true;
wl_list_for_each(config_head, &config->heads, link) {
struct wlr_output *wlr_output = config_head->state.output;
struct sway_output *output = wlr_output->data;
if (!output->enabled || config_head->state.enabled) {
int config_idx = 0;
struct sway_output *sway_output;
wl_list_for_each(sway_output, &root->all_outputs, link) {
if (sway_output == root->fallback_output) {
configs_len--;
continue;
}
struct output_config *oc = new_output_config(output->wlr_output->name);
oc->enabled = false;
if (test_only) {
ok &= test_output_config(oc, output);
} else {
oc = store_output_config(oc);
ok &= apply_output_config(oc, output);
struct matched_output_config *cfg = &configs[config_idx++];
cfg->output = sway_output;
struct wlr_output_configuration_head_v1 *config_head;
wl_list_for_each(config_head, &config->heads, link) {
if (config_head->state.output == sway_output->wlr_output) {
cfg->config = output_config_for_config_head(config_head, sway_output);
break;
}
}
if (!cfg->config) {
cfg->config = find_output_config(sway_output);
}
}
// Then enable outputs that need to
wl_list_for_each(config_head, &config->heads, link) {
struct wlr_output *wlr_output = config_head->state.output;
struct sway_output *output = wlr_output->data;
if (!config_head->state.enabled) {
continue;
}
struct output_config *oc = new_output_config(output->wlr_output->name);
oc->enabled = true;
if (config_head->state.mode != NULL) {
struct wlr_output_mode *mode = config_head->state.mode;
oc->width = mode->width;
oc->height = mode->height;
oc->refresh_rate = mode->refresh / 1000.f;
} else {
oc->width = config_head->state.custom_mode.width;
oc->height = config_head->state.custom_mode.height;
oc->refresh_rate =
config_head->state.custom_mode.refresh / 1000.f;
}
oc->x = config_head->state.x;
oc->y = config_head->state.y;
oc->transform = config_head->state.transform;
oc->scale = config_head->state.scale;
oc->adaptive_sync = config_head->state.adaptive_sync_enabled;
bool ok = apply_output_configs(configs, configs_len, test_only);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
if (test_only) {
ok &= test_output_config(oc, output);
// Only store new configs for successful non-test commits. Old configs,
// test-only and failed commits just get freed.
bool store_config = false;
if (!test_only && ok) {
struct wlr_output_configuration_head_v1 *config_head;
wl_list_for_each(config_head, &config->heads, link) {
if (config_head->state.output == cfg->output->wlr_output) {
store_config = true;
break;
}
}
}
if (store_config) {
store_output_config(cfg->config);
} else {
oc = store_output_config(oc);
ok &= apply_output_config(oc, output);
free_output_config(cfg->config);
}
}
free(configs);
if (ok) {
wlr_output_configuration_v1_send_succeeded(config);
@ -652,6 +675,6 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
oc->power = 1;
break;
}
oc = store_output_config(oc);
apply_output_config(oc, output);
store_output_config(oc);
apply_all_output_configs();
}

View File

@ -32,6 +32,7 @@ static struct modifier_key {
{ XKB_MOD_NAME_NUM, WLR_MODIFIER_MOD2 },
{ "Mod3", WLR_MODIFIER_MOD3 },
{ XKB_MOD_NAME_LOGO, WLR_MODIFIER_LOGO },
{ "Super", WLR_MODIFIER_LOGO },
{ "Mod5", WLR_MODIFIER_MOD5 },
};

View File

@ -117,7 +117,11 @@ static void handle_touch_cancel(struct sway_seat *seat,
}
if (e->surface) {
wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface);
struct wl_client *client = wl_resource_get_client(e->surface->resource);
struct wlr_seat_client *seat_client = wlr_seat_client_for_wl_client(seat->wlr_seat, client);
if (seat_client != NULL) {
wlr_seat_touch_notify_cancel(seat->wlr_seat, seat_client);
}
}
if (wl_list_empty(&e->point_events)) {

View File

@ -240,13 +240,12 @@ bool server_init(struct sway_server *server) {
wlr_renderer_init_wl_shm(server->renderer, server->wl_display);
if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) {
if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) {
server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer(
server->wl_display, 4, server->renderer);
}
if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL &&
debug.legacy_wl_drm) {
wlr_drm_create(server->wl_display, server->renderer);
if (debug.legacy_wl_drm) {
wlr_drm_create(server->wl_display, server->renderer);
}
}
server->allocator = wlr_allocator_autocreate(server->backend,

View File

@ -1046,7 +1046,7 @@ An object with a single string property containing the contents of the config
*Example Reply:*
```
{
"config": "set $mod Mod4\nbindsym $mod+q exit\n"
"config": "set $mod Mod4\\nbindsym $mod+q exit\\n"
}
```

View File

@ -400,6 +400,12 @@ runtime.
only be available for that group. By default, if you overwrite a binding,
swaynag will give you a warning. To silence this, use the _--no-warn_ flag.
For specifying modifier keys, you can use the XKB modifier names _Shift_,
_Lock_ (for Caps Lock), _Control_, _Mod1_ (for Alt), _Mod2_ (for Num Lock),
_Mod3_ (for XKB modifier Mod3), _Mod4_ (for the Logo key), and _Mod5_ (for
AltGr). In addition, you can use the aliases _Ctrl_ (for Control), _Alt_
(for Alt), and _Super_ (for the Logo key).
Unless the flag _--locked_ is set, the command will not be run when a
screen locking program is active. If there is a matching binding with
and without _--locked_, the one with will be preferred when locked and the

View File

@ -9,6 +9,7 @@
#include "sway/tree/workspace.h"
#include "sway/server.h"
#include "log.h"
#include "stringop.h"
#include "util.h"
enum wlr_direction opposite_direction(enum wlr_direction d) {
@ -403,7 +404,7 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
} else if (isdigit(b->name[0])) {
return 1;
}
return 0;
return lenient_strcmp(a->name, b->name);
}
void output_sort_workspaces(struct sway_output *output) {