Merge branch 'swaywm:master' into drag_mode

This commit is contained in:
hmpthcs 2023-06-30 22:20:13 -04:00 committed by GitHub
commit d4405b7349
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 734 additions and 472 deletions

View file

@ -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;

View file

@ -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;

View file

@ -2,7 +2,6 @@
#define _SWAY_DESKTOP_IDLE_INHIBIT_V1_H
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_idle.h>
#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

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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(

View file

@ -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);

View file

@ -21,6 +21,7 @@
#include <wlr/types/wlr_xdg_shell.h>
#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;

View file

@ -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;

View file

@ -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'))

View file

@ -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);

View file

@ -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 },

View file

@ -0,0 +1,26 @@
#include <libinput.h>
#include <string.h>
#include <strings.h>
#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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -6,8 +6,10 @@
#include <wayland-server-core.h>
#include <wlr/config.h>
#include <wlr/backend/headless.h>
#include <wlr/render/swapchain.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
@ -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

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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(

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -2,6 +2,7 @@
#include <float.h>
#include <libevdev/libevdev.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/types/wlr_xcursor_manager.h>
#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;
}

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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));
}
}

View file

@ -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;

View file

@ -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,

View file

@ -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);
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);

View file

@ -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* <identifier> scroll_button_lock enabled|disabled
Enables or disables scroll button lock for specified input device.
*input* <identifier> scroll_factor <floating point value>
Changes the scroll factor for the specified input device. Scroll speed will
be scaled by the given value, which must be non-negative.

View file

@ -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_

View file

@ -389,8 +389,8 @@ runtime.
for_window <criteria> move container to output <output>
*bindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] \
[--to-code] [--input-device=<device>] [--no-warn] [--no-repeat] [Group<1-4>+]<key combo> \
<command>
[--to-code] [--input-device=<device>] [--no-warn] [--no-repeat] [--inhibited] \
[Group<1-4>+]<key combo> <command>
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=<device>] [--no-warn] [Group<1-4>+]<code> <command>
[--locked] [--input-device=<device>] [--no-warn] [--no-repeat] [--inhibited] \
[Group<1-4>+]<code> <command>
is also available for binding with key/button codes instead of key/button names.
*bindswitch* [--locked] [--no-warn] [--reload] <switch>:<state> <command>

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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);
}

View file

@ -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);