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

Compare commits

...

40 Commits

Author SHA1 Message Date
Keith 78ce24a701
Merge 2b5d8a0978 into 646019cad9 2024-04-26 17:58:52 +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
Andri Yngvason 5a7477cb8f Implement transient seat management 2024-03-18 09:07:21 +01:00
Simon Ser dc9f217307 man: document that the scale might be adjusted
fractional-scale only supports representing fractions of 120.

References: https://github.com/swaywm/sway/issues/8057
2024-03-14 23:22:32 +01:00
Simon Ser 9139da6149 man: drop fractional scale warning
With the fractional-scale protocol, clients can render without
being downscaled.
2024-03-14 23:22:32 +01:00
Simon Ser 3bc75221bc Re-create renderer when lost 2024-03-14 22:55:46 +01:00
Simon Ser 2b08e79061 server: fix wlr_seat use-after-free on exit
Same as [1].

I originally tried to properly handle seat destruction, but that
turned out to be a can of worms [2].

[1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4590
[2]: https://github.com/swaywm/sway/pull/8034
2024-03-14 11:59:25 +01:00
Alexander Orzechowski 2e951163c5 Force bilinear scaling when scaling down 2024-03-09 11:47:42 +01:00
Simon Ser 23389ebd1f config/output: drop enabling flag
This was useful when wlroots backends were updating the current
mode on their own. This is no longer the case.
2024-03-08 09:12:12 -05:00
Simon Ser 3ef5abd405 xdg-shell: send WM capabilities 2024-03-08 09:52:14 +03:00
Simon Ser 4e6d7612ff xdg-shell: implement popup repositioning 2024-03-08 09:52:14 +03:00
Simon Ser f2a0e81b24 Fetch input device vendor/product from libinput
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4582
2024-03-07 09:53:40 -05:00
Simon Ser 59f6292383 config: add fallback without env vars for keysym translation XKB keymap 2024-03-06 11:14:50 -05:00
Simon Ser fd9ab9ee06 config: error out on keysym translation XKB state failure
If we can't create the XKB keymap used for keysym translation,
gracefully error out instead of crashing. This can happen if the
XKB_DEFAULT_LAYOUT is set to an invalid value, for instance.

Closes: https://github.com/swaywm/sway/issues/7789
2024-03-06 11:14:50 -05:00
Ronan Pigott 5e18ed3cf0 commands/move: do not force focus on the moved container
My code archaeology isn't good enough to determine what this is here
for, but it isn't correct. We should be able to move containers in a
direction without focusing them. AFAICT i3 doesn't do this, so we
shouldn't either.

This fixes ipc commands like move <dir> with criteria that apply to
containers which are not the current focus.
2024-03-01 10:13:41 +01:00
Luofan Chen 2058209a13 input: Rename WLR_INPUT_DEVICE_TABLET_TOOL to WLR_INPUT_DEVICE_TABLET
wlroots has changed the naming, causing the following build errors when
building:

error: ‘WLR_INPUT_DEVICE_TABLET_TOOL’ undeclared
2024-03-01 09:53:43 +01:00
llyyr 0b84d82b9a ipc: add `scratchpad_state` property to GET_TREE
See previous commit. This restores ipc parity with i3.
2024-02-29 00:51:43 +01:00
llyyr 2867ef646b ipc: add `floating` property to GET_TREE
i3 has had this property for over a decade but it wasn't documented
until a couple of years ago, so it was likely missed when developing
sway. Add the property to get us closer to ipc parity with i3.
2024-02-29 00:51:43 +01:00
Simon Ser fca8474e9b Convert to new pointer enums
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4575
2024-02-28 14:28:11 -05:00
llyyr 469411d484 text_input: don't destroy scene_node twice 2024-02-28 09:34:25 +01:00
Simon Ser 829c75b9c9 Add release script 2024-02-26 09:02:06 -05:00
k3d3 2b5d8a0978 Ignore modifiers on release, to match i3 behaviour
Closes #6456.

The i3 window manager ignores modifiers when a button is being released.
Mimic this behaviour in Sway.
2021-10-17 18:11:30 -04:00
32 changed files with 609 additions and 393 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

@ -114,7 +114,7 @@ void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
void dispatch_cursor_button(struct sway_cursor *cursor,
struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
enum wlr_button_state state);
enum wl_pointer_button_state state);
void dispatch_cursor_axis(struct sway_cursor *cursor,
struct wlr_pointer_axis_event *event);

View File

@ -4,6 +4,7 @@
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_transient_seat_v1.h>
#include "sway/server.h"
#include "sway/config.h"
#include "list.h"
@ -24,6 +25,7 @@ struct sway_input_manager {
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
struct wlr_pointer_gestures_v1 *pointer_gestures;
struct wlr_transient_seat_manager_v1 *transient_seat_manager;
struct wl_listener new_input;
struct wl_listener inhibit_activate;
@ -31,6 +33,7 @@ struct sway_input_manager {
struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor;
struct wl_listener virtual_keyboard_new;
struct wl_listener virtual_pointer_new;
struct wl_listener transient_seat_create;
};
struct sway_input_manager *input_manager_create(struct sway_server *server);

View File

@ -17,7 +17,7 @@ struct sway_seat;
struct sway_seatop_impl {
void (*button)(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state);
enum wl_pointer_button_state state);
void (*pointer_motion)(struct sway_seat *seat, uint32_t time_msec);
void (*pointer_axis)(struct sway_seat *seat,
struct wlr_pointer_axis_event *event);
@ -124,6 +124,7 @@ struct sway_seat {
struct wl_listener start_drag;
struct wl_listener request_set_selection;
struct wl_listener request_set_primary_selection;
struct wl_listener destroy;
struct wl_list devices; // sway_seat_device::link
struct wl_list keyboard_groups; // sway_keyboard_group::link
@ -286,13 +287,13 @@ struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat,
struct sway_workspace *workspace);
void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
uint32_t button, enum wlr_button_state state);
uint32_t button, enum wl_pointer_button_state state);
void seat_consider_warp_to_focus(struct sway_seat *seat);
void seatop_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state);
enum wl_pointer_button_state state);
void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec);

View File

@ -50,7 +50,7 @@ struct sway_output {
enum wl_output_subpixel detected_subpixel;
enum scale_filter_mode scale_filter;
bool enabling, enabled;
bool enabled;
list_t *workspaces;
struct sway_output_state current;

View File

@ -46,6 +46,7 @@ struct sway_server {
struct wl_listener new_output;
struct wl_listener output_layout_change;
struct wl_listener renderer_lost;
struct wlr_idle_notifier_v1 *idle_notifier_v1;
struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1;

View File

@ -192,6 +192,7 @@ struct sway_xdg_popup {
struct wl_listener surface_commit;
struct wl_listener new_popup;
struct wl_listener reposition;
struct wl_listener destroy;
};

31
release.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/sh -eu
prev=$(git describe --tags --abbrev=0)
next=$(meson rewrite kwargs info project / 2>&1 >/dev/null | jq -r '.kwargs["project#/"].version')
case "$next" in
*-dev)
echo "This is a development version"
exit 1
;;
esac
if [ "$prev" = "$next" ]; then
echo "Version not bumped in meson.build"
exit 1
fi
if ! git diff-index --quiet HEAD -- meson.build; then
echo "meson.build not committed"
exit 1
fi
shortlog="$(git shortlog --no-merges "$prev..")"
(echo "sway $next"; echo ""; echo "$shortlog") | git tag "$next" -ase -F -
prefix=sway-$next
archive=$prefix.tar.gz
git archive --prefix="$prefix/" -o "$archive" "$next"
gpg --output "$archive".sig --detach-sig "$archive"
gh release create "sway $next" -t "$next" -n "" -d "$archive" "$archive.sig"

View File

@ -769,15 +769,6 @@ static struct cmd_results *cmd_move_in_direction(
ipc_event_window(container, "move");
}
// Hack to re-focus container
seat_set_raw_focus(config->handler_context.seat, &new_ws->node);
seat_set_focus_container(config->handler_context.seat, container);
if (old_ws != new_ws) {
ipc_event_workspace(old_ws, new_ws, "focus");
workspace_detect_urgent(old_ws);
workspace_detect_urgent(new_ws);
}
container_end_mouse_operation(container);
return cmd_results_new(CMD_SUCCESS, NULL);

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

@ -84,12 +84,12 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
static struct cmd_results *press_or_release(struct sway_cursor *cursor,
char *action, char *button_str) {
enum wlr_button_state state;
enum wl_pointer_button_state state;
uint32_t button;
if (strcasecmp(action, "press") == 0) {
state = WLR_BUTTON_PRESSED;
state = WL_POINTER_BUTTON_STATE_PRESSED;
} else if (strcasecmp(action, "release") == 0) {
state = WLR_BUTTON_RELEASED;
state = WL_POINTER_BUTTON_STATE_RELEASED;
} else {
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
@ -104,16 +104,16 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor,
} else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN
|| button == SWAY_SCROLL_LEFT || button == SWAY_SCROLL_RIGHT) {
// Dispatch axis event
enum wlr_axis_orientation orientation =
enum wl_pointer_axis orientation =
(button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN)
? WLR_AXIS_ORIENTATION_VERTICAL
: WLR_AXIS_ORIENTATION_HORIZONTAL;
? WL_POINTER_AXIS_VERTICAL_SCROLL
: WL_POINTER_AXIS_HORIZONTAL_SCROLL;
double delta = (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_LEFT)
? -1 : 1;
struct wlr_pointer_axis_event event = {
.pointer = NULL,
.time_msec = 0,
.source = WLR_AXIS_SOURCE_WHEEL,
.source = WL_POINTER_AXIS_SOURCE_WHEEL,
.orientation = orientation,
.delta = delta * 15,
.delta_discrete = delta

View File

@ -37,19 +37,26 @@
struct sway_config *config = NULL;
static struct xkb_state *keysym_translation_state_create(
struct xkb_rule_names rules) {
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_SECURE_GETENV);
struct xkb_rule_names rules, uint32_t context_flags) {
struct xkb_context *context = xkb_context_new(context_flags | XKB_CONTEXT_NO_SECURE_GETENV);
struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_names(
context,
&rules,
XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_context_unref(context);
if (xkb_keymap == NULL) {
sway_log(SWAY_ERROR, "Failed to compile keysym translation XKB keymap");
return NULL;
}
return xkb_state_new(xkb_keymap);
}
static void keysym_translation_state_destroy(
struct xkb_state *state) {
if (state == NULL) {
return;
}
xkb_keymap_unref(xkb_state_get_keymap(state));
xkb_state_unref(state);
}
@ -337,8 +344,14 @@ static void config_defaults(struct sway_config *config) {
// The keysym to keycode translation
struct xkb_rule_names rules = {0};
config->keysym_translation_state =
keysym_translation_state_create(rules);
config->keysym_translation_state = keysym_translation_state_create(rules, 0);
if (config->keysym_translation_state == NULL) {
config->keysym_translation_state = keysym_translation_state_create(rules,
XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
}
if (config->keysym_translation_state == NULL) {
goto cleanup;
}
return;
cleanup:
@ -519,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;
@ -985,8 +998,12 @@ void translate_keysyms(struct input_config *input_config) {
struct xkb_rule_names rules = {0};
input_config_fill_rule_names(input_config, &rules);
config->keysym_translation_state =
keysym_translation_state_create(rules);
config->keysym_translation_state = keysym_translation_state_create(rules, 0);
if (config->keysym_translation_state == NULL) {
sway_log(SWAY_ERROR, "Failed to create keysym translation XKB state "
"for device '%s'", input_config->identifier);
return;
}
for (int i = 0; i < config->modes->length; ++i) {
struct sway_mode *mode = config->modes->items[i];

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,31 +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;
// Flag to prevent the output mode event handler from calling us
output->enabling = (!oc || oc->enabled);
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);
output->enabling = false;
return false;
}
output->enabling = false;
if (oc && !oc->enabled) {
sway_log(SWAY_DEBUG, "Disabling output %s", oc->name);
if (output->enabled) {
@ -583,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;
@ -621,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

@ -183,7 +183,15 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer,
}
}
static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output) {
static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output,
struct wlr_scene_buffer *buffer) {
// if we are scaling down, we should always choose linear
if (buffer->dst_width > 0 && buffer->dst_height > 0 && (
buffer->dst_width < buffer->buffer_width ||
buffer->dst_height < buffer->buffer_height)) {
return WLR_SCALE_FILTER_BILINEAR;
}
switch (output->scale_filter) {
case SCALE_FILTER_LINEAR:
return WLR_SCALE_FILTER_BILINEAR;
@ -212,7 +220,7 @@ static void output_configure_scene(struct sway_output *output,
// hack: don't call the scene setter because that will damage all outputs
// We don't want to damage outputs that aren't our current output that
// we're configuring
buffer->filter_mode = get_scale_filter(output);
buffer->filter_mode = get_scale_filter(output, buffer);
wlr_scene_buffer_set_opacity(buffer, opacity);
} else if (node->type == WLR_SCENE_NODE_TREE) {
@ -513,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();
@ -544,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);
@ -644,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

@ -35,6 +35,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&popup->new_popup.link);
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->surface_commit.link);
wl_list_remove(&popup->reposition.link);
wlr_scene_node_destroy(&popup->scene_tree->node);
free(popup);
}
@ -70,6 +71,11 @@ static void popup_handle_surface_commit(struct wl_listener *listener, void *data
}
}
static void popup_handle_reposition(struct wl_listener *listener, void *data) {
struct sway_xdg_popup *popup = wl_container_of(listener, popup, reposition);
popup_unconstrain(popup);
}
static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup,
struct sway_view *view, struct wlr_scene_tree *parent) {
struct wlr_xdg_surface *xdg_surface = wlr_popup->base;
@ -116,6 +122,8 @@ static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup,
popup->surface_commit.notify = popup_handle_surface_commit;
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
popup->new_popup.notify = popup_handle_new_popup;
wl_signal_add(&wlr_popup->events.reposition, &popup->reposition);
popup->reposition.notify = popup_handle_reposition;
wl_signal_add(&wlr_popup->events.destroy, &popup->destroy);
popup->destroy.notify = popup_handle_destroy;
@ -281,6 +289,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
}
// XXX: https://github.com/swaywm/sway/issues/2176
wlr_xdg_surface_schedule_configure(xdg_surface);
// TODO: wlr_xdg_toplevel_set_bounds()
return;
}
@ -566,4 +575,7 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) {
wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base);
xdg_toplevel->base->data = xdg_shell_view;
wlr_xdg_toplevel_set_wm_capabilities(xdg_toplevel,
XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
}

View File

@ -243,7 +243,7 @@ static enum sway_input_idle_source idle_source_from_device(
return IDLE_SOURCE_POINTER;
case WLR_INPUT_DEVICE_TOUCH:
return IDLE_SOURCE_TOUCH;
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET:
return IDLE_SOURCE_TABLET_TOOL;
case WLR_INPUT_DEVICE_TABLET_PAD:
return IDLE_SOURCE_TABLET_PAD;
@ -356,7 +356,7 @@ static void handle_pointer_motion_absolute(
void dispatch_cursor_button(struct sway_cursor *cursor,
struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
enum wlr_button_state state) {
enum wl_pointer_button_state state) {
if (time_msec == 0) {
time_msec = get_current_time_msec();
}
@ -368,7 +368,7 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
struct wlr_pointer_button_event *event = data;
if (event->state == WLR_BUTTON_PRESSED) {
if (event->state == WL_POINTER_BUTTON_STATE_PRESSED) {
cursor->pressed_button_count++;
} else {
if (cursor->pressed_button_count > 0) {
@ -430,7 +430,7 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
if (cursor->pointer_touch_id == cursor->seat->touch_id) {
cursor->pointer_touch_up = true;
dispatch_cursor_button(cursor, &event->touch->base,
event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED);
event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
}
} else {
seatop_touch_up(seat, event);
@ -448,7 +448,7 @@ static void handle_touch_cancel(struct wl_listener *listener, void *data) {
if (cursor->pointer_touch_id == cursor->seat->touch_id) {
cursor->pointer_touch_up = true;
dispatch_cursor_button(cursor, &event->touch->base,
event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED);
event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
}
} else {
seatop_touch_cancel(seat, event);
@ -518,7 +518,7 @@ static void apply_mapping_from_region(struct wlr_input_device *device,
double x1 = region->x1, x2 = region->x2;
double y1 = region->y1, y2 = region->y2;
if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET) {
struct wlr_tablet *tablet = wlr_tablet_from_input_device(device);
if (tablet->width_mm == 0 || tablet->height_mm == 0) {
return;
@ -661,7 +661,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
event->state == WLR_TABLET_TOOL_TIP_UP) {
cursor->simulating_pointer_from_tool_tip = false;
dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec,
BTN_LEFT, WLR_BUTTON_RELEASED);
BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
} else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
// If we started holding the tool tip down on a surface that accepts
@ -673,7 +673,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
} else {
cursor->simulating_pointer_from_tool_tip = true;
dispatch_cursor_button(cursor, &event->tablet->base,
event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED);
event->time_msec, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
}
} else {
@ -776,13 +776,13 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
case WLR_BUTTON_PRESSED:
if (cursor->tool_buttons == 0) {
dispatch_cursor_button(cursor, &event->tablet->base,
event->time_msec, BTN_RIGHT, event->state);
event->time_msec, BTN_RIGHT, WL_POINTER_BUTTON_STATE_PRESSED);
}
break;
case WLR_BUTTON_RELEASED:
if (cursor->tool_buttons <= 1) {
dispatch_cursor_button(cursor, &event->tablet->base,
event->time_msec, BTN_RIGHT, event->state);
event->time_msec, BTN_RIGHT, WL_POINTER_BUTTON_STATE_RELEASED);
}
break;
}

View File

@ -2,7 +2,9 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <wlr/config.h>
#include <wlr/backend/libinput.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
@ -65,8 +67,15 @@ struct sway_seat *input_manager_sway_seat_from_wlr_seat(struct wlr_seat *wlr_sea
}
char *input_device_get_identifier(struct wlr_input_device *device) {
int vendor = device->vendor;
int product = device->product;
int vendor = 0, product = 0;
#if WLR_HAS_LIBINPUT_BACKEND
if (wlr_input_device_is_libinput(device)) {
struct libinput_device *libinput_dev = wlr_libinput_get_device_handle(device);
vendor = libinput_device_get_id_vendor(libinput_dev);
product = libinput_device_get_id_product(libinput_dev);
}
#endif
char *name = strdup(device->name ? device->name : "");
strip_whitespace(name);
@ -111,7 +120,7 @@ const char *input_device_get_type(struct sway_input_device *device) {
return "keyboard";
case WLR_INPUT_DEVICE_TOUCH:
return "touch";
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET:
return "tablet_tool";
case WLR_INPUT_DEVICE_TABLET_PAD:
return "tablet_pad";
@ -424,6 +433,20 @@ void handle_virtual_pointer(struct wl_listener *listener, void *data) {
}
}
static void handle_transient_seat_manager_create_seat(
struct wl_listener *listener, void *data) {
struct wlr_transient_seat_v1 *transient_seat = data;
static uint64_t i;
char name[256];
snprintf(name, sizeof(name), "transient-%"PRIx64, i++);
struct sway_seat *seat = seat_create(name);
if (seat && seat->wlr_seat) {
wlr_transient_seat_v1_ready(transient_seat, seat->wlr_seat);
} else {
wlr_transient_seat_v1_deny(transient_seat);
}
}
struct sway_input_manager *input_manager_create(struct sway_server *server) {
struct sway_input_manager *input =
calloc(1, sizeof(struct sway_input_manager));
@ -459,6 +482,15 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) {
input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display);
input->transient_seat_manager =
wlr_transient_seat_manager_v1_create(server->wl_display);
assert(input->transient_seat_manager);
input->transient_seat_create.notify =
handle_transient_seat_manager_create_seat;
wl_signal_add(&input->transient_seat_manager->events.create_seat,
&input->transient_seat_create);
return input;
}

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 },
};
@ -162,7 +163,7 @@ static void get_active_binding(const struct sway_shortcut_state *state,
bool binding_inhibited = (binding->flags & BINDING_INHIBITED) != 0;
bool binding_release = binding->flags & BINDING_RELEASE;
if (modifiers ^ binding->modifiers ||
if ((modifiers ^ binding->modifiers && !release) ||
release != binding_release ||
locked > binding_locked ||
inhibited > binding_inhibited ||

View File

@ -67,6 +67,12 @@ static void seat_node_destroy(struct sway_seat_node *seat_node) {
}
void seat_destroy(struct sway_seat *seat) {
wlr_seat_destroy(seat->wlr_seat);
}
static void handle_seat_destroy(struct wl_listener *listener, void *data) {
struct sway_seat *seat = wl_container_of(listener, seat, destroy);
if (seat == config->handler_context.seat) {
config->handler_context.seat = input_manager_get_default_seat();
}
@ -87,7 +93,7 @@ void seat_destroy(struct sway_seat *seat) {
wl_list_remove(&seat->request_set_selection.link);
wl_list_remove(&seat->request_set_primary_selection.link);
wl_list_remove(&seat->link);
wlr_seat_destroy(seat->wlr_seat);
wl_list_remove(&seat->destroy.link);
for (int i = 0; i < seat->deferred_bindings->length; i++) {
free_sway_binding(seat->deferred_bindings->items[i]);
}
@ -534,6 +540,9 @@ struct sway_seat *seat_create(const char *seat_name) {
return NULL;
}
seat->destroy.notify = handle_seat_destroy;
wl_signal_add(&seat->wlr_seat->events.destroy, &seat->destroy);
seat->idle_inhibit_sources = seat->idle_wake_sources =
IDLE_SOURCE_KEYBOARD |
IDLE_SOURCE_POINTER |
@ -607,7 +616,7 @@ static void seat_update_capabilities(struct sway_seat *seat) {
case WLR_INPUT_DEVICE_TOUCH:
caps |= WL_SEAT_CAPABILITY_TOUCH;
break;
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET:
caps |= WL_SEAT_CAPABILITY_POINTER;
break;
case WLR_INPUT_DEVICE_SWITCH:
@ -665,7 +674,7 @@ static const char *get_builtin_output_name(void) {
static bool is_touch_or_tablet_tool(struct sway_seat_device *seat_device) {
switch (seat_device->input_device->wlr_device->type) {
case WLR_INPUT_DEVICE_TOUCH:
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET:
return true;
default:
return false;
@ -680,7 +689,7 @@ static void seat_apply_input_mapping(struct sway_seat *seat,
switch (sway_device->input_device->wlr_device->type) {
case WLR_INPUT_DEVICE_POINTER:
case WLR_INPUT_DEVICE_TOUCH:
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET:
break;
default:
return; // these devices don't support mappings
@ -873,7 +882,7 @@ void seat_configure_device(struct sway_seat *seat,
case WLR_INPUT_DEVICE_TOUCH:
seat_configure_touch(seat, seat_device);
break;
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET:
seat_configure_tablet_tool(seat, seat_device);
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
@ -912,7 +921,7 @@ void seat_reset_device(struct sway_seat *seat,
case WLR_INPUT_DEVICE_TOUCH:
seat_reset_input_config(seat, seat_device);
break;
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET:
seat_reset_input_config(seat, seat_device);
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
@ -1520,7 +1529,7 @@ struct seat_config *seat_get_config_by_name(const char *name) {
}
void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
uint32_t button, enum wlr_button_state state) {
uint32_t button, enum wl_pointer_button_state state) {
seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat,
time_msec, button, state);
}
@ -1557,7 +1566,7 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con) {
void seatop_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state) {
enum wl_pointer_button_state state) {
if (seat->seatop_impl->button) {
seat->seatop_impl->button(seat, time_msec, device, button, state);
}

View File

@ -131,7 +131,7 @@ static struct sway_binding* get_active_mouse_binding(
struct sway_binding *current = NULL;
for (int i = 0; i < bindings->length; ++i) {
struct sway_binding *binding = bindings->items[i];
if (modifiers ^ binding->modifiers ||
if ((modifiers ^ binding->modifiers && !release) ||
e->pressed_button_count != (size_t)binding->keys->length ||
release != (binding->flags & BINDING_RELEASE) ||
!(click_region & binding->flags) ||
@ -290,7 +290,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
static bool trigger_pointer_button_binding(struct sway_seat *seat,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state, uint32_t modifiers,
enum wl_pointer_button_state state, uint32_t modifiers,
bool on_titlebar, bool on_border, bool on_contents, bool on_workspace) {
// We can reach this for non-pointer devices if we're currently emulating
// pointer input for one. Emulated input should not trigger bindings. The
@ -304,7 +304,7 @@ static bool trigger_pointer_button_binding(struct sway_seat *seat,
char *device_identifier = device ? input_device_get_identifier(device)
: strdup("*");
struct sway_binding *binding = NULL;
if (state == WLR_BUTTON_PRESSED) {
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
state_add_button(e, button);
binding = get_active_mouse_binding(e,
config->current_mode->mouse_bindings, modifiers, false,
@ -329,7 +329,7 @@ static bool trigger_pointer_button_binding(struct sway_seat *seat,
static void handle_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state) {
enum wl_pointer_button_state state) {
struct sway_cursor *cursor = seat->cursor;
// Determine what's under the cursor
@ -362,7 +362,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle clicking an empty workspace
if (node && node->type == N_WORKSPACE) {
if (state == WLR_BUTTON_PRESSED) {
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
seat_set_focus(seat, node);
transaction_commit_dirty();
}
@ -377,7 +377,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
}
if (state == WLR_BUTTON_PRESSED) {
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
seatop_begin_down_on_surface(seat, surface, sx, sy);
}
seat_pointer_notify_button(seat, time_msec, button, state);
@ -386,7 +386,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle tiling resize via border
if (cont && resize_edge && button == BTN_LEFT &&
state == WLR_BUTTON_PRESSED && !is_floating) {
state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating) {
// If a resize is triggered on a tabbed or stacked container, change
// focus to the tab which already had inactive focus -- otherwise, we'd
// change the active tab when the user probably just wanted to resize.
@ -404,7 +404,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle tiling resize via mod
bool mod_pressed = modifiers & config->floating_mod;
if (cont && !is_floating_or_child && mod_pressed &&
state == WLR_BUTTON_PRESSED) {
state == WL_POINTER_BUTTON_STATE_PRESSED) {
uint32_t btn_resize = config->floating_mod_inverse ?
BTN_LEFT : BTN_RIGHT;
if (button == btn_resize) {
@ -432,7 +432,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
}
// Handle changing focus when clicking on a container
if (cont && state == WLR_BUTTON_PRESSED) {
if (cont && state == WL_POINTER_BUTTON_STATE_PRESSED) {
// Default case: focus the container that was just clicked.
node = &cont->node;
@ -453,7 +453,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle beginning floating move
if (cont && is_floating_or_child && !is_fullscreen_or_child &&
state == WLR_BUTTON_PRESSED) {
state == WL_POINTER_BUTTON_STATE_PRESSED) {
uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
if (button == btn_move && (mod_pressed || on_titlebar)) {
seatop_begin_move_floating(seat, container_toplevel_ancestor(cont));
@ -463,7 +463,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle beginning floating resize
if (cont && is_floating_or_child && !is_fullscreen_or_child &&
state == WLR_BUTTON_PRESSED) {
state == WL_POINTER_BUTTON_STATE_PRESSED) {
// Via border
if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) {
seat_set_focus_container(seat, cont);
@ -489,7 +489,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle moving a tiling container
if (config->tiling_drag && (mod_pressed || on_titlebar) &&
state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating_or_child &&
cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
// If moving a container by its title bar, use a threshold for the drag
if (!mod_pressed && config->tiling_drag_threshold > 0) {
@ -502,14 +502,14 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
}
// Handle mousedown on a container surface
if (surface && cont && state == WLR_BUTTON_PRESSED) {
if (surface && cont && state == WL_POINTER_BUTTON_STATE_PRESSED) {
seatop_begin_down(seat, cont, sx, sy);
seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED);
seat_pointer_notify_button(seat, time_msec, button, WL_POINTER_BUTTON_STATE_PRESSED);
return;
}
// Handle clicking a container surface or decorations
if (cont && state == WLR_BUTTON_PRESSED) {
if (cont && state == WL_POINTER_BUTTON_STATE_PRESSED) {
seat_pointer_notify_button(seat, time_msec, button, state);
return;
}
@ -684,7 +684,7 @@ static void handle_touch_down(struct sway_seat *seat,
pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy,
dx, dy);
dispatch_cursor_button(cursor, &event->touch->base, event->time_msec,
BTN_LEFT, WLR_BUTTON_PRESSED);
BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
}
}
@ -694,9 +694,9 @@ static void handle_touch_down(struct sway_seat *seat,
static uint32_t wl_axis_to_button(struct wlr_pointer_axis_event *event) {
switch (event->orientation) {
case WLR_AXIS_ORIENTATION_VERTICAL:
case WL_POINTER_AXIS_VERTICAL_SCROLL:
return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN;
case WLR_AXIS_ORIENTATION_HORIZONTAL:
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT;
default:
sway_log(SWAY_DEBUG, "Unknown axis orientation");

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)) {
@ -142,7 +146,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
static void handle_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state) {
enum wl_pointer_button_state state) {
seat_pointer_notify_button(seat, time_msec, button, state);
if (seat->cursor->pressed_button_count == 0) {

View File

@ -21,7 +21,7 @@ static void finalize_move(struct sway_seat *seat) {
static void handle_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state) {
enum wl_pointer_button_state state) {
if (seat->cursor->pressed_button_count == 0) {
finalize_move(seat);
}

View File

@ -405,7 +405,7 @@ static void finalize_move(struct sway_seat *seat) {
static void handle_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state) {
enum wl_pointer_button_state state) {
if (seat->cursor->pressed_button_count == 0) {
finalize_move(seat);
}

View File

@ -20,7 +20,7 @@ struct seatop_resize_floating_event {
static void handle_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state) {
enum wl_pointer_button_state state) {
struct seatop_resize_floating_event *e = seat->seatop_data;
struct sway_container *con = e->con;

View File

@ -45,7 +45,7 @@ static struct sway_container *container_get_resize_sibling(
static void handle_button(struct sway_seat *seat, uint32_t time_msec,
struct wlr_input_device *device, uint32_t button,
enum wlr_button_state state) {
enum wl_pointer_button_state state) {
struct seatop_resize_tiling_event *e = seat->seatop_data;
if (seat->cursor->pressed_button_count == 0) {

View File

@ -293,10 +293,6 @@ static void input_popup_update(struct sway_input_popup *popup) {
return;
}
wlr_scene_node_destroy(&popup->scene_tree->node);
wlr_scene_node_destroy(popup->desc.relative);
popup->scene_tree = NULL;
bool cursor_rect = text_input->input->current.features
& WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
struct wlr_surface *focused_surface = text_input->input->focused_surface;

View File

@ -288,6 +288,8 @@ static json_object *ipc_json_create_node(int id, const char* type, char *name,
json_object_object_add(object, "focus", focus);
json_object_object_add(object, "fullscreen_mode", json_object_new_int(0));
json_object_object_add(object, "sticky", json_object_new_boolean(false));
json_object_object_add(object, "floating", NULL);
json_object_object_add(object, "scratchpad_state", NULL);
return object;
}
@ -675,7 +677,8 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
static void ipc_json_describe_container(struct sway_container *c, json_object *object) {
json_object_object_add(object, "name",
c->title ? json_object_new_string(c->title) : NULL);
if (container_is_floating(c)) {
bool floating = container_is_floating(c);
if (floating) {
json_object_object_add(object, "type",
json_object_new_string("floating_con"));
}
@ -693,9 +696,17 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o
json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky));
// sway doesn't track the floating reason, so we can't use "auto_on" or "user_off"
json_object_object_add(object, "floating",
json_object_new_string(floating ? "user_on" : "auto_off"));
json_object_object_add(object, "fullscreen_mode",
json_object_new_int(c->pending.fullscreen_mode));
// sway doesn't track if window was resized in scratchpad, so we can't use "changed"
json_object_object_add(object, "scratchpad_state",
json_object_new_string(!c->scratchpad ? "none" : "fresh"));
struct sway_node *parent = node_get_parent(&c->node);
struct wlr_box parent_box = {0, 0, 0, 0};
@ -1086,10 +1097,6 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
json_object_new_string(device->identifier));
json_object_object_add(object, "name",
json_object_new_string(device->wlr_device->name));
json_object_object_add(object, "vendor",
json_object_new_int(device->wlr_device->vendor));
json_object_object_add(object, "product",
json_object_new_int(device->wlr_device->product));
json_object_object_add(object, "type",
json_object_new_string(
input_device_get_type(device)));
@ -1143,6 +1150,10 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
libinput_dev = wlr_libinput_get_device_handle(device->wlr_device);
json_object_object_add(object, "libinput",
describe_libinput_device(libinput_dev));
json_object_object_add(object, "vendor",
json_object_new_int(libinput_device_get_id_vendor(libinput_dev)));
json_object_object_add(object, "product",
json_object_new_int(libinput_device_get_id_product(libinput_dev)));
}
#endif

View File

@ -65,7 +65,7 @@
#include <wlr/types/wlr_drm_lease_v1.h>
#endif
#define SWAY_XDG_SHELL_VERSION 2
#define SWAY_XDG_SHELL_VERSION 5
#define SWAY_LAYER_SHELL_VERSION 4
#define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1
@ -112,7 +112,8 @@ static bool is_privileged(const struct wl_global *global) {
global == server.session_lock.manager->global ||
global == server.input->keyboard_shortcuts_inhibit->global ||
global == server.input->virtual_keyboard->global ||
global == server.input->virtual_pointer->global;
global == server.input->virtual_pointer->global ||
global == server.input->transient_seat_manager->global;
}
static bool filter_global(const struct wl_client *client,
@ -172,6 +173,45 @@ static void detect_proprietary(struct wlr_backend *backend, void *data) {
drmFreeVersion(version);
}
static void handle_renderer_lost(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, renderer_lost);
sway_log(SWAY_INFO, "Re-creating renderer after GPU reset");
struct wlr_renderer *renderer = wlr_renderer_autocreate(server->backend);
if (renderer == NULL) {
sway_log(SWAY_ERROR, "Unable to create renderer");
return;
}
struct wlr_allocator *allocator =
wlr_allocator_autocreate(server->backend, renderer);
if (allocator == NULL) {
sway_log(SWAY_ERROR, "Unable to create allocator");
wlr_renderer_destroy(renderer);
return;
}
struct wlr_renderer *old_renderer = server->renderer;
struct wlr_allocator *old_allocator = server->allocator;
server->renderer = renderer;
server->allocator = allocator;
wl_list_remove(&server->renderer_lost.link);
wl_signal_add(&server->renderer->events.lost, &server->renderer_lost);
wlr_compositor_set_renderer(server->compositor, renderer);
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
wlr_output_init_render(output->wlr_output,
server->allocator, server->renderer);
}
wlr_allocator_destroy(old_allocator);
wlr_renderer_destroy(old_renderer);
}
bool server_init(struct sway_server *server) {
sway_log(SWAY_DEBUG, "Initializing Wayland server");
server->wl_display = wl_display_create();
@ -195,15 +235,17 @@ bool server_init(struct sway_server *server) {
return false;
}
server->renderer_lost.notify = handle_renderer_lost;
wl_signal_add(&server->renderer->events.lost, &server->renderer_lost);
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,
@ -399,6 +441,7 @@ void server_fini(struct sway_server *server) {
wlr_xwayland_destroy(server->xwayland.wlr_xwayland);
#endif
wl_display_destroy_clients(server->wl_display);
wlr_backend_destroy(server->backend);
wl_display_destroy(server->wl_display);
list_free(server->dirty_nodes);
}

View File

@ -376,6 +376,12 @@ node and will have the following properties:
: integer
: (Only containers and views) The fullscreen mode of the node. 0 means none, 1 means
full workspace, and 2 means global fullscreen
|- floating
: string
: Floating state of container. Can be either "auto_off" or "user_on"
|- scratchpad_state
: string
: Whether the window is in the scratchpad. Can be either "none" or "fresh"
|- app_id
: string
: (Only views) For an xdg-shell view, the name of the application, if set.
@ -1040,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

@ -72,13 +72,11 @@ must be separated by one space. For example:
*output* <name> scale <factor>
Scales the specified output by the specified scale _factor_. An integer is
recommended, but fractional values are also supported. If a fractional
value are specified, be warned that it is not possible to faithfully
represent the contents of your windows - they will be rendered at the next
highest integer scale factor and downscaled. You may be better served by
setting an integer scale factor and adjusting the font size of your
applications to taste. HiDPI isn't supported with Xwayland clients (windows
will blur).
recommended, but fractional values are also supported. You may be better
served by setting an integer scale factor and adjusting the font size of
your applications to taste. HiDPI isn't supported with Xwayland clients
(windows will blur). A fractional scale may be slightly adjusted to match
requirements of the protocol.
*output* <name> scale_filter linear|nearest|smart
Indicates how to scale application buffers that are rendered at a scale

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