diff --git a/include/sway/commands.h b/include/sway/commands.h index 0f2d12d5..652cfc7c 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -267,6 +267,7 @@ sway_cmd input_cmd_scroll_factor; sway_cmd input_cmd_repeat_delay; sway_cmd input_cmd_repeat_rate; sway_cmd input_cmd_scroll_button; +sway_cmd input_cmd_scroll_button_lock; sway_cmd input_cmd_scroll_method; sway_cmd input_cmd_tap; sway_cmd input_cmd_tap_button_map; diff --git a/include/sway/config.h b/include/sway/config.h index a16ddf57..2c1eb41d 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -161,6 +161,7 @@ struct input_config { int repeat_delay; int repeat_rate; int scroll_button; + int scroll_button_lock; int scroll_method; int send_events; int tap; diff --git a/include/sway/desktop/idle_inhibit_v1.h b/include/sway/desktop/idle_inhibit_v1.h index 58d54c68..6dda1af9 100644 --- a/include/sway/desktop/idle_inhibit_v1.h +++ b/include/sway/desktop/idle_inhibit_v1.h @@ -2,7 +2,6 @@ #define _SWAY_DESKTOP_IDLE_INHIBIT_V1_H #include #include -#include "sway/server.h" enum sway_idle_inhibit_mode { INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible) @@ -16,12 +15,9 @@ struct sway_idle_inhibit_manager_v1 { struct wlr_idle_inhibit_manager_v1 *wlr_manager; struct wl_listener new_idle_inhibitor_v1; struct wl_list inhibitors; - - struct wlr_idle *idle; }; struct sway_idle_inhibitor_v1 { - struct sway_idle_inhibit_manager_v1 *manager; struct wlr_idle_inhibitor_v1 *wlr_inhibitor; struct sway_view *view; enum sway_idle_inhibit_mode mode; @@ -33,8 +29,7 @@ struct sway_idle_inhibitor_v1 { bool sway_idle_inhibit_v1_is_active( struct sway_idle_inhibitor_v1 *inhibitor); -void sway_idle_inhibit_v1_check_active( - struct sway_idle_inhibit_manager_v1 *manager); +void sway_idle_inhibit_v1_check_active(void); void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, enum sway_idle_inhibit_mode mode); @@ -48,6 +43,6 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_vi void sway_idle_inhibit_v1_user_inhibitor_destroy( struct sway_idle_inhibitor_v1 *inhibitor); -struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( - struct wl_display *wl_display, struct wlr_idle *idle); +bool sway_idle_inhibit_manager_v1_init(void); + #endif diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 4a3774d9..1636588a 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -35,7 +35,6 @@ struct sway_cursor { pixman_region32_t confine; // invalid if active_constraint == NULL bool active_confine_requires_warp; - struct wlr_pointer_gestures_v1 *pointer_gestures; struct wl_listener hold_begin; struct wl_listener hold_end; struct wl_listener pinch_begin; @@ -53,6 +52,7 @@ struct sway_cursor { struct wl_listener touch_down; struct wl_listener touch_up; + struct wl_listener touch_cancel; struct wl_listener touch_motion; struct wl_listener touch_frame; bool simulating_pointer_from_touch; diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index c9bd08f0..b651e3dd 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -25,6 +25,7 @@ struct sway_input_manager { struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit; struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; struct wlr_virtual_pointer_manager_v1 *virtual_pointer; + struct wlr_pointer_gestures_v1 *pointer_gestures; struct wl_listener new_input; struct wl_listener inhibit_activate; diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 7b2d3d07..35a96ace 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -12,6 +12,7 @@ #include "sway/input/text_input.h" struct sway_seat; +struct render_context; struct sway_seatop_impl { void (*button)(struct sway_seat *seat, uint32_t time_msec, @@ -43,14 +44,15 @@ struct sway_seatop_impl { struct wlr_touch_up_event *event); void (*touch_down)(struct sway_seat *seat, struct wlr_touch_down_event *event, double lx, double ly); + void (*touch_cancel)(struct sway_seat *seat, + struct wlr_touch_cancel_event *event); void (*tablet_tool_motion)(struct sway_seat *seat, struct sway_tablet_tool *tool, uint32_t time_msec); void (*tablet_tool_tip)(struct sway_seat *seat, struct sway_tablet_tool *tool, uint32_t time_msec, enum wlr_tablet_tool_tip_state state); void (*end)(struct sway_seat *seat); void (*unref)(struct sway_seat *seat, struct sway_container *con); - void (*render)(struct sway_seat *seat, struct sway_output *output, - const pixman_region32_t *damage); + void (*render)(struct sway_seat *seat, struct render_context *ctx); bool allow_set_cursor; }; @@ -102,8 +104,9 @@ struct sway_seat { struct sway_workspace *workspace; char *prev_workspace_name; // for workspace back_and_forth - // If the focused layer is set, views cannot receive keyboard focus struct wlr_layer_surface_v1 *focused_layer; + // If the exclusive layer is set, views cannot receive keyboard focus + bool has_exclusive_layer; // If exclusive_client is set, no other clients will receive input events struct wl_client *exclusive_client; @@ -338,6 +341,9 @@ void seatop_touch_up(struct sway_seat *seat, void seatop_touch_down(struct sway_seat *seat, struct wlr_touch_down_event *event, double lx, double ly); +void seatop_touch_cancel(struct sway_seat *seat, + struct wlr_touch_cancel_event *event); + void seatop_rebase(struct sway_seat *seat, uint32_t time_msec); /** @@ -356,8 +362,7 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con); * Instructs a seatop to render anything that it needs to render * (eg. dropzone for move-tiling) */ -void seatop_render(struct sway_seat *seat, struct sway_output *output, - const pixman_region32_t *damage); +void seatop_render(struct sway_seat *seat, struct render_context *ctx); bool seatop_allows_set_cursor(struct sway_seat *seat); diff --git a/include/sway/layers.h b/include/sway/layers.h index f8508493..9220bdb5 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h @@ -55,6 +55,10 @@ struct sway_layer_subsurface { }; struct sway_output; + +struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( + struct wlr_surface *surface); + void arrange_layers(struct sway_output *output); struct sway_layer_surface *layer_from_wlr_layer_surface_v1( diff --git a/include/sway/output.h b/include/sway/output.h index 04202976..50d90d25 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -57,6 +57,7 @@ struct sway_output { uint32_t refresh_nsec; int max_render_time; // In milliseconds struct wl_event_source *repaint_timer; + bool gamma_lut_changed; }; struct sway_output_non_desktop { @@ -65,6 +66,14 @@ struct sway_output_non_desktop { struct wl_listener destroy; }; +struct render_context { + struct sway_output *output; + struct wlr_renderer *renderer; + const pixman_region32_t *output_damage; + + struct wlr_render_pass *pass; +}; + struct sway_output *output_create(struct wlr_output *wlr_output); void output_destroy(struct sway_output *output); @@ -115,7 +124,7 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output); struct sway_workspace *output_get_active_workspace(struct sway_output *output); -void output_render(struct sway_output *output, pixman_region32_t *damage); +void output_render(struct render_context *ctx); void output_surface_for_each_surface(struct sway_output *output, struct wlr_surface *surface, double ox, double oy, @@ -168,8 +177,7 @@ void output_get_box(struct sway_output *output, struct wlr_box *box); enum sway_container_layout output_get_default_layout( struct sway_output *output); -void render_rect(struct sway_output *output, - const pixman_region32_t *output_damage, const struct wlr_box *_box, +void render_rect(struct render_context *ctx, const struct wlr_box *_box, float color[static 4]); void premultiply_alpha(float color[4], float opacity); @@ -180,6 +188,8 @@ enum wlr_direction opposite_direction(enum wlr_direction d); void handle_output_layout_change(struct wl_listener *listener, void *data); +void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data); + void handle_output_manager_apply(struct wl_listener *listener, void *data); void handle_output_manager_test(struct wl_listener *listener, void *data); diff --git a/include/sway/server.h b/include/sway/server.h index a65843ce..0e4ec2be 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -21,6 +21,7 @@ #include #include "config.h" #include "list.h" +#include "sway/desktop/idle_inhibit_v1.h" #if HAVE_XWAYLAND #include "sway/xwayland.h" #endif @@ -53,7 +54,7 @@ struct sway_server { struct wlr_idle *idle; struct wlr_idle_notifier_v1 *idle_notifier_v1; - struct sway_idle_inhibit_manager_v1 *idle_inhibit_manager_v1; + struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1; struct wlr_layer_shell_v1 *layer_shell; struct wl_listener layer_shell_surface; @@ -91,6 +92,9 @@ struct sway_server { struct wl_listener output_manager_apply; struct wl_listener output_manager_test; + struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1; + struct wl_listener gamma_control_set_gamma; + struct { bool locked; struct wlr_session_lock_manager_v1 *manager; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 7fc2d95d..960f9d71 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -160,6 +160,8 @@ struct sway_xwayland_view { struct wl_listener set_window_type; struct wl_listener set_hints; struct wl_listener set_decorations; + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; @@ -177,6 +179,8 @@ struct sway_xwayland_unmanaged { struct wl_listener request_fullscreen; struct wl_listener commit; struct wl_listener set_geometry; + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; diff --git a/meson.build b/meson.build index 559ee962..eeee39cd 100644 --- a/meson.build +++ b/meson.build @@ -48,7 +48,6 @@ wlroots = dependency('wlroots', version: wlroots_version) wlroots_features = { 'xwayland': false, 'libinput_backend': false, - 'gles2_renderer': false, 'session': false, } foreach name, _ : wlroots_features @@ -75,7 +74,6 @@ pango = dependency('pango') pangocairo = dependency('pangocairo') gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) pixman = dependency('pixman-1') -glesv2 = wlroots_features['gles2_renderer'] ? dependency('glesv2') : null_dep libevdev = dependency('libevdev') libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.21.0') : null_dep xcb = dependency('xcb', required: get_option('xwayland')) diff --git a/sway/commands/inhibit_idle.c b/sway/commands/inhibit_idle.c index aebc2bf9..6125736a 100644 --- a/sway/commands/inhibit_idle.c +++ b/sway/commands/inhibit_idle.c @@ -41,7 +41,7 @@ struct cmd_results *cmd_inhibit_idle(int argc, char **argv) { sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor); } else { inhibitor->mode = mode; - sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); + sway_idle_inhibit_v1_check_active(); } } else if (!clear) { sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode); diff --git a/sway/commands/input.c b/sway/commands/input.c index 3075b5f4..306c40f7 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c @@ -27,6 +27,7 @@ static const struct cmd_handler input_handlers[] = { { "repeat_rate", input_cmd_repeat_rate }, { "rotation_angle", input_cmd_rotation_angle }, { "scroll_button", input_cmd_scroll_button }, + { "scroll_button_lock", input_cmd_scroll_button_lock }, { "scroll_factor", input_cmd_scroll_factor }, { "scroll_method", input_cmd_scroll_method }, { "tap", input_cmd_tap }, diff --git a/sway/commands/input/scroll_button_lock.c b/sway/commands/input/scroll_button_lock.c new file mode 100644 index 00000000..f96b6514 --- /dev/null +++ b/sway/commands/input/scroll_button_lock.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "util.h" + +struct cmd_results *input_cmd_scroll_button_lock(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "scroll_button_lock", EXPECTED_AT_LEAST, 1))) { + return error; + } + struct input_config *ic = config->handler_context.input_config; + if (!ic) { + return cmd_results_new(CMD_FAILURE, "No input device defined."); + } + + if (parse_boolean(argv[0], true)) { + ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED; + } else { + ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/config/input.c b/sway/config/input.c index 2ee165c9..44c2be28 100644 --- a/sway/config/input.c +++ b/sway/config/input.c @@ -35,6 +35,7 @@ struct input_config *new_input_config(const char* identifier) { input->pointer_accel = FLT_MIN; input->scroll_factor = FLT_MIN; input->scroll_button = INT_MIN; + input->scroll_button_lock = INT_MIN; input->scroll_method = INT_MIN; input->left_handed = INT_MIN; input->repeat_delay = INT_MIN; @@ -96,6 +97,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { if (src->scroll_button != INT_MIN) { dst->scroll_button = src->scroll_button; } + if (src->scroll_button_lock != INT_MIN) { + dst->scroll_button_lock = src->scroll_button_lock; + } if (src->send_events != INT_MIN) { dst->send_events = src->send_events; } diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index 3a4d0b87..1fa058e3 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -12,7 +12,7 @@ static void destroy_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor) { wl_list_remove(&inhibitor->link); wl_list_remove(&inhibitor->destroy.link); - sway_idle_inhibit_v1_check_active(inhibitor->manager); + sway_idle_inhibit_v1_check_active(); free(inhibitor); } @@ -35,7 +35,6 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { return; } - inhibitor->manager = manager; inhibitor->mode = INHIBIT_IDLE_APPLICATION; inhibitor->wlr_inhibitor = wlr_inhibitor; wl_list_insert(&manager->inhibitors, &inhibitor->link); @@ -43,33 +42,34 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { inhibitor->destroy.notify = handle_destroy; wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy); - sway_idle_inhibit_v1_check_active(manager); + sway_idle_inhibit_v1_check_active(); } void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, enum sway_idle_inhibit_mode mode) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; + struct sway_idle_inhibitor_v1 *inhibitor = calloc(1, sizeof(struct sway_idle_inhibitor_v1)); if (!inhibitor) { return; } - inhibitor->manager = server.idle_inhibit_manager_v1; inhibitor->mode = mode; inhibitor->view = view; - wl_list_insert(&inhibitor->manager->inhibitors, &inhibitor->link); + wl_list_insert(&manager->inhibitors, &inhibitor->link); inhibitor->destroy.notify = handle_destroy; wl_signal_add(&view->events.unmap, &inhibitor->destroy); - sway_idle_inhibit_v1_check_active(inhibitor->manager); + sway_idle_inhibit_v1_check_active(); } struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( struct sway_view *view) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; struct sway_idle_inhibitor_v1 *inhibitor; - wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, - link) { + wl_list_for_each(inhibitor, &manager->inhibitors, link) { if (inhibitor->mode != INHIBIT_IDLE_APPLICATION && inhibitor->view == view) { return inhibitor; @@ -80,9 +80,9 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_view( struct sway_view *view) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; struct sway_idle_inhibitor_v1 *inhibitor; - wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, - link) { + wl_list_for_each(inhibitor, &manager->inhibitors, link) { if (inhibitor->mode == INHIBIT_IDLE_APPLICATION && view_from_wlr_surface(inhibitor->wlr_inhibitor->surface) == view) { return inhibitor; @@ -131,8 +131,8 @@ bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { return false; } -void sway_idle_inhibit_v1_check_active( - struct sway_idle_inhibit_manager_v1 *manager) { +void sway_idle_inhibit_v1_check_active(void) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; struct sway_idle_inhibitor_v1 *inhibitor; bool inhibited = false; wl_list_for_each(inhibitor, &manager->inhibitors, link) { @@ -140,28 +140,22 @@ void sway_idle_inhibit_v1_check_active( break; } } - wlr_idle_set_enabled(manager->idle, NULL, !inhibited); + wlr_idle_set_enabled(server.idle, NULL, !inhibited); wlr_idle_notifier_v1_set_inhibited(server.idle_notifier_v1, inhibited); } -struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( - struct wl_display *wl_display, struct wlr_idle *idle) { - struct sway_idle_inhibit_manager_v1 *manager = - calloc(1, sizeof(struct sway_idle_inhibit_manager_v1)); - if (!manager) { - return NULL; +bool sway_idle_inhibit_manager_v1_init(void) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; + + manager->wlr_manager = wlr_idle_inhibit_v1_create(server.wl_display); + if (!manager->wlr_manager) { + return false; } - manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display); - if (!manager->wlr_manager) { - free(manager); - return NULL; - } - manager->idle = idle; wl_signal_add(&manager->wlr_manager->events.new_inhibitor, &manager->new_idle_inhibitor_v1); manager->new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1; wl_list_init(&manager->inhibitors); - return manager; + return true; } diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index e16bee78..d990d92a 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -17,6 +17,39 @@ #include "sway/tree/arrange.h" #include "sway/tree/workspace.h" +struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( + struct wlr_surface *surface) { + struct wlr_layer_surface_v1 *layer; + do { + if (!surface) { + return NULL; + } + // Topmost layer surface + if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) { + return layer; + } + // Layer subsurface + if (wlr_subsurface_try_from_wlr_surface(surface)) { + surface = wlr_surface_get_root_surface(surface); + continue; + } + + // Layer surface popup + struct wlr_xdg_surface * xdg_popup = NULL; + if ((xdg_popup = wlr_xdg_surface_try_from_wlr_surface(surface)) && + xdg_popup->role == WLR_XDG_SURFACE_ROLE_POPUP) { + if (!xdg_popup->popup->parent) { + return NULL; + } + surface = wlr_surface_get_root_surface(xdg_popup->popup->parent); + continue; + } + + // Return early if the surface is not a layer/xdg_popup/sub surface + return NULL; + } while (true); +} + static void apply_exclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, int32_t margin_top, int32_t margin_right, @@ -218,8 +251,9 @@ void arrange_layers(struct sway_output *output) { for (size_t i = 0; i < nlayers; ++i) { wl_list_for_each_reverse(layer, &output->layers[layers_above_shell[i]], link) { - if (layer->layer_surface->current.keyboard_interactive && - layer->layer_surface->mapped) { + if (layer->layer_surface->current.keyboard_interactive + == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE && + layer->layer_surface->surface->mapped) { topmost = layer; break; } @@ -231,10 +265,12 @@ void arrange_layers(struct sway_output *output) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { + seat->has_exclusive_layer = false; if (topmost != NULL) { seat_set_focus_layer(seat, topmost->layer_surface); } else if (seat->focused_layer && - !seat->focused_layer->current.keyboard_interactive) { + seat->focused_layer->current.keyboard_interactive + != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { seat_set_focus_layer(seat, NULL); } } @@ -253,7 +289,7 @@ static struct sway_layer_surface *find_mapped_layer_by_client( &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) { struct wl_resource *resource = lsurface->layer_surface->resource; if (wl_resource_get_client(resource) == client - && lsurface->layer_surface->mapped) { + && lsurface->layer_surface->surface->mapped) { return lsurface; } } @@ -293,8 +329,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { bool layer_changed = false; if (layer_surface->current.committed != 0 - || layer->mapped != layer_surface->mapped) { - layer->mapped = layer_surface->mapped; + || layer->mapped != layer_surface->surface->mapped) { + layer->mapped = layer_surface->surface->mapped; layer_changed = layer->layer != layer_surface->current.layer; if (layer_changed) { wl_list_remove(&layer->link); @@ -312,6 +348,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { bool extent_changed = memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0; if (extent_changed || layer_changed) { + old_extent.x += output->lx; + old_extent.y += output->ly; output_damage_box(output, &old_extent); output_damage_surface(output, layer->geo.x, layer->geo.y, layer_surface->surface, true); @@ -347,7 +385,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_container_of(listener, sway_layer, destroy); sway_log(SWAY_DEBUG, "Layer surface destroyed (%s)", sway_layer->layer_surface->namespace); - if (sway_layer->layer_surface->mapped) { + if (sway_layer->layer_surface->surface->mapped) { unmap(sway_layer); } @@ -452,9 +490,9 @@ static struct sway_layer_subsurface *create_subsurface( wl_list_insert(&layer_surface->subsurfaces, &subsurface->link); subsurface->map.notify = subsurface_handle_map; - wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); + wl_signal_add(&wlr_subsurface->surface->events.map, &subsurface->map); subsurface->unmap.notify = subsurface_handle_unmap; - wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap); + wl_signal_add(&wlr_subsurface->surface->events.unmap, &subsurface->unmap); subsurface->destroy.notify = subsurface_handle_destroy; wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); subsurface->commit.notify = subsurface_handle_commit; @@ -569,9 +607,9 @@ static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, popup->parent_layer = parent; popup->map.notify = popup_handle_map; - wl_signal_add(&wlr_popup->base->events.map, &popup->map); + wl_signal_add(&wlr_popup->base->surface->events.map, &popup->map); popup->unmap.notify = popup_handle_unmap; - wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); + wl_signal_add(&wlr_popup->base->surface->events.unmap, &popup->unmap); popup->destroy.notify = popup_handle_destroy; wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); popup->commit.notify = popup_handle_commit; @@ -659,9 +697,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { sway_layer->destroy.notify = handle_destroy; wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy); sway_layer->map.notify = handle_map; - wl_signal_add(&layer_surface->events.map, &sway_layer->map); + wl_signal_add(&layer_surface->surface->events.map, &sway_layer->map); sway_layer->unmap.notify = handle_unmap; - wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap); + wl_signal_add(&layer_surface->surface->events.unmap, &sway_layer->unmap); sway_layer->new_popup.notify = handle_new_popup; wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup); sway_layer->new_subsurface.notify = handle_new_subsurface; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 2255b551..476bfd25 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -6,8 +6,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -264,7 +266,7 @@ void output_drag_icons_for_each_surface(struct sway_output *output, double ox = drag_icon->x - output->lx; double oy = drag_icon->y - output->ly; - if (drag_icon->wlr_drag_icon->mapped) { + if (drag_icon->wlr_drag_icon->surface->mapped) { output_surface_for_each_surface(output, drag_icon->wlr_drag_icon->surface, ox, oy, iterator, user_data); @@ -294,7 +296,7 @@ static void output_for_each_surface(struct sway_output *output, if (lock_surface->output != output->wlr_output) { continue; } - if (!lock_surface->mapped) { + if (!lock_surface->surface->mapped) { continue; } @@ -456,7 +458,7 @@ static void count_surface_iterator(struct sway_output *output, } static bool scan_out_fullscreen_view(struct sway_output *output, - struct sway_view *view) { + struct wlr_output_state *pending, struct sway_view *view) { struct wlr_output *wlr_output = output->wlr_output; struct sway_workspace *workspace = output->current.active_workspace; if (!sway_assert(workspace, "Expected an active workspace")) { @@ -522,15 +524,16 @@ static bool scan_out_fullscreen_view(struct sway_output *output, return false; } - wlr_output_attach_buffer(wlr_output, &surface->buffer->base); - if (!wlr_output_test(wlr_output)) { + wlr_output_state_set_buffer(pending, &surface->buffer->base); + + if (!wlr_output_test_state(wlr_output, pending)) { return false; } wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_output); - return wlr_output_commit(wlr_output); + return wlr_output_commit_state(wlr_output, pending); } static void get_frame_damage(struct sway_output *output, @@ -563,6 +566,7 @@ static int output_repaint_timer_handler(void *data) { wlr_output->frame_pending = false; if (!wlr_output->needs_frame && + !output->gamma_lut_changed && !pixman_region32_not_empty(&output->damage_ring.current)) { return 0; } @@ -577,16 +581,31 @@ static int output_repaint_timer_handler(void *data) { fullscreen_con = workspace->current.fullscreen; } - pixman_region32_t frame_damage; - get_frame_damage(output, &frame_damage); - wlr_output_set_damage(wlr_output, &frame_damage); - pixman_region32_fini(&frame_damage); + struct wlr_output_state pending = {0}; + + if (output->gamma_lut_changed) { + output->gamma_lut_changed = false; + struct wlr_gamma_control_v1 *gamma_control = + wlr_gamma_control_manager_v1_get_control( + server.gamma_control_manager_v1, wlr_output); + if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) { + goto out; + } + if (!wlr_output_test_state(wlr_output, &pending)) { + wlr_output_state_finish(&pending); + pending = (struct wlr_output_state){0}; + wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); + } + } + + pending.committed |= WLR_OUTPUT_STATE_DAMAGE; + get_frame_damage(output, &pending.damage); if (fullscreen_con && fullscreen_con->view && !debug.noscanout) { // Try to scan-out the fullscreen view static bool last_scanned_out = false; bool scanned_out = - scan_out_fullscreen_view(output, fullscreen_con->view); + scan_out_fullscreen_view(output, &pending, fullscreen_con->view); if (scanned_out && !last_scanned_out) { sway_log(SWAY_DEBUG, "Scanning out fullscreen view on %s", @@ -600,33 +619,68 @@ static int output_repaint_timer_handler(void *data) { last_scanned_out = scanned_out; if (scanned_out) { - return 0; + goto out; } } + if (!wlr_output_configure_primary_swapchain(wlr_output, &pending, &wlr_output->swapchain)) { + goto out; + } + int buffer_age; - if (!wlr_output_attach_render(output->wlr_output, &buffer_age)) { - return 0; + struct wlr_buffer *buffer = wlr_swapchain_acquire(wlr_output->swapchain, &buffer_age); + if (buffer == NULL) { + goto out; + } + + struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass( + wlr_output->renderer, buffer, NULL); + if (render_pass == NULL) { + wlr_buffer_unlock(buffer); + goto out; } pixman_region32_t damage; pixman_region32_init(&damage); wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage); + if (debug.damage == DAMAGE_RERENDER) { + int width, height; + wlr_output_transformed_resolution(wlr_output, &width, &height); + pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); + } + + struct render_context ctx = { + .output_damage = &damage, + .renderer = wlr_output->renderer, + .output = output, + .pass = render_pass, + }; + struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - output_render(output, &damage); + output_render(&ctx); pixman_region32_fini(&damage); - if (!wlr_output_commit(wlr_output)) { - return 0; + if (!wlr_render_pass_submit(render_pass)) { + wlr_buffer_unlock(buffer); + goto out; + } + + wlr_output_state_set_buffer(&pending, buffer); + wlr_buffer_unlock(buffer); + + if (!wlr_output_commit_state(wlr_output, &pending)) { + goto out; } wlr_damage_ring_rotate(&output->damage_ring); output->last_frame = now; +out: + wlr_output_state_finish(&pending); return 0; } @@ -1042,6 +1096,21 @@ void handle_output_layout_change(struct wl_listener *listener, update_output_manager_config(server); } +void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { + struct sway_server *server = + wl_container_of(listener, server, gamma_control_set_gamma); + const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; + + struct sway_output *output = event->output->data; + + if(!output) { + return; + } + + output->gamma_lut_changed = true; + wlr_output_schedule_frame(output->wlr_output); +} + 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 diff --git a/sway/desktop/render.c b/sway/desktop/render.c index a4d633e0..f08e2c6c 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -27,16 +27,30 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" -#if WLR_HAS_GLES2_RENDERER -#include -#endif - struct render_data { + struct render_context *ctx; const pixman_region32_t *damage; float alpha; struct wlr_box *clip_box; }; +static void transform_output_damage(pixman_region32_t *damage, struct wlr_output *output) { + int ow, oh; + wlr_output_transformed_resolution(output, &ow, &oh); + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); + wlr_region_transform(damage, damage, transform, ow, oh); +} + +static void transform_output_box(struct wlr_box *box, struct wlr_output *output) { + int ow, oh; + wlr_output_transformed_resolution(output, &ow, &oh); + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); + wlr_box_transform(box, box, transform, ow, oh); +} + + /** * Apply scale to a width or height. * @@ -53,82 +67,57 @@ static int scale_length(int length, int offset, float scale) { return roundf((offset + length) * scale) - roundf(offset * scale); } -static void scissor_output(struct wlr_output *wlr_output, - pixman_box32_t *rect) { - struct wlr_renderer *renderer = wlr_output->renderer; - assert(renderer); - - struct wlr_box box = { - .x = rect->x1, - .y = rect->y1, - .width = rect->x2 - rect->x1, - .height = rect->y2 - rect->y1, - }; - - int ow, oh; - wlr_output_transformed_resolution(wlr_output, &ow, &oh); - - enum wl_output_transform transform = - wlr_output_transform_invert(wlr_output->transform); - wlr_box_transform(&box, &box, transform, ow, oh); - - wlr_renderer_scissor(renderer, &box); -} - -static void set_scale_filter(struct wlr_output *wlr_output, - struct wlr_texture *texture, enum scale_filter_mode scale_filter) { -#if WLR_HAS_GLES2_RENDERER - if (!wlr_texture_is_gles2(texture)) { - return; - } - - struct wlr_gles2_texture_attribs attribs; - wlr_gles2_texture_get_attribs(texture, &attribs); - - glBindTexture(attribs.target, attribs.tex); - - switch (scale_filter) { +static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output) { + switch (output->scale_filter) { case SCALE_FILTER_LINEAR: - glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - break; + return WLR_SCALE_FILTER_BILINEAR; case SCALE_FILTER_NEAREST: - glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - break; - case SCALE_FILTER_DEFAULT: - case SCALE_FILTER_SMART: - assert(false); // unreachable + return WLR_SCALE_FILTER_NEAREST; + default: + abort(); // unreachable } -#endif } -static void render_texture(struct wlr_output *wlr_output, - const pixman_region32_t *output_damage, struct wlr_texture *texture, - const struct wlr_fbox *src_box, const struct wlr_box *dst_box, - const float matrix[static 9], float alpha) { - struct wlr_renderer *renderer = wlr_output->renderer; - struct sway_output *output = wlr_output->data; +static void render_texture(struct render_context *ctx, struct wlr_texture *texture, + const struct wlr_fbox *_src_box, const struct wlr_box *dst_box, + const struct wlr_box *clip_box, enum wl_output_transform transform, float alpha) { + struct sway_output *output = ctx->output; + + struct wlr_box proj_box = *dst_box; + + struct wlr_fbox src_box = {0}; + if (_src_box) { + src_box = *_src_box; + } pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, - dst_box->width, dst_box->height); - pixman_region32_intersect(&damage, &damage, output_damage); + pixman_region32_init_rect(&damage, proj_box.x, proj_box.y, + proj_box.width, proj_box.height); + pixman_region32_intersect(&damage, &damage, ctx->output_damage); + + if (clip_box) { + pixman_region32_intersect_rect(&damage, &damage, + clip_box->x, clip_box->y, clip_box->width, clip_box->height); + } + bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { goto damage_finish; } - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - set_scale_filter(wlr_output, texture, output->scale_filter); - if (src_box != NULL) { - wlr_render_subtexture_with_matrix(renderer, texture, src_box, matrix, alpha); - } else { - wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); - } - } + transform_output_box(&proj_box, output->wlr_output); + transform_output_damage(&damage, output->wlr_output); + transform = wlr_output_transform_compose(transform, output->wlr_output->transform); + + wlr_render_pass_add_texture(ctx->pass, &(struct wlr_render_texture_options) { + .texture = texture, + .src_box = src_box, + .dst_box = proj_box, + .transform = transform, + .alpha = &alpha, + .clip = &damage, + .filter_mode = get_scale_filter(output), + }); damage_finish: pixman_region32_fini(&damage); @@ -139,7 +128,6 @@ static void render_surface_iterator(struct sway_output *output, struct wlr_box *_box, void *_data) { struct render_data *data = _data; struct wlr_output *wlr_output = output->wlr_output; - const pixman_region32_t *output_damage = data->damage; float alpha = data->alpha; struct wlr_texture *texture = wlr_surface_get_texture(surface); @@ -150,102 +138,92 @@ static void render_surface_iterator(struct sway_output *output, struct wlr_fbox src_box; wlr_surface_get_buffer_source_box(surface, &src_box); - struct wlr_box proj_box = *_box; - scale_box(&proj_box, wlr_output->scale); - - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &proj_box, transform, 0.0, - wlr_output->transform_matrix); - struct wlr_box dst_box = *_box; - struct wlr_box *clip_box = data->clip_box; - if (clip_box != NULL) { - dst_box.width = fmin(dst_box.width, clip_box->width); - dst_box.height = fmin(dst_box.height, clip_box->height); + struct wlr_box clip_box = *_box; + if (data->clip_box != NULL) { + clip_box.width = fmin(dst_box.width, data->clip_box->width); + clip_box.height = fmin(dst_box.height, data->clip_box->height); } scale_box(&dst_box, wlr_output->scale); + scale_box(&clip_box, wlr_output->scale); - render_texture(wlr_output, output_damage, texture, - &src_box, &dst_box, matrix, alpha); + render_texture(data->ctx, texture, + &src_box, &dst_box, &clip_box, surface->current.transform, alpha); wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_output); } -static void render_layer_toplevel(struct sway_output *output, - const pixman_region32_t *damage, struct wl_list *layer_surfaces) { +static void render_layer_toplevel(struct render_context *ctx, struct wl_list *layer_surfaces) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; - output_layer_for_each_toplevel_surface(output, layer_surfaces, + output_layer_for_each_toplevel_surface(ctx->output, layer_surfaces, render_surface_iterator, &data); } -static void render_layer_popups(struct sway_output *output, - const pixman_region32_t *damage, struct wl_list *layer_surfaces) { +static void render_layer_popups(struct render_context *ctx, struct wl_list *layer_surfaces) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; - output_layer_for_each_popup_surface(output, layer_surfaces, + output_layer_for_each_popup_surface(ctx->output, layer_surfaces, render_surface_iterator, &data); } #if HAVE_XWAYLAND -static void render_unmanaged(struct sway_output *output, - const pixman_region32_t *damage, struct wl_list *unmanaged) { +static void render_unmanaged(struct render_context *ctx, struct wl_list *unmanaged) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; - output_unmanaged_for_each_surface(output, unmanaged, + output_unmanaged_for_each_surface(ctx->output, unmanaged, render_surface_iterator, &data); } #endif -static void render_drag_icons(struct sway_output *output, - const pixman_region32_t *damage, struct wl_list *drag_icons) { +static void render_drag_icons(struct render_context *ctx, struct wl_list *drag_icons) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; - output_drag_icons_for_each_surface(output, drag_icons, + output_drag_icons_for_each_surface(ctx->output, drag_icons, render_surface_iterator, &data); } // _box.x and .y are expected to be layout-local // _box.width and .height are expected to be output-buffer-local -void render_rect(struct sway_output *output, - const pixman_region32_t *output_damage, const struct wlr_box *_box, +void render_rect(struct render_context *ctx, const struct wlr_box *_box, float color[static 4]) { - struct wlr_output *wlr_output = output->wlr_output; - struct wlr_renderer *renderer = wlr_output->renderer; + struct wlr_output *wlr_output = ctx->output->wlr_output; - struct wlr_box box; - memcpy(&box, _box, sizeof(struct wlr_box)); - box.x -= output->lx * wlr_output->scale; - box.y -= output->ly * wlr_output->scale; + struct wlr_box box = *_box; + box.x -= ctx->output->lx * wlr_output->scale; + box.y -= ctx->output->ly * wlr_output->scale; pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, box.x, box.y, + pixman_region32_init_rect(&damage, box.x, box.y, box.width, box.height); - pixman_region32_intersect(&damage, &damage, output_damage); + pixman_region32_intersect(&damage, &damage, ctx->output_damage); bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { goto damage_finish; } - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_render_rect(renderer, &box, color, - wlr_output->transform_matrix); - } + transform_output_damage(&damage, wlr_output); + transform_output_box(&box, wlr_output); + + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = box, + .color = { + .r = color[0], + .g = color[1], + .b = color[2], + .a = color[3], + }, + .clip = &damage, + }); damage_finish: pixman_region32_fini(&damage); @@ -258,11 +236,11 @@ void premultiply_alpha(float color[4], float opacity) { color[2] *= color[3]; } -static void render_view_toplevels(struct sway_view *view, - struct sway_output *output, const pixman_region32_t *damage, float alpha) { +static void render_view_toplevels(struct render_context *ctx, + struct sway_view *view, float alpha) { struct render_data data = { - .damage = damage, .alpha = alpha, + .ctx = ctx, }; struct wlr_box clip_box; if (!container_is_current_floating(view->container)) { @@ -274,25 +252,26 @@ static void render_view_toplevels(struct sway_view *view, } // Render all toplevels without descending into popups double ox = view->container->surface_x - - output->lx - view->geometry.x; + ctx->output->lx - view->geometry.x; double oy = view->container->surface_y - - output->ly - view->geometry.y; - output_surface_for_each_surface(output, view->surface, ox, oy, + ctx->output->ly - view->geometry.y; + output_surface_for_each_surface(ctx->output, view->surface, ox, oy, render_surface_iterator, &data); } -static void render_view_popups(struct sway_view *view, - struct sway_output *output, const pixman_region32_t *damage, float alpha) { +static void render_view_popups(struct render_context *ctx, struct sway_view *view, + float alpha) { struct render_data data = { - .damage = damage, .alpha = alpha, + .ctx = ctx, }; - output_view_for_each_popup_surface(output, view, + output_view_for_each_popup_surface(ctx->output, view, render_surface_iterator, &data); } -static void render_saved_view(struct sway_view *view, - struct sway_output *output, const pixman_region32_t *damage, float alpha) { +static void render_saved_view(struct render_context *ctx, struct sway_view *view, + float alpha) { + struct sway_output *output = ctx->output; struct wlr_output *wlr_output = output->wlr_output; if (wl_list_empty(&view->saved_buffers)) { @@ -326,25 +305,20 @@ static void render_saved_view(struct sway_view *view, } struct wlr_box dst_box = proj_box; - scale_box(&proj_box, wlr_output->scale); - - float matrix[9]; - enum wl_output_transform transform = wlr_output_transform_invert(saved_buf->transform); - wlr_matrix_project_box(matrix, &proj_box, transform, 0, - wlr_output->transform_matrix); - + struct wlr_box clip_box = proj_box; if (!floating) { - dst_box.width = fmin(dst_box.width, + clip_box.width = fmin(dst_box.width, view->container->current.content_width - (saved_buf->x - view->container->current.content_x) + view->saved_geometry.x); - dst_box.height = fmin(dst_box.height, + clip_box.height = fmin(dst_box.height, view->container->current.content_height - (saved_buf->y - view->container->current.content_y) + view->saved_geometry.y); } scale_box(&dst_box, wlr_output->scale); + scale_box(&clip_box, wlr_output->scale); - render_texture(wlr_output, damage, saved_buf->buffer->texture, - &saved_buf->source_box, &dst_box, matrix, alpha); + render_texture(ctx, saved_buf->buffer->texture, + &saved_buf->source_box, &dst_box, &clip_box, saved_buf->transform, alpha); } // FIXME: we should set the surface that this saved buffer originates from @@ -355,13 +329,13 @@ static void render_saved_view(struct sway_view *view, /** * Render a view's surface and left/bottom/right borders. */ -static void render_view(struct sway_output *output, const pixman_region32_t *damage, +static void render_view(struct render_context *ctx, struct sway_container *con, struct border_colors *colors) { struct sway_view *view = con->view; if (!wl_list_empty(&view->saved_buffers)) { - render_saved_view(view, output, damage, view->container->alpha); + render_saved_view(ctx, view, view->container->alpha); } else if (view->surface) { - render_view_toplevels(view, output, damage, view->container->alpha); + render_view_toplevels(ctx, view, view->container->alpha); } if (con->current.border == B_NONE || con->current.border == B_CSD) { @@ -369,7 +343,7 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam } struct wlr_box box; - float output_scale = output->wlr_output->scale; + float output_scale = ctx->output->wlr_output->scale; float color[4]; struct sway_container_state *state = &con->current; @@ -381,7 +355,7 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam box.width = state->border_thickness; box.height = state->content_height; scale_box(&box, output_scale); - render_rect(output, damage, &box, color); + render_rect(ctx, &box, color); } list_t *siblings = container_get_current_siblings(con); @@ -400,7 +374,7 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam box.width = state->border_thickness; box.height = state->content_height; scale_box(&box, output_scale); - render_rect(output, damage, &box, color); + render_rect(ctx, &box, color); } if (state->border_bottom) { @@ -415,7 +389,7 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam box.width = state->width; box.height = state->border_thickness; scale_box(&box, output_scale); - render_rect(output, damage, &box, color); + render_rect(ctx, &box, color); } } @@ -428,13 +402,13 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam * The height is: 1px border, 3px padding, font height, 3px padding, 1px border * The left side is: 1px border, 2px padding, title */ -static void render_titlebar(struct sway_output *output, - const pixman_region32_t *output_damage, struct sway_container *con, +static void render_titlebar(struct render_context *ctx, struct sway_container *con, int x, int y, int width, struct border_colors *colors, struct wlr_texture *title_texture, struct wlr_texture *marks_texture) { struct wlr_box box; float color[4]; + struct sway_output *output = ctx->output; float output_scale = output->wlr_output->scale; double output_x = output->lx; double output_y = output->ly; @@ -451,7 +425,7 @@ static void render_titlebar(struct sway_output *output, box.width = width; box.height = titlebar_border_thickness; scale_box(&box, output_scale); - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Single pixel bar below title box.x = x; @@ -459,7 +433,7 @@ static void render_titlebar(struct sway_output *output, box.width = width; box.height = titlebar_border_thickness; scale_box(&box, output_scale); - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Single pixel left edge box.x = x; @@ -467,7 +441,7 @@ static void render_titlebar(struct sway_output *output, box.width = titlebar_border_thickness; box.height = container_titlebar_height() - titlebar_border_thickness * 2; scale_box(&box, output_scale); - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Single pixel right edge box.x = x + width - titlebar_border_thickness; @@ -475,7 +449,7 @@ static void render_titlebar(struct sway_output *output, box.width = titlebar_border_thickness; box.height = container_titlebar_height() - titlebar_border_thickness * 2; scale_box(&box, output_scale); - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); int inner_x = x - output_x + titlebar_h_padding; int bg_y = y + titlebar_border_thickness; @@ -516,30 +490,26 @@ static void render_titlebar(struct sway_output *output, texture_box.y = round((bg_y - output_y) * output_scale) + ob_padding_above; - float matrix[9]; - wlr_matrix_project_box(matrix, &texture_box, - WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); - - if (ob_inner_width < texture_box.width) { - texture_box.width = ob_inner_width; + struct wlr_box clip_box = texture_box; + if (ob_inner_width < clip_box.width) { + clip_box.width = ob_inner_width; } - render_texture(output->wlr_output, output_damage, marks_texture, - NULL, &texture_box, matrix, con->alpha); + render_texture(ctx, marks_texture, + NULL, &texture_box, &clip_box, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); // Padding above memcpy(&color, colors->background, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = texture_box.x + round(output_x * output_scale); + box.x = clip_box.x + round(output_x * output_scale); box.y = roundf((y + titlebar_border_thickness) * output_scale); - box.width = texture_box.width; + box.width = clip_box.width; box.height = ob_padding_above; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Padding below - box.y += ob_padding_above + texture_box.height; + box.y += ob_padding_above + clip_box.height; box.height = ob_padding_below; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } // Title text @@ -591,31 +561,27 @@ static void render_titlebar(struct sway_output *output, texture_box.y = round((bg_y - output_y) * output_scale) + ob_padding_above; - float matrix[9]; - wlr_matrix_project_box(matrix, &texture_box, - WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); - - if (ob_inner_width - ob_marks_width < texture_box.width) { - texture_box.width = ob_inner_width - ob_marks_width; + struct wlr_box clip_box = texture_box; + if (ob_inner_width - ob_marks_width < clip_box.width) { + clip_box.width = ob_inner_width - ob_marks_width; } - render_texture(output->wlr_output, output_damage, title_texture, - NULL, &texture_box, matrix, con->alpha); + render_texture(ctx, title_texture, + NULL, &texture_box, &clip_box, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); // Padding above memcpy(&color, colors->background, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = texture_box.x + round(output_x * output_scale); + box.x = clip_box.x + round(output_x * output_scale); box.y = roundf((y + titlebar_border_thickness) * output_scale); - box.width = texture_box.width; + box.width = clip_box.width; box.height = ob_padding_above; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Padding below - box.y += ob_padding_above + texture_box.height; + box.y += ob_padding_above + clip_box.height; box.height = ob_padding_below; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } // Determine the left + right extends of the textures (output-buffer local) @@ -649,7 +615,7 @@ static void render_titlebar(struct sway_output *output, box.x = ob_left_x + ob_left_width + round(output_x * output_scale); box.y = roundf(bg_y * output_scale); box.height = ob_bg_height; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } // Padding on left side @@ -663,7 +629,7 @@ static void render_titlebar(struct sway_output *output, if (box.x + box.width < left_x) { box.width += left_x - box.x - box.width; } - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Padding on right side box.x = x + width - titlebar_h_padding; @@ -677,14 +643,13 @@ static void render_titlebar(struct sway_output *output, box.width += box.x - right_rx; box.x = right_rx; } - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } /** * Render the top border line for a view using "border pixel". */ -static void render_top_border(struct sway_output *output, - const pixman_region32_t *output_damage, struct sway_container *con, +static void render_top_border(struct render_context *ctx, struct sway_container *con, struct border_colors *colors) { struct sway_container_state *state = &con->current; if (!state->border_top) { @@ -692,7 +657,7 @@ static void render_top_border(struct sway_output *output, } struct wlr_box box; float color[4]; - float output_scale = output->wlr_output->scale; + float output_scale = ctx->output->wlr_output->scale; // Child border - top edge memcpy(&color, colors->child_border, sizeof(float) * 4); @@ -702,7 +667,7 @@ static void render_top_border(struct sway_output *output, box.width = state->width; box.height = state->border_thickness; scale_box(&box, output_scale); - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } struct parent_data { @@ -713,8 +678,8 @@ struct parent_data { struct sway_container *active_child; }; -static void render_container(struct sway_output *output, - const pixman_region32_t *damage, struct sway_container *con, bool parent_focused); +static void render_container(struct render_context *ctx, + struct sway_container *con, bool parent_focused); /** * Render a container's children using a L_HORIZ or L_VERT layout. @@ -722,8 +687,7 @@ static void render_container(struct sway_output *output, * Wrap child views in borders and leave child containers borderless because * they'll apply their own borders to their children. */ -static void render_containers_linear(struct sway_output *output, - const pixman_region32_t *damage, struct parent_data *parent) { +static void render_containers_linear(struct render_context *ctx, struct parent_data *parent) { for (int i = 0; i < parent->children->length; ++i) { struct sway_container *child = parent->children->items[i]; @@ -753,15 +717,15 @@ static void render_containers_linear(struct sway_output *output, } if (state->border == B_NORMAL) { - render_titlebar(output, damage, child, floor(state->x), + render_titlebar(ctx, child, floor(state->x), floor(state->y), state->width, colors, title_texture, marks_texture); } else if (state->border == B_PIXEL) { - render_top_border(output, damage, child, colors); + render_top_border(ctx, child, colors); } - render_view(output, damage, child, colors); + render_view(ctx, child, colors); } else { - render_container(output, damage, child, + render_container(ctx, child, parent->focused || child->current.focused); } } @@ -778,8 +742,7 @@ static bool container_has_focused_child(struct sway_container *con) { /** * Render a container's children using the L_TABBED layout. */ -static void render_containers_tabbed(struct sway_output *output, - const pixman_region32_t *damage, struct parent_data *parent) { +static void render_containers_tabbed(struct render_context *ctx, struct parent_data *parent) { if (!parent->children->length) { return; } @@ -827,7 +790,7 @@ static void render_containers_tabbed(struct sway_output *output, tab_width = parent->box.width - tab_width * i; } - render_titlebar(output, damage, child, x, parent->box.y, tab_width, + render_titlebar(ctx, child, x, parent->box.y, tab_width, colors, title_texture, marks_texture); if (child == current) { @@ -837,9 +800,9 @@ static void render_containers_tabbed(struct sway_output *output, // Render surface and left/right/bottom borders if (current->view) { - render_view(output, damage, current, current_colors); + render_view(ctx, current, current_colors); } else { - render_container(output, damage, current, + render_container(ctx, current, parent->focused || current->current.focused); } } @@ -847,8 +810,7 @@ static void render_containers_tabbed(struct sway_output *output, /** * Render a container's children using the L_STACKED layout. */ -static void render_containers_stacked(struct sway_output *output, - const pixman_region32_t *damage, struct parent_data *parent) { +static void render_containers_stacked(struct render_context *ctx, struct parent_data *parent) { if (!parent->children->length) { return; } @@ -890,7 +852,7 @@ static void render_containers_stacked(struct sway_output *output, } int y = parent->box.y + titlebar_height * i; - render_titlebar(output, damage, child, parent->box.x, y, + render_titlebar(ctx, child, parent->box.x, y, parent->box.width, colors, title_texture, marks_texture); if (child == current) { @@ -900,19 +862,18 @@ static void render_containers_stacked(struct sway_output *output, // Render surface and left/right/bottom borders if (current->view) { - render_view(output, damage, current, current_colors); + render_view(ctx, current, current_colors); } else { - render_container(output, damage, current, + render_container(ctx, current, parent->focused || current->current.focused); } } -static void render_containers(struct sway_output *output, - const pixman_region32_t *damage, struct parent_data *parent) { +static void render_containers(struct render_context *ctx, struct parent_data *parent) { if (config->hide_lone_tab && parent->children->length == 1) { struct sway_container *child = parent->children->items[0]; if (child->view) { - render_containers_linear(output,damage, parent); + render_containers_linear(ctx, parent); return; } } @@ -921,19 +882,19 @@ static void render_containers(struct sway_output *output, case L_NONE: case L_HORIZ: case L_VERT: - render_containers_linear(output, damage, parent); + render_containers_linear(ctx, parent); break; case L_STACKED: - render_containers_stacked(output, damage, parent); + render_containers_stacked(ctx, parent); break; case L_TABBED: - render_containers_tabbed(output, damage, parent); + render_containers_tabbed(ctx, parent); break; } } -static void render_container(struct sway_output *output, - const pixman_region32_t *damage, struct sway_container *con, bool focused) { +static void render_container(struct render_context *ctx, + struct sway_container *con, bool focused) { struct parent_data data = { .layout = con->current.layout, .box = { @@ -946,11 +907,11 @@ static void render_container(struct sway_output *output, .focused = focused, .active_child = con->current.focused_inactive_child, }; - render_containers(output, damage, &data); + render_containers(ctx, &data); } -static void render_workspace(struct sway_output *output, - const pixman_region32_t *damage, struct sway_workspace *ws, bool focused) { +static void render_workspace(struct render_context *ctx, + struct sway_workspace *ws, bool focused) { struct parent_data data = { .layout = ws->current.layout, .box = { @@ -963,11 +924,11 @@ static void render_workspace(struct sway_output *output, .focused = focused, .active_child = ws->current.focused_inactive_child, }; - render_containers(output, damage, &data); + render_containers(ctx, &data); } -static void render_floating_container(struct sway_output *soutput, - const pixman_region32_t *damage, struct sway_container *con) { +static void render_floating_container(struct render_context *ctx, + struct sway_container *con) { if (con->view) { struct sway_view *view = con->view; struct border_colors *colors; @@ -989,20 +950,19 @@ static void render_floating_container(struct sway_output *soutput, } if (con->current.border == B_NORMAL) { - render_titlebar(soutput, damage, con, floor(con->current.x), + render_titlebar(ctx, con, floor(con->current.x), floor(con->current.y), con->current.width, colors, title_texture, marks_texture); } else if (con->current.border == B_PIXEL) { - render_top_border(soutput, damage, con, colors); + render_top_border(ctx, con, colors); } - render_view(soutput, damage, con, colors); + render_view(ctx, con, colors); } else { - render_container(soutput, damage, con, con->current.focused); + render_container(ctx, con, con->current.focused); } } -static void render_floating(struct sway_output *soutput, - const pixman_region32_t *damage) { +static void render_floating(struct render_context *ctx) { for (int i = 0; i < root->outputs->length; ++i) { struct sway_output *output = root->outputs->items[i]; for (int j = 0; j < output->current.workspaces->length; ++j) { @@ -1015,23 +975,23 @@ static void render_floating(struct sway_output *soutput, if (floater->current.fullscreen_mode != FULLSCREEN_NONE) { continue; } - render_floating_container(soutput, damage, floater); + render_floating_container(ctx, floater); } } } } -static void render_seatops(struct sway_output *output, - const pixman_region32_t *damage) { +static void render_seatops(struct render_context *ctx) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { - seatop_render(seat, output, damage); + seatop_render(seat, ctx); } } -void output_render(struct sway_output *output, pixman_region32_t *damage) { - struct wlr_output *wlr_output = output->wlr_output; - struct wlr_renderer *renderer = output->server->renderer; +void output_render(struct render_context *ctx) { + struct wlr_output *wlr_output = ctx->output->wlr_output; + struct sway_output *output = ctx->output; + const pixman_region32_t *damage = ctx->output_damage; struct sway_workspace *workspace = output->current.active_workspace; if (workspace == NULL) { @@ -1043,42 +1003,42 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { fullscreen_con = workspace->current.fullscreen; } - if (!wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height)) { + if (!pixman_region32_not_empty(damage)) { + // Output isn't damaged but needs buffer swap return; } - if (debug.damage == DAMAGE_RERENDER) { - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(damage, damage, 0, 0, width, height); - } - - if (!pixman_region32_not_empty(damage)) { - // Output isn't damaged but needs buffer swap - goto renderer_end; - } - if (debug.damage == DAMAGE_HIGHLIGHT) { - wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = { .width = wlr_output->width, .height = wlr_output->height }, + .color = { .r = 1, .g = 1, .b = 0, .a = 1 }, + }); } + pixman_region32_t transformed_damage; + pixman_region32_init(&transformed_damage); + pixman_region32_copy(&transformed_damage, damage); + transform_output_damage(&transformed_damage, wlr_output); + if (server.session_lock.locked) { - float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + struct wlr_render_color clear_color = { + .a = 1.0f + }; if (server.session_lock.lock == NULL) { // abandoned lock -> red BG - clear_color[0] = 1.f; - } - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); + clear_color.r = 1.f; } + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = { .width = wlr_output->width, .height = wlr_output->height }, + .color = clear_color, + .clip = &transformed_damage, + }); + if (server.session_lock.lock != NULL) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; struct wlr_session_lock_surface_v1 *lock_surface; @@ -1086,7 +1046,7 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { if (lock_surface->output != wlr_output) { continue; } - if (!lock_surface->mapped) { + if (!lock_surface->surface->mapped) { continue; } @@ -1102,24 +1062,20 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { } if (fullscreen_con) { - float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = { .width = wlr_output->width, .height = wlr_output->height }, + .color = { .r = 0, .g = 0, .b = 0, .a = 1 }, + .clip = &transformed_damage, + }); if (fullscreen_con->view) { if (!wl_list_empty(&fullscreen_con->view->saved_buffers)) { - render_saved_view(fullscreen_con->view, output, damage, 1.0f); + render_saved_view(ctx, fullscreen_con->view, 1.0f); } else if (fullscreen_con->view->surface) { - render_view_toplevels(fullscreen_con->view, - output, damage, 1.0f); + render_view_toplevels(ctx, fullscreen_con->view, 1.0f); } } else { - render_container(output, damage, fullscreen_con, + render_container(ctx, fullscreen_con, fullscreen_con->current.focused); } @@ -1127,60 +1083,56 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { struct sway_container *floater = workspace->current.floating->items[i]; if (container_is_transient_for(floater, fullscreen_con)) { - render_floating_container(output, damage, floater); + render_floating_container(ctx, floater); } } #if HAVE_XWAYLAND - render_unmanaged(output, damage, &root->xwayland_unmanaged); + render_unmanaged(ctx, &root->xwayland_unmanaged); #endif } else { - float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = { .width = wlr_output->width, .height = wlr_output->height }, + .color = { .r = 0.25f, .g = 0.25f, .b = 0.25f, .a = 1 }, + .clip = &transformed_damage, + }); - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } - - render_layer_toplevel(output, damage, + render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer_toplevel(output, damage, + render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - render_workspace(output, damage, workspace, workspace->current.focused); - render_floating(output, damage); + render_workspace(ctx, workspace, workspace->current.focused); + render_floating(ctx); #if HAVE_XWAYLAND - render_unmanaged(output, damage, &root->xwayland_unmanaged); + render_unmanaged(ctx, &root->xwayland_unmanaged); #endif - render_layer_toplevel(output, damage, + render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - render_layer_popups(output, damage, + render_layer_popups(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer_popups(output, damage, + render_layer_popups(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - render_layer_popups(output, damage, + render_layer_popups(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); } - render_seatops(output, damage); + render_seatops(ctx); struct sway_seat *seat = input_manager_current_seat(); struct sway_container *focus = seat_get_focused_container(seat); if (focus && focus->view) { - render_view_popups(focus->view, output, damage, focus->alpha); + render_view_popups(ctx, focus->view, focus->alpha); } render_overlay: - render_layer_toplevel(output, damage, + render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_layer_popups(output, damage, + render_layer_popups(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_drag_icons(output, damage, &root->drag_icons); + render_drag_icons(ctx, &root->drag_icons); renderer_end: - wlr_renderer_scissor(renderer, NULL); - wlr_output_render_software_cursors(wlr_output, damage); - wlr_renderer_end(renderer); + pixman_region32_fini(&transformed_damage); + wlr_output_add_software_cursors_to_render_pass(wlr_output, ctx->pass, damage); } diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index f5a3a053..6947e138 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -344,7 +344,7 @@ static void transaction_progress(void) { server.queued_transaction = NULL; if (!server.pending_transaction) { - sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); + sway_idle_inhibit_v1_check_active(); return; } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 9b6456da..377a0f1c 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -104,8 +104,8 @@ static struct sway_xdg_popup *popup_create( wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; - wl_signal_add(&xdg_surface->events.map, &popup->child.surface_map); - wl_signal_add(&xdg_surface->events.unmap, &popup->child.surface_unmap); + wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map); + wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap); popup_unconstrain(popup); @@ -344,7 +344,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel; struct sway_view *view = &xdg_shell_view->view; - if (!toplevel->base->mapped) { + if (!toplevel->base->surface->mapped) { return; } @@ -529,10 +529,10 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel; xdg_shell_view->map.notify = handle_map; - wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); + wl_signal_add(&xdg_surface->surface->events.map, &xdg_shell_view->map); xdg_shell_view->unmap.notify = handle_unmap; - wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap); + wl_signal_add(&xdg_surface->surface->events.unmap, &xdg_shell_view->unmap); xdg_shell_view->destroy.notify = handle_destroy; wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 9c29f66b..a52cf4ad 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -125,8 +125,10 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { } static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xsurface = data; - if (!xsurface->mapped) { + struct sway_xwayland_unmanaged *surface = + wl_container_of(listener, surface, request_activate); + struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } struct sway_seat *seat = input_manager_current_seat(); @@ -138,12 +140,29 @@ static void unmanaged_handle_request_activate(struct wl_listener *listener, void seat_set_focus_surface(seat, xsurface->surface, false); } +static void unmanaged_handle_associate(struct wl_listener *listener, void *data) { + struct sway_xwayland_unmanaged *surface = + wl_container_of(listener, surface, associate); + struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; + wl_signal_add(&xsurface->surface->events.map, &surface->map); + surface->map.notify = unmanaged_handle_map; + wl_signal_add(&xsurface->surface->events.unmap, &surface->unmap); + surface->unmap.notify = unmanaged_handle_unmap; +} + +static void unmanaged_handle_dissociate(struct wl_listener *listener, void *data) { + struct sway_xwayland_unmanaged *surface = + wl_container_of(listener, surface, dissociate); + wl_list_remove(&surface->map.link); + wl_list_remove(&surface->unmap.link); +} + static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { struct sway_xwayland_unmanaged *surface = wl_container_of(listener, surface, destroy); wl_list_remove(&surface->request_configure.link); - wl_list_remove(&surface->map.link); - wl_list_remove(&surface->unmap.link); + wl_list_remove(&surface->associate.link); + wl_list_remove(&surface->dissociate.link); wl_list_remove(&surface->destroy.link); wl_list_remove(&surface->override_redirect.link); wl_list_remove(&surface->request_activate.link); @@ -159,7 +178,7 @@ static void unmanaged_handle_override_redirect(struct wl_listener *listener, voi wl_container_of(listener, surface, override_redirect); struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - bool mapped = xsurface->mapped; + bool mapped = xsurface->surface != NULL && xsurface->surface->mapped; if (mapped) { unmanaged_handle_unmap(&surface->unmap, NULL); } @@ -186,10 +205,10 @@ static struct sway_xwayland_unmanaged *create_unmanaged( wl_signal_add(&xsurface->events.request_configure, &surface->request_configure); surface->request_configure.notify = unmanaged_handle_request_configure; - wl_signal_add(&xsurface->events.map, &surface->map); - surface->map.notify = unmanaged_handle_map; - wl_signal_add(&xsurface->events.unmap, &surface->unmap); - surface->unmap.notify = unmanaged_handle_unmap; + wl_signal_add(&xsurface->events.associate, &surface->associate); + surface->associate.notify = unmanaged_handle_associate; + wl_signal_add(&xsurface->events.dissociate, &surface->dissociate); + surface->dissociate.notify = unmanaged_handle_dissociate; wl_signal_add(&xsurface->events.destroy, &surface->destroy); surface->destroy.notify = unmanaged_handle_destroy; wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); @@ -472,8 +491,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&xwayland_view->set_window_type.link); wl_list_remove(&xwayland_view->set_hints.link); wl_list_remove(&xwayland_view->set_decorations.link); - wl_list_remove(&xwayland_view->map.link); - wl_list_remove(&xwayland_view->unmap.link); + wl_list_remove(&xwayland_view->associate.link); + wl_list_remove(&xwayland_view->dissociate.link); wl_list_remove(&xwayland_view->override_redirect.link); view_begin_destroy(&xwayland_view->view); } @@ -495,8 +514,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { static void handle_map(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, map); - struct wlr_xwayland_surface *xsurface = data; struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; view->natural_width = xsurface->width; view->natural_height = xsurface->height; @@ -515,10 +534,10 @@ static void handle_map(struct wl_listener *listener, void *data) { static void handle_override_redirect(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, override_redirect); - struct wlr_xwayland_surface *xsurface = data; struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - bool mapped = xsurface->mapped; + bool mapped = xsurface->surface != NULL && xsurface->surface->mapped; if (mapped) { handle_unmap(&xwayland_view->unmap, NULL); } @@ -537,7 +556,7 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface_configure_event *ev = data; struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, ev->width, ev->height); return; @@ -566,7 +585,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) wl_container_of(listener, xwayland_view, request_fullscreen); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } container_set_fullscreen(view->container, xsurface->fullscreen); @@ -580,7 +599,7 @@ static void handle_request_minimize(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, request_minimize); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } @@ -595,7 +614,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, request_move); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } if (!container_is_floating(view->container) || @@ -611,7 +630,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, request_resize); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } if (!container_is_floating(view->container)) { @@ -627,7 +646,7 @@ static void handle_request_activate(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, request_activate); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_request_activate(view, NULL); @@ -640,7 +659,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_title); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_update_title(view, false); @@ -652,7 +671,7 @@ static void handle_set_class(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_class); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_execute_criteria(view); @@ -663,7 +682,7 @@ static void handle_set_role(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_role); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_execute_criteria(view); @@ -699,7 +718,7 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_window_type); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_execute_criteria(view); @@ -710,7 +729,7 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_hints); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints); @@ -725,6 +744,24 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { } } +static void handle_associate(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, associate); + struct wlr_xwayland_surface *xsurface = + xwayland_view->view.wlr_xwayland_surface; + wl_signal_add(&xsurface->surface->events.unmap, &xwayland_view->unmap); + xwayland_view->unmap.notify = handle_unmap; + wl_signal_add(&xsurface->surface->events.map, &xwayland_view->map); + xwayland_view->map.notify = handle_map; +} + +static void handle_dissociate(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, dissociate); + wl_list_remove(&xwayland_view->map.link); + wl_list_remove(&xwayland_view->unmap.link); +} + struct sway_view *view_from_wlr_xwayland_surface( struct wlr_xwayland_surface *xsurface) { return xsurface->data; @@ -794,11 +831,11 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu &xwayland_view->set_decorations); xwayland_view->set_decorations.notify = handle_set_decorations; - wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); - xwayland_view->unmap.notify = handle_unmap; + wl_signal_add(&xsurface->events.associate, &xwayland_view->associate); + xwayland_view->associate.notify = handle_associate; - wl_signal_add(&xsurface->events.map, &xwayland_view->map); - xwayland_view->map.notify = handle_map; + wl_signal_add(&xsurface->events.dissociate, &xwayland_view->dissociate); + xwayland_view->dissociate.notify = handle_dissociate; wl_signal_add(&xsurface->events.set_override_redirect, &xwayland_view->override_redirect); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 75d055cd..f970e6a2 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -236,7 +236,7 @@ void cursor_update_image(struct sway_cursor *cursor, // Try a node's resize edge enum wlr_edges edge = find_resize_edge(node->sway_container, NULL, cursor); if (edge == WLR_EDGE_NONE) { - cursor_set_image(cursor, "left_ptr", NULL); + cursor_set_image(cursor, "default", NULL); } else if (container_is_floating(node->sway_container)) { cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); } else { @@ -247,12 +247,12 @@ void cursor_update_image(struct sway_cursor *cursor, } } } else { - cursor_set_image(cursor, "left_ptr", NULL); + cursor_set_image(cursor, "default", NULL); } } static void cursor_hide(struct sway_cursor *cursor) { - wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); + wlr_cursor_unset_image(cursor->cursor); cursor->hidden = true; wlr_seat_pointer_notify_clear_focus(cursor->seat->wlr_seat); } @@ -509,6 +509,24 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { } } +static void handle_touch_cancel(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_cancel); + struct wlr_touch_cancel_event *event = data; + cursor_handle_activity_from_device(cursor, &event->touch->base); + + struct sway_seat *seat = cursor->seat; + + if (cursor->simulating_pointer_from_touch) { + 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); + } + } else { + seatop_touch_cancel(seat, event); + } +} + static void handle_touch_motion(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_motion); @@ -1050,10 +1068,9 @@ void cursor_set_image(struct sway_cursor *cursor, const char *image, } if (!image) { - wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); + wlr_cursor_unset_image(cursor->cursor); } else if (!current_image || strcmp(current_image, image) != 0) { - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image, - cursor->cursor); + wlr_cursor_set_xcursor(cursor->cursor, cursor->xcursor_manager, image); } } @@ -1100,6 +1117,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) { wl_list_remove(&cursor->frame.link); wl_list_remove(&cursor->touch_down.link); wl_list_remove(&cursor->touch_up.link); + wl_list_remove(&cursor->touch_cancel.link); wl_list_remove(&cursor->touch_motion.link); wl_list_remove(&cursor->touch_frame.link); wl_list_remove(&cursor->tool_axis.link); @@ -1136,9 +1154,6 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { wl_list_init(&cursor->image_surface_destroy.link); cursor->image_surface_destroy.notify = handle_image_surface_destroy; - // gesture events - cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display); - wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin); cursor->hold_begin.notify = handle_pointer_hold_begin; wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end); @@ -1181,6 +1196,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up); cursor->touch_up.notify = handle_touch_up; + wl_signal_add(&wlr_cursor->events.touch_cancel, &cursor->touch_cancel); + cursor->touch_cancel.notify = handle_touch_cancel; + wl_signal_add(&wlr_cursor->events.touch_motion, &cursor->touch_motion); cursor->touch_motion.notify = handle_touch_motion; diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 1115ba5e..db82bb4c 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -495,6 +495,8 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) { wl_signal_add(&input->keyboard_shortcuts_inhibit->events.new_inhibitor, &input->keyboard_shortcuts_inhibit_new_inhibitor); + input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display); + return input; } @@ -532,6 +534,18 @@ static void retranslate_keysyms(struct input_config *input_config) { return; } } + + for (int i = 0; i < config->input_type_configs->length; ++i) { + struct input_config *ic = config->input_type_configs->items[i]; + if (ic->xkb_layout || ic->xkb_file) { + // this is the first config with xkb_layout or xkb_file + if (ic->identifier == input_config->identifier) { + translate_keysyms(ic); + } + + return; + } + } } static void input_manager_configure_input( diff --git a/sway/input/libinput.c b/sway/input/libinput.c index dd4fc0be..43875634 100644 --- a/sway/input/libinput.c +++ b/sway/input/libinput.c @@ -166,6 +166,18 @@ static bool set_scroll_button(struct libinput_device *dev, uint32_t button) { return true; } +static bool set_scroll_button_lock(struct libinput_device *dev, + enum libinput_config_scroll_button_lock_state lock) { + uint32_t scroll = libinput_device_config_scroll_get_methods(dev); + if ((scroll & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0 || + libinput_device_config_scroll_get_button_lock(dev) == lock) { + return false; + } + sway_log(SWAY_DEBUG, "scroll_set_button_lock(%" PRIu32 ")", lock); + log_status(libinput_device_config_scroll_set_button_lock(dev, lock)); + return true; +} + static bool set_dwt(struct libinput_device *device, bool dwt) { if (!libinput_device_config_dwt_is_available(device) || libinput_device_config_dwt_get_enabled(device) == dwt) { @@ -276,6 +288,9 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device if (ic->scroll_button != INT_MIN) { changed |= set_scroll_button(device, ic->scroll_button); } + if (ic->scroll_button_lock != INT_MIN) { + changed |= set_scroll_button_lock(device, ic->scroll_button_lock); + } if (ic->dwt != INT_MIN) { changed |= set_dwt(device, ic->dwt); } diff --git a/sway/input/seat.c b/sway/input/seat.c index 14931ce0..82f4eb5f 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -367,7 +367,7 @@ static void handle_new_node(struct wl_listener *listener, void *data) { } static void drag_icon_damage_whole(struct sway_drag_icon *icon) { - if (!icon->wlr_drag_icon->mapped) { + if (!icon->wlr_drag_icon->surface->mapped) { return; } desktop_damage_surface(icon->wlr_drag_icon->surface, icon->x, icon->y, true); @@ -511,9 +511,9 @@ static void handle_start_drag(struct wl_listener *listener, void *data) { icon->surface_commit.notify = drag_icon_handle_surface_commit; wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); icon->unmap.notify = drag_icon_handle_unmap; - wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap); + wl_signal_add(&wlr_drag_icon->surface->events.unmap, &icon->unmap); icon->map.notify = drag_icon_handle_map; - wl_signal_add(&wlr_drag_icon->events.map, &icon->map); + wl_signal_add(&wlr_drag_icon->surface->events.map, &icon->map); icon->destroy.notify = drag_icon_handle_destroy; wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); @@ -671,7 +671,7 @@ static void seat_update_capabilities(struct sway_seat *seat) { } else { wlr_seat_set_capabilities(seat->wlr_seat, caps); if ((previous_caps & WL_SEAT_CAPABILITY_POINTER) == 0) { - cursor_set_image(seat->cursor, "left_ptr", NULL); + cursor_set_image(seat->cursor, "default", NULL); } } } @@ -1039,7 +1039,7 @@ void seat_configure_xcursor(struct sway_seat *seat) { wlr_xcursor_manager_load(server.xwayland.xcursor_manager, 1); struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor( - server.xwayland.xcursor_manager, "left_ptr", 1); + server.xwayland.xcursor_manager, "default", 1); if (xcursor != NULL) { struct wlr_xcursor_image *image = xcursor->images[0]; wlr_xwayland_set_cursor( @@ -1082,7 +1082,7 @@ void seat_configure_xcursor(struct sway_seat *seat) { // Reset the cursor so that we apply it to outputs that just appeared cursor_set_image(seat->cursor, NULL, NULL); - cursor_set_image(seat->cursor, "left_ptr", NULL); + cursor_set_image(seat->cursor, "default", NULL); wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, seat->cursor->cursor->y); } @@ -1295,11 +1295,15 @@ static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *n } void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { - if (seat->focused_layer) { + // Prevents the layer from losing focus if it has keyboard exclusivity + if (seat->has_exclusive_layer) { struct wlr_layer_surface_v1 *layer = seat->focused_layer; seat_set_focus_layer(seat, NULL); seat_set_workspace_focus(seat, node); seat_set_focus_layer(seat, layer); + } else if (seat->focused_layer) { + seat_set_focus_layer(seat, NULL); + seat_set_workspace_focus(seat, node); } else { seat_set_workspace_focus(seat, node); } @@ -1347,14 +1351,20 @@ void seat_set_focus_layer(struct sway_seat *seat, seat_set_focus(seat, previous); } return; - } else if (!layer || seat->focused_layer == layer) { + } else if (!layer) { return; } - assert(layer->mapped); - seat_set_focus_surface(seat, layer->surface, true); - if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { - seat->focused_layer = layer; + assert(layer->surface->mapped); + if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP && + layer->current.keyboard_interactive + == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { + seat->has_exclusive_layer = true; } + if (seat->focused_layer == layer) { + return; + } + seat_set_focus_surface(seat, layer->surface, true); + seat->focused_layer = layer; } void seat_set_exclusive_client(struct sway_seat *seat, @@ -1638,6 +1648,12 @@ void seatop_touch_down(struct sway_seat *seat, struct wlr_touch_down_event *even } } +void seatop_touch_cancel(struct sway_seat *seat, struct wlr_touch_cancel_event *event) { + if (seat->seatop_impl->touch_cancel) { + seat->seatop_impl->touch_cancel(seat, event); + } +} + void seatop_tablet_tool_tip(struct sway_seat *seat, struct sway_tablet_tool *tool, uint32_t time_msec, enum wlr_tablet_tool_tip_state state) { @@ -1726,10 +1742,9 @@ void seatop_end(struct sway_seat *seat) { seat->seatop_impl = NULL; } -void seatop_render(struct sway_seat *seat, struct sway_output *output, - const pixman_region32_t *damage) { +void seatop_render(struct sway_seat *seat, struct render_context *ctx) { if (seat->seatop_impl->render) { - seat->seatop_impl->render(seat, output, damage); + seat->seatop_impl->render(seat, ctx); } } diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index 853b7da4..39ba3c40 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include "gesture.h" @@ -9,6 +10,7 @@ #include "sway/input/cursor.h" #include "sway/input/seat.h" #include "sway/input/tablet.h" +#include "sway/layers.h" #include "sway/output.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" @@ -365,10 +367,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, return; } - // Handle clicking a layer surface - struct wlr_layer_surface_v1 *layer; - if (surface && - (layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) { + // Handle clicking a layer surface and its popups/subsurfaces + struct wlr_layer_surface_v1 *layer = NULL; + if ((layer = toplevel_layer_surface_from_surface(surface))) { if (layer->current.keyboard_interactive) { seat_set_focus_layer(seat, layer); transaction_commit_dirty(); @@ -545,6 +546,21 @@ static void check_focus_follows_mouse(struct sway_seat *seat, if (wlr_output == NULL) { return; } + + struct wlr_surface *surface = NULL; + double sx, sy; + node_at_coords(seat, seat->cursor->cursor->x, seat->cursor->cursor->y, + &surface, &sx, &sy); + + // Focus topmost layer surface + struct wlr_layer_surface_v1 *layer = NULL; + if ((layer = toplevel_layer_surface_from_surface(surface)) && + layer->current.keyboard_interactive) { + seat_set_focus_layer(seat, layer); + transaction_commit_dirty(); + return; + } + struct sway_output *hovered_output = wlr_output->data; if (focus && hovered_output != node_get_output(focus)) { struct sway_workspace *ws = output_get_active_workspace(hovered_output); @@ -934,7 +950,7 @@ static void handle_hold_begin(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_hold_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->fingers); } } @@ -946,7 +962,7 @@ static void handle_hold_end(struct sway_seat *seat, if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) { struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_hold_end( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->cancelled); return; } @@ -979,7 +995,7 @@ static void handle_pinch_begin(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_pinch_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->fingers); } } @@ -995,7 +1011,7 @@ static void handle_pinch_update(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_pinch_update( - cursor->pointer_gestures, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->dx, event->dy, event->scale, event->rotation); @@ -1009,7 +1025,7 @@ static void handle_pinch_end(struct sway_seat *seat, if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) { struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_pinch_end( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->cancelled); return; } @@ -1042,7 +1058,7 @@ static void handle_swipe_begin(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_swipe_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->fingers); } } @@ -1059,7 +1075,7 @@ static void handle_swipe_update(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_swipe_update( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->dx, event->dy); } } @@ -1070,7 +1086,7 @@ static void handle_swipe_end(struct sway_seat *seat, struct seatop_default_event *seatop = seat->seatop_data; if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) { struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_swipe_end(cursor->pointer_gestures, + wlr_pointer_gestures_v1_send_swipe_end(server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->cancelled); return; } diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index 6447134e..36f9bb60 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c @@ -64,11 +64,11 @@ static void handle_touch_up(struct sway_seat *seat, } } + wlr_seat_touch_notify_up(seat->wlr_seat, event->time_msec, event->touch_id); + if (wl_list_empty(&e->point_events)) { seatop_begin_default(seat); } - - wlr_seat_touch_notify_up(seat->wlr_seat, event->time_msec, event->touch_id); } static void handle_touch_down(struct sway_seat *seat, @@ -104,6 +104,28 @@ static void handle_touch_down(struct sway_seat *seat, } } +static void handle_touch_cancel(struct sway_seat *seat, + struct wlr_touch_cancel_event *event) { + struct seatop_down_event *e = seat->seatop_data; + struct seatop_touch_point_event *point_event, *tmp; + + wl_list_for_each_safe(point_event, tmp, &e->point_events, link) { + if (point_event->touch_id == event->touch_id) { + wl_list_remove(&point_event->link); + free(point_event); + break; + } + } + + if (e->surface) { + wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface); + } + + if (wl_list_empty(&e->point_events)) { + seatop_begin_default(seat); + } +} + static void handle_pointer_axis(struct sway_seat *seat, struct wlr_pointer_axis_event *event) { struct sway_input_device *input_device = @@ -189,6 +211,7 @@ static const struct sway_seatop_impl seatop_impl = { .touch_motion = handle_touch_motion, .touch_up = handle_touch_up, .touch_down = handle_touch_down, + .touch_cancel = handle_touch_cancel, .unref = handle_unref, .end = handle_end, .allow_set_cursor = true, diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index 5498e909..26704d0d 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -31,21 +31,20 @@ struct seatop_move_tiling_event { bool insert_after_target; }; -static void handle_render(struct sway_seat *seat, - struct sway_output *output, const pixman_region32_t *damage) { +static void handle_render(struct sway_seat *seat, struct render_context *ctx) { struct seatop_move_tiling_event *e = seat->seatop_data; if (!e->threshold_reached) { return; } - if (e->target_node && node_get_output(e->target_node) == output) { + if (e->target_node && node_get_output(e->target_node) == ctx->output) { float color[4]; memcpy(&color, config->border_colors.focused.indicator, sizeof(float) * 4); premultiply_alpha(color, 0.5); struct wlr_box box; memcpy(&box, &e->drop_box, sizeof(struct wlr_box)); - scale_box(&box, output->wlr_output->scale); - render_rect(output, damage, &box, color); + scale_box(&box, ctx->output->wlr_output->scale); + render_rect(ctx, &box, color); } } diff --git a/sway/ipc-json.c b/sway/ipc-json.c index c7cbea01..58356d4e 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -1019,6 +1019,17 @@ static json_object *describe_libinput_device(struct libinput_device *device) { uint32_t button = libinput_device_config_scroll_get_button(device); json_object_object_add(object, "scroll_button", json_object_new_int(button)); + const char *lock = "unknown"; + switch (libinput_device_config_scroll_get_button_lock(device)) { + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED: + lock = "enabled"; + break; + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED: + lock = "disabled"; + break; + } + json_object_object_add(object, "scroll_button_lock", + json_object_new_string(lock)); } } diff --git a/sway/lock.c b/sway/lock.c index 6d9e991b..53456172 100644 --- a/sway/lock.c +++ b/sway/lock.c @@ -60,7 +60,7 @@ static void destroy_lock_surface(struct sway_session_lock_surface *surf) { struct wlr_session_lock_surface_v1 *other; wl_list_for_each(other, &server.session_lock.lock->surfaces, link) { - if (other != surf->lock_surface && other->mapped) { + if (other != surf->lock_surface && other->surface->mapped) { next_focus = other->surface; break; } @@ -104,7 +104,7 @@ static void handle_new_surface(struct wl_listener *listener, void *data) { surf->surface = lock_surface->surface; surf->output = output; surf->map.notify = handle_surface_map; - wl_signal_add(&lock_surface->events.map, &surf->map); + wl_signal_add(&lock_surface->surface->events.map, &surf->map); surf->destroy.notify = handle_surface_destroy; wl_signal_add(&lock_surface->events.destroy, &surf->destroy); surf->surface_commit.notify = handle_surface_commit; diff --git a/sway/meson.build b/sway/meson.build index b362fd65..739d5f96 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -172,6 +172,7 @@ sway_sources = files( 'commands/input/repeat_delay.c', 'commands/input/repeat_rate.c', 'commands/input/scroll_button.c', + 'commands/input/scroll_button_lock.c', 'commands/input/scroll_factor.c', 'commands/input/scroll_method.c', 'commands/input/tap.c', @@ -223,7 +224,6 @@ sway_deps = [ math, pango, pcre2, - glesv2, pixman, threads, wayland_server, diff --git a/sway/server.c b/sway/server.c index 0cf767b7..cc4719d7 100644 --- a/sway/server.c +++ b/sway/server.c @@ -55,7 +55,7 @@ #endif #define SWAY_XDG_SHELL_VERSION 2 -#define SWAY_LAYER_SHELL_VERSION 3 +#define SWAY_LAYER_SHELL_VERSION 4 #if WLR_HAS_DRM_BACKEND static void handle_drm_lease_request(struct wl_listener *listener, void *data) { @@ -114,7 +114,11 @@ bool server_init(struct sway_server *server) { server->data_device_manager = wlr_data_device_manager_create(server->wl_display); - wlr_gamma_control_manager_v1_create(server->wl_display); + server->gamma_control_manager_v1 = + wlr_gamma_control_manager_v1_create(server->wl_display); + server->gamma_control_set_gamma.notify = handle_gamma_control_set_gamma; + wl_signal_add(&server->gamma_control_manager_v1->events.set_gamma, + &server->gamma_control_set_gamma); server->new_output.notify = handle_new_output; wl_signal_add(&server->backend->events.new_output, &server->new_output); @@ -126,8 +130,7 @@ bool server_init(struct sway_server *server) { server->idle = wlr_idle_create(server->wl_display); server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display); - server->idle_inhibit_manager_v1 = - sway_idle_inhibit_manager_v1_create(server->wl_display, server->idle); + sway_idle_inhibit_manager_v1_init(); server->layer_shell = wlr_layer_shell_v1_create(server->wl_display, SWAY_LAYER_SHELL_VERSION); diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 1662d55a..082b68c2 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -185,6 +185,9 @@ The following commands may only be used in the configuration file. debug-events*, or as a x11 mouse button (button[1-3,8,9]). If set to _disable_, it disables the scroll_method on_button_down. +*input* scroll_button_lock enabled|disabled + Enables or disables scroll button lock for specified input device. + *input* scroll_factor Changes the scroll factor for the specified input device. Scroll speed will be scaled by the given value, which must be non-negative. diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index 42aaaab6..f4a5ccff 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -1195,6 +1195,9 @@ following properties will be included for devices that support them: : int : The scroll button to use when _scroll_method_ is _on_button_down_. This will be given as an input event code +|- scroll_button_lock +: string +: Whether scroll button lock is enabled. It can be _enabled_ or _disabled_ |- dwt : string : Whether disable-while-typing is enabled. It can be _enabled_ or _disabled_ diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 25082c41..78d7d231 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -389,8 +389,8 @@ runtime. for_window move container to output *bindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] \ -[--to-code] [--input-device=] [--no-warn] [--no-repeat] [Group<1-4>+] \ - +[--to-code] [--input-device=] [--no-warn] [--no-repeat] [--inhibited] \ +[Group<1-4>+] Binds _key combo_ to execute the sway command _command_ when pressed. You may use XKB key names here (*wev*(1) is a good tool for discovering these). With the flag _--release_, the command is executed when the key combo is @@ -454,7 +454,8 @@ runtime. ``` *bindcode* [--whole-window] [--border] [--exclude-titlebar] [--release] \ -[--locked] [--input-device=] [--no-warn] [Group<1-4>+] +[--locked] [--input-device=] [--no-warn] [--no-repeat] [--inhibited] \ +[Group<1-4>+] is also available for binding with key/button codes instead of key/button names. *bindswitch* [--locked] [--no-warn] [--reload] : diff --git a/sway/xdg_activation_v1.c b/sway/xdg_activation_v1.c index e97989c8..c26ee19a 100644 --- a/sway/xdg_activation_v1.c +++ b/sway/xdg_activation_v1.c @@ -17,7 +17,7 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, return; } - if (!xdg_surface->mapped) { + if (!xdg_surface->surface->mapped) { // This is a startup notification. If we are tracking it, the data // field is a launcher_ctx. struct launcher_ctx *ctx = event->token->data; diff --git a/swaybar/input.c b/swaybar/input.c index 8eccf542..358c69cb 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -82,7 +82,7 @@ void update_cursor(struct swaybar_seat *seat) { pointer->cursor_theme = wl_cursor_theme_load( cursor_theme, cursor_size * scale, seat->bar->shm); struct wl_cursor *cursor; - cursor = wl_cursor_theme_get_cursor(pointer->cursor_theme, "left_ptr"); + cursor = wl_cursor_theme_get_cursor(pointer->cursor_theme, "default"); pointer->cursor_image = cursor->images[0]; wl_surface_set_buffer_scale(pointer->cursor_surface, scale); wl_surface_attach(pointer->cursor_surface, @@ -207,7 +207,7 @@ static void workspace_next(struct swaybar *bar, struct swaybar_output *output, } } - if (new) { + if (new && new != active) { ipc_send_workspace_command(bar, new->name); // Since we're asking Sway to switch to 'new', it should become visible. diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 9d81a9fb..33ae6544 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -426,12 +426,9 @@ bool ipc_initialize(struct swaybar *bar) { } free(res); - struct swaybar_config *config = bar->config; - char subscribe[128]; // suitably large buffer - len = snprintf(subscribe, 128, - "[ \"barconfig_update\" , \"bar_state_update\" %s %s ]", - config->binding_mode_indicator ? ", \"mode\"" : "", - config->workspace_buttons ? ", \"workspace\"" : ""); + char *subscribe = + "[ \"barconfig_update\", \"bar_state_update\", \"mode\", \"workspace\" ]"; + len = strlen(subscribe); free(ipc_single_command(bar->ipc_event_socketfd, IPC_SUBSCRIBE, subscribe, &len)); return true; diff --git a/swaybar/tray/watcher.c b/swaybar/tray/watcher.c index 551e1d12..2458a8c2 100644 --- a/swaybar/tray/watcher.c +++ b/swaybar/tray/watcher.c @@ -106,7 +106,7 @@ static int register_host(sd_bus_message *msg, void *data, sd_bus_error *error) { sway_log(SWAY_DEBUG, "Registering Status Notifier Host '%s'", service); list_add(watcher->hosts, strdup(service)); sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface, - "StatusNotifierHostRegistered", "s", service); + "StatusNotifierHostRegistered", ""); } else { sway_log(SWAY_DEBUG, "Status Notifier Host '%s' already registered", service); } diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c index 08e26127..1b114e28 100644 --- a/swaynag/swaynag.c +++ b/swaynag/swaynag.c @@ -154,7 +154,7 @@ static void update_cursor(struct swaynag_seat *seat) { pointer->cursor_theme = wl_cursor_theme_load( cursor_theme, cursor_size * swaynag->scale, swaynag->shm); struct wl_cursor *cursor = - wl_cursor_theme_get_cursor(pointer->cursor_theme, "left_ptr"); + wl_cursor_theme_get_cursor(pointer->cursor_theme, "default"); pointer->cursor_image = cursor->images[0]; wl_surface_set_buffer_scale(pointer->cursor_surface, swaynag->scale);