diff options
35 files changed, 2703 insertions, 237 deletions
diff --git a/backend/meson.build b/backend/meson.build index bac43063..c0ed76f1 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -28,14 +28,15 @@ backend_files = files( ) backend_deps = [ - wayland_server, + drm, egl, gbm, libinput, - wlr_render, - wlr_protos, - drm, pixman, + xkbcommon, + wayland_server, + wlr_protos, + wlr_render, ] if host_machine.system().startswith('freebsd') diff --git a/examples/idle.c b/examples/idle.c index 57c366d1..2b155c68 100644 --- a/examples/idle.c +++ b/examples/idle.c @@ -6,8 +6,8 @@ #include <pthread.h> #include <wayland-client.h> #include <wayland-client-protocol.h> -#include <idle-client-protocol.h> #include <wlr/util/log.h> +#include "idle-client-protocol.h" static struct org_kde_kwin_idle *idle_manager = NULL; static struct wl_seat *seat = NULL; diff --git a/examples/screenshot.c b/examples/screenshot.c index 7de2ab8e..c163df75 100644 --- a/examples/screenshot.c +++ b/examples/screenshot.c @@ -23,20 +23,20 @@ #define _XOPEN_SOURCE 700 #define _POSIX_C_SOURCE 199309L +#include <errno.h> +#include <fcntl.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> +#include <sys/param.h> #include <sys/wait.h> #include <unistd.h> -#include <fcntl.h> -#include <errno.h> #include <wayland-client.h> -#include <limits.h> -#include <sys/param.h> -#include <screenshooter-client-protocol.h> -#include "util/os-compatibility.h" #include <wlr/util/log.h> +#include "screenshooter-client-protocol.h" +#include "util/os-compatibility.h" static struct wl_shm *shm = NULL; static struct orbital_screenshooter *screenshooter = NULL; diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 6572b242..0132a7e8 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -15,6 +15,7 @@ #include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xdg_shell_v6.h> +#include <wlr/types/wlr_xdg_shell.h> #include "rootston/config.h" #include "rootston/output.h" #include "rootston/view.h" @@ -34,6 +35,7 @@ struct roots_desktop { struct wlr_compositor *compositor; struct wlr_wl_shell *wl_shell; struct wlr_xdg_shell_v6 *xdg_shell_v6; + struct wlr_xdg_shell *xdg_shell; struct wlr_gamma_control_manager *gamma_control_manager; struct wlr_screenshooter *screenshooter; struct wlr_server_decoration_manager *server_decoration_manager; @@ -43,6 +45,7 @@ struct roots_desktop { struct wl_listener new_output; struct wl_listener layout_change; struct wl_listener xdg_shell_v6_surface; + struct wl_listener xdg_shell_surface; struct wl_listener wl_shell_surface; struct wl_listener decoration_new; @@ -72,6 +75,7 @@ void view_update_position(struct roots_view *view, double x, double y); void view_update_size(struct roots_view *view, uint32_t width, uint32_t height); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); +void handle_xdg_shell_surface(struct wl_listener *listener, void *data); void handle_wl_shell_surface(struct wl_listener *listener, void *data); void handle_xwayland_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/view.h b/include/rootston/view.h index b61ac330..198086c1 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -6,6 +6,7 @@ #include <wlr/types/wlr_box.h> #include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_xdg_shell_v6.h> +#include <wlr/types/wlr_xdg_shell.h> struct roots_wl_shell_surface { struct roots_view *view; @@ -36,6 +37,21 @@ struct roots_xdg_surface_v6 { uint32_t pending_move_resize_configure_serial; }; +struct roots_xdg_surface { + struct roots_view *view; + + struct wl_listener destroy; + struct wl_listener new_popup; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; + + struct wl_listener surface_commit; + + uint32_t pending_move_resize_configure_serial; +}; + struct roots_xwayland_surface { struct roots_view *view; @@ -54,6 +70,7 @@ struct roots_xwayland_surface { enum roots_view_type { ROOTS_WL_SHELL_VIEW, ROOTS_XDG_SHELL_V6_VIEW, + ROOTS_XDG_SHELL_VIEW, #ifdef WLR_HAS_XWAYLAND ROOTS_XWAYLAND_VIEW, #endif @@ -90,6 +107,7 @@ struct roots_view { union { struct wlr_wl_shell_surface *wl_shell_surface; struct wlr_xdg_surface_v6 *xdg_surface_v6; + struct wlr_xdg_surface *xdg_surface; #ifdef WLR_HAS_XWAYLAND struct wlr_xwayland_surface *xwayland_surface; #endif @@ -97,6 +115,7 @@ struct roots_view { union { struct roots_wl_shell_surface *roots_wl_shell_surface; struct roots_xdg_surface_v6 *roots_xdg_surface_v6; + struct roots_xdg_surface *roots_xdg_surface; #ifdef WLR_HAS_XWAYLAND struct roots_xwayland_surface *roots_xwayland_surface; #endif @@ -154,6 +173,13 @@ struct roots_xdg_popup_v6 { struct wl_listener new_popup; }; +struct roots_xdg_popup { + struct roots_view_child view_child; + struct wlr_xdg_popup *wlr_popup; + struct wl_listener destroy; + struct wl_listener new_popup; +}; + void view_get_box(const struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); void view_move(struct roots_view *view, double x, double y); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 5c2ffee0..a8138a80 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -157,6 +157,7 @@ void wlr_output_set_gamma(struct wlr_output *output, uint32_t wlr_output_get_gamma_size(struct wlr_output *output); void wlr_output_set_fullscreen_surface(struct wlr_output *output, struct wlr_surface *surface); +struct wlr_output *wlr_output_from_resource(struct wl_resource *resource); struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output); diff --git a/include/wlr/types/wlr_region.h b/include/wlr/types/wlr_region.h index 6d59ee5e..ffacea72 100644 --- a/include/wlr/types/wlr_region.h +++ b/include/wlr/types/wlr_region.h @@ -1,13 +1,16 @@ #ifndef WLR_TYPES_WLR_REGION_H #define WLR_TYPES_WLR_REGION_H +#include <pixman.h> + struct wl_resource; /* * Implements the given resource as region. - * Sets the associated pixman_region32_t as userdata. */ void wlr_region_create(struct wl_client *client, struct wl_resource *res, - uint32_t id); + uint32_t id); + +pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource); #endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index b03cab6e..124c1cb8 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -530,4 +530,6 @@ bool wlr_seat_touch_has_grab(struct wlr_seat *seat); */ bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial); +struct wlr_seat_client *wlr_seat_client_from_resource(struct wl_resource *resource); + #endif diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 998b5ae5..203345bd 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -164,4 +164,6 @@ void wlr_surface_set_role_committed(struct wlr_surface *surface, void (*role_committed)(struct wlr_surface *surface, void *role_data), void *role_data); +struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource); + #endif diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h new file mode 100644 index 00000000..8422863c --- /dev/null +++ b/include/wlr/types/wlr_xdg_shell.h @@ -0,0 +1,232 @@ +#ifndef WLR_TYPES_WLR_XDG_SHELL_H +#define WLR_TYPES_WLR_XDG_SHELL_H + +#include <wlr/types/wlr_box.h> +#include <wlr/types/wlr_seat.h> +#include <wayland-server.h> + +struct wlr_xdg_shell { + struct wl_global *wl_global; + struct wl_list clients; + struct wl_list popup_grabs; + uint32_t ping_timeout; + + struct wl_listener display_destroy; + + struct { + struct wl_signal new_surface; + } events; + + void *data; +}; + +struct wlr_xdg_client { + struct wlr_xdg_shell *shell; + struct wl_resource *resource; + struct wl_client *client; + struct wl_list surfaces; + + struct wl_list link; // wlr_xdg_shell::clients + + uint32_t ping_serial; + struct wl_event_source *ping_timer; +}; + +struct wlr_xdg_popup { + struct wlr_xdg_surface *base; + struct wl_list link; + + struct wl_resource *resource; + bool committed; + struct wlr_xdg_surface *parent; + struct wlr_seat *seat; + struct wlr_box geometry; + + struct wl_list grab_link; // wlr_xdg_popup_grab::popups +}; + +// each seat gets a popup grab +struct wlr_xdg_popup_grab { + struct wl_client *client; + struct wlr_seat_pointer_grab pointer_grab; + struct wlr_seat_keyboard_grab keyboard_grab; + struct wlr_seat *seat; + struct wl_list popups; + struct wl_list link; // wlr_xdg_shell::popup_grabs +}; + +enum wlr_xdg_surface_role { + WLR_XDG_SURFACE_ROLE_NONE, + WLR_XDG_SURFACE_ROLE_TOPLEVEL, + WLR_XDG_SURFACE_ROLE_POPUP, +}; + +struct wlr_xdg_toplevel_state { + bool maximized; + bool fullscreen; + bool resizing; + bool activated; + + uint32_t width; + uint32_t height; + + uint32_t max_width; + uint32_t max_height; + + uint32_t min_width; + uint32_t min_height; +}; + +struct wlr_xdg_toplevel { + struct wl_resource *resource; + struct wlr_xdg_surface *base; + struct wlr_xdg_surface *parent; + bool added; + struct wlr_xdg_toplevel_state next; // client protocol requests + struct wlr_xdg_toplevel_state pending; // user configure requests + struct wlr_xdg_toplevel_state current; +}; + +struct wlr_xdg_surface_configure { + struct wl_list link; // wlr_xdg_surface::configure_list + uint32_t serial; + struct wlr_xdg_toplevel_state state; +}; + +struct wlr_xdg_surface { + struct wlr_xdg_client *client; + struct wl_resource *resource; + struct wlr_surface *surface; + struct wl_list link; // wlr_xdg_client::surfaces + enum wlr_xdg_surface_role role; + + union { + struct wlr_xdg_toplevel *toplevel_state; + struct wlr_xdg_popup *popup_state; + }; + + struct wl_list popups; // wlr_xdg_popup::link + + bool configured; + bool added; + uint32_t configure_serial; + struct wl_event_source *configure_idle; + uint32_t configure_next_serial; + struct wl_list configure_list; + + char *title; + char *app_id; + + bool has_next_geometry; + struct wlr_box *next_geometry; + struct wlr_box *geometry; + + struct wl_listener surface_destroy_listener; + + struct { + struct wl_signal destroy; + struct wl_signal ping_timeout; + struct wl_signal new_popup; + + struct wl_signal request_maximize; + struct wl_signal request_fullscreen; + struct wl_signal request_minimize; + struct wl_signal request_move; + struct wl_signal request_resize; + struct wl_signal request_show_window_menu; + } events; + + void *data; +}; + +struct wlr_xdg_toplevel_move_event { + struct wlr_xdg_surface *surface; + struct wlr_seat_client *seat; + uint32_t serial; +}; + +struct wlr_xdg_toplevel_resize_event { + struct wlr_xdg_surface *surface; + struct wlr_seat_client *seat; + uint32_t serial; + uint32_t edges; +}; + +struct wlr_xdg_toplevel_set_fullscreen_event { + struct wlr_xdg_surface *surface; + bool fullscreen; + struct wlr_output *output; +}; + +struct wlr_xdg_toplevel_show_window_menu_event { + struct wlr_xdg_surface *surface; + struct wlr_seat_client *seat; + uint32_t serial; + uint32_t x, y; +}; + +struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display); +void wlr_xdg_shell_destroy(struct wlr_xdg_shell *xdg_shell); + +/** + * Send a ping to the surface. If the surface does not respond in a reasonable + * amount of time, the ping_timeout event will be emitted. + */ +void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface); + +/** + * Request that this toplevel surface be the given size. Returns the associated + * configure serial. + */ +uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, + uint32_t width, uint32_t height); + +/** + * Request that this toplevel surface show itself in an activated or deactivated + * state. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, + bool activated); + +/** + * Request that this toplevel surface consider itself maximized or not + * maximized. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, + bool maximized); + +/** + * Request that this toplevel surface consider itself fullscreen or not + * fullscreen. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, + bool fullscreen); + +/** + * Request that this toplevel surface consider itself to be resizing or not + * resizing. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, + bool resizing); + +/** + * Request that this toplevel surface closes. + */ +void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface); + +/** + * Compute the popup position in surface-local coordinates. + */ +void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface, + double *popup_sx, double *popup_sy); + +/** + * Find a popup within this surface at the surface-local coordinates. Returns + * the popup and coordinates in the topmost surface coordinate system or NULL if + * no popup is found at that location. + */ +struct wlr_xdg_surface *wlr_xdg_surface_popup_at( + struct wlr_xdg_surface *surface, double sx, double sy, + double *popup_sx, double *popup_sy); + +#endif diff --git a/meson.build b/meson.build index 1cf7781a..2fc78d33 100644 --- a/meson.build +++ b/meson.build @@ -49,7 +49,7 @@ add_project_arguments('-DWL_HIDE_DEPRECATED', language: 'c') wayland_server = dependency('wayland-server') wayland_client = dependency('wayland-client') wayland_egl = dependency('wayland-egl') -wayland_protos = dependency('wayland-protocols') +wayland_protos = dependency('wayland-protocols', version: '>=1.12') egl = dependency('egl') glesv2 = dependency('glesv2') drm = dependency('libdrm') diff --git a/protocol/meson.build b/protocol/meson.build index 0db7c03c..2853971f 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -22,6 +22,7 @@ wayland_scanner_client = generator( protocols = [ [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], + [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], 'gamma-control.xml', 'gtk-primary-selection.xml', 'idle.xml', @@ -31,11 +32,8 @@ protocols = [ client_protocols = [ [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], - 'gamma-control.xml', - 'gtk-primary-selection.xml', 'idle.xml', 'screenshooter.xml', - 'server-decoration.xml', ] wl_protos_src = [] diff --git a/render/egl.c b/render/egl.c index f1208a72..21c446f1 100644 --- a/render/egl.c +++ b/render/egl.c @@ -132,7 +132,9 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor); wlr_log(L_INFO, "Supported EGL extensions: %s", egl->egl_exts_str); + wlr_log(L_INFO, "EGL vendor: %s", eglQueryString(egl->display, EGL_VENDOR)); wlr_log(L_INFO, "Using %s", glGetString(GL_VERSION)); + wlr_log(L_INFO, "GL vendor: %s", glGetString(GL_VENDOR)); wlr_log(L_INFO, "Supported OpenGL ES extensions: %s", egl->gl_exts_str); if (strstr(egl->egl_exts_str, "EGL_WL_bind_wayland_display") == NULL || diff --git a/render/meson.build b/render/meson.build index 1a5a85b8..8aa70cea 100644 --- a/render/meson.build +++ b/render/meson.build @@ -22,7 +22,7 @@ lib_wlr_render = static_library( glapi[0], glapi[1], include_directories: wlr_inc, - dependencies: [glesv2, egl, pixman], + dependencies: [egl, glesv2, pixman, wayland_server], ) wlr_render = declare_dependency( diff --git a/rootston/desktop.c b/rootston/desktop.c index 80ccbc25..6b28a41c 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -15,6 +15,7 @@ #include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xdg_shell_v6.h> +#include <wlr/types/wlr_xdg_shell.h> #include <wlr/util/log.h> #include "rootston/seat.h" #include "rootston/server.h" @@ -639,6 +640,11 @@ struct roots_desktop *desktop_create(struct roots_server *server, &desktop->xdg_shell_v6_surface); desktop->xdg_shell_v6_surface.notify = handle_xdg_shell_v6_surface; + desktop->xdg_shell = wlr_xdg_shell_create(server->wl_display); + wl_signal_add(&desktop->xdg_shell->events.new_surface, + &desktop->xdg_shell_surface); + desktop->xdg_shell_surface.notify = handle_xdg_shell_surface; + desktop->wl_shell = wlr_wl_shell_create(server->wl_display); wl_signal_add(&desktop->wl_shell->events.new_surface, &desktop->wl_shell_surface); diff --git a/rootston/meson.build b/rootston/meson.build index a53812e3..9dbe37c2 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -10,6 +10,7 @@ sources = [ 'seat.c', 'wl_shell.c', 'xdg_shell_v6.c', + 'xdg_shell.c', ] if get_option('enable_xwayland') sources += ['xwayland.c'] diff --git a/rootston/output.c b/rootston/output.c index 1ea4412e..8ef383c3 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -8,6 +8,7 @@ #include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_xdg_shell_v6.h> +#include <wlr/types/wlr_xdg_shell.h> #include <wlr/util/log.h> #include <wlr/util/region.h> #include "rootston/config.h" @@ -81,6 +82,34 @@ static void xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, } } +static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, + double base_x, double base_y, float rotation, + surface_iterator_func_t iterator, void *user_data) { + double width = surface->surface->current->width; + double height = surface->surface->current->height; + + struct wlr_xdg_popup *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface *popup = popup_state->base; + if (!popup->configured) { + continue; + } + + double popup_width = popup->surface->current->width; + double popup_height = popup->surface->current->height; + + double popup_sx, popup_sy; + wlr_xdg_surface_popup_get_position(popup, &popup_sx, &popup_sy); + rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, + width, height, rotation); + + surface_for_each_surface(popup->surface, base_x + popup_sx, + base_y + popup_sy, rotation, iterator, user_data); + xdg_surface_for_each_surface(popup, base_x + popup_sx, + base_y + popup_sy, rotation, iterator, user_data); + } +} + static void wl_shell_surface_for_each_surface( struct wlr_wl_shell_surface *surface, double lx, double ly, float rotation, bool is_child, surface_iterator_func_t iterator, @@ -117,6 +146,12 @@ static void view_for_each_surface(struct roots_view *view, xdg_surface_v6_for_each_surface(view->xdg_surface_v6, view->x, view->y, view->rotation, iterator, user_data); break; + case ROOTS_XDG_SHELL_VIEW: + surface_for_each_surface(view->wlr_surface, view->x, view->y, + view->rotation, iterator, user_data); + xdg_surface_for_each_surface(view->xdg_surface, view->x, view->y, + view->rotation, iterator, user_data); + break; case ROOTS_WL_SHELL_VIEW: wl_shell_surface_for_each_surface(view->wl_shell_surface, view->x, view->y, view->rotation, false, iterator, user_data); @@ -337,6 +372,8 @@ static bool has_standalone_surface(struct roots_view *view) { switch (view->type) { case ROOTS_XDG_SHELL_V6_VIEW: return wl_list_empty(&view->xdg_surface_v6->popups); + case ROOTS_XDG_SHELL_VIEW: + return wl_list_empty(&view->xdg_surface->popups); case ROOTS_WL_SHELL_VIEW: return wl_list_empty(&view->wl_shell_surface->popups); #ifdef WLR_HAS_XWAYLAND diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c new file mode 100644 index 00000000..8340de46 --- /dev/null +++ b/rootston/xdg_shell.c @@ -0,0 +1,363 @@ +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <wayland-server.h> +#include <wlr/types/wlr_box.h> +#include <wlr/types/wlr_surface.h> +#include <wlr/types/wlr_xdg_shell.h> +#include <wlr/util/log.h> +#include "rootston/desktop.h" +#include "rootston/input.h" +#include "rootston/server.h" + +static void popup_destroy(struct roots_view_child *child) { + assert(child->destroy == popup_destroy); + struct roots_xdg_popup *popup = (struct roots_xdg_popup *)child; + if (popup == NULL) { + return; + } + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->new_popup.link); + view_child_finish(&popup->view_child); + free(popup); +} + +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct roots_xdg_popup *popup = + wl_container_of(listener, popup, destroy); + popup_destroy((struct roots_view_child *)popup); +} + +static struct roots_xdg_popup *popup_create(struct roots_view *view, + struct wlr_xdg_popup *wlr_popup); + +static void popup_handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_xdg_popup *popup = + wl_container_of(listener, popup, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + popup_create(popup->view_child.view, wlr_popup); +} + +static struct roots_xdg_popup *popup_create(struct roots_view *view, + struct wlr_xdg_popup *wlr_popup) { + struct roots_xdg_popup *popup = + calloc(1, sizeof(struct roots_xdg_popup)); + if (popup == NULL) { + return NULL; + } + popup->wlr_popup = wlr_popup; + popup->view_child.destroy = popup_destroy; + view_child_init(&popup->view_child, view, wlr_popup->base->surface); + popup->destroy.notify = popup_handle_destroy; + wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); + popup->new_popup.notify = popup_handle_new_popup; + wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); + return popup; +} + + +static void get_size(const struct roots_view *view, struct wlr_box *box) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + + if (surface->geometry->width > 0 && surface->geometry->height > 0) { + box->width = surface->geometry->width; + box->height = surface->geometry->height; + } else { + box->width = view->wlr_surface->current->width; + box->height = view->wlr_surface->current->height; + } +} + +static void activate(struct roots_view *view, bool active) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + wlr_xdg_toplevel_set_activated(surface, active); + } +} + +static void apply_size_constraints(struct wlr_xdg_surface *surface, + uint32_t width, uint32_t height, uint32_t *dest_width, + uint32_t *dest_height) { + *dest_width = width; + *dest_height = height; + + struct wlr_xdg_toplevel_state *state = &surface->toplevel_state->current; + if (width < state->min_width) { + *dest_width = state->min_width; + } else if (state->max_width > 0 && + width > state->max_width) { + *dest_width = state->max_width; + } + if (height < state->min_height) { + *dest_height = state->min_height; + } else if (state->max_height > 0 && + height > state->max_height) { + *dest_height = state->max_height; + } +} + +static void resize(struct roots_view *view, uint32_t width, uint32_t height) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + uint32_t constrained_width, constrained_height; + apply_size_constraints(surface, width, height, &constrained_width, + &constrained_height); + + wlr_xdg_toplevel_set_size(surface, constrained_width, + constrained_height); +} + +static void move_resize(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct roots_xdg_surface *roots_surface = view->roots_xdg_surface; + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + bool update_x = x != view->x; + bool update_y = y != view->y; + + uint32_t constrained_width, constrained_height; + apply_size_constraints(surface, width, height, &constrained_width, + &constrained_height); + + if (update_x) { + x = x + width - constrained_width; + } + if (update_y) { + y = y + height - constrained_height; + } + + view->pending_move_resize.update_x = update_x; + view->pending_move_resize.update_y = update_y; + view->pending_move_resize.x = x; + view->pending_move_resize.y = y; + view->pending_move_resize.width = constrained_width; + view->pending_move_resize.height = constrained_height; + + uint32_t serial = wlr_xdg_toplevel_set_size(surface, constrained_width, + constrained_height); + if (serial > 0) { + roots_surface->pending_move_resize_configure_serial = serial; + } else if (roots_surface->pending_move_resize_configure_serial == 0) { + view_update_position(view, x, y); + } +} + +static void maximize(struct roots_view *view, bool maximized) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + wlr_xdg_toplevel_set_maximized(surface, maximized); +} + +static void set_fullscreen(struct roots_view *view, bool fullscreen) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); +} + +static void close(struct roots_view *view) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); + struct wlr_xdg_surface *surface = view->xdg_surface; + if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + wlr_xdg_toplevel_send_close(surface); + } +} + +static void handle_request_move(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_move); + struct roots_view *view = roots_xdg_surface->view; + struct roots_input *input = view->desktop->server->input; + struct wlr_xdg_toplevel_move_event *e = data; + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + // TODO verify event serial + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { + return; + } + roots_seat_begin_move(seat, view); +} + +static void handle_request_resize(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_resize); + struct roots_view *view = roots_xdg_surface->view; + struct roots_input *input = view->desktop->server->input; + struct wlr_xdg_toplevel_resize_event *e = data; + // TODO verify event serial + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + assert(seat); + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { + return; + } + roots_seat_begin_resize(seat, view, e->edges); +} + +static void handle_request_maximize(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_maximize); + struct roots_view *view = roots_xdg_surface->view; + struct wlr_xdg_surface *surface = view->xdg_surface; + + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + view_maximize(view, surface->toplevel_state->next.maximized); +} + +static void handle_request_fullscreen(struct wl_listener *listener, + void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_fullscreen); + struct roots_view *view = roots_xdg_surface->view; + struct wlr_xdg_surface *surface = view->xdg_surface; + struct wlr_xdg_toplevel_set_fullscreen_event *e = data; + + if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + return; + } + + view_set_fullscreen(view, e->fullscreen, e->output); +} + +static void handle_surface_commit(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_surface = + wl_container_of(listener, roots_surface, surface_commit); + struct roots_view *view = roots_surface->view; + struct wlr_xdg_surface *surface = view->xdg_surface; + + view_apply_damage(view); + + struct wlr_box size; + get_size(view, &size); + view_update_size(view, size.width, size.height); + + uint32_t pending_serial = + roots_surface->pending_move_resize_configure_serial; + if (pending_serial > 0 && pending_serial >= surface->configure_serial) { + double x = view->x; + double y = view->y; + if (view->pending_move_resize.update_x) { + x = view->pending_move_resize.x + view->pending_move_resize.width - + size.width; + } + if (view->pending_move_resize.update_y) { + y = view->pending_move_resize.y + view->pending_move_resize.height - + size.height; + } + view_update_position(view, x, y); + + if (pending_serial == surface->configure_serial) { + roots_surface->pending_move_resize_configure_serial = 0; + } + } +} + +static void handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + popup_create(roots_xdg_surface->view, wlr_popup); +} + +static void handle_destroy(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, destroy); + wl_list_remove(&roots_xdg_surface->surface_commit.link); + wl_list_remove(&roots_xdg_surface->destroy.link); + wl_list_remove(&roots_xdg_surface->new_popup.link); + wl_list_remove(&roots_xdg_surface->request_move.link); + wl_list_remove(&roots_xdg_surface->request_resize.link); + wl_list_remove(&roots_xdg_surface->request_maximize.link); + wl_list_remove(&roots_xdg_surface->request_fullscreen.link); + wl_list_remove(&roots_xdg_surface->view->link); + view_finish(roots_xdg_surface->view); + free(roots_xdg_surface->view); + free(roots_xdg_surface); +} + +void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { + struct wlr_xdg_surface *surface = data; + assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE); + + if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + wlr_log(L_DEBUG, "new xdg popup"); + return; + } + + struct roots_desktop *desktop = + wl_container_of(listener, desktop, xdg_shell_surface); + + wlr_log(L_DEBUG, "new xdg toplevel: title=%s, app_id=%s", + surface->title, surface->app_id); + wlr_xdg_surface_ping(surface); + + struct roots_xdg_surface *roots_surface = + calloc(1, sizeof(struct roots_xdg_surface)); + if (!roots_surface) { + return; + } + roots_surface->surface_commit.notify = handle_surface_commit; + wl_signal_add(&surface->surface->events.commit, + &roots_surface->surface_commit); + roots_surface->destroy.notify = handle_destroy; + wl_signal_add(&surface->events.destroy, &roots_surface->destroy); + roots_surface->request_move.notify = handle_request_move; + wl_signal_add(&surface->events.request_move, &roots_surface->request_move); + roots_surface->request_resize.notify = handle_request_resize; + wl_signal_add(&surface->events.request_resize, + &roots_surface->request_resize); + roots_surface->request_maximize.notify = handle_request_maximize; + wl_signal_add(&surface->events.request_maximize, + &roots_surface->request_maximize); + roots_surface->request_fullscreen.notify = handle_request_fullscreen; + wl_signal_add(&surface->events.request_fullscreen, + &roots_surface->request_fullscreen); + roots_surface->new_popup.notify = handle_new_popup; + wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); + + struct roots_view *view = calloc(1, sizeof(struct roots_view)); + if (!view) { + free(roots_surface); + return; + } + view->type = ROOTS_XDG_SHELL_VIEW; + + view->xdg_surface = surface; + view->roots_xdg_surface = roots_surface; + view->wlr_surface = surface->surface; + view->activate = activate; + view->resize = resize; + view->move_resize = move_resize; + view->maximize = maximize; + view->set_fullscreen = set_fullscreen; + view->close = close; + roots_surface->view = view; + + struct wlr_box box; + get_size(view, &box); + view->width = box.width; + view->height = box.height; + + view_init(view, desktop); + wl_list_insert(&desktop->views, &view->link); + + view_setup(view); +} diff --git a/types/meson.build b/types/meson.build index 2731f9bc..3e40be02 100644 --- a/types/meson.build +++ b/types/meson.build @@ -26,7 +26,8 @@ lib_wlr_types = static_library( 'wlr_wl_shell.c', 'wlr_xcursor_manager.c', 'wlr_xdg_shell_v6.c', + 'wlr_xdg_shell.c', ), include_directories: wlr_inc, - dependencies: [wayland_server, pixman, wlr_protos], + dependencies: [pixman, xkbcommon, wayland_server, wlr_protos], ) diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 925e0019..008f2e51 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -7,13 +7,21 @@ #include <wlr/util/log.h> #include "util/signal.h" +static const struct wl_compositor_interface wl_compositor_impl; + +static struct wlr_compositor *compositor_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_compositor_interface, + &wl_compositor_impl)); + return wl_resource_get_user_data(resource); +} + static void destroy_surface_listener(struct wl_listener *listener, void *data) { wl_list_remove(wl_resource_get_link(data)); } static void wl_compositor_create_surface(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - struct wlr_compositor *compositor = wl_resource_get_user_data(resource); + struct wlr_compositor *compositor = compositor_from_resource(resource); struct wl_resource *surface_resource = wl_resource_create(client, &wl_surface_interface, wl_resource_get_version(resource), id); @@ -44,13 +52,13 @@ static void wl_compositor_create_region(struct wl_client *client, wlr_region_create(client, resource, id); } -struct wl_compositor_interface wl_compositor_impl = { +static const struct wl_compositor_interface wl_compositor_impl = { .create_surface = wl_compositor_create_surface, .create_region = wl_compositor_create_region }; static void wl_compositor_destroy(struct wl_resource *resource) { - struct wlr_compositor *compositor = wl_resource_get_user_data(resource); + struct wlr_compositor *compositor = compositor_from_resource(resource); struct wl_resource *_resource = NULL; wl_resource_for_each(_resource, &compositor->wl_resources) { if (_resource == resource) { @@ -96,8 +104,8 @@ static void subcompositor_get_subsurface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource) { - struct wlr_surface *surface = wl_resource_get_user_data(surface_resource); - struct wlr_surface *parent = wl_resource_get_user_data(parent_resource); + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); + struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); static const char msg[] = "get_subsurface: wl_subsurface@"; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index b8ef820b..50c94bc5 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -14,6 +14,24 @@ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) +static const struct wl_data_offer_interface data_offer_impl; + +static struct wlr_data_offer *data_offer_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_data_offer_interface, + &data_offer_impl)); + return wl_resource_get_user_data(resource); +} + +static const struct wl_data_source_interface data_source_impl; + +static struct client_data_source *client_data_source_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_data_source_interface, + &data_source_impl)); + return wl_resource_get_user_data(resource); +} + static uint32_t data_offer_choose_action(struct wlr_data_offer *offer) { uint32_t offer_actions, preferred_action = 0; if (wl_resource_get_version(offer->resource) >= @@ -78,7 +96,7 @@ static void data_offer_update_action(struct wlr_data_offer *offer) { static void data_offer_accept(struct wl_client *client, struct wl_resource *resource, uint32_t serial, const char *mime_type) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (!offer->source || offer != offer->source->offer) { return; @@ -94,7 +112,7 @@ static void data_offer_accept(struct wl_client *client, static void data_offer_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (offer->source && offer == offer->source->offer) { offer->source->send(offer->source, mime_type, fd); @@ -126,7 +144,7 @@ static void data_source_notify_finish(struct wlr_data_source *source) { static void data_offer_finish(struct wl_client *client, struct wl_resource *resource) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (!offer->source || offer->source->offer != offer) { return; @@ -138,7 +156,7 @@ static void data_offer_finish(struct wl_client *client, static void data_offer_set_actions(struct wl_client *client, struct wl_resource *resource, uint32_t actions, uint32_t preferred_action) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (actions & ~ALL_ACTIONS) { wl_resource_post_error(offer->resource, @@ -162,7 +180,7 @@ static void data_offer_set_actions(struct wl_client *client, } static void data_offer_resource_destroy(struct wl_resource *resource) { - struct wlr_data_offer *offer = wl_resource_get_user_data(resource); + struct wlr_data_offer *offer = data_offer_from_resource(resource); if (!offer->source) { goto out; @@ -332,16 +350,25 @@ void wlr_seat_set_selection(struct wlr_seat *seat, } } +static const struct wl_data_device_interface data_device_impl; + +static struct wlr_seat_client *seat_client_from_data_device_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_data_device_interface, + &data_device_impl)); + return wl_resource_get_user_data(resource); +} + static void data_device_set_selection(struct wl_client *client, - struct wl_resource *dd_resource, struct wl_resource *source_resource, - uint32_t serial) { + struct wl_resource *device_resource, + struct wl_resource *source_resource, uint32_t serial) { struct client_data_source *source = NULL; if (source_resource != NULL) { - source = wl_resource_get_user_data(source_resource); + source = client_data_source_from_resource(source_resource); } struct wlr_seat_client *seat_client = - wl_resource_get_user_data(dd_resource); + seat_client_from_data_device_resource(device_resource); struct wlr_data_source *wlr_source = (struct wlr_data_source *)source; wlr_seat_set_selection(seat_client->seat, wlr_source, serial); @@ -783,17 +810,19 @@ static void data_device_start_drag(struct wl_client *client, struct wl_resource *origin_resource, struct wl_resource *icon_resource, uint32_t serial) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(device_resource); - struct wlr_surface *origin = wl_resource_get_user_data(origin_resource); + seat_client_from_data_device_resource(device_resource); + struct wlr_surface *origin = wlr_surface_from_resource(origin_resource); struct wlr_data_source *source = NULL; struct wlr_surface *icon = NULL; if (source_resource) { - source = wl_resource_get_user_data(source_resource); + struct client_data_source *client_source = + client_data_source_from_resource(source_resource); + source = (struct wlr_data_source *)client_source; } if (icon_resource) { - icon = wl_resource_get_user_data(icon_resource); + icon = wlr_surface_from_resource(icon_resource); } if (icon) { if (wlr_surface_set_role(icon, "wl_data_device-icon", @@ -876,7 +905,7 @@ static void data_source_destroy(struct wl_client *client, static void data_source_set_actions(struct wl_client *client, struct wl_resource *resource, uint32_t dnd_actions) { struct client_data_source *source = - wl_resource_get_user_data(resource); + client_data_source_from_resource(resource); if (source->source.actions >= 0) { wl_resource_post_error(source->resource, @@ -905,7 +934,8 @@ static void data_source_set_actions(struct wl_client *client, static void data_source_offer(struct wl_client *client, struct wl_resource *resource, const char *mime_type) { - struct client_data_source *source = wl_resource_get_user_data(resource); + struct client_data_source *source = + client_data_source_from_resource(resource); char **p = wl_array_add(&source->source.mime_types, sizeof(*p)); if (p) { @@ -919,14 +949,15 @@ static void data_source_offer(struct wl_client *client, } } -static struct wl_data_source_interface data_source_impl = { +static const struct wl_data_source_interface data_source_impl = { .offer = data_source_offer, .destroy = data_source_destroy, .set_actions = data_source_set_actions, }; static void data_source_resource_handle_destroy(struct wl_resource *resource) { - struct client_data_source *source = wl_resource_get_user_data(resource); + struct client_data_source *source = + client_data_source_from_resource(resource); wlr_data_source_finish(&source->source); free(source); } @@ -956,7 +987,7 @@ void data_device_manager_get_data_device(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); struct wl_resource *resource = wl_resource_create(client, &wl_data_device_interface, wl_resource_get_version(manager_resource), diff --git a/types/wlr_gamma_control.c b/types/wlr_gamma_control.c index 861427bd..61c058c4 100644 --- a/types/wlr_gamma_control.c +++ b/types/wlr_gamma_control.c @@ -23,9 +23,18 @@ static void gamma_control_destroy(struct wlr_gamma_control *gamma_control) { free(gamma_control); } +static const struct gamma_control_interface gamma_control_impl; + +struct wlr_gamma_control *gamma_control_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &gamma_control_interface, + &gamma_control_impl)); + return wl_resource_get_user_data(resource); +} + static void gamma_control_destroy_resource(struct wl_resource *resource) { struct wlr_gamma_control *gamma_control = - wl_resource_get_user_data(resource); + gamma_control_from_resource(resource); gamma_control_destroy(gamma_control); } @@ -40,7 +49,7 @@ static void gamma_control_set_gamma(struct wl_client *client, struct wl_resource *gamma_control_resource, struct wl_array *red, struct wl_array *green, struct wl_array *blue) { struct wlr_gamma_control *gamma_control = - wl_resource_get_user_data(gamma_control_resource); + gamma_control_from_resource(gamma_control_resource); if (red->size != green->size || red->size != blue->size) { wl_resource_post_error(gamma_control_resource, @@ -68,12 +77,21 @@ static const struct gamma_control_interface gamma_control_impl = { .reset_gamma = gamma_control_reset_gamma, }; +static const struct gamma_control_manager_interface gamma_control_manager_impl; + +struct wlr_gamma_control_manager *gamma_control_manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &gamma_control_manager_interface, + &gamma_control_manager_impl)); + return wl_resource_get_user_data(resource); +} + static void gamma_control_manager_get_gamma_control(struct wl_client *client, struct wl_resource *gamma_control_manager_resource, uint32_t id, struct wl_resource *output_resource) { struct wlr_gamma_control_manager *manager = - wl_resource_get_user_data(gamma_control_manager_resource); - struct wlr_output *output = wl_resource_get_user_data(output_resource); + gamma_control_manager_from_resource(gamma_control_manager_resource); + struct wlr_output *output = wlr_output_from_resource(output_resource); struct wlr_gamma_control *gamma_control = calloc(1, sizeof(struct wlr_gamma_control)); @@ -109,7 +127,7 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client, wlr_output_get_gamma_size(output)); } -static struct gamma_control_manager_interface gamma_control_manager_impl = { +static const struct gamma_control_manager_interface gamma_control_manager_impl = { .get_gamma_control = gamma_control_manager_get_gamma_control, }; diff --git a/types/wlr_idle.c b/types/wlr_idle.c index 9eddc42b..51963aea 100644 --- a/types/wlr_idle.c +++ b/types/wlr_idle.c @@ -7,6 +7,15 @@ #include "idle-protocol.h" #include "util/signal.h" +static const struct org_kde_kwin_idle_timeout_interface idle_timeout_impl; + +static struct wlr_idle_timeout *idle_timeout_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &org_kde_kwin_idle_timeout_interface, &idle_timeout_impl)); + return wl_resource_get_user_data(resource); +} + static void idle_timeout_destroy(struct wlr_idle_timeout *timer) { wl_list_remove(&timer->input_listener.link); wl_list_remove(&timer->seat_destroy.link); @@ -34,7 +43,7 @@ static void handle_activity(struct wlr_idle_timeout *timer) { } static void handle_timer_resource_destroy(struct wl_resource *timer_resource) { - struct wlr_idle_timeout *timer = wl_resource_get_user_data(timer_resource); + struct wlr_idle_timeout *timer = idle_timeout_from_resource(timer_resource); if (timer != NULL) { idle_timeout_destroy(timer); } @@ -54,17 +63,27 @@ static void release_idle_timeout(struct wl_client *client, static void simulate_activity(struct wl_client *client, struct wl_resource *resource){ - struct wlr_idle_timeout *timer = wl_resource_get_user_data(resource); + struct wlr_idle_timeout *timer = idle_timeout_from_resource(resource); handle_activity(timer); } -static struct org_kde_kwin_idle_timeout_interface idle_timeout_impl = { +static const struct org_kde_kwin_idle_timeout_interface idle_timeout_impl = { .release = release_idle_timeout, .simulate_user_activity = simulate_activity, }; +static const struct org_kde_kwin_idle_interface idle_impl; + +static struct wlr_idle *idle_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &org_kde_kwin_idle_interface, + &idle_impl)); + return wl_resource_get_user_data(resource); +} + static void handle_input_notification(struct wl_listener *listener, void *data) { - struct wlr_idle_timeout *timer = wl_container_of(listener, timer, input_listener); + struct wlr_idle_timeout *timer = + wl_container_of(listener, timer, input_listener); struct wlr_seat *seat = data; if (timer->seat == seat) { handle_activity(timer); @@ -72,13 +91,11 @@ static void handle_input_notification(struct wl_listener *listener, void *data) } static void create_idle_timer(struct wl_client *client, - struct wl_resource *idle_resource, - uint32_t id, - struct wl_resource *seat_resource, - uint32_t timeout) { - struct wlr_idle *idle = wl_resource_get_user_data(idle_resource); + struct wl_resource *idle_resource, uint32_t id, + struct wl_resource *seat_resource, uint32_t timeout) { + struct wlr_idle *idle = idle_from_resource(idle_resource); struct wlr_seat_client *client_seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); struct wlr_idle_timeout *timer = calloc(1, sizeof(struct wlr_idle_timeout)); @@ -122,7 +139,7 @@ static void create_idle_timer(struct wl_client *client, wl_event_source_timer_update(timer->idle_source, timer->timeout); } -static struct org_kde_kwin_idle_interface idle_impl = { +static const struct org_kde_kwin_idle_interface idle_impl = { .get_idle_timeout = create_idle_timer, }; diff --git a/types/wlr_output.c b/types/wlr_output.c index 504d0209..809b1959 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -17,7 +17,7 @@ static void wl_output_send_to_resource(struct wl_resource *resource) { assert(resource); - struct wlr_output *output = wl_resource_get_user_data(resource); + struct wlr_output *output = wlr_output_from_resource(resource); assert(output); const uint32_t version = wl_resource_get_version(resource); if (version >= WL_OUTPUT_GEOMETRY_SINCE_VERSION) { @@ -53,7 +53,7 @@ static void wl_output_send_to_resource(struct wl_resource *resource) { static void wlr_output_send_current_mode_to_resource( struct wl_resource *resource) { assert(resource); - struct wlr_output *output = wl_resource_get_user_data(resource); + struct wlr_output *output = wlr_output_from_resource(resource); assert(output); const uint32_t version = wl_resource_get_version(resource); if (version < WL_OUTPUT_MODE_SINCE_VERSION) { @@ -75,7 +75,7 @@ static void wlr_output_send_current_mode_to_resource( } static void wl_output_destroy(struct wl_resource *resource) { - struct wlr_output *output = wl_resource_get_user_data(resource); + struct wlr_output *output = wlr_output_from_resource(resource); struct wl_resource *_resource = NULL; wl_resource_for_each(_resource, &output->wl_resources) { if (_resource == resource) { @@ -648,6 +648,12 @@ void wlr_output_set_fullscreen_surface(struct wlr_output *output, &output->fullscreen_surface_destroy); } +struct wlr_output *wlr_output_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_output_interface, + &wl_output_impl)); + return wl_resource_get_user_data(resource); +} + static void output_cursor_damage_whole(struct wlr_output_cursor *cursor) { struct wlr_box box; diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index 28fe63c1..9c267405 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -1,18 +1,26 @@ #define _XOPEN_SOURCE 700 #include <assert.h> -#include <gtk-primary-selection-protocol.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <wlr/types/wlr_primary_selection.h> #include <wlr/types/wlr_seat.h> #include <wlr/util/log.h> +#include "gtk-primary-selection-protocol.h" #include "util/signal.h" +static const struct gtk_primary_selection_offer_interface offer_impl; + +static struct wlr_primary_selection_offer *offer_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + >k_primary_selection_offer_interface, &offer_impl)); + return wl_resource_get_user_data(resource); +} + static void offer_handle_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - struct wlr_primary_selection_offer *offer = - wl_resource_get_user_data(resource); + struct wlr_primary_selection_offer *offer = offer_from_resource(resource); if (offer->source && offer == offer->source->offer) { offer->source->send(offer->source, mime_type, fd); @@ -32,8 +40,7 @@ static const struct gtk_primary_selection_offer_interface offer_impl = { }; static void offer_resource_handle_destroy(struct wl_resource *resource) { - struct wlr_primary_selection_offer *offer = - wl_resource_get_user_data(resource); + struct wlr_primary_selection_offer *offer = offer_from_resource(resource); if (!offer->source) { goto out; @@ -122,9 +129,19 @@ static struct wlr_primary_selection_offer *source_send_offer( return offer; } +static const struct gtk_primary_selection_source_interface source_impl; + +static struct client_data_source *client_data_source_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + >k_primary_selection_source_interface, &source_impl)); + return wl_resource_get_user_data(resource); +} + static void source_handle_offer(struct wl_client *client, struct wl_resource *resource, const char *mime_type) { - struct client_data_source *source = wl_resource_get_user_data(resource); + struct client_data_source *source = + client_data_source_from_resource(resource); char **p = wl_array_add(&source->source.mime_types, sizeof(*p)); if (p) { @@ -150,7 +167,7 @@ static const struct gtk_primary_selection_source_interface source_impl = { static void source_resource_handle_destroy(struct wl_resource *resource) { struct client_data_source *source = - wl_resource_get_user_data(resource); + client_data_source_from_resource(resource); wlr_primary_selection_source_finish(&source->source); free(source); } @@ -241,11 +258,11 @@ static void device_handle_set_selection(struct wl_client *client, uint32_t serial) { struct client_data_source *source = NULL; if (source_resource != NULL) { - source = wl_resource_get_user_data(source_resource); + source = client_data_source_from_resource(source_resource); } struct wlr_seat_client *seat_client = - wl_resource_get_user_data(resource); + wlr_seat_client_from_resource(resource); struct wlr_primary_selection_source *wlr_source = (struct wlr_primary_selection_source *)source; @@ -317,7 +334,7 @@ void device_manager_handle_get_device(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); uint32_t version = wl_resource_get_version(manager_resource); struct wl_resource *resource = wl_resource_create(client, diff --git a/types/wlr_region.c b/types/wlr_region.c index 322088b5..6309c1a9 100644 --- a/types/wlr_region.c +++ b/types/wlr_region.c @@ -3,16 +3,17 @@ #include <stdio.h> #include <stdlib.h> #include <wayland-server.h> +#include <wlr/types/wlr_region.h> static void region_add(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - pixman_region32_t *region = wl_resource_get_user_data(resource); + pixman_region32_t *region = wlr_region_from_resource(resource); pixman_region32_union_rect(region, region, x, y, width, height); } static void region_subtract(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - pixman_region32_t *region = wl_resource_get_user_data(resource); + pixman_region32_t *region = wlr_region_from_resource(resource); pixman_region32_union_rect(region, region, x, y, width, height); pixman_region32_t rect; @@ -25,14 +26,14 @@ static void region_destroy(struct wl_client *client, struct wl_resource *resourc wl_resource_destroy(resource); } -static const struct wl_region_interface region_interface = { +static const struct wl_region_interface region_impl = { .destroy = region_destroy, .add = region_add, .subtract = region_subtract, }; static void destroy_region(struct wl_resource *resource) { - pixman_region32_t *reg = wl_resource_get_user_data(resource); + pixman_region32_t *reg = wlr_region_from_resource(resource); pixman_region32_fini(reg); free(reg); } @@ -54,6 +55,12 @@ void wlr_region_create(struct wl_client *client, struct wl_resource *res, wl_resource_post_no_memory(res); return; } - wl_resource_set_implementation(region_resource, ®ion_interface, region, + wl_resource_set_implementation(region_resource, ®ion_impl, region, destroy_region); } + +pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_region_interface, + ®ion_impl)); + return wl_resource_get_user_data(resource); +} diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index 04757fb6..e756b6aa 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -9,6 +9,13 @@ #include <wlr/util/log.h> #include "screenshooter-protocol.h" +static struct wlr_screenshot *screenshot_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &orbital_screenshot_interface, + NULL)); + return wl_resource_get_user_data(resource); +} + struct screenshot_state { struct wl_shm_buffer *shm_buffer; struct wlr_screenshot *screenshot; @@ -24,7 +31,7 @@ static void screenshot_destroy(struct wlr_screenshot *screenshot) { static void handle_screenshot_resource_destroy( struct wl_resource *screenshot_resource) { struct wlr_screenshot *screenshot = - wl_resource_get_user_data(screenshot_resource); + screenshot_from_resource(screenshot_resource); if (screenshot != NULL) { screenshot_destroy(screenshot); } @@ -59,13 +66,22 @@ cleanup: free(state); } +static const struct orbital_screenshooter_interface screenshooter_impl; + +static struct wlr_screenshooter *screenshooter_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &orbital_screenshooter_interface, + &screenshooter_impl)); + return wl_resource_get_user_data(resource); +} + static void screenshooter_shoot(struct wl_client *client, struct wl_resource *screenshooter_resource, uint32_t id, struct wl_resource *output_resource, struct wl_resource *buffer_resource) { struct wlr_screenshooter *screenshooter = - wl_resource_get_user_data(screenshooter_resource); - struct wlr_output *output = wl_resource_get_user_data(output_resource); + screenshooter_from_resource(screenshooter_resource); + struct wlr_output *output = wlr_output_from_resource(output_resource); struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); if (renderer == NULL) { @@ -133,7 +149,7 @@ static void screenshooter_shoot(struct wl_client *client, wlr_output_schedule_frame(output); } -static struct orbital_screenshooter_interface screenshooter_impl = { +static const struct orbital_screenshooter_interface screenshooter_impl = { .shoot = screenshooter_shoot, }; diff --git a/types/wlr_seat.c b/types/wlr_seat.c index d60e0e0d..93f6d872 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -23,15 +23,24 @@ static void pointer_send_frame(struct wl_resource *resource) { } } +static const struct wl_pointer_interface wl_pointer_impl; + +static struct wlr_seat_client *seat_client_from_pointer_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_pointer_interface, + &wl_pointer_impl)); + return wl_resource_get_user_data(resource); +} + static void wl_pointer_set_cursor(struct wl_client *client, struct wl_resource *pointer_resource, uint32_t serial, struct wl_resource *surface_resource, int32_t hotspot_x, int32_t hotspot_y) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(pointer_resource); + seat_client_from_pointer_resource(pointer_resource); struct wlr_surface *surface = NULL; if (surface_resource != NULL) { - surface = wl_resource_get_user_data(surface_resource); + surface = wlr_surface_from_resource(surface_resource); if (wlr_surface_set_role(surface, "wl_pointer-cursor", surface_resource, WL_POINTER_ERROR_ROLE) < 0) { @@ -67,7 +76,7 @@ static void wl_pointer_destroy(struct wl_resource *resource) { static void wl_seat_get_pointer(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { return; } @@ -126,7 +135,7 @@ static void seat_client_send_repeat_info(struct wlr_seat_client *client, static void wl_seat_get_keyboard(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { return; } @@ -160,7 +169,7 @@ static void wl_touch_destroy(struct wl_resource *resource) { static void wl_seat_get_touch(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) { return; } @@ -177,7 +186,8 @@ static void wl_seat_get_touch(struct wl_client *client, } static void wlr_seat_client_resource_destroy(struct wl_resource *seat_resource) { - struct wlr_seat_client *client = wl_resource_get_user_data(seat_resource); + struct wlr_seat_client *client = + wlr_seat_client_from_resource(seat_resource); wlr_signal_emit_safe(&client->events.destroy, client); if (client == client->seat->pointer_state.focused_client) { @@ -1250,3 +1260,10 @@ bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) { return serial == seat->pointer_state.grab_serial || serial == seat->touch_state.grab_serial; } + +struct wlr_seat_client *wlr_seat_client_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_seat_interface, + &wl_seat_impl)); + return wl_resource_get_user_data(resource); +} diff --git a/types/wlr_server_decoration.c b/types/wlr_server_decoration.c index 556193e2..6d332033 100644 --- a/types/wlr_server_decoration.c +++ b/types/wlr_server_decoration.c @@ -1,11 +1,21 @@ #include <assert.h> -#include <server-decoration-protocol.h> #include <stdlib.h> #include <wlr/types/wlr_server_decoration.h> #include <wlr/types/wlr_surface.h> #include <wlr/util/log.h> +#include "server-decoration-protocol.h" #include "util/signal.h" +static const struct org_kde_kwin_server_decoration_interface + server_decoration_impl; + +static struct wlr_server_decoration *decoration_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &org_kde_kwin_server_decoration_interface, &server_decoration_impl)); + return wl_resource_get_user_data(resource); +} + static void server_decoration_handle_release(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -14,7 +24,7 @@ static void server_decoration_handle_release(struct wl_client *client, static void server_decoration_handle_request_mode(struct wl_client *client, struct wl_resource *resource, uint32_t mode) { struct wlr_server_decoration *decoration = - wl_resource_get_user_data(resource); + decoration_from_resource(resource); if (decoration->mode == mode) { return; } @@ -35,7 +45,7 @@ static void server_decoration_destroy( static void server_decoration_destroy_resource(struct wl_resource *resource) { struct wlr_server_decoration *decoration = - wl_resource_get_user_data(resource); + decoration_from_resource(resource); if (decoration != NULL) { server_decoration_destroy(decoration); } @@ -49,17 +59,28 @@ static void server_decoration_handle_surface_destroy( } static const struct org_kde_kwin_server_decoration_interface -server_decoration_impl = { + server_decoration_impl = { .release = server_decoration_handle_release, .request_mode = server_decoration_handle_request_mode, }; +static const struct org_kde_kwin_server_decoration_manager_interface + server_decoration_manager_impl; + +static struct wlr_server_decoration_manager *manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &org_kde_kwin_server_decoration_manager_interface, + &server_decoration_manager_impl)); + return wl_resource_get_user_data(resource); +} + static void server_decoration_manager_handle_create(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *surface_resource) { struct wlr_server_decoration_manager *manager = - wl_resource_get_user_data(manager_resource); - struct wlr_surface *surface = wl_resource_get_user_data(surface_resource); + manager_from_resource(manager_resource); + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); struct wlr_server_decoration *decoration = calloc(1, sizeof(struct wlr_server_decoration)); @@ -102,7 +123,7 @@ static void server_decoration_manager_handle_create(struct wl_client *client, } static const struct org_kde_kwin_server_decoration_manager_interface -server_decoration_manager_impl = { + server_decoration_manager_impl = { .create = server_decoration_manager_handle_create, }; diff --git a/types/wlr_surface.c b/types/wlr_surface.c index c47565c4..e2588167 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -4,6 +4,7 @@ #include <wlr/render/egl.h> #include <wlr/render/interface.h> #include <wlr/render/matrix.h> +#include <wlr/types/wlr_region.h> #include <wlr/types/wlr_surface.h> #include <wlr/util/log.h> #include <wlr/util/region.h> @@ -50,7 +51,7 @@ static void surface_destroy(struct wl_client *client, static void surface_attach(struct wl_client *client, struct wl_resource *resource, struct wl_resource *buffer, int32_t sx, int32_t sy) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_BUFFER; surface->pending->sx = sx; @@ -62,7 +63,7 @@ static void surface_attach(struct wl_client *client, static void surface_damage(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); if (width < 0 || height < 0) { return; } @@ -72,15 +73,21 @@ static void surface_damage(struct wl_client *client, x, y, width, height); } +static struct wlr_frame_callback *frame_callback_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_callback_interface, NULL)); + return wl_resource_get_user_data(resource); +} + static void destroy_frame_callback(struct wl_resource *resource) { - struct wlr_frame_callback *cb = wl_resource_get_user_data(resource); + struct wlr_frame_callback *cb = frame_callback_from_resource(resource); wl_list_remove(&cb->link); free(cb); } static void surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); struct wlr_frame_callback *cb = calloc(1, sizeof(struct wlr_frame_callback)); @@ -97,8 +104,8 @@ static void surface_frame(struct wl_client *client, return; } - wl_resource_set_implementation(cb->resource, - NULL, cb, destroy_frame_callback); + wl_resource_set_implementation(cb->resource, NULL, cb, + destroy_frame_callback); wl_list_insert(surface->pending->frame_callback_list.prev, &cb->link); @@ -108,13 +115,13 @@ static void surface_frame(struct wl_client *client, static void surface_set_opaque_region(struct wl_client *client, struct wl_resource *resource, struct wl_resource *region_resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); if ((surface->pending->invalid & WLR_SURFACE_INVALID_OPAQUE_REGION)) { pixman_region32_clear(&surface->pending->opaque); } surface->pending->invalid |= WLR_SURFACE_INVALID_OPAQUE_REGION; if (region_resource) { - pixman_region32_t *region = wl_resource_get_user_data(region_resource); + pixman_region32_t *region = wlr_region_from_resource(region_resource); pixman_region32_copy(&surface->pending->opaque, region); } else { pixman_region32_clear(&surface->pending->opaque); @@ -124,10 +131,10 @@ static void surface_set_opaque_region(struct wl_client *client, static void surface_set_input_region(struct wl_client *client, struct wl_resource *resource, struct wl_resource *region_resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_INPUT_REGION; if (region_resource) { - pixman_region32_t *region = wl_resource_get_user_data(region_resource); + pixman_region32_t *region = wlr_region_from_resource(region_resource); pixman_region32_copy(&surface->pending->input, region); } else { pixman_region32_init_rect(&surface->pending->input, @@ -465,7 +472,7 @@ static void wlr_subsurface_commit(struct wlr_subsurface *subsurface) { static void surface_commit(struct wl_client *client, struct wl_resource *resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); struct wlr_subsurface *subsurface = surface->subsurface; if (subsurface) { @@ -483,7 +490,7 @@ static void surface_commit(struct wl_client *client, static void surface_set_buffer_transform(struct wl_client *client, struct wl_resource *resource, int transform) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_TRANSFORM; surface->pending->transform = transform; } @@ -491,7 +498,7 @@ static void surface_set_buffer_transform(struct wl_client *client, static void surface_set_buffer_scale(struct wl_client *client, struct wl_resource *resource, int32_t scale) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_SCALE; surface->pending->scale = scale; } @@ -500,7 +507,7 @@ static void surface_damage_buffer(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); if (width < 0 || height < 0) { return; } @@ -523,6 +530,12 @@ const struct wl_surface_interface surface_interface = { .damage_buffer = surface_damage_buffer }; +struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_surface_interface, + &surface_interface)); + return wl_resource_get_user_data(resource); +} + static struct wlr_surface_state *wlr_surface_state_create() { struct wlr_surface_state *state = calloc(1, sizeof(struct wlr_surface_state)); @@ -578,7 +591,7 @@ void wlr_subsurface_destroy(struct wlr_subsurface *subsurface) { } static void destroy_surface(struct wl_resource *resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); wlr_signal_emit_safe(&surface->events.destroy, surface); if (surface->subsurface) { @@ -658,8 +671,17 @@ int wlr_surface_set_role(struct wlr_surface *surface, const char *role, return -1; } +static const struct wl_subsurface_interface subsurface_implementation; + +static struct wlr_subsurface *subsurface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_subsurface_interface, + &subsurface_implementation)); + return wl_resource_get_user_data(resource); +} + static void subsurface_resource_destroy(struct wl_resource *resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); if (subsurface) { wlr_subsurface_destroy(subsurface); @@ -673,7 +695,7 @@ static void subsurface_destroy(struct wl_client *client, static void subsurface_set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); struct wlr_surface *surface = subsurface->surface; surface->pending->invalid |= WLR_SURFACE_INVALID_SUBSURFACE_POSITION; @@ -698,10 +720,10 @@ static struct wlr_subsurface *subsurface_find_sibling( static void subsurface_place_above(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); struct wlr_surface *sibling_surface = - wl_resource_get_user_data(sibling_resource); + wlr_surface_from_resource(sibling_resource); struct wlr_subsurface *sibling = subsurface_find_sibling(subsurface, sibling_surface); @@ -722,10 +744,10 @@ static void subsurface_place_above(struct wl_client *client, static void subsurface_place_below(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); struct wlr_surface *sibling_surface = - wl_resource_get_user_data(sibling_resource); + wlr_surface_from_resource(sibling_resource); struct wlr_subsurface *sibling = subsurface_find_sibling(subsurface, sibling_surface); @@ -746,7 +768,7 @@ static void subsurface_place_below(struct wl_client *client, static void subsurface_set_sync(struct wl_client *client, struct wl_resource *resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); if (subsurface) { subsurface->synchronized = true; @@ -755,7 +777,7 @@ static void subsurface_set_sync(struct wl_client *client, static void subsurface_set_desync(struct wl_client *client, struct wl_resource *resource) { - struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource); + struct wlr_subsurface *subsurface = subsurface_from_resource(resource); if (subsurface && subsurface->synchronized) { subsurface->synchronized = false; diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index 85749ddd..cac64c44 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -94,10 +94,19 @@ static const struct wlr_pointer_grab_interface shell_pointer_grab_impl = { .axis = shell_pointer_grab_axis, }; +static const struct wl_shell_surface_interface shell_surface_impl; + +static struct wlr_wl_shell_surface *shell_surface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_shell_surface_interface, + &shell_surface_impl)); + return wl_resource_get_user_data(resource); +} + static void shell_surface_protocol_pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { wlr_log(L_DEBUG, "got shell surface pong"); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); if (surface->ping_serial != serial) { return; } @@ -109,9 +118,8 @@ static void shell_surface_protocol_pong(struct wl_client *client, static void shell_surface_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); + struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { wlr_log(L_DEBUG, "invalid serial for grab"); @@ -172,9 +180,8 @@ static void shell_surface_destroy_popup_state( static void shell_surface_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, enum wl_shell_surface_resize edges) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); + struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource); if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { wlr_log(L_DEBUG, "invalid serial for grab"); @@ -207,7 +214,7 @@ static void shell_surface_set_state(struct wlr_wl_shell_surface *surface, static void shell_surface_protocol_set_toplevel(struct wl_client *client, struct wl_resource *resource) { wlr_log(L_DEBUG, "got shell surface toplevel"); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); shell_surface_set_state(surface, WLR_WL_SHELL_SURFACE_STATE_TOPLEVEL, NULL, NULL); } @@ -243,9 +250,8 @@ static void shell_surface_protocol_set_transient(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource, int32_t x, int32_t y, enum wl_shell_surface_transient flags) { wlr_log(L_DEBUG, "got shell surface transient"); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_surface *parent = - wl_resource_get_user_data(parent_resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); + struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); // TODO: check if parent_resource == NULL? struct wlr_wl_shell_surface *wl_parent = @@ -275,10 +281,10 @@ static void shell_surface_protocol_set_fullscreen(struct wl_client *client, struct wl_resource *resource, enum wl_shell_surface_fullscreen_method method, uint32_t framerate, struct wl_resource *output_resource) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { - output = wl_resource_get_user_data(output_resource); + output = wlr_output_from_resource(output_resource); } shell_surface_set_state(surface, WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN, @@ -298,11 +304,10 @@ static void shell_surface_protocol_set_popup(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, struct wl_resource *parent_resource, int32_t x, int32_t y, enum wl_shell_surface_transient flags) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); struct wlr_seat_client *seat_client = - wl_resource_get_user_data(seat_resource); - struct wlr_surface *parent = - wl_resource_get_user_data(parent_resource); + wlr_seat_client_from_resource(seat_resource); + struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); struct wlr_wl_shell_popup_grab *grab = shell_popup_grab_from_seat(surface->shell, seat_client->seat); if (!grab) { @@ -355,10 +360,10 @@ static void shell_surface_protocol_set_popup(struct wl_client *client, static void shell_surface_protocol_set_maximized(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { - output = wl_resource_get_user_data(output_resource); + output = wlr_output_from_resource(output_resource); } shell_surface_set_state(surface, WLR_WL_SHELL_SURFACE_STATE_MAXIMIZED, @@ -375,7 +380,7 @@ static void shell_surface_protocol_set_maximized(struct wl_client *client, static void shell_surface_protocol_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { wlr_log(L_DEBUG, "new shell surface title: %s", title); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); char *tmp = strdup(title); if (tmp == NULL) { @@ -391,7 +396,7 @@ static void shell_surface_protocol_set_title(struct wl_client *client, static void shell_surface_protocol_set_class(struct wl_client *client, struct wl_resource *resource, const char *class) { wlr_log(L_DEBUG, "new shell surface class: %s", class); - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); char *tmp = strdup(class); if (tmp == NULL) { @@ -439,7 +444,7 @@ static void shell_surface_destroy(struct wlr_wl_shell_surface *surface) { } static void shell_surface_resource_destroy(struct wl_resource *resource) { - struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); + struct wlr_wl_shell_surface *surface = shell_surface_from_resource(resource); if (surface != NULL) { shell_surface_destroy(surface); } @@ -480,16 +485,24 @@ static int shell_surface_ping_timeout(void *user_data) { return 1; } +static const struct wl_shell_interface shell_impl; + +static struct wlr_wl_shell *shell_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_shell_interface, &shell_impl)); + return wl_resource_get_user_data(resource); +} + static void shell_protocol_get_shell_surface(struct wl_client *client, struct wl_resource *shell_resource, uint32_t id, struct wl_resource *surface_resource) { - struct wlr_surface *surface = wl_resource_get_user_data(surface_resource); + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); if (wlr_surface_set_role(surface, wlr_wl_shell_surface_role, shell_resource, WL_SHELL_ERROR_ROLE)) { return; } - struct wlr_wl_shell *wl_shell = wl_resource_get_user_data(shell_resource); + struct wlr_wl_shell *wl_shell = shell_from_resource(shell_resource); struct wlr_wl_shell_surface *wl_surface = calloc(1, sizeof(struct wlr_wl_shell_surface)); if (wl_surface == NULL) { @@ -548,7 +561,7 @@ static void shell_protocol_get_shell_surface(struct wl_client *client, wl_list_insert(&wl_shell->surfaces, &wl_surface->link); } -static struct wl_shell_interface shell_impl = { +static const struct wl_shell_interface shell_impl = { .get_shell_surface = shell_protocol_get_shell_surface }; diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c new file mode 100644 index 00000000..990926cf --- /dev/null +++ b/types/wlr_xdg_shell.c @@ -0,0 +1,1534 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-server.h> +#include <wlr/config.h> +#include <wlr/types/wlr_seat.h> +#include <wlr/types/wlr_surface.h> +#include <wlr/types/wlr_xdg_shell.h> +#include <wlr/util/log.h> +#include "util/signal.h" +#include "xdg-shell-protocol.h" + +static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; +static const char *wlr_desktop_xdg_popup_role = "xdg_popup"; + +struct wlr_xdg_positioner { + struct wl_resource *resource; + + struct wlr_box anchor_rect; + enum xdg_positioner_anchor anchor; + enum xdg_positioner_gravity gravity; + enum xdg_positioner_constraint_adjustment constraint_adjustment; + + struct { + int32_t width, height; + } size; + + struct { + int32_t x, y; + } offset; +}; + + +static void resource_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static struct wlr_xdg_surface *xdg_popup_grab_get_topmost( + struct wlr_xdg_popup_grab *grab) { + struct wlr_xdg_popup *popup; + wl_list_for_each(popup, &grab->popups, grab_link) { + return popup->base; + } + + return NULL; +} + +static void xdg_pointer_grab_end(struct wlr_seat_pointer_grab *grab) { + struct wlr_xdg_popup_grab *popup_grab = grab->data; + + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) { + xdg_popup_send_popup_done(popup->resource); + } + + wlr_seat_pointer_end_grab(grab->seat); +} + +static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab, + struct wlr_surface *surface, double sx, double sy) { + struct wlr_xdg_popup_grab *popup_grab = grab->data; + if (wl_resource_get_client(surface->resource) == popup_grab->client) { + wlr_seat_pointer_enter(grab->seat, surface, sx, sy); + } else { + wlr_seat_pointer_clear_focus(grab->seat); + } +} + +static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab, + uint32_t time, double sx, double sy) { + wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); +} + +static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab, + uint32_t time, uint32_t button, uint32_t state) { + uint32_t serial = + wlr_seat_pointer_send_button(grab->seat, time, button, state); + if (serial) { + return serial; + } else { + xdg_pointer_grab_end(grab); + return 0; + } +} + +static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab, + uint32_t time, enum wlr_axis_orientation orientation, double value) { + wlr_seat_pointer_send_axis(grab->seat, time, orientation, value); +} + +static void xdg_pointer_grab_cancel(struct wlr_seat_pointer_grab *grab) { + xdg_pointer_grab_end(grab); +} + +static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = { + .enter = xdg_pointer_grab_enter, + .motion = xdg_pointer_grab_motion, + .button = xdg_pointer_grab_button, + .cancel = xdg_pointer_grab_cancel, + .axis = xdg_pointer_grab_axis, +}; + +static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab, + struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes, + struct wlr_keyboard_modifiers *modifiers) { + // keyboard focus should remain on the popup +} + +static void xdg_keyboard_grab_key(struct wlr_seat_keyboard_grab *grab, uint32_t time, + uint32_t key, uint32_t state) { + wlr_seat_keyboard_send_key(grab->seat, time, key, state); +} + +static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab, + struct wlr_keyboard_modifiers *modifiers) { + wlr_seat_keyboard_send_modifiers(grab->seat, modifiers); +} + +static void xdg_keyboard_grab_cancel(struct wlr_seat_keyboard_grab *grab) { + wlr_seat_keyboard_end_grab(grab->seat); +} + +static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = { + .enter = xdg_keyboard_grab_enter, + .key = xdg_keyboard_grab_key, + .modifiers = xdg_keyboard_grab_modifiers, + .cancel = xdg_keyboard_grab_cancel, +}; + +static struct wlr_xdg_popup_grab *xdg_shell_popup_grab_from_seat( + struct wlr_xdg_shell *shell, struct wlr_seat *seat) { + struct wlr_xdg_popup_grab *xdg_grab; + wl_list_for_each(xdg_grab, &shell->popup_grabs, link) { + if (xdg_grab->seat == seat) { + return xdg_grab; + } + } + + xdg_grab = calloc(1, sizeof(struct wlr_xdg_popup_grab)); + if (!xdg_grab) { + return NULL; + } + + xdg_grab->pointer_grab.data = xdg_grab; + xdg_grab->pointer_grab.interface = &xdg_pointer_grab_impl; + xdg_grab->keyboard_grab.data = xdg_grab; + xdg_grab->keyboard_grab.interface = &xdg_keyboard_grab_impl; + + wl_list_init(&xdg_grab->popups); + + wl_list_insert(&shell->popup_grabs, &xdg_grab->link); + xdg_grab->seat = seat; + + return xdg_grab; +} + + +static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { + // TODO: probably need to ungrab before this event + wlr_signal_emit_safe(&surface->events.destroy, surface); + + if (surface->configure_idle) { + wl_event_source_remove(surface->configure_idle); + } + + struct wlr_xdg_surface_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + free(configure); + } + + if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + wl_resource_set_user_data(surface->toplevel_state->resource, NULL); + free(surface->toplevel_state); + } + + if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + wl_resource_set_user_data(surface->popup_state->resource, NULL); + + if (surface->popup_state->seat) { + struct wlr_xdg_popup_grab *grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + surface->popup_state->seat); + + struct wlr_xdg_surface *topmost = + xdg_popup_grab_get_topmost(grab); + + if (topmost != surface) { + wl_resource_post_error(surface->client->resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was destroyed while it was not the topmost " + "popup."); + } + + wl_list_remove(&surface->popup_state->grab_link); + + if (wl_list_empty(&grab->popups)) { + if (grab->seat->pointer_state.grab == &grab->pointer_grab) { + wlr_seat_pointer_end_grab(grab->seat); + } + if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) { + wlr_seat_keyboard_end_grab(grab->seat); + } + } + } + + wl_list_remove(&surface->popup_state->link); + free(surface->popup_state); + } + + wl_resource_set_user_data(surface->resource, NULL); + wl_list_remove(&surface->link); + wl_list_remove(&surface->surface_destroy_listener.link); + wlr_surface_set_role_committed(surface->surface, NULL, NULL); + free(surface->geometry); + free(surface->next_geometry); + free(surface->title); + free(surface->app_id); + free(surface); +} + + +static const struct xdg_positioner_interface xdg_positioner_implementation; + +static struct wlr_xdg_positioner *xdg_positioner_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_positioner_interface, + &xdg_positioner_implementation)); + return wl_resource_get_user_data(resource); +} + +static void xdg_positioner_destroy(struct wl_resource *resource) { + struct wlr_xdg_positioner *positioner = + xdg_positioner_from_resource(resource); + free(positioner); +} + +static void xdg_positioner_protocol_set_size(struct wl_client *client, + struct wl_resource *resource, int32_t width, int32_t height) { + struct wlr_xdg_positioner *positioner = + xdg_positioner_from_resource(resource); + + if (width < 1 || height < 1) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "width and height must be positive and non-zero"); + return; + } + + positioner->size.width = width; + positioner->size.height = height; +} + +static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y, int32_t width, + int32_t height) { + struct wlr_xdg_positioner *positioner = + xdg_positioner_from_resource(resource); + + if (width < 0 || height < 0) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "width and height must be positive"); + return; + } + + positioner->anchor_rect.x = x; + positioner->anchor_rect.y = y; + positioner->anchor_rect.width = width; + positioner->anchor_rect.height = height; +} + +static void xdg_positioner_protocol_set_anchor(struct wl_client *client, + struct wl_resource *resource, uint32_t anchor) { + struct wlr_xdg_positioner *positioner = + xdg_positioner_from_resource(resource); + + if (anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "invalid anchor value"); + return; + } + + positioner->anchor = anchor; +} + +static void xdg_positioner_protocol_set_gravity(struct wl_client *client, + struct wl_resource *resource, uint32_t gravity) { + struct wlr_xdg_positioner *positioner = + xdg_positioner_from_resource(resource); + + if (gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "invalid gravity value"); + return; + } + + positioner->gravity = gravity; +} + +static void xdg_positioner_protocol_set_constraint_adjustment( + struct wl_client *client, struct wl_resource *resource, + uint32_t constraint_adjustment) { + struct wlr_xdg_positioner *positioner = + xdg_positioner_from_resource(resource); + + positioner->constraint_adjustment = constraint_adjustment; +} + +static void xdg_positioner_protocol_set_offset(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y) { + struct wlr_xdg_positioner *positioner = + xdg_positioner_from_resource(resource); + + positioner->offset.x = x; + positioner->offset.y = y; +} + +static const struct xdg_positioner_interface + xdg_positioner_implementation = { + .destroy = resource_destroy, + .set_size = xdg_positioner_protocol_set_size, + .set_anchor_rect = xdg_positioner_protocol_set_anchor_rect, + .set_anchor = xdg_positioner_protocol_set_anchor, + .set_gravity = xdg_positioner_protocol_set_gravity, + .set_constraint_adjustment = + xdg_positioner_protocol_set_constraint_adjustment, + .set_offset = xdg_positioner_protocol_set_offset, +}; + +static void xdg_shell_create_positioner(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t id) { + struct wlr_xdg_positioner *positioner = + calloc(1, sizeof(struct wlr_xdg_positioner)); + if (positioner == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + /* set widths to detect improper usages of get_popup */ + positioner->size.width = -1; + positioner->anchor_rect.width = -1; + + positioner->resource = wl_resource_create(wl_client, + &xdg_positioner_interface, + wl_resource_get_version(resource), + id); + if (positioner->resource == NULL) { + free(positioner); + wl_client_post_no_memory(wl_client); + return; + } + + wl_resource_set_implementation(positioner->resource, + &xdg_positioner_implementation, + positioner, xdg_positioner_destroy); +} + +static struct wlr_box xdg_positioner_get_geometry( + struct wlr_xdg_positioner *positioner, + struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent) { + struct wlr_box geometry = { + .x = positioner->offset.x, + .y = positioner->offset.y, + .width = positioner->size.width, + .height = positioner->size.height, + }; + + switch (positioner->anchor) { + case XDG_POSITIONER_ANCHOR_TOP: + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + geometry.y += positioner->anchor_rect.y; + break; + case XDG_POSITIONER_ANCHOR_BOTTOM: + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + geometry.y += + positioner->anchor_rect.y + positioner->anchor_rect.height; + break; + default: + geometry.y += + positioner->anchor_rect.y + positioner->anchor_rect.height / 2; + break; + } + + switch (positioner->anchor) { + case XDG_POSITIONER_ANCHOR_LEFT: + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + geometry.x += positioner->anchor_rect.x; + break; + case XDG_POSITIONER_ANCHOR_RIGHT: + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; + break; + default: + geometry.x += + positioner->anchor_rect.x + positioner->anchor_rect.width / 2; + break; + } + + switch (positioner->gravity) { + case XDG_POSITIONER_GRAVITY_TOP: + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + geometry.y -= geometry.height; + break; + case XDG_POSITIONER_GRAVITY_BOTTOM: + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + geometry.y = geometry.y; + break; + default: + geometry.y -= geometry.height / 2; + break; + } + + switch (positioner->gravity) { + case XDG_POSITIONER_GRAVITY_LEFT: + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + geometry.x -= geometry.width; + break; + case XDG_POSITIONER_GRAVITY_RIGHT: + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + geometry.x = geometry.x; + break; + default: + geometry.x -= geometry.width / 2; + break; + } + + if (positioner->constraint_adjustment == + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE) { + return geometry; + } + + // TODO: add compositor policy configuration and the code here + + return geometry; +} + + +static const struct xdg_popup_interface xdg_popup_implementation; + +static struct wlr_xdg_surface *xdg_surface_from_xdg_popup_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_popup_interface, + &xdg_popup_implementation)); + return wl_resource_get_user_data(resource); +} + +static void xdg_popup_protocol_grab(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_popup_resource(resource); + struct wlr_seat_client *seat_client = + wlr_seat_client_from_resource(seat_resource); + + if (surface->popup_state->committed) { + wl_resource_post_error(surface->popup_state->resource, + XDG_POPUP_ERROR_INVALID_GRAB, + "xdg_popup is already mapped"); + return; + } + + struct wlr_xdg_popup_grab *popup_grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + seat_client->seat); + + struct wlr_xdg_surface *topmost = xdg_popup_grab_get_topmost(popup_grab); + bool parent_is_toplevel = + surface->popup_state->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; + + if ((topmost == NULL && !parent_is_toplevel) || + (topmost != NULL && topmost != surface->popup_state->parent)) { + wl_resource_post_error(surface->client->resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was not created on the topmost popup"); + return; + } + + popup_grab->client = surface->client->client; + surface->popup_state->seat = seat_client->seat; + + wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); + + wlr_seat_pointer_start_grab(seat_client->seat, + &popup_grab->pointer_grab); + wlr_seat_keyboard_start_grab(seat_client->seat, + &popup_grab->keyboard_grab); +} + +static const struct xdg_popup_interface xdg_popup_implementation = { + .destroy = resource_destroy, + .grab = xdg_popup_protocol_grab, +}; + +static void xdg_popup_resource_destroy(struct wl_resource *resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_popup_resource(resource); + if (surface != NULL) { + xdg_surface_destroy(surface); + } +} + +static const struct xdg_surface_interface xdg_surface_implementation; + +static struct wlr_xdg_surface *xdg_surface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_surface_interface, + &xdg_surface_implementation)); + return wl_resource_get_user_data(resource); +} + +static void xdg_surface_get_popup(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *parent_resource, + struct wl_resource *positioner_resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_resource(resource); + struct wlr_xdg_surface *parent = + xdg_surface_from_resource(parent_resource); + struct wlr_xdg_positioner *positioner = + xdg_positioner_from_resource(positioner_resource); + + if (positioner->size.width == -1 || positioner->anchor_rect.width == -1) { + wl_resource_post_error(resource, + XDG_WM_BASE_ERROR_INVALID_POSITIONER, + "positioner object is not complete"); + return; + } + + if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_popup_role, + resource, XDG_WM_BASE_ERROR_ROLE)) { + return; + } + + surface->popup_state = calloc(1, sizeof(struct wlr_xdg_popup)); + if (!surface->popup_state) { + wl_resource_post_no_memory(resource); + return; + } + + surface->popup_state->resource = + wl_resource_create(client, &xdg_popup_interface, + wl_resource_get_version(resource), id); + if (surface->popup_state->resource == NULL) { + free(surface->popup_state); + wl_resource_post_no_memory(resource); + return; + } + + surface->role = WLR_XDG_SURFACE_ROLE_POPUP; + surface->popup_state->base = surface; + surface->popup_state->parent = parent; + surface->popup_state->geometry = + xdg_positioner_get_geometry(positioner, surface, parent); + wl_list_insert(&parent->popups, &surface->popup_state->link); + + wl_resource_set_implementation(surface->popup_state->resource, + &xdg_popup_implementation, surface, + xdg_popup_resource_destroy); + + wlr_signal_emit_safe(&parent->events.new_popup, surface->popup_state); +} + + +static const struct xdg_toplevel_interface xdg_toplevel_implementation; + +static struct wlr_xdg_surface *xdg_surface_from_xdg_toplevel_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_toplevel_interface, + &xdg_toplevel_implementation)); + return wl_resource_get_user_data(resource); +} + +static void xdg_toplevel_protocol_set_parent(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *parent_resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + struct wlr_xdg_surface *parent = NULL; + + if (parent_resource != NULL) { + parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); + } + + surface->toplevel_state->parent = parent; +} + +static void xdg_toplevel_protocol_set_title(struct wl_client *client, + struct wl_resource *resource, const char *title) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + char *tmp; + + tmp = strdup(title); + if (tmp == NULL) { + return; + } + + free(surface->title); + surface->title = tmp; +} + +static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, + struct wl_resource *resource, const char *app_id) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + char *tmp; + + tmp = strdup(app_id); + if (tmp == NULL) { + return; + } + + free(surface->app_id); + surface->app_id = tmp; +} + +static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, int32_t x, int32_t y) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + struct wlr_seat_client *seat = + wlr_seat_client_from_resource(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { + wlr_log(L_DEBUG, "invalid serial for grab"); + return; + } + + struct wlr_xdg_toplevel_show_window_menu_event event = { + .surface = surface, + .seat = seat, + .serial = serial, + .x = x, + .y = y, + }; + + wlr_signal_emit_safe(&surface->events.request_show_window_menu, &event); +} + +static void xdg_toplevel_protocol_move(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + struct wlr_seat_client *seat = + wlr_seat_client_from_resource(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { + wlr_log(L_DEBUG, "invalid serial for grab"); + return; + } + + struct wlr_xdg_toplevel_move_event event = { + .surface = surface, + .seat = seat, + .serial = serial, + }; + + wlr_signal_emit_safe(&surface->events.request_move, &event); +} + +static void xdg_toplevel_protocol_resize(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, uint32_t edges) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + struct wlr_seat_client *seat = + wlr_seat_client_from_resource(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { + wlr_log(L_DEBUG, "invalid serial for grab"); + return; + } + + struct wlr_xdg_toplevel_resize_event event = { + .surface = surface, + .seat = seat, + .serial = serial, + .edges = edges, + }; + + wlr_signal_emit_safe(&surface->events.request_resize, &event); +} + +static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, + struct wl_resource *resource, int32_t width, int32_t height) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + surface->toplevel_state->next.max_width = width; + surface->toplevel_state->next.max_height = height; +} + +static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, + struct wl_resource *resource, int32_t width, int32_t height) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + surface->toplevel_state->next.min_width = width; + surface->toplevel_state->next.min_height = height; +} + +static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + surface->toplevel_state->next.maximized = true; + wlr_signal_emit_safe(&surface->events.request_maximize, surface); +} + +static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + surface->toplevel_state->next.maximized = false; + wlr_signal_emit_safe(&surface->events.request_maximize, surface); +} + +static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *output_resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + + struct wlr_output *output = NULL; + if (output_resource != NULL) { + output = wlr_output_from_resource(output_resource); + } + + surface->toplevel_state->next.fullscreen = true; + + struct wlr_xdg_toplevel_set_fullscreen_event event = { + .surface = surface, + .fullscreen = true, + .output = output, + }; + + wlr_signal_emit_safe(&surface->events.request_fullscreen, &event); +} + +static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + + surface->toplevel_state->next.fullscreen = false; + + struct wlr_xdg_toplevel_set_fullscreen_event event = { + .surface = surface, + .fullscreen = false, + .output = NULL, + }; + + wlr_signal_emit_safe(&surface->events.request_fullscreen, &event); +} + +static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + wlr_signal_emit_safe(&surface->events.request_minimize, surface); +} + +static const struct xdg_toplevel_interface xdg_toplevel_implementation = { + .destroy = resource_destroy, + .set_parent = xdg_toplevel_protocol_set_parent, + .set_title = xdg_toplevel_protocol_set_title, + .set_app_id = xdg_toplevel_protocol_set_app_id, + .show_window_menu = xdg_toplevel_protocol_show_window_menu, + .move = xdg_toplevel_protocol_move, + .resize = xdg_toplevel_protocol_resize, + .set_max_size = xdg_toplevel_protocol_set_max_size, + .set_min_size = xdg_toplevel_protocol_set_min_size, + .set_maximized = xdg_toplevel_protocol_set_maximized, + .unset_maximized = xdg_toplevel_protocol_unset_maximized, + .set_fullscreen = xdg_toplevel_protocol_set_fullscreen, + .unset_fullscreen = xdg_toplevel_protocol_unset_fullscreen, + .set_minimized = xdg_toplevel_protocol_set_minimized +}; + +static void xdg_surface_resource_destroy(struct wl_resource *resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_resource(resource); + if (surface != NULL) { + xdg_surface_destroy(surface); + } +} + +static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + if (surface != NULL) { + xdg_surface_destroy(surface); + } +} + +static void xdg_surface_get_toplevel(struct wl_client *client, + struct wl_resource *resource, uint32_t id) { + struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); + + if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, + resource, XDG_WM_BASE_ERROR_ROLE)) { + return; + } + + surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel)); + if (surface->toplevel_state == NULL) { + wl_resource_post_no_memory(resource); + return; + } + + surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; + surface->toplevel_state->base = surface; + + struct wl_resource *toplevel_resource = wl_resource_create(client, + &xdg_toplevel_interface, wl_resource_get_version(resource), id); + if (toplevel_resource == NULL) { + free(surface->toplevel_state); + wl_resource_post_no_memory(resource); + return; + } + + surface->toplevel_state->resource = toplevel_resource; + + wl_resource_set_implementation(toplevel_resource, + &xdg_toplevel_implementation, surface, + xdg_toplevel_resource_destroy); +} + +static void wlr_xdg_toplevel_ack_configure( + struct wlr_xdg_surface *surface, + struct wlr_xdg_surface_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->next = configure->state; + surface->toplevel_state->pending.width = 0; + surface->toplevel_state->pending.height = 0; +} + +static void xdg_surface_ack_configure(struct wl_client *client, + struct wl_resource *resource, uint32_t serial) { + struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); + + if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) { + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + return; + } + + bool found = false; + struct wlr_xdg_surface_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + if (configure->serial < serial) { + wl_list_remove(&configure->link); + free(configure); + } else if (configure->serial == serial) { + wl_list_remove(&configure->link); + found = true; + break; + } else { + break; + } + } + if (!found) { + wl_resource_post_error(surface->client->resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, + "wrong configure serial: %u", serial); + return; + } + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + wlr_xdg_toplevel_ack_configure(surface, configure); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + break; + } + + surface->configured = true; + surface->configure_serial = serial; + + free(configure); +} + +static void xdg_surface_set_window_geometry(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y, int32_t width, + int32_t height) { + struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); + + if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) { + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + return; + } + + surface->has_next_geometry = true; + surface->next_geometry->height = height; + surface->next_geometry->width = width; + surface->next_geometry->x = x; + surface->next_geometry->y = y; + +} + +static const struct xdg_surface_interface xdg_surface_implementation = { + .destroy = resource_destroy, + .get_toplevel = xdg_surface_get_toplevel, + .get_popup = xdg_surface_get_popup, + .ack_configure = xdg_surface_ack_configure, + .set_window_geometry = xdg_surface_set_window_geometry, +}; + +static bool wlr_xdg_surface_toplevel_state_compare( + struct wlr_xdg_toplevel *state) { + struct { + struct wlr_xdg_toplevel_state state; + uint32_t width, height; + } configured; + + // is pending state different from current state? + if (!state->base->configured) { + return false; + } + + if (wl_list_empty(&state->base->configure_list)) { + // last configure is actually the current state, just use it + configured.state = state->current; + configured.width = state->base->surface->current->width; + configured.height = state->base->surface->current->width; + } else { + struct wlr_xdg_surface_configure *configure = + wl_container_of(state->base->configure_list.prev, configure, link); + configured.state = configure->state; + configured.width = configure->state.width; + configured.height = configure->state.height; + } + + if (state->pending.activated != configured.state.activated) { + return false; + } + if (state->pending.fullscreen != configured.state.fullscreen) { + return false; + } + if (state->pending.maximized != configured.state.maximized) { + return false; + } + if (state->pending.resizing != configured.state.resizing) { + return false; + } + + if (state->pending.width == configured.width && + state->pending.height == configured.height) { + return true; + } + + if (state->pending.width == 0 && state->pending.height == 0) { + return true; + } + + return false; +} + +static void wlr_xdg_toplevel_send_configure( + struct wlr_xdg_surface *surface, + struct wlr_xdg_surface_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + uint32_t *s; + struct wl_array states; + + configure->state = surface->toplevel_state->pending; + + wl_array_init(&states); + if (surface->toplevel_state->pending.maximized) { + s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_MAXIMIZED; + } + if (surface->toplevel_state->pending.fullscreen) { + s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_FULLSCREEN; + } + if (surface->toplevel_state->pending.resizing) { + s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_RESIZING; + } + if (surface->toplevel_state->pending.activated) { + s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_ACTIVATED; + } + + uint32_t width = surface->toplevel_state->pending.width; + uint32_t height = surface->toplevel_state->pending.height; + + if (width == 0 || height == 0) { + width = surface->geometry->width; + height = surface->geometry->height; + } + + xdg_toplevel_send_configure(surface->toplevel_state->resource, width, + height, &states); + + wl_array_release(&states); + return; + +error_out: + wl_array_release(&states); + wl_resource_post_no_memory(surface->toplevel_state->resource); +} + +static void wlr_xdg_surface_send_configure(void *user_data) { + struct wlr_xdg_surface *surface = user_data; + + surface->configure_idle = NULL; + + struct wlr_xdg_surface_configure *configure = + calloc(1, sizeof(struct wlr_xdg_surface_configure)); + if (configure == NULL) { + wl_client_post_no_memory(surface->client->client); + return; + } + + wl_list_insert(surface->configure_list.prev, &configure->link); + configure->serial = surface->configure_next_serial; + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + wlr_xdg_toplevel_send_configure(surface, configure); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + xdg_popup_send_configure(surface->popup_state->resource, + surface->popup_state->geometry.x, + surface->popup_state->geometry.y, + surface->popup_state->geometry.width, + surface->popup_state->geometry.height); + break; + } + + xdg_surface_send_configure(surface->resource, configure->serial); +} + +static uint32_t wlr_xdg_surface_schedule_configure( + struct wlr_xdg_surface *surface) { + struct wl_display *display = wl_client_get_display(surface->client->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + bool pending_same = false; + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + pending_same = + wlr_xdg_surface_toplevel_state_compare(surface->toplevel_state); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + break; + } + + if (surface->configure_idle != NULL) { + if (!pending_same) { + // configure request already scheduled + return surface->configure_next_serial; + } + + // configure request not necessary anymore + wl_event_source_remove(surface->configure_idle); + surface->configure_idle = NULL; + return 0; + } else { + if (pending_same) { + // configure request not necessary + return 0; + } + + surface->configure_next_serial = wl_display_next_serial(display); + surface->configure_idle = wl_event_loop_add_idle(loop, + wlr_xdg_surface_send_configure, surface); + return surface->configure_next_serial; + } +} + +static void handle_wlr_surface_destroyed(struct wl_listener *listener, + void *data) { + struct wlr_xdg_surface *xdg_surface = + wl_container_of(listener, xdg_surface, surface_destroy_listener); + xdg_surface_destroy(xdg_surface); +} + +static void wlr_xdg_surface_toplevel_committed( + struct wlr_xdg_surface *surface) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + + if (!wlr_surface_has_buffer(surface->surface) + && !surface->toplevel_state->added) { + // on the first commit, send a configure request to tell the client it + // is added + wlr_xdg_surface_schedule_configure(surface); + surface->toplevel_state->added = true; + return; + } + + if (!wlr_surface_has_buffer(surface->surface)) { + return; + } + + surface->toplevel_state->current = surface->toplevel_state->next; +} + +static void wlr_xdg_surface_popup_committed( + struct wlr_xdg_surface *surface) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); + + if (!surface->popup_state->committed) { + wlr_xdg_surface_schedule_configure(surface); + surface->popup_state->committed = true; + } +} + +static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, + void *role_data) { + struct wlr_xdg_surface *surface = role_data; + + if (wlr_surface_has_buffer(surface->surface) && !surface->configured) { + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface has never been configured"); + return; + } + + if (surface->has_next_geometry) { + surface->has_next_geometry = false; + surface->geometry->x = surface->next_geometry->x; + surface->geometry->y = surface->next_geometry->y; + surface->geometry->width = surface->next_geometry->width; + surface->geometry->height = surface->next_geometry->height; + } + + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_NONE: + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + wlr_xdg_surface_toplevel_committed(surface); + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + wlr_xdg_surface_popup_committed(surface); + break; + } + + if (surface->configured && !surface->added) { + surface->added = true; + wlr_signal_emit_safe(&surface->client->shell->events.new_surface, surface); + } +} + +static const struct xdg_wm_base_interface xdg_shell_impl; + +static struct wlr_xdg_client *xdg_client_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &xdg_wm_base_interface, + &xdg_shell_impl)); + return wl_resource_get_user_data(resource); +} + +static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, + struct wl_resource *client_resource, uint32_t id, + struct wl_resource *surface_resource) { + struct wlr_xdg_client *client = + xdg_client_from_resource(client_resource); + + struct wlr_xdg_surface *surface; + if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface)))) { + wl_client_post_no_memory(wl_client); + return; + } + + if (!(surface->geometry = calloc(1, sizeof(struct wlr_box)))) { + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { + free(surface->geometry); + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + surface->client = client; + surface->role = WLR_XDG_SURFACE_ROLE_NONE; + surface->surface = wlr_surface_from_resource(surface_resource); + surface->resource = wl_resource_create(wl_client, + &xdg_surface_interface, wl_resource_get_version(client_resource), + id); + if (surface->resource == NULL) { + free(surface->next_geometry); + free(surface->geometry); + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + if (wlr_surface_has_buffer(surface->surface)) { + wl_resource_destroy(surface->resource); + free(surface->next_geometry); + free(surface->geometry); + free(surface); + wl_resource_post_error(surface_resource, + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface must not have a buffer at creation"); + return; + } + + wl_list_init(&surface->configure_list); + wl_list_init(&surface->popups); + + wl_signal_init(&surface->events.request_maximize); + wl_signal_init(&surface->events.request_fullscreen); + wl_signal_init(&surface->events.request_minimize); + wl_signal_init(&surface->events.request_move); + wl_signal_init(&surface->events.request_resize); + wl_signal_init(&surface->events.request_show_window_menu); + wl_signal_init(&surface->events.destroy); + wl_signal_init(&surface->events.ping_timeout); + wl_signal_init(&surface->events.new_popup); + + wl_signal_add(&surface->surface->events.destroy, + &surface->surface_destroy_listener); + surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; + + wlr_surface_set_role_committed(surface->surface, + handle_wlr_surface_committed, surface); + + wlr_log(L_DEBUG, "new xdg_surface %p (res %p)", surface, surface->resource); + wl_resource_set_implementation(surface->resource, + &xdg_surface_implementation, surface, xdg_surface_resource_destroy); + wl_list_insert(&client->surfaces, &surface->link); +} + +static void xdg_shell_pong(struct wl_client *wl_client, + struct wl_resource *resource, uint32_t serial) { + struct wlr_xdg_client *client = xdg_client_from_resource(resource); + + if (client->ping_serial != serial) { + return; + } + + wl_event_source_timer_update(client->ping_timer, 0); + client->ping_serial = 0; +} + +static const struct xdg_wm_base_interface xdg_shell_impl = { + .destroy = resource_destroy, + .create_positioner = xdg_shell_create_positioner, + .get_xdg_surface = xdg_shell_get_xdg_surface, + .pong = xdg_shell_pong, +}; + +static void wlr_xdg_client_destroy(struct wl_resource *resource) { + struct wlr_xdg_client *client = xdg_client_from_resource(resource); + + struct wlr_xdg_surface *surface, *tmp = NULL; + wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { + xdg_surface_destroy(surface); + } + + if (client->ping_timer != NULL) { + wl_event_source_remove(client->ping_timer); + } + + wl_list_remove(&client->link); + free(client); +} + +static int wlr_xdg_client_ping_timeout(void *user_data) { + struct wlr_xdg_client *client = user_data; + + struct wlr_xdg_surface *surface; + wl_list_for_each(surface, &client->surfaces, link) { + wlr_signal_emit_safe(&surface->events.ping_timeout, surface); + } + + client->ping_serial = 0; + return 1; +} + +static void xdg_shell_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) { + struct wlr_xdg_shell *xdg_shell = data; + assert(wl_client && xdg_shell); + + struct wlr_xdg_client *client = + calloc(1, sizeof(struct wlr_xdg_client)); + if (client == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + wl_list_init(&client->surfaces); + + client->resource = + wl_resource_create(wl_client, &xdg_wm_base_interface, version, id); + if (client->resource == NULL) { + free(client); + wl_client_post_no_memory(wl_client); + return; + } + client->client = wl_client; + client->shell = xdg_shell; + + wl_resource_set_implementation(client->resource, &xdg_shell_impl, client, + wlr_xdg_client_destroy); + wl_list_insert(&xdg_shell->clients, &client->link); + + struct wl_display *display = wl_client_get_display(client->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + client->ping_timer = wl_event_loop_add_timer(loop, + wlr_xdg_client_ping_timeout, client); + if (client->ping_timer == NULL) { + wl_client_post_no_memory(client->client); + } +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_xdg_shell *xdg_shell = + wl_container_of(listener, xdg_shell, display_destroy); + wlr_xdg_shell_destroy(xdg_shell); +} + +struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display) { + struct wlr_xdg_shell *xdg_shell = + calloc(1, sizeof(struct wlr_xdg_shell)); + if (!xdg_shell) { + return NULL; + } + + xdg_shell->ping_timeout = 10000; + + wl_list_init(&xdg_shell->clients); + wl_list_init(&xdg_shell->popup_grabs); + + struct wl_global *wl_global = wl_global_create(display, + &xdg_wm_base_interface, 1, xdg_shell, xdg_shell_bind); + if (!wl_global) { + free(xdg_shell); + return NULL; + } + xdg_shell->wl_global = wl_global; + + wl_signal_init(&xdg_shell->events.new_surface); + + xdg_shell->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &xdg_shell->display_destroy); + + return xdg_shell; +} + +void wlr_xdg_shell_destroy(struct wlr_xdg_shell *xdg_shell) { + if (!xdg_shell) { + return; + } + wl_list_remove(&xdg_shell->display_destroy.link); + wl_global_destroy(xdg_shell->wl_global); + free(xdg_shell); +} + +void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) { + if (surface->client->ping_serial != 0) { + // already pinged + return; + } + + surface->client->ping_serial = + wl_display_next_serial(wl_client_get_display(surface->client->client)); + wl_event_source_timer_update(surface->client->ping_timer, + surface->client->shell->ping_timeout); + xdg_wm_base_send_ping(surface->client->resource, + surface->client->ping_serial); +} + +uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, + uint32_t width, uint32_t height) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.width = width; + surface->toplevel_state->pending.height = height; + + return wlr_xdg_surface_schedule_configure(surface); +} + +uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, + bool activated) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.activated = activated; + + return wlr_xdg_surface_schedule_configure(surface); +} + +uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, + bool maximized) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.maximized = maximized; + + return wlr_xdg_surface_schedule_configure(surface); +} + +uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, + bool fullscreen) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.fullscreen = fullscreen; + + return wlr_xdg_surface_schedule_configure(surface); +} + +uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, + bool resizing) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel_state->pending.resizing = resizing; + + return wlr_xdg_surface_schedule_configure(surface); +} + +void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + xdg_toplevel_send_close(surface->toplevel_state->resource); +} + +void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface, + double *popup_sx, double *popup_sy) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); + struct wlr_xdg_surface *parent = surface->popup_state->parent; + *popup_sx = parent->geometry->x + surface->popup_state->geometry.x - + surface->geometry->x; + *popup_sy = parent->geometry->y + surface->popup_state->geometry.y - + surface->geometry->y; +} + +struct wlr_xdg_surface *wlr_xdg_surface_popup_at( + struct wlr_xdg_surface *surface, double sx, double sy, + double *popup_sx, double *popup_sy) { + // XXX: I think this is so complicated because we're mixing geometry + // coordinates with surface coordinates. Input handling should only deal + // with surface coordinates. + struct wlr_xdg_popup *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface *popup = popup_state->base; + + double _popup_sx = + surface->geometry->x + popup_state->geometry.x; + double _popup_sy = + surface->geometry->y + popup_state->geometry.y; + int popup_width = popup_state->geometry.width; + int popup_height = popup_state->geometry.height; + + struct wlr_xdg_surface *_popup = + wlr_xdg_surface_popup_at(popup, + sx - _popup_sx + popup->geometry->x, + sy - _popup_sy + popup->geometry->y, + popup_sx, popup_sy); + if (_popup) { + *popup_sx = *popup_sx + _popup_sx - popup->geometry->x; + *popup_sy = *popup_sy + _popup_sy - popup->geometry->y; + return _popup; + } + + if ((sx > _popup_sx && sx < _popup_sx + popup_width) && + (sy > _popup_sy && sy < _popup_sy + popup_height)) { + if (pixman_region32_contains_point(&popup->surface->current->input, + sx - _popup_sx + popup->geometry->x, + sy - _popup_sy + popup->geometry->y, NULL)) { + *popup_sx = _popup_sx - popup->geometry->x; + *popup_sy = _popup_sy - popup->geometry->y; + return popup; + } + } + } + + return NULL; +} diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index eb18f022..e07d78a1 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -223,9 +223,19 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { } +static const struct zxdg_positioner_v6_interface + zxdg_positioner_v6_implementation; + +static struct wlr_xdg_positioner_v6 *xdg_positioner_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_positioner_v6_interface, + &zxdg_positioner_v6_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_positioner_destroy(struct wl_resource *resource) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); free(positioner); } @@ -233,12 +243,12 @@ static void xdg_positioner_destroy(struct wl_resource *resource) { static void xdg_positioner_protocol_set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (width < 1 || height < 1) { wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "width and height must be positives and non-zero"); + "width and height must be positive and non-zero"); return; } @@ -250,12 +260,12 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (width < 1 || height < 1) { wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "width and height must be positives and non-zero"); + "width and height must be positive and non-zero"); return; } @@ -268,7 +278,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, static void xdg_positioner_protocol_set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP ) && (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) || @@ -286,7 +296,7 @@ static void xdg_positioner_protocol_set_anchor(struct wl_client *client, static void xdg_positioner_protocol_set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); if (((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) && (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) || @@ -305,7 +315,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment( struct wl_client *client, struct wl_resource *resource, uint32_t constraint_adjustment) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); positioner->constraint_adjustment = constraint_adjustment; } @@ -313,7 +323,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment( static void xdg_positioner_protocol_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(resource); + xdg_positioner_from_resource(resource); positioner->offset.x = x; positioner->offset.y = y; @@ -355,52 +365,6 @@ static void xdg_shell_create_positioner(struct wl_client *wl_client, positioner, xdg_positioner_destroy); } -static void xdg_popup_protocol_grab(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_seat_client *seat_client = wl_resource_get_user_data(seat_resource); - - if (surface->popup_state->committed) { - wl_resource_post_error(surface->popup_state->resource, - ZXDG_POPUP_V6_ERROR_INVALID_GRAB, - "xdg_popup is already mapped"); - return; - } - - struct wlr_xdg_popup_grab_v6 *popup_grab = - xdg_shell_popup_grab_from_seat(surface->client->shell, - seat_client->seat); - - struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab); - bool parent_is_toplevel = - surface->popup_state->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; - - if ((topmost == NULL && !parent_is_toplevel) || - (topmost != NULL && topmost != surface->popup_state->parent)) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was not created on the topmost popup"); - return; - } - - popup_grab->client = surface->client->client; - surface->popup_state->seat = seat_client->seat; - - wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); - - wlr_seat_pointer_start_grab(seat_client->seat, - &popup_grab->pointer_grab); - wlr_seat_keyboard_start_grab(seat_client->seat, - &popup_grab->keyboard_grab); -} - -static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { - .destroy = resource_destroy, - .grab = xdg_popup_protocol_grab, -}; - - static struct wlr_box xdg_positioner_get_geometry( struct wlr_xdg_positioner_v6 *positioner, struct wlr_xdg_surface_v6 *surface, struct wlr_xdg_surface_v6 *parent) { @@ -456,23 +420,90 @@ static struct wlr_box xdg_positioner_get_geometry( return geometry; } + +static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation; + +static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_popup_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_popup_v6_interface, + &zxdg_popup_v6_implementation)); + return wl_resource_get_user_data(resource); +} + +static void xdg_popup_protocol_grab(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial) { + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_popup_resource(resource); + struct wlr_seat_client *seat_client = + wlr_seat_client_from_resource(seat_resource); + + if (surface->popup_state->committed) { + wl_resource_post_error(surface->popup_state->resource, + ZXDG_POPUP_V6_ERROR_INVALID_GRAB, + "xdg_popup is already mapped"); + return; + } + + struct wlr_xdg_popup_grab_v6 *popup_grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + seat_client->seat); + + struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab); + bool parent_is_toplevel = + surface->popup_state->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; + + if ((topmost == NULL && !parent_is_toplevel) || + (topmost != NULL && topmost != surface->popup_state->parent)) { + wl_resource_post_error(surface->client->resource, + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was not created on the topmost popup"); + return; + } + + popup_grab->client = surface->client->client; + surface->popup_state->seat = seat_client->seat; + + wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); + + wlr_seat_pointer_start_grab(seat_client->seat, + &popup_grab->pointer_grab); + wlr_seat_keyboard_start_grab(seat_client->seat, + &popup_grab->keyboard_grab); +} + +static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { + .destroy = resource_destroy, + .grab = xdg_popup_protocol_grab, +}; + static void xdg_popup_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_popup_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } } +static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation; + +static struct wlr_xdg_surface_v6 *xdg_surface_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_surface_v6_interface, + &zxdg_surface_v6_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_surface_get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent_resource, struct wl_resource *positioner_resource) { struct wlr_xdg_surface_v6 *surface = - wl_resource_get_user_data(resource); + xdg_surface_from_resource(resource); struct wlr_xdg_surface_v6 *parent = - wl_resource_get_user_data(parent_resource); + xdg_surface_from_resource(parent_resource); struct wlr_xdg_positioner_v6 *positioner = - wl_resource_get_user_data(positioner_resource); + xdg_positioner_from_resource(positioner_resource); if (positioner->size.width == 0 || positioner->anchor_rect.width == 0) { wl_resource_post_error(resource, @@ -516,13 +547,23 @@ static void xdg_surface_get_popup(struct wl_client *client, } +static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation; + +static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_toplevel_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_toplevel_v6_interface, + &zxdg_toplevel_v6_implementation)); + return wl_resource_get_user_data(resource); +} + static void xdg_toplevel_protocol_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_xdg_surface_v6 *parent = NULL; + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); + struct wlr_xdg_surface_v6 *parent = NULL; if (parent_resource != NULL) { - parent = wl_resource_get_user_data(parent_resource); + parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); } surface->toplevel_state->parent = parent; @@ -530,10 +571,10 @@ static void xdg_toplevel_protocol_set_parent(struct wl_client *client, static void xdg_toplevel_protocol_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - char *tmp; + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); - tmp = strdup(title); + char *tmp = strdup(title); if (tmp == NULL) { return; } @@ -544,10 +585,10 @@ static void xdg_toplevel_protocol_set_title(struct wl_client *client, static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - char *tmp; + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); - tmp = strdup(app_id); + char *tmp = strdup(app_id); if (tmp == NULL) { return; } @@ -559,9 +600,10 @@ static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -589,9 +631,10 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, static void xdg_toplevel_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -617,9 +660,10 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, static void xdg_toplevel_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_seat_client *seat = - wl_resource_get_user_data(seat_resource); + wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { wl_resource_post_error(surface->toplevel_state->resource, @@ -645,39 +689,44 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.max_width = width; surface->toplevel_state->next.max_height = height; } static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.min_width = width; surface->toplevel_state->next.min_height = height; } static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.maximized = true; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.maximized = false; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); struct wlr_output *output = NULL; if (output_resource != NULL) { - output = wl_resource_get_user_data(output_resource); + output = wlr_output_from_resource(output_resource); } surface->toplevel_state->next.fullscreen = true; @@ -693,7 +742,8 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); surface->toplevel_state->next.fullscreen = false; @@ -708,7 +758,8 @@ static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); wlr_signal_emit_safe(&surface->events.request_minimize, surface); } @@ -731,14 +782,15 @@ static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = }; static void xdg_surface_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } } static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_toplevel_resource(resource); if (surface != NULL) { xdg_surface_destroy(surface); } @@ -746,7 +798,7 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { static void xdg_surface_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, resource, ZXDG_SHELL_V6_ERROR_ROLE)) { @@ -788,7 +840,7 @@ static void wlr_xdg_toplevel_v6_ack_configure( static void xdg_surface_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { wl_resource_post_error(surface->resource, @@ -838,7 +890,7 @@ static void xdg_surface_ack_configure(struct wl_client *client, static void xdg_surface_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { wl_resource_post_error(surface->resource, @@ -867,9 +919,7 @@ static bool wlr_xdg_surface_v6_toplevel_state_compare( struct wlr_xdg_toplevel_v6 *state) { struct { struct wlr_xdg_toplevel_v6_state state; - uint32_t width; - uint32_t height; - + uint32_t width, height; } configured; // is pending state different from current state? @@ -1128,11 +1178,20 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, } } +static const struct zxdg_shell_v6_interface xdg_shell_impl; + +static struct wlr_xdg_client_v6 *xdg_client_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zxdg_shell_v6_interface, + &xdg_shell_impl)); + return wl_resource_get_user_data(resource); +} + static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, struct wl_resource *client_resource, uint32_t id, struct wl_resource *surface_resource) { struct wlr_xdg_client_v6 *client = - wl_resource_get_user_data(client_resource); + xdg_client_from_resource(client_resource); struct wlr_xdg_surface_v6 *surface; if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { @@ -1155,7 +1214,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, surface->client = client; surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; - surface->surface = wl_resource_get_user_data(surface_resource); + surface->surface = wlr_surface_from_resource(surface_resource); surface->resource = wl_resource_create(wl_client, &zxdg_surface_v6_interface, wl_resource_get_version(client_resource), id); @@ -1206,7 +1265,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, static void xdg_shell_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); if (client->ping_serial != serial) { return; @@ -1216,7 +1275,7 @@ static void xdg_shell_pong(struct wl_client *wl_client, client->ping_serial = 0; } -static struct zxdg_shell_v6_interface xdg_shell_impl = { +static const struct zxdg_shell_v6_interface xdg_shell_impl = { .destroy = resource_destroy, .create_positioner = xdg_shell_create_positioner, .get_xdg_surface = xdg_shell_get_xdg_surface, @@ -1224,7 +1283,7 @@ static struct zxdg_shell_v6_interface xdg_shell_impl = { }; static void wlr_xdg_client_v6_destroy(struct wl_resource *resource) { - struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); struct wlr_xdg_surface_v6 *surface, *tmp = NULL; wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { diff --git a/xwayland/meson.build b/xwayland/meson.build index de05cfaa..2ccdf4cb 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -15,6 +15,7 @@ lib_wlr_xwayland = static_library( xcb_image, xcb_render, xcb_icccm, + xkbcommon, pixman, ], ) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 10bc2e30..94dfdaab 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -742,7 +742,7 @@ static void xwm_handle_surface_id_message(struct wlr_xwm *xwm, struct wl_resource *resource = wl_client_get_object(xwm->xwayland->client, id); if (resource) { - struct wlr_surface *surface = wl_resource_get_user_data(resource); + struct wlr_surface *surface = wlr_surface_from_resource(resource); xsurface->surface_id = 0; xwm_map_shell_surface(xwm, xsurface, surface); } else { |