Compare commits

..

13 commits

Author SHA1 Message Date
someever
e51f9d7183 Fix typos in sway-ipc.7.scd
Some sections of the man page were difficult to understand. This fixes
several typos and grammatical errors.
2026-04-12 19:49:33 +02:00
Alexander Orzechowski
81246fc6dc container: Move foreign toplevel enter/leave events to view
It made sense to put it on the container level because the protocol cares
about the toplevel and that includes its decorations. But, this breaks
down when we consider if the container's view is fullscreen and the container
decorations are disabled. Moving it to the view manages this expected lifetime
better. Since the buffer is now part of the view, the buffer will get
negative coordinates to act as if it's part of the container when we
want to.

A known issue is that we will send spurious leave/enter events while
we reconfigure the scene for entering/exiting fullscreen. The fix for
this loops back to atomic updates to scene and that is outside of the scope
of this commit.

Fixes: #9000
2026-04-12 13:46:38 +02:00
Hugo Osvaldo Barrera
1606311553 Don't ignore initialisation errors
server_init ignores all errors. In practice, theses result in a
segfault, potentially much later and losing any unsaved work.

Properly handle initialisation errors and bail immediately.
2026-04-10 13:13:42 +02:00
Hugo Osvaldo Barrera
909a2ddb5f Centre fullscreen surfaces smaller than output
Sway renders fullscreen surfaces smaller than the output left-aligned.

From xdg-shell:

> If the surface doesn't cover the whole output, the compositor will
> position the surface in the center of the output and compensate with
> with border fill covering the rest of the output. The content of the
> border fill is undefined, but should be assumed to be in some way that
> attempts to blend into the surrounding area (e.g. solid black).

Render surfaces smaller than the output centred. Can be tested easily
with:

    weston-simple-egl -f -r

Fixes: https://github.com/swaywm/sway/issues/8845
2026-03-26 18:41:48 +01:00
Simon Ser
ec7e0186e0 build: bump version to 1.13-dev 2026-03-26 16:30:37 +01:00
Hugo Osvaldo Barrera
f50f78c0d9 ext-workspace-v1: initial implementation
Maintain a 1:1 relationship between workspace groups and outputs, so
that moving a workspace across groups effectively moves it across
outputs.

ext_workspace_handle_v1::id is never emitted; sway has no concept of ids
or of stable vs temporary workspaces. Everything is ephemeral to the
current session.

ext_workspace_handle_v1::coordinates is never emitted; sway does not
organise workspaces into any sort of grid.

ext_workspace_handle_v1::assign is mostly untested, because no client
current implements this. Perhaps it's best to not-advertise the feature
for now?

Deactivating a workspace is a no-op. This functionality doesn't really
align with sway, although it could potentially be implemented to "switch
to previous workspace on this output" as a follow-up.

Removing a workspace is a no-op.

Implements: https://github.com/swaywm/sway/issues/8812
2026-03-24 17:25:33 +01:00
Hugo Osvaldo Barrera
7ba11d6dee Make workspace_move_to_output reusable
Move workspace_move_to_output out of the command handler, so it can be
re-used for ext_workspace_handle_v1::assign.
2026-03-24 17:25:33 +01:00
llyyr
131045ce55 sway_text_node: properly check cairo_t status in text_calc_size
cairo_create never returns NULL, so the previous null check never
triggered. Use cairo_status instead.
2026-03-21 11:18:26 +01:00
llyyr
dea166a27c common/pango: use pangocairo directly instead of cairo_create(NULL)
We never need a cairo context for anything here. Use
pango_cairo_font_map_get_default() and pango_font_map_create_context()
directly instead of bootstrapping via a nil cairo context.

Same as last commit, but just a cosmetic fix in this case since we don't
actually use the cairo context for anything
2026-03-21 11:18:26 +01:00
llyyr
e4870d84a2 sway_text_node: fix cairo_create without a backing surface
This fixes sway not being able to draw text on text nodes.

cairo_create(NULL) returns a nil object in an error state rather than
NULL, causing the null check to never trigger and passing a broken cairo
context to get_text_size, which was fine until 40e1dcd29f adding error
handling to it and causing pango_cairo_update_layout to fail with a NULL
pointer.
2026-03-21 11:18:26 +01:00
Stephane Fontaine
8378c560c1 call disable container in arrange_root 2026-03-20 22:53:22 -04:00
Félix Poisot
82227d6103 common/pango: get_text_size out pointers may be NULL
Fixes: 2c2a2ec380
Closes: https://github.com/swaywm/sway/issues/9082
2026-03-20 09:51:55 +01:00
llyyr
85a4b19ac4 build: bump wlroots version
Upstream bumped to 0.21.0-dev 627da39e76
2026-03-19 16:24:39 -04:00
15 changed files with 314 additions and 125 deletions

View file

@ -25,7 +25,7 @@ packages:
- hwdata-dev
sources:
- https://github.com/swaywm/sway
- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.20
- https://gitlab.freedesktop.org/wlroots/wlroots.git
tasks:
- wlroots: |
cd wlroots

View file

@ -22,7 +22,7 @@ packages:
- hwdata
sources:
- https://github.com/swaywm/sway
- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.20
- https://gitlab.freedesktop.org/wlroots/wlroots.git
tasks:
- wlroots: |
cd wlroots

View file

@ -31,7 +31,7 @@ packages:
- misc/hwdata
sources:
- https://github.com/swaywm/sway
- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.20
- https://gitlab.freedesktop.org/wlroots/wlroots.git
tasks:
- setup: |
cd sway

View file

@ -176,7 +176,7 @@ void handle_new_output(struct wl_listener *listener, void *data);
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
void sway_session_lock_init(void);
bool sway_session_lock_init(void);
void sway_session_lock_add_output(struct sway_session_lock *lock,
struct sway_output *output);
bool sway_session_lock_has_surface(struct sway_session_lock *lock,

View file

@ -91,10 +91,6 @@ struct sway_container {
} border;
struct wlr_scene_tree *content_tree;
struct wlr_scene_buffer *output_handler;
struct wl_listener outputs_update;
struct wl_listener output_handler_destroy;
struct sway_container_state current;
struct sway_container_state pending;

View file

@ -69,6 +69,9 @@ struct sway_view {
struct wlr_scene_tree *scene_tree;
struct wlr_scene_tree *content_tree;
struct wlr_scene_tree *saved_surface_tree;
struct wlr_scene_buffer *output_handler;
struct wl_listener outputs_update;
struct wlr_scene *image_capture_scene;
struct wlr_ext_image_capture_source_v1 *image_capture_source;

View file

@ -162,7 +162,7 @@ void workspace_squash(struct sway_workspace *workspace);
void workspace_move_to_output(struct sway_workspace *workspace,
struct sway_output *output);
void sway_ext_workspace_init(void);
bool sway_ext_workspace_init(void);
void sway_ext_workspace_output_enable(struct sway_output *output);
void sway_ext_workspace_output_disable(struct sway_output *output);

View file

@ -1,7 +1,7 @@
project(
'sway',
'c',
version: '1.12-rc1',
version: '1.13-dev',
license: 'MIT',
meson_version: '>=1.3',
default_options: [
@ -39,14 +39,14 @@ if is_freebsd
endif
# Execute the wlroots subproject, if any
wlroots_version = ['>=0.20.0', '<0.21.0']
wlroots_version = ['>=0.21.0', '<0.22.0']
subproject(
'wlroots',
default_options: ['examples=false'],
required: false,
version: wlroots_version,
)
wlroots = dependency('wlroots-0.20', version: wlroots_version, fallback: 'wlroots')
wlroots = dependency('wlroots-0.21', version: wlroots_version, fallback: 'wlroots')
wlroots_features = {
'xwayland': false,
'libinput_backend': false,

View file

@ -395,10 +395,6 @@ static void arrange_container(struct sway_container *con,
// make sure it's enabled for viewing
wlr_scene_node_set_enabled(&con->scene_tree->node, true);
if (con->output_handler) {
wlr_scene_buffer_set_dest_size(con->output_handler, width, height);
}
if (con->view) {
int border_top = container_titlebar_height();
int border_width = con->current.border_thickness;
@ -456,6 +452,13 @@ static void arrange_container(struct sway_container *con,
wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree);
wlr_scene_node_set_position(&con->view->scene_tree->node,
border_left, border_top);
// the output handler for the view wants to detect events for the entire
// container so give it negative coordinates to move it back over the
// decorations
wlr_scene_node_set_position(&con->view->output_handler->node,
-border_left, -border_top);
wlr_scene_buffer_set_dest_size(con->view->output_handler, width, height);
} else {
// make sure to disable the title bar if the parent is not managing it
if (title_bar) {
@ -495,6 +498,11 @@ static void arrange_fullscreen(struct wlr_scene_tree *tree,
// if we only care about the view, disable any decorations
wlr_scene_node_set_enabled(&fs->scene_tree->node, false);
// reconfigure the output handler (for foreign toplevel) to cover the
// view without container decorations
wlr_scene_node_set_position(&fs->view->output_handler->node, 0, 0);
wlr_scene_buffer_set_dest_size(fs->view->output_handler, width, height);
} else {
fs_node = &fs->scene_tree->node;
arrange_container(fs, width, height, true, container_get_gaps(fs));

View file

@ -344,8 +344,12 @@ bool sway_session_lock_has_surface(struct sway_session_lock *lock,
return false;
}
void sway_session_lock_init(void) {
bool sway_session_lock_init(void) {
server.session_lock.manager = wlr_session_lock_manager_v1_create(server.wl_display);
if (!server.session_lock.manager) {
sway_log(SWAY_ERROR, "Failed to create session lock manager");
return false;
}
server.session_lock.new_lock.notify = handle_session_lock;
server.session_lock.manager_destroy.notify = handle_session_lock_destroy;
@ -353,4 +357,5 @@ void sway_session_lock_init(void) {
&server.session_lock.new_lock);
wl_signal_add(&server.session_lock.manager->events.destroy,
&server.session_lock.manager_destroy);
return true;
}

View file

@ -244,13 +244,25 @@ static void handle_new_foreign_toplevel_capture_request(struct wl_listener *list
bool server_init(struct sway_server *server) {
sway_log(SWAY_DEBUG, "Initializing Wayland server");
server->wl_display = wl_display_create();
if (!server->wl_display) {
sway_log(SWAY_ERROR, "Failed to create wl_display");
return false;
}
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
wl_display_set_global_filter(server->wl_display, filter_global, NULL);
wl_display_set_default_max_buffer_size(server->wl_display, 1024 * 1024);
wlr_fixes_create(server->wl_display, 1);
if (!wlr_fixes_create(server->wl_display, 1)) {
sway_log(SWAY_ERROR, "Failed to create wp_fixes global");
return false;
}
root = root_create(server->wl_display);
if (!root) {
sway_log(SWAY_ERROR, "Failed to create root");
wl_display_destroy(server->wl_display);
return false;
}
server->backend = wlr_backend_autocreate(server->wl_event_loop, &server->session);
if (!server->backend) {
@ -271,15 +283,23 @@ bool server_init(struct sway_server *server) {
wlr_renderer_init_wl_shm(server->renderer, server->wl_display);
if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) {
if (wlr_renderer_get_drm_fd(server->renderer) >= 0 &&
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, 5, server->renderer);
if (!server->linux_dmabuf_v1) {
sway_log(SWAY_ERROR, "Failed to create linux-dmabuf v1");
return false;
}
}
if (wlr_renderer_get_drm_fd(server->renderer) >= 0 &&
server->renderer->features.timeline &&
server->backend->features.timeline) {
wlr_linux_drm_syncobj_manager_v1_create(server->wl_display, 1,
wlr_renderer_get_drm_fd(server->renderer));
if (!wlr_linux_drm_syncobj_manager_v1_create(server->wl_display, 1,
wlr_renderer_get_drm_fd(server->renderer))) {
sway_log(SWAY_ERROR, "Failed to create linux-drm-syncobj v1");
return false;
}
}
server->allocator = wlr_allocator_autocreate(server->backend,
@ -291,14 +311,29 @@ bool server_init(struct sway_server *server) {
server->compositor = wlr_compositor_create(server->wl_display, 6,
server->renderer);
if (!server->compositor) {
sway_log(SWAY_ERROR, "Failed to create compositor");
return false;
}
wlr_subcompositor_create(server->wl_display);
if (!wlr_subcompositor_create(server->wl_display)) {
sway_log(SWAY_ERROR, "Failed to create subcompositor");
return false;
}
server->data_device_manager =
wlr_data_device_manager_create(server->wl_display);
if (!server->data_device_manager) {
sway_log(SWAY_ERROR, "Failed to create data device manager");
return false;
}
server->gamma_control_manager_v1 =
wlr_gamma_control_manager_v1_create(server->wl_display);
if (!server->gamma_control_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create gamma control manager");
return false;
}
wlr_scene_set_gamma_control_manager_v1(root->root_scene,
server->gamma_control_manager_v1);
@ -307,26 +342,53 @@ bool server_init(struct sway_server *server) {
server->xdg_output_manager_v1 =
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
if (!server->xdg_output_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create XDG output manager");
return false;
}
server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display);
sway_idle_inhibit_manager_v1_init();
if (!server->idle_notifier_v1) {
sway_log(SWAY_ERROR, "Failed to create idle notifier");
return false;
}
if (!sway_idle_inhibit_manager_v1_init()) {
sway_log(SWAY_ERROR, "Failed to init idle inhibit manager");
return false;
}
server->layer_shell = wlr_layer_shell_v1_create(server->wl_display,
SWAY_LAYER_SHELL_VERSION);
if (!server->layer_shell) {
sway_log(SWAY_ERROR, "Failed to create layer shell");
return false;
}
wl_signal_add(&server->layer_shell->events.new_surface,
&server->layer_shell_surface);
server->layer_shell_surface.notify = handle_layer_shell_surface;
server->xdg_shell = wlr_xdg_shell_create(server->wl_display,
SWAY_XDG_SHELL_VERSION);
if (!server->xdg_shell) {
sway_log(SWAY_ERROR, "Failed to create XDG shell");
return false;
}
wl_signal_add(&server->xdg_shell->events.new_toplevel,
&server->xdg_shell_toplevel);
server->xdg_shell_toplevel.notify = handle_xdg_shell_toplevel;
server->tablet_v2 = wlr_tablet_v2_create(server->wl_display);
if (!server->tablet_v2) {
sway_log(SWAY_ERROR, "Failed to create tablet manager");
return false;
}
server->server_decoration_manager =
wlr_server_decoration_manager_create(server->wl_display);
if (!server->server_decoration_manager) {
sway_log(SWAY_ERROR, "Failed to create server decoration manager");
return false;
}
wlr_server_decoration_manager_set_default_mode(
server->server_decoration_manager,
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
@ -337,6 +399,10 @@ bool server_init(struct sway_server *server) {
server->xdg_decoration_manager =
wlr_xdg_decoration_manager_v1_create(server->wl_display);
if (!server->xdg_decoration_manager) {
sway_log(SWAY_ERROR, "Failed to create XDG decoration manager");
return false;
}
wl_signal_add(
&server->xdg_decoration_manager->events.new_toplevel_decoration,
&server->xdg_decoration);
@ -345,18 +411,36 @@ bool server_init(struct sway_server *server) {
server->relative_pointer_manager =
wlr_relative_pointer_manager_v1_create(server->wl_display);
if (!server->relative_pointer_manager) {
sway_log(SWAY_ERROR, "Failed to create relative pointer manager");
return false;
}
server->pointer_constraints =
wlr_pointer_constraints_v1_create(server->wl_display);
if (!server->pointer_constraints) {
sway_log(SWAY_ERROR, "Failed to create pointer constraints");
return false;
}
server->pointer_constraint.notify = handle_pointer_constraint;
wl_signal_add(&server->pointer_constraints->events.new_constraint,
&server->pointer_constraint);
wlr_presentation_create(server->wl_display, server->backend, SWAY_PRESENTATION_VERSION);
wlr_alpha_modifier_v1_create(server->wl_display);
if (!wlr_presentation_create(server->wl_display, server->backend, SWAY_PRESENTATION_VERSION)) {
sway_log(SWAY_ERROR, "Failed to create presentation");
return false;
}
if (!wlr_alpha_modifier_v1_create(server->wl_display)) {
sway_log(SWAY_ERROR, "Failed to create alpha modifier");
return false;
}
server->output_manager_v1 =
wlr_output_manager_v1_create(server->wl_display);
if (!server->output_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create output manager");
return false;
}
server->output_manager_apply.notify = handle_output_manager_apply;
wl_signal_add(&server->output_manager_v1->events.apply,
&server->output_manager_apply);
@ -366,19 +450,43 @@ bool server_init(struct sway_server *server) {
server->output_power_manager_v1 =
wlr_output_power_manager_v1_create(server->wl_display);
if (!server->output_power_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create output power manager");
return false;
}
server->output_power_manager_set_mode.notify =
handle_output_power_manager_set_mode;
wl_signal_add(&server->output_power_manager_v1->events.set_mode,
&server->output_power_manager_set_mode);
server->input_method = wlr_input_method_manager_v2_create(server->wl_display);
if (!server->input_method) {
sway_log(SWAY_ERROR, "Failed to create input method manager");
return false;
}
server->text_input = wlr_text_input_manager_v3_create(server->wl_display);
if (!server->text_input) {
sway_log(SWAY_ERROR, "Failed to create text input manager");
return false;
}
server->foreign_toplevel_list =
wlr_ext_foreign_toplevel_list_v1_create(server->wl_display, SWAY_FOREIGN_TOPLEVEL_LIST_VERSION);
if (!server->foreign_toplevel_list) {
sway_log(SWAY_ERROR, "Failed to create foreign toplevel list");
return false;
}
server->foreign_toplevel_manager =
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
if (!server->foreign_toplevel_manager) {
sway_log(SWAY_ERROR, "Failed to create foreign toplevel manager");
return false;
}
sway_session_lock_init();
sway_ext_workspace_init();
if (!sway_session_lock_init()) {
return false;
}
if (!sway_ext_workspace_init()) {
return false;
}
#if WLR_HAS_DRM_BACKEND
server->drm_lease_manager=
@ -394,26 +502,74 @@ bool server_init(struct sway_server *server) {
#endif
server->export_dmabuf_manager_v1 = wlr_export_dmabuf_manager_v1_create(server->wl_display);
if (!server->export_dmabuf_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create export dmabuf manager");
return false;
}
server->screencopy_manager_v1 = wlr_screencopy_manager_v1_create(server->wl_display);
if (!server->screencopy_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create screencopy manager");
return false;
}
server->ext_image_copy_capture_manager_v1 = wlr_ext_image_copy_capture_manager_v1_create(server->wl_display, 1);
wlr_ext_output_image_capture_source_manager_v1_create(server->wl_display, 1);
if (!server->ext_image_copy_capture_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create ext image copy capture manager");
return false;
}
if (!wlr_ext_output_image_capture_source_manager_v1_create(server->wl_display, 1)) {
sway_log(SWAY_ERROR, "Failed to create ext output image capture source manager");
return false;
}
server->wlr_data_control_manager_v1 = wlr_data_control_manager_v1_create(server->wl_display);
if (!server->wlr_data_control_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create data control manager");
return false;
}
server->ext_data_control_manager_v1 = wlr_ext_data_control_manager_v1_create(server->wl_display, 1);
if (!server->ext_data_control_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create ext data control manager");
return false;
}
server->security_context_manager_v1 = wlr_security_context_manager_v1_create(server->wl_display);
wlr_viewporter_create(server->wl_display);
wlr_single_pixel_buffer_manager_v1_create(server->wl_display);
if (!server->security_context_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create security context manager");
return false;
}
if (!wlr_viewporter_create(server->wl_display)) {
sway_log(SWAY_ERROR, "Failed to create viewporter");
return false;
}
if (!wlr_single_pixel_buffer_manager_v1_create(server->wl_display)) {
sway_log(SWAY_ERROR, "Failed to create single pixel buffer manager");
return false;
}
server->content_type_manager_v1 =
wlr_content_type_manager_v1_create(server->wl_display, 1);
wlr_fractional_scale_manager_v1_create(server->wl_display, 1);
if (!server->content_type_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create content type manager");
return false;
}
if (!wlr_fractional_scale_manager_v1_create(server->wl_display, 1)) {
sway_log(SWAY_ERROR, "Failed to create fractional scale manager");
return false;
}
server->ext_foreign_toplevel_image_capture_source_manager_v1 =
wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(server->wl_display, 1);
if (!server->ext_foreign_toplevel_image_capture_source_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create ext foreign toplevel image capture source manager");
return false;
}
server->new_foreign_toplevel_capture_request.notify = handle_new_foreign_toplevel_capture_request;
wl_signal_add(&server->ext_foreign_toplevel_image_capture_source_manager_v1->events.new_request,
&server->new_foreign_toplevel_capture_request);
server->tearing_control_v1 =
wlr_tearing_control_manager_v1_create(server->wl_display, 1);
if (!server->tearing_control_v1) {
sway_log(SWAY_ERROR, "Failed to create tearing control manager");
return false;
}
server->tearing_control_new_object.notify = handle_new_tearing_hint;
wl_signal_add(&server->tearing_control_v1->events.new_object,
&server->tearing_control_new_object);
@ -421,10 +577,24 @@ bool server_init(struct sway_server *server) {
struct wlr_xdg_foreign_registry *foreign_registry =
wlr_xdg_foreign_registry_create(server->wl_display);
wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry);
wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry);
if (!foreign_registry) {
sway_log(SWAY_ERROR, "Failed to create XDG foreign registry");
return false;
}
if (!wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry)) {
sway_log(SWAY_ERROR, "Failed to create XDG foreign v1");
return false;
}
if (!wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry)) {
sway_log(SWAY_ERROR, "Failed to create XDG foreign v2");
return false;
}
server->xdg_activation_v1 = wlr_xdg_activation_v1_create(server->wl_display);
if (!server->xdg_activation_v1) {
sway_log(SWAY_ERROR, "Failed to create XDG activation");
return false;
}
server->xdg_activation_v1_request_activate.notify =
xdg_activation_v1_handle_request_activate;
wl_signal_add(&server->xdg_activation_v1->events.request_activate,
@ -436,6 +606,10 @@ bool server_init(struct sway_server *server) {
struct wlr_xdg_toplevel_tag_manager_v1 *xdg_toplevel_tag_manager_v1 =
wlr_xdg_toplevel_tag_manager_v1_create(server->wl_display, 1);
if (!xdg_toplevel_tag_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create XDG toplevel tag manager");
return false;
}
server->xdg_toplevel_tag_manager_v1_set_tag.notify =
xdg_toplevel_tag_manager_v1_handle_set_tag;
wl_signal_add(&xdg_toplevel_tag_manager_v1->events.set_tag,
@ -443,6 +617,10 @@ bool server_init(struct sway_server *server) {
struct wlr_cursor_shape_manager_v1 *cursor_shape_manager =
wlr_cursor_shape_manager_v1_create(server->wl_display, 2);
if (!cursor_shape_manager) {
sway_log(SWAY_ERROR, "Failed to create cursor shape manager");
return false;
}
server->request_set_cursor_shape.notify = handle_request_set_cursor_shape;
wl_signal_add(&cursor_shape_manager->events.request_set_shape, &server->request_set_cursor_shape);
@ -471,11 +649,18 @@ bool server_init(struct sway_server *server) {
});
free(transfer_functions);
free(primaries);
if (!cm) {
sway_log(SWAY_ERROR, "Failed to create color manager");
return false;
}
wlr_scene_set_color_manager_v1(root->root_scene, cm);
}
wlr_color_representation_manager_v1_create_with_renderer(
server->wl_display, 1, server->renderer);
if (!wlr_color_representation_manager_v1_create_with_renderer(
server->wl_display, 1, server->renderer)) {
sway_log(SWAY_ERROR, "Failed to create color representation manager");
return false;
}
wl_list_init(&server->pending_launcher_ctxs);
@ -515,8 +700,16 @@ bool server_init(struct sway_server *server) {
}
server->dirty_nodes = create_list();
if (!server->dirty_nodes) {
sway_log(SWAY_ERROR, "Failed to create dirty nodes list");
return false;
}
server->input = input_manager_create(server);
if (!server->input) {
sway_log(SWAY_ERROR, "Failed to create input manager");
return false;
}
input_manager_get_default_seat(); // create seat0
return true;

View file

@ -802,7 +802,7 @@ node and will have the following properties:
Retrieve the currently set marks
*REPLY*++
An array of marks current set. Since each mark can only be set for one
An array of marks currently set. Since each mark can only be set for one
container, this is a set so each value is unique and the order is undefined.
*Example Reply:*
@ -833,13 +833,13 @@ An array of bar IDs, which are strings
*MESSAGE*++
When sent with a bar ID as the payload, this retrieves the config associated
with the specified by the bar ID in the payload. This is used by swaybar, but
could also be used for third party bars
with the bar ID specified in the payload. This is used by swaybar, but could
also be used for third-party bars
*REPLY*++
An object that represents the configuration for the bar with the bar ID sent as
the payload. The following properties exists and more information about what
their value mean can be found in *sway-bar*(5):
the payload. The following properties exist, with more information about their
values in *sway-bar*(5):
[- *PROPERTY*
:- *DATA TYPE*
@ -1040,7 +1040,7 @@ An object containing the following properties:
## 8. GET_BINDING_MODES
*MESSAGE*++
Retrieve the list of binding modes that currently configured
Retrieve the list of binding modes that are currently configured
*REPLY*++
An array of strings, with each string being the name of a binding mode. This
@ -1154,13 +1154,13 @@ following properties:
_tablet\_tool_, _tablet\_pad_, or _switch_
|- xkb_active_layout_name
: string
: (Only keyboards) The name of the active keyboard layout in use
: (Only keyboards) The name of the active keyboard layout
|- xkb_layout_names
: array
: (Only keyboards) A list a layout names configured for the keyboard
|- xkb_active_layout_index
: integer
: (Only keyboards) The index of the active keyboard layout in use
: (Only keyboards) The index of the active keyboard layout
|- scroll_factor
: floating
: (Only pointers) Multiplier applied on scroll event values.
@ -1467,7 +1467,7 @@ one seat. Each object has the following properties:
# EVENTS
Events are a way for client to get notified of changes to sway. A client can
Events are a way for clients to get notified of changes to sway. A client can
subscribe to any events it wants to be notified of changes for. The event is
sent in the same format as a reply. The following events are currently
available:
@ -1478,7 +1478,7 @@ available:
|- 0x80000000
: workspace
:[ Sent whenever an event involving a workspace occurs such as initialization
of a new workspace or a different workspace gains focus
of a new workspace or another workspace gaining focus
|- 0x80000001
: output
: Sent when outputs are updated
@ -1487,7 +1487,7 @@ available:
: Sent whenever the binding mode changes
|- 0x80000003
: window
: Sent whenever an event involving a window occurs such as being reparented,
: Sent whenever an event involving a window occurs such as it being reparented,
focused, or closed
|- 0x80000004
: barconfig_update
@ -1503,7 +1503,7 @@ available:
: Sent when an ipc client sends a _SEND\_TICK_ message
|- 0x80000014
: bar_state_update
: Send when the visibility of a bar should change due to a modifier
: Sent when the visibility of a bar should change due to a modifier
|- 0x80000015
: input
: Sent when something related to input devices changes
@ -1522,10 +1522,10 @@ single object with the following properties:
:[ The type of change that occurred. See below for more information
|- current
: object
: An object representing the workspace effected or _null_ for _reload_ changes
: An object representing the affected workspace or _null_ for _reload_ changes
|- old
: object
: For a _focus_ change, this is will be an object representing the workspace
: For a _focus_ change, this will be an object representing the workspace
being switched from. Otherwise, it is _null_
@ -1543,7 +1543,7 @@ The following change types are currently available:
|- rename
: The workspace was renamed
|- urgent
: A window on the workspace has had their urgency hint set or all urgency hints
: A window on the workspace has had its urgency hint set or all urgency hints
for windows on the workspace have been cleared
|- reload
: The configuration file has been reloaded
@ -1653,7 +1653,7 @@ object with the following properties:
:[ The type of change that occurred. See below for more information
|- container
: object
: An object representing the window effected
: An object representing the affected window
The following change types are currently available:
@ -1816,7 +1816,7 @@ event is a single object with the following properties:
: Whether this event was triggered by subscribing to the tick events
|- payload
: string
: The payload given with a _SEND\_TICK_ message, if any. Otherwise, an empty
: The payload provided in a _SEND\_TICK_ message, if any. Otherwise, an empty
string
@ -1838,7 +1838,7 @@ event is a single object with the following properties:
:- *DESCRIPTION*
|- id
: string
:[ The bar ID effected
:[ The bar ID affected
|- visible_by_modifier
: boolean
: Whether the bar should be made visible due to a modifier being pressed
@ -1854,7 +1854,7 @@ event is a single object with the following properties:
## 0x80000015. INPUT
Sent when something related to the input devices changes. The event is a single
Sent when something related to input devices changes. The event is a single
object with the following properties:
[- *PROPERTY*
@ -1865,7 +1865,7 @@ object with the following properties:
:[ What has changed
|- input
: object
: An object representing the input that is identical the ones GET_INPUTS gives
: An object representing the input that is identical to the ones GET_INPUTS gives
The following change types are currently available:
[- *TYPE*

View file

@ -25,50 +25,6 @@
#include "log.h"
#include "stringop.h"
static void handle_outputs_update(
struct wl_listener *listener, void *data) {
struct sway_container *con = wl_container_of(
listener, con, outputs_update);
struct wlr_scene_outputs_update_event *event = data;
struct wlr_foreign_toplevel_handle_v1 *toplevel = con->view->foreign_toplevel;
if (toplevel) {
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output, *tmp;
wl_list_for_each_safe(toplevel_output, tmp, &toplevel->outputs, link) {
bool active = false;
for (size_t i = 0; i < event->size; i++) {
struct wlr_scene_output *scene_output = event->active[i];
if (scene_output->output == toplevel_output->output) {
active = true;
break;
}
}
if (!active) {
wlr_foreign_toplevel_handle_v1_output_leave(toplevel, toplevel_output->output);
}
}
for (size_t i = 0; i < event->size; i++) {
struct wlr_scene_output *scene_output = event->active[i];
wlr_foreign_toplevel_handle_v1_output_enter(toplevel, scene_output->output);
}
}
}
static void handle_destroy(
struct wl_listener *listener, void *data) {
struct sway_container *con = wl_container_of(
listener, con, output_handler_destroy);
container_begin_destroy(con);
}
static bool handle_point_accepts_input(
struct wlr_scene_buffer *buffer, double *x, double *y) {
return false;
}
static struct wlr_scene_rect *alloc_rect_node(struct wlr_scene_tree *parent,
bool *failed) {
if (*failed) {
@ -135,22 +91,6 @@ struct sway_container *container_create(struct sway_view *view) {
c->border.bottom = alloc_rect_node(c->border.tree, &failed);
c->border.left = alloc_rect_node(c->border.tree, &failed);
c->border.right = alloc_rect_node(c->border.tree, &failed);
c->output_handler = wlr_scene_buffer_create(c->border.tree, NULL);
if (!c->output_handler) {
sway_log(SWAY_ERROR, "Failed to allocate a scene node");
failed = true;
}
if (!failed) {
c->outputs_update.notify = handle_outputs_update;
wl_signal_add(&c->output_handler->events.outputs_update,
&c->outputs_update);
c->output_handler_destroy.notify = handle_destroy;
wl_signal_add(&c->output_handler->node.events.destroy,
&c->output_handler_destroy);
c->output_handler->point_accepts_input = handle_point_accepts_input;
}
}
if (!failed && !scene_descriptor_assign(&c->scene_tree->node,
@ -522,7 +462,6 @@ void container_destroy(struct sway_container *con) {
if (con->view && con->view->container == con) {
con->view->container = NULL;
wlr_scene_node_destroy(&con->output_handler->node);
if (con->view->destroying) {
view_destroy(con->view);
}
@ -564,11 +503,6 @@ void container_begin_destroy(struct sway_container *con) {
if (con->pending.parent || con->pending.workspace) {
container_detach(con);
}
if (con->view && con->view->container == con) {
wl_list_remove(&con->outputs_update.link);
wl_list_remove(&con->output_handler_destroy.link);
}
}
void container_reap_empty(struct sway_container *con) {

View file

@ -38,6 +38,41 @@
#include "sway/xdg_decoration.h"
#include "stringop.h"
static void handle_outputs_update(
struct wl_listener *listener, void *data) {
struct sway_view *view = wl_container_of(listener, view, outputs_update);
struct wlr_scene_outputs_update_event *event = data;
struct wlr_foreign_toplevel_handle_v1 *toplevel = view->foreign_toplevel;
if (toplevel) {
struct wlr_foreign_toplevel_handle_v1_output *toplevel_output, *tmp;
wl_list_for_each_safe(toplevel_output, tmp, &toplevel->outputs, link) {
bool active = false;
for (size_t i = 0; i < event->size; i++) {
struct wlr_scene_output *scene_output = event->active[i];
if (scene_output->output == toplevel_output->output) {
active = true;
break;
}
}
if (!active) {
wlr_foreign_toplevel_handle_v1_output_leave(toplevel, toplevel_output->output);
}
}
for (size_t i = 0; i < event->size; i++) {
struct wlr_scene_output *scene_output = event->active[i];
wlr_foreign_toplevel_handle_v1_output_enter(toplevel, scene_output->output);
}
}
}
static bool handle_point_accepts_input(
struct wlr_scene_buffer *buffer, double *x, double *y) {
return false;
}
bool view_init(struct sway_view *view, enum sway_view_type type,
const struct sway_view_impl *impl) {
bool failed = false;
@ -51,12 +86,23 @@ bool view_init(struct sway_view *view, enum sway_view_type type,
goto err;
}
view->output_handler = wlr_scene_buffer_create(view->scene_tree, NULL);
if (!view->output_handler) {
sway_log(SWAY_ERROR, "Failed to allocate a scene node");
goto err;
}
view->image_capture_scene = wlr_scene_create();
if (view->image_capture_scene == NULL) {
goto err;
}
view->image_capture_scene->restack_xwayland_surfaces = false;
view->outputs_update.notify = handle_outputs_update;
wl_signal_add(&view->output_handler->events.outputs_update,
&view->outputs_update);
view->output_handler->point_accepts_input = handle_point_accepts_input;
view->type = type;
view->impl = impl;
view->executed_criteria = create_list();
@ -102,6 +148,7 @@ void view_begin_destroy(struct sway_view *view) {
return;
}
view->destroying = true;
wl_list_remove(&view->outputs_update.link);
if (!view->container) {
view_destroy(view);
@ -1229,8 +1276,10 @@ void view_save_buffer(struct sway_view *view) {
return;
}
// Enable and disable the saved surface tree like so to atomitaclly update
// the tree. This will prevent over damaging or other weirdness.
// Make sure the output handler is placed above the saved surface so we don't send
// spurious events to the foreign toplevel handler. Also, make the saved surface tree
// is disabled until it is ready to replace the real surface.
wlr_scene_node_place_below(&view->saved_surface_tree->node, &view->output_handler->node);
wlr_scene_node_set_enabled(&view->saved_surface_tree->node, false);
wlr_scene_node_for_each_buffer(&view->content_tree->node,

View file

@ -97,17 +97,18 @@ static void handle_commit(struct wl_listener *listener, void *data) {
}
// Initialize ext-workspace. Must be called once at startup.
void sway_ext_workspace_init(void) {
bool sway_ext_workspace_init(void) {
server.workspace_manager_v1 =
wlr_ext_workspace_manager_v1_create(server.wl_display, 1);
if (!server.workspace_manager_v1) {
sway_log(SWAY_ERROR, "Failed to create ext_workspace_manager_v1");
return;
return false;
}
server.workspace_manager_v1_commit.notify = handle_commit;
wl_signal_add(&server.workspace_manager_v1->events.commit,
&server.workspace_manager_v1_commit);
return true;
}
// Must be called whenever an output is enabled.