Compare commits

..

17 Commits

Author SHA1 Message Date
bonsaiiV
f280b1ac77
Merge c32e795053 into d7a76d381b 2024-09-11 09:28:08 +03:00
Kenny Levinsen
d7a76d381b config/output: Rename to apply_stored_output_configs 2024-09-10 14:13:36 -04:00
Kenny Levinsen
29b3f00e6f config/output: Accept a list of output_configs to use
Instead of using a single finalized output config per output, accept a
regular list of output configs like the one ultimately stored for
configuration purposes. This allows the output management code to test
an augmented configuration while still using the same output config
logic, without having to mutate the stored configuration.

This in turn allows us to make a few APIs private. A bug note about an
existing issue with derade to off is added as well.
2024-09-10 14:13:36 -04:00
Kenny Levinsen
0496477f92 config/output: Always start with default in find_output_config
We always need to start out with the default configuration, regardless
of whether the config is reloading or not to ensure that config
decisions are stable given a specific configuration.
2024-09-10 14:13:36 -04:00
Kenny Levinsen
a0c0349934 config/output: Support multiple matches in find_output_config
Simplify find_output_config and inline the search through the output
configs instead of using list_seq_find with a comparator function. The
new implementation will merge any amount of matched configs in order,
which will be relied upon in a future commit.
2024-09-10 14:13:36 -04:00
Adam Chovanec
fb5eadc363 readme: update Czech translation 2024-09-08 16:06:26 +02:00
llyyr
c5ba7f23a5 sway/input/keyboard: always set active keyboard if there is none
Previously, we incorrectly only set active keyboard for non-virtual
devices. 4c3c060211 incorrectly put
unrelated code in `sway_keyboard_set_layout`.

Fixes: 4c3c060211
2024-09-08 14:18:01 +02:00
Kenny Levinsen
f4a6b0395f tree/arrange; Skip arranging disabled outputs
Disabled outputs might not have a geometry to arrange for, so skip the
arrange to avoid messing up the workspace geometry.
2024-09-07 20:11:30 -04:00
Kenny Levinsen
14bff7b451 desktop/transaction: Deactivate workspace on inactive outputs
If the output is not active, it might not have a valid geometry to
arrange for. Outputs do not gain a geometry until modeset, so if an
output is connected with a configuration present to disable it, it will
not have a geometry. If the output has a past workspace restored, this
will be attemtped arranged to fit a 0x0 rectangle, which asserts when
trying to sort out borders.

Consider the workspace activated only if the output itself is active to
get the scene nodes disabled.
2024-09-07 20:11:30 -04:00
Kenny Levinsen
4f9ce4675c tree/arrange: Remove redundant output geometry update
This is handled by apply_output_configs.
2024-09-07 20:11:30 -04:00
Alexander Orzechowski
fc6b8d6af2 container: Skip % char if it doesn't match a view property
The else condition was missed here and we would never skip the % char
if it didn't end up matching with any property. Since we fail to skip
we would re-evaluate the % in an infinite loop never achieving any
forward-progress.

Fixes: https://github.com/swaywm/sway/issues/8333
2024-09-07 01:19:31 +02:00
Kenny Levinsen
4fe054c6db tree/output: Avoid duplicate input mapping configure 2024-09-05 18:19:16 -04:00
Kenny Levinsen
cfb292cca7 desktop/output: Avoid duplicate output manager update 2024-09-05 18:19:16 -04:00
Kenny Levinsen
af28ac04a4 (desktop|tree)/output: Do not use layout listener to arrange
Output layout changes originate from the centralized modeset
infrastructure and request_state which already takes care of arranging
and updating outputs as needed.
2024-09-04 13:49:35 -04:00
Kenny Levinsen
6045ad9a02 tree/output: Rely on modeset arranging root
output_enable/output_disable are only called from modeset, and from
output destroy which requests modeset. As such, they can rely on the
modeset handling arrange.
2024-09-04 13:49:35 -04:00
Kenny Levinsen
b83e5aaa54 desktop/output: Do not use commit listener to arrange
The reasoning for using a commit handler is to ensure that all paths for
output changes are correctly handled. With the centralized modeset
infrastructure in place, we can move the logic there. This allows us to
be smarter and avoid extraneous arranges, output manager updates and
transaction commits.

The side-effect is a minor duplication for the special-case
request_state, but the shared path will be relied upon further in future
commits to justify this duplication.
2024-09-04 13:49:35 -04:00
Norbert Bolanowski
be840f730e move title_format to container 2024-09-02 16:49:05 -04:00
20 changed files with 241 additions and 309 deletions

View File

@ -1,6 +1,6 @@
# sway
[English][en] - **[Česky][cs]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [Svenska][sv] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
[English][en] - [عربي][ar] - **[Česky][cs]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [ქართული][ge] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Norsk][no] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Svenska][sv] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
sway je s [i3] kompatibilní [Wayland] kompozitor. Přečtěte si [FAQ]. Připojte se na
[IRC kanál][IRC channel] \(#sway na irc.libera.chat).
@ -32,10 +32,11 @@ Nainstalujte závislosti:
* pango
* cairo
* gdk-pixbuf2 (volitelné: oznamovací oblast)
* [swaybg] (volitelné: tapeta)
* [scdoc] (volitelné: manuálové stránky) \*
* git (volitelné: informace o verzi) \*
_\* Závislost pouze pro sestavení_
_\* Závislost pouze pro kompilaci_
Spusťte tyto příkazy:
@ -56,12 +57,13 @@ Spusťte `sway` z TTY. Některé správce zobrazení mohou fungovat, ale nejsou
podporovány sway (je známo, že gdm funguje docela dobře).
[en]: https://github.com/swaywm/sway#readme
[ar]: README.ar.md
[cs]: README.cs.md
[de]: README.de.md
[dk]: README.dk.md
[es]: README.es.md
[fr]: README.fr.md
[sv]: README.sv.md
[ge]: README.ge.md
[gr]: README.gr.md
[hi]: README.hi.md
[hu]: README.hu.md
@ -70,10 +72,12 @@ podporovány sway (je známo, že gdm funguje docela dobře).
[ja]: README.ja.md
[ko]: README.ko.md
[nl]: README.nl.md
[no]: README.no.md
[pl]: README.pl.md
[pt]: README.pt.md
[ro]: README.ro.md
[ru]: README.ru.md
[sv]: README.sv.md
[tr]: README.tr.md
[uk]: README.uk.md
[zh-CN]: README.zh-CN.md
@ -86,4 +90,5 @@ podporovány sway (je známo, že gdm funguje docela dobře).
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[swaybg]: https://github.com/swaywm/swaybg/
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View File

@ -296,14 +296,6 @@ 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
*/
@ -693,13 +685,10 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt
struct output_config *new_output_config(const char *name);
bool apply_output_configs(struct matched_output_config *configs,
size_t configs_len, bool test_only, bool degrade_to_off);
bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
bool test_only, bool degrade_to_off);
void apply_all_output_configs(void);
void sort_output_configs_by_priority(struct matched_output_config *configs,
size_t configs_len);
void apply_stored_output_configs(void);
/**
* store_output_config stores a new output config. An output may be matched by

View File

@ -57,7 +57,6 @@ struct sway_output {
struct wl_listener layout_destroy;
struct wl_listener destroy;
struct wl_listener commit;
struct wl_listener present;
struct wl_listener frame;
struct wl_listener request_state;
@ -135,8 +134,6 @@ enum sway_container_layout output_get_default_layout(
enum wlr_direction opposite_direction(enum wlr_direction d);
void handle_output_layout_change(struct wl_listener *listener, void *data);
void handle_output_manager_apply(struct wl_listener *listener, void *data);
void handle_output_manager_test(struct wl_listener *listener, void *data);
@ -146,4 +143,6 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
void update_output_manager_config(struct sway_server *server);
#endif

View File

@ -45,7 +45,6 @@ struct sway_server {
struct sway_input_manager *input;
struct wl_listener new_output;
struct wl_listener output_layout_change;
struct wl_listener renderer_lost;
struct wlr_idle_notifier_v1 *idle_notifier_v1;

View File

@ -102,6 +102,8 @@ struct sway_container {
char *title; // The view's title (unformatted)
char *formatted_title; // The title displayed in the title bar
int title_width;
char *title_format;
enum sway_container_layout prev_split_layout;
@ -183,6 +185,8 @@ void container_update_title_bar(struct sway_container *container);
void container_update_marks(struct sway_container *container);
size_t parse_title_format(struct sway_container *container, char *buffer);
size_t container_build_representation(enum sway_container_layout layout,
list_t *children, char *buffer);

View File

@ -16,8 +16,6 @@ struct sway_root {
struct sway_node node;
struct wlr_output_layout *output_layout;
struct wl_listener output_layout_change;
// scene node layout:
// - root
// - staging

View File

@ -80,8 +80,6 @@ struct sway_view {
// Used when changing a view from tiled to floating.
int natural_width, natural_height;
char *title_format;
bool using_csd;
struct timespec urgent;

View File

@ -111,7 +111,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
// 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_all_output_configs();
apply_stored_output_configs();
if (background) {
if (!spawn_swaybg()) {
return cmd_results_new(CMD_FAILURE,

View File

@ -1,3 +1,4 @@
#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include "sway/commands.h"
#include "sway/config.h"
@ -11,16 +12,19 @@ struct cmd_results *cmd_title_format(int argc, char **argv) {
return error;
}
struct sway_container *container = config->handler_context.container;
if (!container || !container->view) {
if (!container) {
return cmd_results_new(CMD_INVALID,
"Only views can have a title_format");
"Only valid containers can have a title_format");
}
struct sway_view *view = container->view;
char *format = join_args(argv, argc);
if (view->title_format) {
free(view->title_format);
if (container->title_format) {
free(container->title_format);
}
container->title_format = format;
if (container->view) {
view_update_title(container->view, true);
} else {
container_update_representation(container);
}
view->title_format = format;
view_update_title(view, true);
return cmd_results_new(CMD_SUCCESS, NULL);
}

View File

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

View File

@ -11,9 +11,12 @@
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_swapchain_manager.h>
#include "sway/config.h"
#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/root.h"
#include "log.h"
#include "util.h"
@ -22,13 +25,6 @@
#include <wlr/backend/drm.h>
#endif
int output_name_cmp(const void *item, const void *data) {
const struct output_config *output = item;
const char *name = data;
return strcmp(output->name, name);
}
void output_get_identifier(char *identifier, size_t len,
struct sway_output *output) {
struct wlr_output *wlr_output = output->wlr_output;
@ -588,69 +584,52 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
return true;
}
static void default_output_config(struct output_config *oc,
struct wlr_output *wlr_output) {
oc->enabled = 1;
oc->power = 1;
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
if (mode != NULL) {
oc->width = mode->width;
oc->height = mode->height;
oc->refresh_rate = mode->refresh / 1000.f;
}
oc->x = oc->y = -1;
oc->scale = 0; // auto
oc->scale_filter = SCALE_FILTER_DEFAULT;
struct sway_output *output = wlr_output->data;
oc->subpixel = output->detected_subpixel;
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
oc->max_render_time = 0;
oc->allow_tearing = 0;
}
// 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) {
// find_output_config_from_list returns a merged output_config containing all
// stored configuration that applies to the specified output.
static struct output_config *find_output_config_from_list(
struct output_config **configs, size_t configs_len,
struct sway_output *sway_output) {
const char *name = sway_output->wlr_output->name;
struct output_config *oc = NULL;
struct output_config *result = new_output_config(name);
if (config->reloading) {
default_output_config(result, sway_output->wlr_output);
if (result == NULL) {
return NULL;
}
// Set output defaults for the "base" configuration
result->enabled = 1;
result->power = 1;
result->scale = 0; // auto
result->subpixel = sway_output->detected_subpixel;
result->transform = WL_OUTPUT_TRANSFORM_NORMAL;
result->max_render_time = 0;
result->allow_tearing = 0;
char id[128];
output_get_identifier(id, sizeof(id), sway_output);
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;
// We take a new config and merge on top, in order, the wildcard config,
// output config by name, and output config by identifier to form the final
// config. If there are multiple matches, they are merged in order.
struct output_config *oc = NULL;
const char *names[] = {"*", name, id, NULL};
for (const char **name = &names[0]; *name; name++) {
for (size_t idx = 0; idx < configs_len; idx++) {
oc = configs[idx];
if (strcmp(oc->name, *name) == 0) {
merge_output_config(result, oc);
}
}
}
return result;
}
struct output_config *find_output_config(struct sway_output *sway_output) {
return find_output_config_from_list(
(struct output_config **)config->output_configs->items,
config->output_configs->length, sway_output);
}
static bool config_has_manual_mode(struct output_config *oc) {
if (!oc) {
return false;
@ -663,6 +642,14 @@ static bool config_has_manual_mode(struct output_config *oc) {
return false;
}
/**
* An output config pre-matched to an output
*/
struct matched_output_config {
struct sway_output *output;
struct output_config *config;
};
struct search_context {
struct wlr_output_swapchain_manager *swapchain_mgr;
struct wlr_backend_output_state *states;
@ -881,12 +868,12 @@ static int compare_matched_output_config_priority(const void *a, const void *b)
return 0;
}
void sort_output_configs_by_priority(struct matched_output_config *configs,
size_t configs_len) {
static void sort_output_configs_by_priority(
struct matched_output_config *configs, size_t configs_len) {
qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority);
}
bool apply_output_configs(struct matched_output_config *configs,
static bool apply_resolved_output_configs(struct matched_output_config *configs,
size_t configs_len, bool test_only, bool degrade_to_off) {
struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
if (!states) {
@ -963,8 +950,13 @@ bool apply_output_configs(struct matched_output_config *configs,
sway_log(SWAY_DEBUG, "Finalizing config for %s",
cfg->output->wlr_output->name);
finalize_output_config(cfg->config, cfg->output);
arrange_layers(cfg->output);
}
arrange_root();
update_output_manager_config(&server);
transaction_commit_dirty();
out:
wlr_output_swapchain_manager_finish(&swapchain_mgr);
for (size_t idx = 0; idx < configs_len; idx++) {
@ -989,11 +981,12 @@ out:
return ok;
}
void apply_all_output_configs(void) {
bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
bool test_only, bool degrade_to_off) {
size_t configs_len = wl_list_length(&root->all_outputs);
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
if (!configs) {
return;
return false;
}
int config_idx = 0;
@ -1006,16 +999,22 @@ void apply_all_output_configs(void) {
struct matched_output_config *config = &configs[config_idx++];
config->output = sway_output;
config->config = find_output_config(sway_output);
config->config = find_output_config_from_list(ocs, ocs_len, sway_output);
}
sort_output_configs_by_priority(configs, configs_len);
apply_output_configs(configs, configs_len, false, true);
bool ok = apply_resolved_output_configs(configs, configs_len, test_only, degrade_to_off);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
free_output_config(cfg->config);
}
free(configs);
return ok;
}
void apply_stored_output_configs(void) {
apply_output_configs((struct output_config **)config->output_configs->items,
config->output_configs->length, false, true);
}
void free_output_config(struct output_config *oc) {

View File

@ -356,7 +356,7 @@ static void handle_frame(struct wl_listener *listener, void *user_data) {
wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data);
}
static void update_output_manager_config(struct sway_server *server) {
void update_output_manager_config(struct sway_server *server) {
struct wlr_output_configuration_v1 *config =
wlr_output_configuration_v1_create();
@ -386,10 +386,7 @@ static int timer_modeset_handle(void *data) {
wl_event_source_remove(server->delayed_modeset);
server->delayed_modeset = NULL;
apply_all_output_configs();
transaction_commit_dirty();
update_output_manager_config(server);
apply_stored_output_configs();
return 0;
}
@ -414,7 +411,6 @@ static void begin_destroy(struct sway_output *output) {
wl_list_remove(&output->layout_destroy.link);
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->commit.link);
wl_list_remove(&output->present.link);
wl_list_remove(&output->frame.link);
wl_list_remove(&output->request_state.link);
@ -437,26 +433,6 @@ static void handle_layout_destroy(struct wl_listener *listener, void *data) {
begin_destroy(output);
}
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, commit);
struct wlr_output_event_commit *event = data;
if (!output->enabled) {
return;
}
if (event->state->committed & (
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_TRANSFORM |
WLR_OUTPUT_STATE_SCALE)) {
arrange_layers(output);
arrange_output(output);
transaction_commit_dirty();
update_output_manager_config(output->server);
}
}
static void handle_present(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, present);
struct wlr_output_event_present *output_event = data;
@ -473,7 +449,20 @@ static void handle_request_state(struct wl_listener *listener, void *data) {
struct sway_output *output =
wl_container_of(listener, output, request_state);
const struct wlr_output_event_request_state *event = data;
uint32_t committed = event->state->committed;
wlr_output_commit_state(output->wlr_output, event->state);
if (committed & (
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_TRANSFORM |
WLR_OUTPUT_STATE_SCALE)) {
arrange_layers(output);
arrange_output(output);
transaction_commit_dirty();
update_output_manager_config(output->server);
}
}
static unsigned int last_headless_num = 0;
@ -537,8 +526,6 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->layout_destroy.notify = handle_layout_destroy;
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
wl_signal_add(&wlr_output->events.commit, &output->commit);
output->commit.notify = handle_commit;
wl_signal_add(&wlr_output->events.present, &output->present);
output->present.notify = handle_present;
wl_signal_add(&wlr_output->events.frame, &output->frame);
@ -556,17 +543,9 @@ void handle_new_output(struct wl_listener *listener, void *data) {
request_modeset(server);
}
void handle_output_layout_change(struct wl_listener *listener,
void *data) {
struct sway_server *server =
wl_container_of(listener, server, output_layout_change);
update_output_manager_config(server);
}
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);
struct wlr_output_configuration_head_v1 *config_head) {
struct output_config *oc = new_output_config(config_head->state.output->name);
oc->enabled = config_head->state.enabled;
if (!oc->enabled) {
return oc;
@ -592,71 +571,48 @@ static struct output_config *output_config_for_config_head(
}
static void output_manager_apply(struct sway_server *server,
struct wlr_output_configuration_v1 *config, bool test_only) {
size_t configs_len = wl_list_length(&root->all_outputs);
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
struct wlr_output_configuration_v1 *cfg, bool test_only) {
bool ok = false;
size_t configs_len = config->output_configs->length + wl_list_length(&cfg->heads);
struct output_config **configs = calloc(configs_len, sizeof(*configs));
if (!configs) {
return;
goto done;
}
size_t start_new_configs = config->output_configs->length;
for (size_t idx = 0; idx < start_new_configs; idx++) {
configs[idx] = config->output_configs->items[idx];
}
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 *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);
}
size_t config_idx = start_new_configs;
struct wlr_output_configuration_head_v1 *config_head;
wl_list_for_each(config_head, &cfg->heads, link) {
// Generate the configuration and store it as a temporary
// config. We keep a record of it so we can remove it later.
struct output_config *oc = output_config_for_config_head(config_head);
configs[config_idx++] = oc;
}
sort_output_configs_by_priority(configs, configs_len);
bool ok = apply_output_configs(configs, configs_len, test_only, false);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
// Only store new configs for successful non-test commits. Old configs,
// test-only and failed commits just get freed.
bool store_config = false;
// Try to commit without degrade to off enabled. Note that this will fail
// if any output configured for enablement fails to be enabled, even if it
// was not part of the config heads we were asked to configure.
ok = apply_output_configs(configs, configs_len, test_only, false);
for (size_t idx = start_new_configs; idx < configs_len; idx++) {
struct output_config *cfg = configs[idx];
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);
store_output_config(cfg);
} else {
free_output_config(cfg->config);
free_output_config(cfg);
}
}
free(configs);
done:
if (ok) {
wlr_output_configuration_v1_send_succeeded(config);
wlr_output_configuration_v1_send_succeeded(cfg);
} else {
wlr_output_configuration_v1_send_failed(config);
}
wlr_output_configuration_v1_destroy(config);
if (!test_only) {
update_output_manager_config(server);
wlr_output_configuration_v1_send_failed(cfg);
}
wlr_output_configuration_v1_destroy(cfg);
}
void handle_output_manager_apply(struct wl_listener *listener, void *data) {

View File

@ -559,7 +559,7 @@ static void arrange_output(struct sway_output *output, int width, int height) {
for (int i = 0; i < output->current.workspaces->length; i++) {
struct sway_workspace *child = output->current.workspaces->items[i];
bool activated = output->current.active_workspace == child;
bool activated = output->current.active_workspace == child && output->wlr_output->enabled;
wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);

View File

@ -1028,13 +1028,6 @@ static void sway_keyboard_set_layout(struct sway_keyboard *keyboard,
}
}
// If the seat has no active keyboard, set this one
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
if (current_keyboard == NULL) {
wlr_seat_set_keyboard(seat, keyboard->wlr);
}
if (keymap_changed) {
ipc_event_input("xkb_keymap",
keyboard->seat_device->input_device);
@ -1078,6 +1071,13 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
sway_keyboard_set_layout(keyboard, input_config);
}
// If the seat has no active keyboard, set this one
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
if (current_keyboard == NULL) {
wlr_seat_set_keyboard(seat, keyboard->wlr);
}
wl_list_remove(&keyboard->keyboard_key.link);
wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
keyboard->keyboard_key.notify = handle_keyboard_key;

View File

@ -277,9 +277,6 @@ bool server_init(struct sway_server *server) {
server->new_output.notify = handle_new_output;
wl_signal_add(&server->backend->events.new_output, &server->new_output);
server->output_layout_change.notify = handle_output_layout_change;
wl_signal_add(&root->output_layout->events.change,
&server->output_layout_change);
server->xdg_output_manager_v1 =
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);

View File

@ -314,14 +314,9 @@ void arrange_output(struct sway_output *output) {
if (config->reloading) {
return;
}
struct wlr_box output_box;
wlr_output_layout_get_box(root->output_layout,
output->wlr_output, &output_box);
output->lx = output_box.x;
output->ly = output_box.y;
output->width = output_box.width;
output->height = output_box.height;
if (!output->wlr_output->enabled) {
return;
}
for (int i = 0; i < output->workspaces->length; ++i) {
struct sway_workspace *workspace = output->workspaces->items[i];
arrange_workspace(workspace);

View File

@ -22,6 +22,7 @@
#include "sway/tree/workspace.h"
#include "sway/xdg_decoration.h"
#include "list.h"
#include "pango.h"
#include "log.h"
#include "stringop.h"
@ -499,6 +500,7 @@ void container_destroy(struct sway_container *con) {
}
free(con->title);
free(con->formatted_title);
free(con->title_format);
list_free(con->pending.children);
list_free(con->current.children);
@ -645,6 +647,91 @@ bool container_has_ancestor(struct sway_container *descendant,
return false;
}
static char *escape_pango_markup(const char *buffer) {
size_t length = escape_markup_text(buffer, NULL);
char *escaped_title = calloc(length + 1, sizeof(char));
escape_markup_text(buffer, escaped_title);
return escaped_title;
}
static size_t append_prop(char *buffer, const char *value) {
if (!value) {
return 0;
}
// If using pango_markup in font, we need to escape all markup chars
// from values to make sure tags are not inserted by clients
if (config->pango_markup) {
char *escaped_value = escape_pango_markup(value);
lenient_strcat(buffer, escaped_value);
size_t len = strlen(escaped_value);
free(escaped_value);
return len;
} else {
lenient_strcat(buffer, value);
return strlen(value);
}
}
/**
* Calculate and return the length of the formatted title.
* If buffer is not NULL, also populate the buffer with the formatted title.
*/
size_t parse_title_format(struct sway_container *container, char *buffer) {
if (!container->title_format || strcmp(container->title_format, "%title") == 0) {
if (container->view) {
return append_prop(buffer, view_get_title(container->view));
} else {
return container_build_representation(container->pending.layout, container->pending.children, buffer);
}
}
size_t len = 0;
char *format = container->title_format;
char *next = strchr(format, '%');
while (next) {
// Copy everything up to the %
lenient_strncat(buffer, format, next - format);
len += next - format;
format = next;
if (strncmp(next, "%title", 6) == 0) {
if (container->view) {
len += append_prop(buffer, view_get_title(container->view));
} else {
len += container_build_representation(container->pending.layout, container->pending.children, buffer);
}
format += 6;
} else if (container->view) {
if (strncmp(next, "%app_id", 7) == 0) {
len += append_prop(buffer, view_get_app_id(container->view));
format += 7;
} else if (strncmp(next, "%class", 6) == 0) {
len += append_prop(buffer, view_get_class(container->view));
format += 6;
} else if (strncmp(next, "%instance", 9) == 0) {
len += append_prop(buffer, view_get_instance(container->view));
format += 9;
} else if (strncmp(next, "%shell", 6) == 0) {
len += append_prop(buffer, view_get_shell(container->view));
format += 6;
} else {
lenient_strcat(buffer, "%");
++format;
++len;
}
} else {
lenient_strcat(buffer, "%");
++format;
++len;
}
next = strchr(format, '%');
}
lenient_strcat(buffer, format);
len += strlen(format);
return len;
}
/**
* Calculate and return the length of the tree representation.
* An example tree representation is: V[Terminal, Firefox]
@ -700,16 +787,14 @@ size_t container_build_representation(enum sway_container_layout layout,
void container_update_representation(struct sway_container *con) {
if (!con->view) {
size_t len = container_build_representation(con->pending.layout,
con->pending.children, NULL);
size_t len = parse_title_format(con, NULL);
free(con->formatted_title);
con->formatted_title = calloc(len + 1, sizeof(char));
if (!sway_assert(con->formatted_title,
"Unable to allocate title string")) {
return;
}
container_build_representation(con->pending.layout, con->pending.children,
con->formatted_title);
parse_title_format(con, con->formatted_title);
if (con->title_bar.title_text) {
sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);

View File

@ -180,12 +180,7 @@ void output_enable(struct sway_output *output) {
ws->layout = output_get_default_layout(output);
}
input_manager_configure_xcursor();
wl_signal_emit_mutable(&root->events.new_node, &output->node);
arrange_layers(output);
arrange_root();
}
static void evacuate_sticky(struct sway_workspace *old_ws,
@ -300,13 +295,6 @@ void output_disable(struct sway_output *output) {
list_del(root->outputs, index);
output->enabled = false;
arrange_root();
// Reconfigure all devices, since devices with map_to_output directives for
// an output that goes offline should stop sending events as long as the
// output remains offline.
input_manager_configure_all_input_mappings();
}
void output_begin_destroy(struct sway_output *output) {

View File

@ -19,12 +19,6 @@
struct sway_root *root;
static void output_layout_handle_change(struct wl_listener *listener,
void *data) {
arrange_root();
transaction_commit_dirty();
}
struct sway_root *root_create(struct wl_display *wl_display) {
struct sway_root *root = calloc(1, sizeof(struct sway_root));
if (!root) {
@ -81,14 +75,10 @@ struct sway_root *root_create(struct wl_display *wl_display) {
root->non_desktop_outputs = create_list();
root->scratchpad = create_list();
root->output_layout_change.notify = output_layout_handle_change;
wl_signal_add(&root->output_layout->events.change,
&root->output_layout_change);
return root;
}
void root_destroy(struct sway_root *root) {
wl_list_remove(&root->output_layout_change.link);
list_free(root->scratchpad);
list_free(root->non_desktop_outputs);
list_free(root->outputs);

View File

@ -34,7 +34,6 @@
#include "sway/tree/workspace.h"
#include "sway/config.h"
#include "sway/xdg_decoration.h"
#include "pango.h"
#include "stringop.h"
bool view_init(struct sway_view *view, enum sway_view_type type,
@ -81,8 +80,6 @@ void view_destroy(struct sway_view *view) {
view_assign_ctx(view, NULL);
wlr_scene_node_destroy(&view->scene_tree->node);
free(view->title_format);
if (view->impl->destroy) {
view->impl->destroy(view);
} else {
@ -991,77 +988,6 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
return NULL;
}
static char *escape_pango_markup(const char *buffer) {
size_t length = escape_markup_text(buffer, NULL);
char *escaped_title = calloc(length + 1, sizeof(char));
escape_markup_text(buffer, escaped_title);
return escaped_title;
}
static size_t append_prop(char *buffer, const char *value) {
if (!value) {
return 0;
}
// If using pango_markup in font, we need to escape all markup chars
// from values to make sure tags are not inserted by clients
if (config->pango_markup) {
char *escaped_value = escape_pango_markup(value);
lenient_strcat(buffer, escaped_value);
size_t len = strlen(escaped_value);
free(escaped_value);
return len;
} else {
lenient_strcat(buffer, value);
return strlen(value);
}
}
/**
* Calculate and return the length of the formatted title.
* If buffer is not NULL, also populate the buffer with the formatted title.
*/
static size_t parse_title_format(struct sway_view *view, char *buffer) {
if (!view->title_format || strcmp(view->title_format, "%title") == 0) {
return append_prop(buffer, view_get_title(view));
}
size_t len = 0;
char *format = view->title_format;
char *next = strchr(format, '%');
while (next) {
// Copy everything up to the %
lenient_strncat(buffer, format, next - format);
len += next - format;
format = next;
if (strncmp(next, "%title", 6) == 0) {
len += append_prop(buffer, view_get_title(view));
format += 6;
} else if (strncmp(next, "%app_id", 7) == 0) {
len += append_prop(buffer, view_get_app_id(view));
format += 7;
} else if (strncmp(next, "%class", 6) == 0) {
len += append_prop(buffer, view_get_class(view));
format += 6;
} else if (strncmp(next, "%instance", 9) == 0) {
len += append_prop(buffer, view_get_instance(view));
format += 9;
} else if (strncmp(next, "%shell", 6) == 0) {
len += append_prop(buffer, view_get_shell(view));
format += 6;
} else {
lenient_strcat(buffer, "%");
++format;
++len;
}
next = strchr(format, '%');
}
lenient_strcat(buffer, format);
len += strlen(format);
return len;
}
void view_update_app_id(struct sway_view *view) {
const char *app_id = view_get_app_id(view);
@ -1090,7 +1016,7 @@ void view_update_title(struct sway_view *view, bool force) {
free(view->container->title);
free(view->container->formatted_title);
size_t len = parse_title_format(view, NULL);
size_t len = parse_title_format(view->container, NULL);
if (len) {
char *buffer = calloc(len + 1, sizeof(char));
@ -1098,7 +1024,7 @@ void view_update_title(struct sway_view *view, bool force) {
return;
}
parse_title_format(view, buffer);
parse_title_format(view->container, buffer);
view->container->formatted_title = buffer;
} else {
view->container->formatted_title = NULL;