From 81456203b2e3502570fb268d7762d2b324c2e4a8 Mon Sep 17 00:00:00 2001 From: "Sergio L. Pascual" Date: Tue, 16 Feb 2016 23:30:32 +0100 Subject: [PATCH 01/23] Dirty Wayland backend implementation. --- Headers/cairo/WaylandCairoSurface.h | 16 + Headers/wayland/WaylandServer.h | 118 ++ .../xdg-shell-unstable-v5-client-protocol.h | 559 ++++++ Source/GSBackend.m | 7 + Source/cairo/CairoContext.m | 6 + Source/cairo/GNUmakefile | 16 +- Source/cairo/WaylandCairoSurface.m | 262 +++ Source/wayland/GNUmakefile | 50 + Source/wayland/GNUmakefile.preamble | 51 + Source/wayland/WaylandServer.m | 1554 +++++++++++++++++ .../wayland/xdg-shell-unstable-v5-protocol.c | 129 ++ config.h.in | 1 + configure.ac | 10 +- 13 files changed, 2772 insertions(+), 7 deletions(-) create mode 100644 Headers/cairo/WaylandCairoSurface.h create mode 100644 Headers/wayland/WaylandServer.h create mode 100644 Headers/wayland/xdg-shell-unstable-v5-client-protocol.h create mode 100644 Source/cairo/WaylandCairoSurface.m create mode 100644 Source/wayland/GNUmakefile create mode 100644 Source/wayland/GNUmakefile.preamble create mode 100644 Source/wayland/WaylandServer.m create mode 100644 Source/wayland/xdg-shell-unstable-v5-protocol.c diff --git a/Headers/cairo/WaylandCairoSurface.h b/Headers/cairo/WaylandCairoSurface.h new file mode 100644 index 00000000..71e32921 --- /dev/null +++ b/Headers/cairo/WaylandCairoSurface.h @@ -0,0 +1,16 @@ +/* + Copyright (C) 2016 Sergio L. Pascual +*/ + +#ifndef WaylandCairoSurface_h +#define WaylandCairoSurface_h + +#include "cairo/CairoSurface.h" + +@interface WaylandCairoSurface : CairoSurface +{ +} +@end + + +#endif diff --git a/Headers/wayland/WaylandServer.h b/Headers/wayland/WaylandServer.h new file mode 100644 index 00000000..5c656f63 --- /dev/null +++ b/Headers/wayland/WaylandServer.h @@ -0,0 +1,118 @@ +/* WaylandServer + + Backend server using Wayland. + + Copyright (C) 2016 Sergio L. Pascual +*/ + +#ifndef _WaylandServer_h_INCLUDE +#define _WaylandServer_h_INCLUDE + +#include "config.h" + +#include +#include +#include +#include + +#include "cairo/WaylandCairoSurface.h" +#include "wayland/xdg-shell-unstable-v5-client-protocol.h" + +struct pointer { + struct wl_pointer *wlpointer; + float x; + float y; + uint32_t last_click_button; + uint32_t last_click_time; + float last_click_x; + float last_click_y; + + uint32_t serial; + struct window *focus; +}; + +typedef struct _WaylandConfig { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_shell *shell; + struct xdg_shell *xdg_shell; + struct wl_shm *shm; + struct wl_seat *seat; + struct wl_keyboard *keyboard; + struct wl_surface *surface; + struct wl_shell_surface *shell_surface; + struct wl_buffer *buffer; + + struct wl_list output_list; + int output_count; + struct wl_list window_list; + int window_count; + int last_window_id; + + struct pointer pointer; + struct xkb_context *xkb_context; + struct { + struct xkb_keymap *keymap; + struct xkb_state *state; + xkb_mod_mask_t control_mask; + xkb_mod_mask_t alt_mask; + xkb_mod_mask_t shift_mask; + } xkb; + int modifiers; + + int seat_version; +} WaylandConfig; + +struct output { + WaylandConfig *wlconfig; + struct wl_output *output; + uint32_t server_output_id; + struct wl_list link; + int alloc_x; + int alloc_y; + int width; + int height; + int transform; + int scale; + char *make; + char *model; + + //display_output_handler_t destroy_handler; + void *user_data; +}; + +struct window { + WaylandConfig *wlconfig; + id instance; + int window_id; + struct wl_list link; + + float pos_x; + float pos_y; + float width; + float height; + float saved_pos_x; + float saved_pos_y; + int is_out; + + unsigned char *data; + struct wl_surface *surface; + struct wl_buffer *buffer; + struct wl_shell_surface *shell_surface; + struct xdg_surface *xdg_surface; + struct output *output; + WaylandCairoSurface *wcs; +}; + + +cairo_surface_t * +create_shm_buffer(struct window *window); + +@interface WaylandServer : GSDisplayServer +{ + WaylandConfig *wlconfig; +} +@end + +#endif /* _XGServer_h_INCLUDE */ diff --git a/Headers/wayland/xdg-shell-unstable-v5-client-protocol.h b/Headers/wayland/xdg-shell-unstable-v5-client-protocol.h new file mode 100644 index 00000000..74f198d6 --- /dev/null +++ b/Headers/wayland/xdg-shell-unstable-v5-client-protocol.h @@ -0,0 +1,559 @@ +/* + * Copyright © 2008-2013 Kristian Høgsberg + * Copyright © 2013 Rafael Antognolli + * Copyright © 2013 Jasper St. Pierre + * Copyright © 2010-2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef XDG_SHELL_UNSTABLE_V5_CLIENT_PROTOCOL_H +#define XDG_SHELL_UNSTABLE_V5_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_shell; +struct xdg_surface; + +extern const struct wl_interface xdg_shell_interface; +extern const struct wl_interface xdg_surface_interface; +extern const struct wl_interface xdg_popup_interface; + +#ifndef XDG_SHELL_VERSION_ENUM +#define XDG_SHELL_VERSION_ENUM +/** + * xdg_shell_version - latest protocol version + * @XDG_SHELL_VERSION_CURRENT: Always the latest version + * + * The 'current' member of this enum gives the version of the protocol. + * Implementations can compare this to the version they implement using + * static_assert to ensure the protocol and implementation versions match. + */ +enum xdg_shell_version { + XDG_SHELL_VERSION_CURRENT = 5, +}; +#endif /* XDG_SHELL_VERSION_ENUM */ + +#ifndef XDG_SHELL_ERROR_ENUM +#define XDG_SHELL_ERROR_ENUM +enum xdg_shell_error { + XDG_SHELL_ERROR_ROLE = 0, + XDG_SHELL_ERROR_DEFUNCT_SURFACES = 1, + XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP = 2, + XDG_SHELL_ERROR_INVALID_POPUP_PARENT = 3, +}; +#endif /* XDG_SHELL_ERROR_ENUM */ + +/** + * xdg_shell - create desktop-style surfaces + * @ping: check if the client is alive + * + * xdg_shell allows clients to turn a wl_surface into a "real window" + * which can be dragged, resized, stacked, and moved around by the user. + * Everything about this interface is suited towards traditional desktop + * environments. + */ +struct xdg_shell_listener { + /** + * ping - check if the client is alive + * @serial: pass this to the pong request + * + * The ping event asks the client if it's still alive. Pass the + * serial specified in the event back to the compositor by sending + * a "pong" request back with the specified serial. + * + * Compositors can use this to determine if the client is still + * alive. It's unspecified what will happen if the client doesn't + * respond to the ping request, or in what timeframe. Clients + * should try to respond in a reasonable amount of time. + * + * A compositor is free to ping in any way it wants, but a client + * must always respond to any xdg_shell object it created. + */ + void (*ping)(void *data, + struct xdg_shell *xdg_shell, + uint32_t serial); +}; + +static inline int +xdg_shell_add_listener(struct xdg_shell *xdg_shell, + const struct xdg_shell_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_shell, + (void (**)(void)) listener, data); +} + +#define XDG_SHELL_DESTROY 0 +#define XDG_SHELL_USE_UNSTABLE_VERSION 1 +#define XDG_SHELL_GET_XDG_SURFACE 2 +#define XDG_SHELL_GET_XDG_SURFACE_SPECIAL 3 +#define XDG_SHELL_GET_XDG_POPUP 4 +#define XDG_SHELL_PONG 5 + +static inline void +xdg_shell_set_user_data(struct xdg_shell *xdg_shell, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_shell, user_data); +} + +static inline void * +xdg_shell_get_user_data(struct xdg_shell *xdg_shell) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_shell); +} + +static inline void +xdg_shell_destroy(struct xdg_shell *xdg_shell) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_shell, + XDG_SHELL_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_shell); +} + +static inline void +xdg_shell_use_unstable_version(struct xdg_shell *xdg_shell, int32_t version) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_shell, + XDG_SHELL_USE_UNSTABLE_VERSION, version); +} + +static inline struct xdg_surface * +xdg_shell_get_xdg_surface(struct xdg_shell *xdg_shell, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell, + XDG_SHELL_GET_XDG_SURFACE, &xdg_surface_interface, NULL, surface); + + return (struct xdg_surface *) id; +} + +static inline struct xdg_surface * +xdg_shell_get_xdg_surface_special(struct xdg_shell *xdg_shell, struct wl_surface *surface, uint32_t type) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell, + XDG_SHELL_GET_XDG_SURFACE_SPECIAL, &xdg_surface_interface, NULL, surface, type); + + return (struct xdg_surface *) id; +} + +static inline struct xdg_popup * +xdg_shell_get_xdg_popup(struct xdg_shell *xdg_shell, struct wl_surface *surface, struct wl_surface *parent, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell, + XDG_SHELL_GET_XDG_POPUP, &xdg_popup_interface, NULL, surface, parent, seat, serial, x, y); + + return (struct xdg_popup *) id; +} + +static inline void +xdg_shell_pong(struct xdg_shell *xdg_shell, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_shell, + XDG_SHELL_PONG, serial); +} + +#ifndef XDG_SURFACE_RESIZE_EDGE_ENUM +#define XDG_SURFACE_RESIZE_EDGE_ENUM +/** + * xdg_surface_resize_edge - edge values for resizing + * @XDG_SURFACE_RESIZE_EDGE_NONE: (none) + * @XDG_SURFACE_RESIZE_EDGE_TOP: (none) + * @XDG_SURFACE_RESIZE_EDGE_BOTTOM: (none) + * @XDG_SURFACE_RESIZE_EDGE_LEFT: (none) + * @XDG_SURFACE_RESIZE_EDGE_TOP_LEFT: (none) + * @XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT: (none) + * @XDG_SURFACE_RESIZE_EDGE_RIGHT: (none) + * @XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT: (none) + * @XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT: (none) + * + * These values are used to indicate which edge of a surface is being + * dragged in a resize operation. + */ +enum xdg_surface_resize_edge { + XDG_SURFACE_RESIZE_EDGE_NONE = 0, + XDG_SURFACE_RESIZE_EDGE_TOP = 1, + XDG_SURFACE_RESIZE_EDGE_BOTTOM = 2, + XDG_SURFACE_RESIZE_EDGE_LEFT = 4, + XDG_SURFACE_RESIZE_EDGE_TOP_LEFT = 5, + XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_SURFACE_RESIZE_EDGE_RIGHT = 8, + XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* XDG_SURFACE_RESIZE_EDGE_ENUM */ + +#ifndef XDG_SURFACE_STATE_ENUM +#define XDG_SURFACE_STATE_ENUM +/** + * xdg_surface_state - the surface is now activated + * @XDG_SURFACE_STATE_MAXIMIZED: the surface is maximized + * @XDG_SURFACE_STATE_FULLSCREEN: the surface is fullscreen + * @XDG_SURFACE_STATE_RESIZING: the surface is being resized + * @XDG_SURFACE_STATE_ACTIVATED: the surface is now activated + * + * Client window decorations should be painted as if the window is + * active. Do not assume this means that the window actually has keyboard + * or pointer focus. + */ +enum xdg_surface_state { + XDG_SURFACE_STATE_MAXIMIZED = 1, + XDG_SURFACE_STATE_FULLSCREEN = 2, + XDG_SURFACE_STATE_RESIZING = 3, + XDG_SURFACE_STATE_ACTIVATED = 4, +}; +#endif /* XDG_SURFACE_STATE_ENUM */ + +/** + * xdg_surface - A desktop window + * @configure: suggest a surface change + * @close: surface wants to be closed + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides requests to treat surfaces like windows, allowing to set + * properties like maximized, fullscreen, minimized, and to move and resize + * them, and associate metadata like title and app id. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. Prior to committing the new + * state, it can set up initial configuration, such as maximizing or + * setting a window geometry. + * + * Even without attaching a buffer the compositor must respond to initial + * committed configuration, for instance sending a configure event with + * expected window geometry if the client maximized its surface during + * initialization. + * + * For a surface to be mapped by the compositor the client must have + * committed both an xdg_surface state and a buffer. + */ +struct xdg_surface_listener { + /** + * configure - suggest a surface change + * @x: (none) + * @y: (none) + * @width: (none) + * @height: (none) + * @states: (none) + * @serial: (none) + * + * The configure event asks the client to resize its surface or + * to change its state. + * + * The width and height arguments specify a hint to the window + * about how its surface should be resized in window geometry + * coordinates. See set_window_geometry. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. This may happen when the + * compositor need to configure the state of the surface but + * doesn't have any information about any previous or expected + * dimension. + * + * The states listed in the event specify how the width/height + * arguments should be interpreted, and possibly how it should be + * drawn. + * + * Clients should arrange their surface for the new size and + * states, and then send a ack_configure request with the serial + * sent in this configure event at some point before committing the + * new surface. + * + * If the client receives multiple configure events before it can + * respond to one, it is free to discard all but the last event it + * received. + */ + void (*configure)(void *data, + struct xdg_surface *xdg_surface, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + struct wl_array *states, + uint32_t serial); + /** + * close - surface wants to be closed + * + * The close event is sent by the compositor when the user wants + * the surface to be closed. This should be equivalent to the user + * clicking the close button in client-side decorations, if your + * application has any... + * + * This is only a request that the user intends to close your + * window. The client may choose to ignore this request, or show a + * dialog to ask the user to save their data... + */ + void (*close)(void *data, + struct xdg_surface *xdg_surface); +}; + +static inline int +xdg_surface_add_listener(struct xdg_surface *xdg_surface, + const struct xdg_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, + (void (**)(void)) listener, data); +} + +#define XDG_SURFACE_DESTROY 0 +#define XDG_SURFACE_SET_PARENT 1 +#define XDG_SURFACE_SET_TITLE 2 +#define XDG_SURFACE_SET_APP_ID 3 +#define XDG_SURFACE_SHOW_WINDOW_MENU 4 +#define XDG_SURFACE_MOVE 5 +#define XDG_SURFACE_RESIZE 6 +#define XDG_SURFACE_ACK_CONFIGURE 7 +#define XDG_SURFACE_SET_WINDOW_GEOMETRY 8 +#define XDG_SURFACE_SET_MAXIMIZED 9 +#define XDG_SURFACE_UNSET_MAXIMIZED 10 +#define XDG_SURFACE_SET_FULLSCREEN 11 +#define XDG_SURFACE_UNSET_FULLSCREEN 12 +#define XDG_SURFACE_SET_MINIMIZED 13 + +static inline void +xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); +} + +static inline void * +xdg_surface_get_user_data(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); +} + +static inline void +xdg_surface_destroy(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_surface); +} + +static inline void +xdg_surface_set_parent(struct xdg_surface *xdg_surface, struct xdg_surface *parent) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_PARENT, parent); +} + +static inline void +xdg_surface_set_title(struct xdg_surface *xdg_surface, const char *title) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_TITLE, title); +} + +static inline void +xdg_surface_set_app_id(struct xdg_surface *xdg_surface, const char *app_id) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_APP_ID, app_id); +} + +static inline void +xdg_surface_show_window_menu(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SHOW_WINDOW_MENU, seat, serial, x, y); +} + +static inline void +xdg_surface_move(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_MOVE, seat, serial); +} + +static inline void +xdg_surface_resize(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_RESIZE, seat, serial, edges); +} + +static inline void +xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_ACK_CONFIGURE, serial); +} + +static inline void +xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_WINDOW_GEOMETRY, x, y, width, height); +} + +static inline void +xdg_surface_set_maximized(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_MAXIMIZED); +} + +static inline void +xdg_surface_unset_maximized(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_UNSET_MAXIMIZED); +} + +static inline void +xdg_surface_set_fullscreen(struct xdg_surface *xdg_surface, struct wl_output *output) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_FULLSCREEN, output); +} + +static inline void +xdg_surface_unset_fullscreen(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_UNSET_FULLSCREEN); +} + +static inline void +xdg_surface_set_minimized(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_MINIMIZED); +} + +/** + * xdg_popup - short-lived, popup surfaces for menus + * @popup_done: popup interaction is done + * + * A popup surface is a short-lived, temporary surface that can be used + * to implement menus. It takes an explicit grab on the surface that will + * be dismissed when the user dismisses the popup. This can be done by the + * user clicking outside the surface, using the keyboard, or even locking + * the screen through closing the lid or a timeout. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. The xdg_popup object is now + * inert and cannot be reactivated, so clients should destroy it. + * Explicitly destroying the xdg_popup object will also dismiss the popup + * and unmap the surface. + * + * Clients will receive events for all their surfaces during this grab + * (which is an "owner-events" grab in X11 parlance). This is done so that + * users can navigate through submenus and other "nested" popup windows + * without having to dismiss the topmost popup. + * + * Clients that want to dismiss the popup when another surface of their own + * is clicked should dismiss the popup using the destroy request. + * + * The parent surface must have either an xdg_surface or xdg_popup role. + * + * Specifying an xdg_popup for the parent means that the popups are nested, + * with this popup now being the topmost popup. Nested popups must be + * destroyed in the reverse order they were created in, e.g. the only popup + * you are allowed to destroy at all times is the topmost one. + * + * If there is an existing popup when creating a new popup, the parent must + * be the current topmost popup. + * + * A parent surface must be mapped before the new popup is mapped. + * + * When compositors choose to dismiss a popup, they will likely dismiss + * every nested popup as well. When a compositor dismisses popups, it will + * follow the same dismissing order as required from the client. + * + * The x and y arguments passed when creating the popup object specify + * where the top left of the popup should be placed, relative to the local + * surface coordinates of the parent surface. See xdg_shell.get_xdg_popup. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * + * For a surface to be mapped by the compositor the client must have + * committed both the xdg_popup state and a buffer. + */ +struct xdg_popup_listener { + /** + * popup_done - popup interaction is done + * + * The popup_done event is sent out when a popup is dismissed by + * the compositor. The client should destroy the xdg_popup object + * at this point. + */ + void (*popup_done)(void *data, + struct xdg_popup *xdg_popup); +}; + +static inline int +xdg_popup_add_listener(struct xdg_popup *xdg_popup, + const struct xdg_popup_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, + (void (**)(void)) listener, data); +} + +#define XDG_POPUP_DESTROY 0 + +static inline void +xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); +} + +static inline void * +xdg_popup_get_user_data(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); +} + +static inline void +xdg_popup_destroy(struct xdg_popup *xdg_popup) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_popup); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Source/GSBackend.m b/Source/GSBackend.m index e0003a46..eb89388f 100644 --- a/Source/GSBackend.m +++ b/Source/GSBackend.m @@ -45,6 +45,11 @@ + (void) initializeBackend; @interface WIN32Server (Initialize) + (void) initializeBackend; @end +#elif BUILD_SERVER == SERVER_wayland +#include +@interface WaylandServer (Initialize) ++ (void) initializeBackend; +@end #endif /* Call the correct initalization routines for the choosen @@ -63,6 +68,8 @@ + (void) initializeBackend [XGServer initializeBackend]; #elif BUILD_SERVER == SERVER_win32 [WIN32Server initializeBackend]; +#elif BUILD_SERVER == SERVER_wayland + [WaylandServer initializeBackend]; #else [NSException raise: NSInternalInconsistencyException format: @"No Window Server configured in backend"]; diff --git a/Source/cairo/CairoContext.m b/Source/cairo/CairoContext.m index 17644e0e..a67839ba 100644 --- a/Source/cairo/CairoContext.m +++ b/Source/cairo/CairoContext.m @@ -70,6 +70,12 @@ # define _CAIRO_SURFACE_CLASSNAME Win32CairoSurface # include "cairo/Win32CairoSurface.h" # endif /* USE_GLITZ */ +#elif BUILD_SERVER == SERVER_wayland +# include "wayland/WaylandServer.h" +# define _CAIRO_GSTATE_CLASSNAME CairoGState +# include "cairo/CairoGState.h" +# define _CAIRO_SURFACE_CLASSNAME WaylandCairoSurface +# include "cairo/WaylandCairoSurface.h" #else # error Invalid server for Cairo backend : non implemented #endif /* BUILD_SERVER */ diff --git a/Source/cairo/GNUmakefile b/Source/cairo/GNUmakefile index 27e6cb5f..ffe2060f 100644 --- a/Source/cairo/GNUmakefile +++ b/Source/cairo/GNUmakefile @@ -49,12 +49,16 @@ ifeq ($(BUILD_SERVER),x11) cairo_OBJC_FILES += XGCairoSurface.m XGCairoXImageSurface.m XGCairoModernSurface.m endif else - ifeq ($(BUILD_GRAPHICS),cairo) - ifeq ($(WITH_GLITZ),yes) - cairo_OBJC_FILES += Win32CairoGlitzSurface.m - else - cairo_OBJC_FILES += Win32CairoSurface.m Win32CairoGState.m - # Win32CairoXImageSurface.m + ifeq ($(BUILD_SERVER),wayland) + cairo_OBJC_FILES += WaylandCairoSurface.m + else + ifeq ($(BUILD_GRAPHICS),cairo) + ifeq ($(WITH_GLITZ),yes) + cairo_OBJC_FILES += Win32CairoGlitzSurface.m + else + cairo_OBJC_FILES += Win32CairoSurface.m Win32CairoGState.m + # Win32CairoXImageSurface.m + endif endif endif endif diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m new file mode 100644 index 00000000..a27a55ad --- /dev/null +++ b/Source/cairo/WaylandCairoSurface.m @@ -0,0 +1,262 @@ +/* + Copyright (C) 2016 Sergio L. Pascual +*/ + +#include "wayland/WaylandServer.h" +#include "cairo/WaylandCairoSurface.h" +#include + +#include +#include +#include +#include + + +#define GSWINDEVICE ((struct window *)gsDevice) + + +int +os_fd_set_cloexec(int fd) +{ + long flags; + + if (fd == -1) + return -1; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + return -1; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + return -1; + + return 0; +} + +static int +set_cloexec_or_close(int fd) +{ + if (os_fd_set_cloexec(fd) != 0) { + close(fd); + return -1; + } + return fd; +} + +static int +create_tmpfile_cloexec(char *tmpname) +{ + int fd; + + fd = mkstemp(tmpname); + if (fd >= 0) { + fd = set_cloexec_or_close(fd); + unlink(tmpname); + } + + return fd; +} + +int +os_create_anonymous_file(off_t size) +{ + static const char template[] = "/weston-shared-XXXXXX"; + const char *path; + char *name; + int fd; + int ret; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + + name = malloc(strlen(path) + sizeof(template)); + if (!name) + return -1; + + strcpy(name, path); + strcat(name, template); + + fd = create_tmpfile_cloexec(name); + + free(name); + + if (fd < 0) + return -1; + + ret = posix_fallocate(fd, 0, size); + if (ret != 0) { + close(fd); + errno = ret; + return -1; + } + + return fd; +} + +cairo_surface_t * +create_shm_buffer(struct window *window) +{ + struct wl_shm_pool *pool; + cairo_surface_t *surface; + int fd, size, stride; + + stride = window->width * 4; + size = stride * window->height; + + fd = os_create_anonymous_file(size); + if (fd < 0) { + NSLog(@"creating a buffer file for surface failed"); + return NULL; + } + + window->data = + mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (window->data == MAP_FAILED) { + NSLog(@"error mapping anonymous file"); + close(fd); + return NULL; + } + + pool = wl_shm_create_pool(window->wlconfig->shm, fd, size); + + surface = cairo_image_surface_create_for_data(window->data, + CAIRO_FORMAT_ARGB32, + window->width, + window->height, + stride); + + window->buffer = + wl_shm_pool_create_buffer(pool, 0, + window->width, window->height, stride, + WL_SHM_FORMAT_ARGB8888); + wl_shm_pool_destroy(pool); + + close(fd); + + return surface; +} + +@implementation WaylandCairoSurface + +- (id) initWithDevice: (void*)device +{ + struct window *window = (struct window *) device; + NSDebugLog(@"WaylandCairoSurface: initWithDevice win=%d", window->window_id); + + gsDevice = device; + + //_surface = window->main_surface->cairo_surface; + _surface = create_shm_buffer(window); + if (_surface == NULL) { + NSDebugLog(@"can't create cairo surface"); + return 0; + } + + wl_surface_attach(window->surface, window->buffer, 0, 0); + + window->wcs = self; + + return self; +} + +- (void) dealloc +{ + struct window *window = (struct window*) gsDevice; + NSDebugLog(@"WaylandCairoSurface: dealloc win=%d", window->window_id); + [super dealloc]; +} + +- (NSSize) size +{ + NSDebugLog(@"WaylandCairoSurface: size"); + struct window *window = (struct window*) gsDevice; + return NSMakeSize(window->width, window->height); +} + +- (void) setSurface: (cairo_surface_t*)surface +{ + NSDebugLog(@"WaylandCairoSurface: setSurface"); + _surface = surface; +} + +- (void) handleExposeRect: (NSRect)rect +{ + NSDebugLog(@"handleExposeRect"); + struct window *window = (struct window*) gsDevice; + struct wl_surface *wlsurface = window->surface; + cairo_surface_t *cairo_surface; + double backupOffsetX = 0; + double backupOffsetY = 0; + int x = NSMinX(rect); + int y = NSMinY(rect); + int width = NSWidth(rect); + int height = NSHeight(rect); + + NSDebugLog(@"updating region: %dx%d %dx%d", x, y, width, height); + + if (cairo_surface_status(_surface) != CAIRO_STATUS_SUCCESS) + { + NSWarnMLog(@"cairo initial window error status: %s\n", + cairo_status_to_string(cairo_surface_status(_surface))); + } + + /* + cairo_surface = create_shm_buffer(window); + if (cairo_surface == NULL) { + NSDebugLog(@"can't create cairo surface"); + return; + } + */ + cairo_surface = _surface; + cairo_surface_get_device_offset(cairo_surface, &backupOffsetX, &backupOffsetY); + cairo_surface_set_device_offset(cairo_surface, 0, 0); + + + cairo_t *cr = cairo_create(cairo_surface); + if (width != window->width && 0) { + NSDebugLog(@"fake drawing"); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + + cairo_rectangle(cr, 0, 0, width, height); + cairo_set_source_rgba(cr, 0, 0, 0, 0.8); + cairo_fill(cr); + + cairo_rectangle(cr, 10, 10, width - 20, height - 20); + cairo_set_source_rgba(cr, 1.0, 0, 0, 1); + cairo_fill(cr); + + cairo_select_font_face(cr, "sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cr, 12); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); + cairo_move_to(cr, 30, 30); + cairo_show_text(cr, "Hello, world!"); + } else { + NSDebugLog(@"real drawing"); + + cairo_rectangle(cr, x, y, width, height); + cairo_clip(cr); + cairo_set_source_surface(cr, cairo_surface, 0, 0); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + } + + cairo_destroy(cr); + + cairo_surface_set_device_offset(_surface, backupOffsetX, backupOffsetY); + + wl_surface_attach(wlsurface, window->buffer, 0, 0); + wl_surface_damage(wlsurface, 0, 0, window->width, window->height); + wl_surface_commit(wlsurface); + + wl_display_dispatch_pending(window->wlconfig->display); + wl_display_flush(window->wlconfig->display); + NSDebugLog(@"handleExposeRect exit"); +} + +@end + diff --git a/Source/wayland/GNUmakefile b/Source/wayland/GNUmakefile new file mode 100644 index 00000000..264cc7fc --- /dev/null +++ b/Source/wayland/GNUmakefile @@ -0,0 +1,50 @@ +# +# Main makefile for GNUstep Backend win32 +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; see the file COPYING.LIB. +# If not, see or write to the +# Free Software Foundation, 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +PACKAGE_NAME = gnustep-back +GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../../back.make + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../../config.make + +# The library to be compiled, as a library or as a bundle +SUBPROJECT_NAME=wayland + +wayland_LOCALIZED_RESOURCE_FILES = \ + +# The C source files to be compiled +wayland_C_FILES = \ +xdg-shell-unstable-v5-protocol.c \ + +# The Objective-C source files to be compiled +wayland_OBJC_FILES = \ +WaylandServer.m \ + +-include GNUmakefile.preamble + +include $(GNUSTEP_MAKEFILES)/subproject.make + +-include GNUmakefile.postamble diff --git a/Source/wayland/GNUmakefile.preamble b/Source/wayland/GNUmakefile.preamble new file mode 100644 index 00000000..d7461719 --- /dev/null +++ b/Source/wayland/GNUmakefile.preamble @@ -0,0 +1,51 @@ + +# GNUmakefile.preamble +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Adam Fedor +# +# This file is part of the GNUstep Backend. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; see the file COPYING.LIB. +# If not, see or write to the +# Free Software Foundation, 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +ADDITIONAL_CPPFLAGS += -Wall $(CONFIG_SYSTEM_DEFS) + +# Additional flags to pass to the Objective-C compiler +ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS += -I../../Headers \ + -I../$(GNUSTEP_TARGET_DIR) $(GRAPHIC_CFLAGS) + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = + +# +# Flags dealing with installing and uninstalling +# diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m new file mode 100644 index 00000000..cb4a7e04 --- /dev/null +++ b/Source/wayland/WaylandServer.m @@ -0,0 +1,1554 @@ +/* WaylandServer - Wayland Server Class + + Copyright (C) 2016 Sergio L. Pascual +*/ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wayland/WaylandServer.h" + +static void +handle_geometry(void *data, + struct wl_output *wl_output, + int x, int y, + int physical_width, + int physical_height, + int subpixel, + const char *make, + const char *model, + int transform) +{ + NSDebugLog(@"handle_geometry"); + struct output *output = data; + + output->alloc_x = x; + output->alloc_y = y; + output->transform = transform; + + if (output->make) + free(output->make); + output->make = strdup(make); + + if (output->model) + free(output->model); + output->model = strdup(model); +} + +static void +handle_done(void *data, + struct wl_output *wl_output) +{ + NSDebugLog(@"handle_done"); +} + +static void +handle_scale(void *data, + struct wl_output *wl_output, + int32_t scale) +{ + NSDebugLog(@"handle_scale"); + struct output *output = data; + + output->scale = scale; +} + +static void +handle_mode(void *data, + struct wl_output *wl_output, + uint32_t flags, + int width, + int height, + int refresh) +{ + NSDebugLog(@"handle_mode"); + struct output *output = data; + + if (flags & WL_OUTPUT_MODE_CURRENT) { + output->width = width; + output->height = height /*- 30*/; + NSDebugLog(@"handle_mode output=%dx%d", width, height); + /* XXX - Should we implement this? + if (display->output_configure_handler) + (*display->output_configure_handler) + (output, display->user_data); + */ + } +} + +static const struct wl_output_listener output_listener = { + handle_geometry, + handle_mode, + handle_done, + handle_scale +}; + +static void +add_output(WaylandConfig *wlconfig, uint32_t id) +{ + NSDebugLog(@"add_output"); + + struct output *output; + + output = (struct output *) malloc(sizeof(struct output)); + memset(output, 0, sizeof(struct output)); + output->wlconfig = wlconfig; + output->scale = 1; + output->output = + wl_registry_bind(wlconfig->registry, id, &wl_output_interface, 2); + output->server_output_id = id; + wl_list_insert(wlconfig->output_list.prev, &output->link); + (wlconfig->output_count)++; + + wl_output_add_listener(output->output, &output_listener, output); +} + +static void +output_destroy(struct output *output) +{ + NSDebugLog(@"output_destroy"); + + /* XXX - Should we implement this? + if (output->destroy_handler) + (*output->destroy_handler)(output, output->user_data); + */ + + wl_output_destroy(output->output); + wl_list_remove(&output->link); + free(output); +} + +static void +destroy_output(WaylandConfig *wlconfig, uint32_t id) +{ + struct output *output; + + wl_list_for_each(output, &wlconfig->output_list, link) { + if (output->server_output_id == id) { + output_destroy(output); + (wlconfig->output_count)--; + break; + } + } +} + +static void +pointer_handle_enter(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface, + wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + NSDebugLog(@"pointer_handle_enter"); + if (!surface) { + NSDebugLog(@"no surface"); + return; + } + + WaylandConfig *wlconfig = data; + struct window *window = wl_surface_get_user_data(surface); + float sx = wl_fixed_to_double(sx_w); + float sy = wl_fixed_to_double(sy_w); + + wlconfig->pointer.x = sx; + wlconfig->pointer.y = sy; + wlconfig->pointer.focus = window; +} + +static void +pointer_handle_leave(void *data, struct wl_pointer *pointer, + uint32_t serial, struct wl_surface *surface) +{ + NSDebugLog(@"pointer_handle_leave"); + if (!surface) { + NSDebugLog(@"no surface"); + return; + } + + WaylandConfig *wlconfig = data; + struct window *window = wl_surface_get_user_data(surface); + + if (wlconfig->pointer.focus->window_id == window->window_id) { + wlconfig->pointer.focus = NULL; + wlconfig->pointer.serial = 0; + } +} + +static void +pointer_handle_motion(void *data, struct wl_pointer *pointer, + uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + WaylandConfig *wlconfig = data; + struct window *window; + float sx = wl_fixed_to_double(sx_w); + float sy = wl_fixed_to_double(sy_w); + NSDebugLog(@"pointer_handle_motion: %fx%f", sx, sy); + + if (wlconfig->pointer.focus && wlconfig->pointer.serial) { + window = wlconfig->pointer.focus; + NSEvent *event; + NSEventType eventType; + NSPoint eventLocation; + NSGraphicsContext *gcontext; + unsigned int eventFlags; + int tick; + float deltaX = sx - window->wlconfig->pointer.x; + float deltaY = sy - window->wlconfig->pointer.y; + + NSDebugLog(@"obtaining locations: wayland=%fx%f pointer=%fx%f", + sx, sy, window->wlconfig->pointer.x, window->wlconfig->pointer.y); + + gcontext = GSCurrentContext(); + eventLocation = NSMakePoint(sx, + window->height - sy); + + eventFlags = 0; + eventType = NSLeftMouseDragged; + + tick = 0; + + + NSDebugLog(@"sending pointer delta: %fx%f, window=%d", deltaX, deltaY, window->window_id); + + event = [NSEvent mouseEventWithType: eventType + location: eventLocation + modifierFlags: eventFlags + timestamp: (NSTimeInterval) time / 1000.0 + windowNumber: (int)window->window_id + context: gcontext + eventNumber: time + clickCount: 1 + pressure: 1.0 + buttonNumber: 0 /* FIXME */ + deltaX: deltaX + deltaY: deltaY + deltaZ: 0.]; + + [GSCurrentServer() postEvent: event atStart: NO]; + } + + wlconfig->pointer.x = sx; + wlconfig->pointer.y = sy; +} + +static void +pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state_w) +{ + NSDebugLog(@"pointer_handle_button: button=%d", button); + WaylandConfig *wlconfig = data; + NSEvent *event; + NSEventType eventType; + NSPoint eventLocation; + NSGraphicsContext *gcontext; + unsigned int eventFlags; + float deltaX = 0.0; + float deltaY = 0.0; + int clickCount = 1; + int tick; + enum wl_pointer_button_state state = state_w; + struct window *window = wlconfig->pointer.focus; + + gcontext = GSCurrentContext(); + eventLocation = NSMakePoint(wlconfig->pointer.x, + window->height - wlconfig->pointer.y); + eventFlags = 0; + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (button == wlconfig->pointer.last_click_button && + time - wlconfig->pointer.last_click_time < 300 && + abs(wlconfig->pointer.x - wlconfig->pointer.last_click_x) < 3 && + abs(wlconfig->pointer.y - wlconfig->pointer.last_click_y) < 3) { + NSDebugLog(@"handle_button HIT: b=%d t=%d x=%f y=%f", button, time, wlconfig->pointer.x, wlconfig->pointer.y); + wlconfig->pointer.last_click_time = 0; + clickCount++; + } else { + NSDebugLog(@"handle_button MISS: b=%d t=%d x=%f y=%f", button, time, wlconfig->pointer.x, wlconfig->pointer.y); + wlconfig->pointer.last_click_button = button; + wlconfig->pointer.last_click_time = time; + wlconfig->pointer.last_click_x = wlconfig->pointer.x; + wlconfig->pointer.last_click_y = wlconfig->pointer.y; + } + + switch (button) { + case BTN_LEFT: + eventType = NSLeftMouseDown; + break; + case BTN_RIGHT: + eventType = NSRightMouseDown; + break; + } + wlconfig->pointer.serial = serial; + } else { + switch (button) { + case BTN_LEFT: + eventType = NSLeftMouseUp; + break; + case BTN_RIGHT: + eventType = NSRightMouseUp; + break; + } + wlconfig->pointer.serial = 0; + } + + tick = serial; + + NSDebugLog(@"sending pointer event at: %fx%f, window=%d", wlconfig->pointer.x, wlconfig->pointer.y, window->window_id); + + event = [NSEvent mouseEventWithType: eventType + location: eventLocation + modifierFlags: eventFlags + timestamp: (NSTimeInterval) time / 1000.0 + windowNumber: (int)window->window_id + context: gcontext + eventNumber: tick + clickCount: clickCount + pressure: 1.0 + buttonNumber: 0 /* FIXME */ + deltaX: deltaX + deltaY: deltaY + deltaZ: 0.]; + + [GSCurrentServer() postEvent: event atStart: NO]; +} + +static void +pointer_handle_axis(void *data, struct wl_pointer *pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) +{ +} + +static const struct wl_pointer_listener pointer_listener = { + pointer_handle_enter, + pointer_handle_leave, + pointer_handle_motion, + pointer_handle_button, + pointer_handle_axis, +}; + +static void +keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, + uint32_t format, int fd, uint32_t size) +{ + NSDebugLog(@"keyboard_handle_keymap"); + WaylandConfig *wlconfig = data; + struct xkb_keymap *keymap; + struct xkb_state *state; + char *map_str; + + if (!data) { + close(fd); + return; + } + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + close(fd); + return; + } + + wlconfig->xkb_context = xkb_context_new(0); + if (wlconfig->xkb_context == NULL) { + fprintf(stderr, "Failed to create XKB context\n"); + return; + } + + keymap = xkb_keymap_new_from_string(wlconfig->xkb_context, + map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, + 0); + munmap(map_str, size); + close(fd); + + if (!keymap) { + fprintf(stderr, "failed to compile keymap\n"); + return; + } + + state = xkb_state_new(keymap); + if (!state) { + fprintf(stderr, "failed to create XKB state\n"); + xkb_keymap_unref(keymap); + return; + } + + xkb_keymap_unref(wlconfig->xkb.keymap); + xkb_state_unref(wlconfig->xkb.state); + wlconfig->xkb.keymap = keymap; + wlconfig->xkb.state = state; + + wlconfig->xkb.control_mask = + 1 << xkb_keymap_mod_get_index(wlconfig->xkb.keymap, "Control"); + wlconfig->xkb.alt_mask = + 1 << xkb_keymap_mod_get_index(wlconfig->xkb.keymap, "Mod1"); + wlconfig->xkb.shift_mask = + 1 << xkb_keymap_mod_get_index(wlconfig->xkb.keymap, "Shift"); + +} + +static void +keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, + uint32_t serial, struct wl_surface *surface, + struct wl_array *keys) +{ + NSDebugLog(@"keyboard_handle_enter"); +} + +static void +keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, + uint32_t serial, struct wl_surface *surface) +{ + NSDebugLog(@"keyboard_handle_leave"); +} + +static void +keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, + uint32_t serial, uint32_t mods_depressed, + uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) +{ + NSDebugLog(@"keyboard_handle_modifiers"); + WaylandConfig *wlconfig = data; + struct input *input = data; + xkb_mod_mask_t mask; + + /* If we're not using a keymap, then we don't handle PC-style modifiers */ + if (!wlconfig->xkb.keymap) + return; + + xkb_state_update_mask(wlconfig->xkb.state, mods_depressed, mods_latched, + mods_locked, 0, 0, group); + mask = xkb_state_serialize_mods(wlconfig->xkb.state, + XKB_STATE_MODS_DEPRESSED | + XKB_STATE_MODS_LATCHED); + wlconfig->modifiers = 0; + if (mask & wlconfig->xkb.control_mask) + wlconfig->modifiers |= NSCommandKeyMask; + if (mask & wlconfig->xkb.alt_mask) + wlconfig->modifiers |= NSAlternateKeyMask; + if (mask & wlconfig->xkb.shift_mask) + wlconfig->modifiers |= NSShiftKeyMask; + +} + +static void +keyboard_handle_key(void *data, struct wl_keyboard *keyboard, + uint32_t serial, uint32_t time, uint32_t key, + uint32_t state_w) +{ + NSDebugLog(@"keyboard_handle_key: %d", key); + WaylandConfig *wlconfig = data; + uint32_t code, num_syms; + enum wl_keyboard_key_state state = state_w; + const xkb_keysym_t *syms; + xkb_keysym_t sym; + struct itimerspec its; + struct window *window = wlconfig->pointer.focus; + + if (!window) { + return; + } + + if (key == 28) { + sym = NSCarriageReturnCharacter; + } else if (key == 14) { + sym = NSDeleteCharacter; + } else { + code = key + 8; + + num_syms = xkb_state_key_get_syms(wlconfig->xkb.state, code, &syms); + + sym = XKB_KEY_NoSymbol; + if (num_syms == 1) + sym = syms[0]; + } + + NSString *s = [NSString stringWithUTF8String: &sym]; + NSEventType eventType; + + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + eventType = NSKeyDown; + } else { + eventType = NSKeyUp; + } + + NSEvent *ev = [NSEvent keyEventWithType: eventType + location: NSZeroPoint + modifierFlags: wlconfig->modifiers + timestamp: time / 1000.0 + windowNumber: window->window_id + context: GSCurrentContext() + characters: s + charactersIgnoringModifiers: s + isARepeat: NO + keyCode: code]; + + [GSCurrentServer() postEvent: ev atStart: NO]; + + NSDebugLog(@"keyboard_handle_key: %@", s); +} + +static void +keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, + int32_t rate, int32_t delay) +{ + NSDebugLog(@"keyboard_handle_repeat_info"); +} + +static const struct wl_keyboard_listener keyboard_listener = { + keyboard_handle_keymap, + keyboard_handle_enter, + keyboard_handle_leave, + keyboard_handle_key, + keyboard_handle_modifiers, + keyboard_handle_repeat_info +}; + +static void +seat_handle_capabilities(void *data, struct wl_seat *seat, + enum wl_seat_capability caps) +{ + WaylandConfig *wlconfig = data; + + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlconfig->pointer.wlpointer) { + wlconfig->pointer.wlpointer = wl_seat_get_pointer(seat); + wl_pointer_set_user_data(wlconfig->pointer.wlpointer, wlconfig); + wl_pointer_add_listener(wlconfig->pointer.wlpointer, &pointer_listener, + wlconfig); + } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlconfig->pointer.wlpointer) { + if (wlconfig->seat_version >= WL_POINTER_RELEASE_SINCE_VERSION) + wl_pointer_release(wlconfig->pointer.wlpointer); + else + wl_pointer_destroy(wlconfig->pointer.wlpointer); + wlconfig->pointer.wlpointer = NULL; + } + + wl_display_dispatch_pending(wlconfig->display); + wl_display_flush(wlconfig->display); + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wlconfig->keyboard) { + wlconfig->keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_set_user_data(wlconfig->keyboard, wlconfig); + wl_keyboard_add_listener(wlconfig->keyboard, &keyboard_listener, + wlconfig); + } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wlconfig->keyboard) { + if (wlconfig->seat_version >= WL_KEYBOARD_RELEASE_SINCE_VERSION) + wl_keyboard_release(wlconfig->keyboard); + else + wl_keyboard_destroy(wlconfig->keyboard); + wlconfig->keyboard = NULL; + } + +#if 0 + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) { + input->touch = wl_seat_get_touch(seat); + wl_touch_set_user_data(input->touch, input); + wl_touch_add_listener(input->touch, &touch_listener, input); + } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) { + if (input->seat_version >= WL_TOUCH_RELEASE_SINCE_VERSION) + wl_touch_release(input->touch); + else + wl_touch_destroy(input->touch); + input->touch = NULL; + } +#endif +} + +static const struct wl_seat_listener seat_listener = { + seat_handle_capabilities, +}; + +static void +add_seat(WaylandConfig *wlconfig, uint32_t name, uint32_t version) +{ + wlconfig->pointer.wlpointer = NULL; + wlconfig->seat_version = version; + wlconfig->seat = wl_registry_bind(wlconfig->registry, name, + &wl_seat_interface, 1); + wl_seat_add_listener(wlconfig->seat, &seat_listener, wlconfig); +} + +static void +shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) +{ +} + +struct wl_shm_listener shm_listener = { + shm_format +}; + +static void +handle_ping(void *data, struct wl_shell_surface *shell_surface, + uint32_t serial) +{ + NSDebugLog(@"handle_ping"); + struct window *window = (struct window *) data; + wl_shell_surface_pong(shell_surface, serial); + wl_display_dispatch_pending(window->wlconfig->display); + wl_display_flush(window->wlconfig->display); +} + +static void +handle_configure(void *data, struct wl_shell_surface *shell_surface, + uint32_t edges, int32_t width, int32_t height) +{ +} + +static void +handle_popup_done(void *data, struct wl_shell_surface *shell_surface) +{ +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + handle_ping, + handle_configure, + handle_popup_done +}; + +static void +xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial) +{ + WaylandConfig *wlconfig = data; + xdg_shell_pong(shell, serial); + wl_display_dispatch_pending(wlconfig->display); + wl_display_flush(wlconfig->display); + +} + +static const struct xdg_shell_listener xdg_shell_listener = { + xdg_shell_ping, +}; + +static void +handle_surface_configure(void *data, struct xdg_surface *xdg_surface, + int32_t x, int32_t y, + int32_t width, int32_t height, + struct wl_array *states, uint32_t serial) +{ + struct window *window = data; + WaylandConfig *wlconfig = window->wlconfig; + NSDebugLog(@"handle_surface_configure: win=%d", window->window_id); + + NSEvent *ev = nil; + NSWindow *nswindow = GSWindowWithNumber(window->window_id); + + if (wlconfig->pointer.focus && + wlconfig->pointer.focus->window_id == window->window_id) { + ev = [NSEvent otherEventWithType: NSAppKitDefined + location: NSZeroPoint + modifierFlags: 0 + timestamp: 0 + windowNumber: (int)window->window_id + context: GSCurrentContext() + subtype: GSAppKitWindowFocusIn + data1: 0 + data2: 0]; + + [nswindow sendEvent: ev]; + } + +#if 0 + struct window *window = data; + int moved = 0; + NSDebugLog(@"configure window=%d pos=%dx%d size=%dx%d", + window->window_id, x, y, width, height); + NSDebugLog(@"current values pos=%dx%d size=%dx%d", + window->pos_x, window->pos_y, window->width, window->height); + + if (!window->is_out && (window->pos_x != x || window->pos_y != y)) { + window->pos_x = x; + window->pos_y = y; + moved = 1; + } + + xdg_surface_ack_configure(window->xdg_surface, serial); + NSRect rect = NSMakeRect(0, 0, + window->width, window->height); + [window->instance flushwindowrect:rect :window->window_id]; + + wl_display_dispatch_pending(window->wlconfig->display); + wl_display_flush(window->wlconfig->display); + + if (moved) { + NSDebugLog(@"window moved, notifying AppKit"); + NSEvent *ev = nil; + NSWindow *nswindow = GSWindowWithNumber(window->window_id); + + ev = [NSEvent otherEventWithType: NSAppKitDefined + location: NSZeroPoint + modifierFlags: 0 + timestamp: 0 + windowNumber: (int)window->window_id + context: GSCurrentContext() + subtype: GSAppKitWindowMoved + data1: window->pos_x + data2: WaylandToNS(window, window->pos_y)]; + + [nswindow sendEvent: ev]; + } +#endif +} + +static void +handle_surface_delete(void *data, struct xdg_surface *xdg_surface) +{ + NSDebugLog(@"handle_surface_delete"); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + handle_surface_configure, + handle_surface_delete, +}; + +static void +handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + WaylandConfig *wlconfig = data; + + if (strcmp(interface, "wl_compositor") == 0) { + wlconfig->compositor = + wl_registry_bind(wlconfig->registry, name, + &wl_compositor_interface, 1); + /* + } else if (strcmp(interface, "wl_shell") == 0) { + wlconfig->shell = + wl_registry_bind(registry, name, + &wl_shell_interface, 1); + */ + } else if (strcmp(interface, "xdg_shell") == 0) { + wlconfig->xdg_shell = wl_registry_bind(registry, name, + &xdg_shell_interface, 1); + xdg_shell_use_unstable_version(wlconfig->xdg_shell, 5); + xdg_shell_add_listener(wlconfig->xdg_shell, + &xdg_shell_listener, wlconfig); + } else if (strcmp(interface, "wl_shm") == 0) { + wlconfig->shm = wl_registry_bind(wlconfig->registry, name, + &wl_shm_interface, 1); + wl_shm_add_listener(wlconfig->shm, &shm_listener, wlconfig); + } else if (strcmp(interface, "wl_output") == 0) { + add_output(wlconfig, name); + } else if (strcmp(interface, "wl_seat") == 0) { + add_seat(wlconfig, name, version); + } +} + +static void +handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + handle_global, + handle_global_remove +}; + +struct window * +get_window_with_id(WaylandConfig *wlconfig, int winid) +{ + struct window *window; + + wl_list_for_each(window, &wlconfig->window_list, link) { + if (window->window_id == winid) { + return window; + } + } + + return NULL; +} + +float WaylandToNS(struct window *window, float wl_y) +{ + return (window->output->height - wl_y - window->height); +} + +int NSToWayland(struct window *window, int ns_y) +{ + return (window->output->height - ns_y - window->height); +} + +@implementation WaylandServer + +/* Initialize AppKit backend */ ++ (void) initializeBackend +{ + NSDebugLog(@"Initializing GNUstep Wayland backend"); + [GSDisplayServer setDefaultServerClass: [WaylandServer class]]; +} + +- (id) _initWaylandContext +{ + wlconfig = (WaylandConfig *) malloc(sizeof(WaylandConfig)); + memset(wlconfig, 0, sizeof(WaylandConfig)); + wlconfig->last_window_id = 1; + wl_list_init(&wlconfig->output_list); + wl_list_init(&wlconfig->window_list); + + wlconfig->display = wl_display_connect(NULL); + if (!wlconfig->display) { + [NSException raise: NSWindowServerCommunicationException + format: @"Unable to connect Wayland Server"]; + } + + wlconfig->registry = wl_display_get_registry(wlconfig->display); + wl_registry_add_listener(wlconfig->registry, + ®istry_listener, wlconfig); + wl_display_dispatch(wlconfig->display); + wl_display_roundtrip(wlconfig->display); + + return self; +} + +- (void) receivedEvent: (void*)data + type: (RunLoopEventType)type + extra: (void*)extra + forMode: (NSString*)mode +{ + NSDebugLog(@"receivedEvent"); + if (type == ET_RDESC){ + if (wl_display_dispatch(wlconfig->display) == -1) { + [NSException raise: NSWindowServerCommunicationException + format: @"Connection to Wayland Server lost"]; + } + } +} + +- (void) setupRunLoopInputSourcesForMode: (NSString*)mode +{ + NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; + int fdWaylandHandle = wl_display_get_fd(wlconfig->display); + + [currentRunLoop addEvent: (void*)fdWaylandHandle + type: ET_RDESC + watcher: (id)self + forMode: mode]; +} + +- (id) initWithAttributes: (NSDictionary *)info +{ + NSDebugLog(@"WaylandServer initWithAttributes"); + [super initWithAttributes: info]; + [self _initWaylandContext]; + + [self setupRunLoopInputSourcesForMode: NSDefaultRunLoopMode]; + [self setupRunLoopInputSourcesForMode: NSConnectionReplyMode]; + [self setupRunLoopInputSourcesForMode: NSModalPanelRunLoopMode]; + [self setupRunLoopInputSourcesForMode: NSEventTrackingRunLoopMode]; + + return self; +} + +- (void) dealloc +{ + NSDebugLog(@"Destroying Wayland Server"); + [super dealloc]; +} + +- (BOOL) handlesWindowDecorations +{ + return NO; +} + +- (void) restrictWindow: (int)win toImage: (NSImage*)image +{ + NSDebugLog(@"restrictWindow"); +} + +- (NSRect) boundsForScreen: (int)screen +{ + NSDebugLog(@"boundsForScreen: %d", screen); + struct output *output; + + wl_list_for_each(output, &wlconfig->output_list, link) { + NSDebugLog(@"screen found: %dx%d", output->width, output->height); + return NSMakeRect(0, 0, output->width, output->height); + } + + NSDebugLog(@"can't find screen"); + return NSZeroRect; +} + +- (NSWindowDepth) windowDepthForScreen: (int)screen +{ + NSDebugLog(@"windowDepthForScreen: %d", screen); + return (_GSRGBBitValue | 8); +} + +- (const NSWindowDepth *) availableDepthsForScreen: (int)screen +{ + NSDebugLog(@"availableDepthsForScreen"); + return NULL; +} + +- (NSArray *) screenList +{ + NSDebugLog(@"screenList"); + NSMutableArray *screens = + [NSMutableArray arrayWithCapacity: wlconfig->output_count]; + struct output *output; + + wl_list_for_each(output, &wlconfig->output_list, link) { + [screens addObject: [NSNumber numberWithInt: output->server_output_id]]; + NSDebugLog(@"adding screen with output_id=%d", output->server_output_id); + NSDebugLog(@"output dimensions: %dx%d %dx%d", + output->alloc_x, output->alloc_y, + output->width, output->height); + } + + return screens; +} + +- (void *) serverDevice +{ + NSDebugLog(@"serverDevice"); + return NULL; +} + +- (void *) windowDevice: (int)win +{ + NSDebugLog(@"windowDevice"); + return NULL; +} + +- (void) beep +{ + NSDebugLog(@"beep"); +} + +@end + + +@implementation WaylandServer (WindowOps) + +- (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style + : (int)screen +{ + NSDebugLog(@"window: screen=%d frame=%@", screen, NSStringFromRect(frame)); + struct window *window; + struct output *output; + struct wl_surface *wlsurface; + cairo_surface_t *cairo_surface; + cairo_t *cr; + int width; + int height; + int altered = 0; + int window_type = 0; + + /* We're not allowed to create a zero rect window */ + if (NSWidth(frame) <= 0 || NSHeight(frame) <= 0) { + NSDebugLog(@"trying try create a zero rect window"); + frame.size.width = 2; + frame.size.height = 2; + } + + window = malloc(sizeof(struct window)); + memset(window, 0, sizeof(struct window)); + + wl_list_for_each(output, &wlconfig->output_list, link) { + if (output->server_output_id == screen) { + window->output = output; + break; + } + } + + if (!window->output) { + NSDebugLog(@"can't find screen %d", screen); + free(window); + return 0; + } + + window->wlconfig = wlconfig; + window->instance = self; + window->is_out = 0; + window->width = width = NSWidth(frame); + window->height = height = NSHeight(frame); + window->pos_x = frame.origin.x; + window->pos_y = NSToWayland(window, frame.origin.y); + + wlsurface = wl_compositor_create_surface(wlconfig->compositor); + if (wlsurface == NULL) { + NSDebugLog(@"can't create wayland surface"); + return 0; + } + /* + window->shell_surface = wl_shell_get_shell_surface(wlconfig->shell, + wlsurface); + if (window->shell_surface) { + NSDebugLog(@"shell surface is present"); + wl_shell_surface_add_listener(window->shell_surface, + &shell_surface_listener, window); + wl_shell_surface_set_toplevel(window->shell_surface); + } else { + NSDebugLog(@"shell surface is missing"); + } + */ + + if (style & NSMainMenuWindowMask) { + window->xdg_surface = + xdg_shell_get_xdg_surface_special(wlconfig->xdg_shell, wlsurface, 2); + NSDebugLog(@"window id=%d will be a panel", wlconfig->last_window_id); + } + else if (style & NSBackgroundWindowMask) + window->xdg_surface = + xdg_shell_get_xdg_surface_special(wlconfig->xdg_shell, wlsurface, 1); + else + window->xdg_surface = + xdg_shell_get_xdg_surface_special(wlconfig->xdg_shell, wlsurface, 0); + + + xdg_surface_set_user_data(window->xdg_surface, window); + xdg_surface_add_listener(window->xdg_surface, + &xdg_surface_listener, window); + + if (window->pos_x < 0) { + window->pos_x = 0; + altered = 1; + } + +#if 0 + if (window->pos_y < 31) { + window->pos_y = 31; + altered = 1; + } +#endif + + NSDebugLog(@"creating new window with id=%d: pos=%fx%f, size=%fx%f", + window->window_id, window->pos_x, window->pos_y, + window->width, window->height); + xdg_surface_set_window_geometry(window->xdg_surface, + window->pos_x, + window->pos_y, + window->width, + window->height); + wl_surface_commit(wlsurface); + + wl_surface_set_user_data(wlsurface, window); + window->surface = wlsurface; + + window->window_id = wlconfig->last_window_id; + wl_list_insert(wlconfig->window_list.prev, &window->link); + (wlconfig->last_window_id)++; + (wlconfig->window_count)++; + + wl_display_dispatch_pending(wlconfig->display); + wl_display_flush(wlconfig->display); + + [self _setWindowOwnedByServer: (int)window->window_id]; + + if (altered) { + NSEvent *ev = [NSEvent otherEventWithType: NSAppKitDefined + location: NSZeroPoint + modifierFlags: 0 + timestamp: 0 + windowNumber: (int)window->window_id + context: GSCurrentContext() + subtype: GSAppKitWindowMoved + data1: window->pos_x + data2: WaylandToNS(window, window->pos_y)]; + [(GSWindowWithNumber(window->window_id)) sendEvent: ev]; + NSDebugLog(@"window: notifying of move=%fx%f", window->pos_x, WaylandToNS(window, window->pos_y)); + } + + + return window->window_id; +} + +- (void) termwindow: (int) win +{ + NSDebugLog(@"termwindow: win=%d", win); + struct window *window = get_window_with_id(wlconfig, win); + + if (window->xdg_surface) { + xdg_surface_destroy(window->xdg_surface); + } + + wl_surface_destroy(window->surface); + wl_buffer_destroy(window->buffer); + wl_list_remove(&window->link); + + free(window); +} + +- (int) nativeWindow: (void *)winref + : (NSRect*)frame + : (NSBackingStoreType*)type + : (unsigned int*)style + : (int*)screen +{ + NSDebugLog(@"nativeWindow"); + return 0; +} + +- (void) stylewindow: (unsigned int) style : (int) win +{ + NSDebugLog(@"stylewindow"); +} + +- (void) windowbacking: (NSBackingStoreType)type : (int) win +{ + NSDebugLog(@"windowbacking"); +} + +- (void) titlewindow: (NSString *) window_title : (int) win +{ + NSDebugLog(@"titlewindow: win=%d title=%@", win, window_title); + if (window_title == @"Window") { + return; + } + + struct window *window = get_window_with_id(wlconfig, win); + const char *cString = [window_title UTF8String]; + + xdg_surface_set_title(window->xdg_surface, cString); +} + +- (void) miniwindow: (int) win +{ + NSDebugLog(@"miniwindow"); + [self orderwindow: NSWindowOut :0 :win]; +} + +- (void) setWindowdevice: (int) winId forContext: (NSGraphicsContext *)ctxt +{ + NSDebugLog(@"setWindowdevice: %d", winId); + struct window *window; + + window = get_window_with_id(wlconfig, winId); + + GSSetDevice(ctxt, window, 0.0, window->height); + DPSinitmatrix(ctxt); + DPSinitclip(ctxt); +} + +- (void) orderwindow: (int) op : (int) otherWin : (int) win +{ + NSDebugLog(@"orderwindow: %d", win); + struct window *window = get_window_with_id(wlconfig, win); + + if (op == NSWindowOut) { + NSDebugLog(@"orderwindow: NSWindowOut"); + //window->pos_x += 32000; + //window->pos_y += 32000; + window->is_out = 1; + xdg_surface_set_window_geometry(window->xdg_surface, + window->pos_x + 32000, + window->pos_y + 32000, + window->width, + window->height); + NSRect rect = NSMakeRect(0, 0, + window->width, window->height); + [window->instance flushwindowrect:rect :window->window_id]; + + wl_display_dispatch_pending(window->wlconfig->display); + wl_display_flush(window->wlconfig->display); + + + //xdg_surface_set_minimized(window->xdg_surface); + } else /*if (window->is_out)*/ { + NSDebugLog(@"orderwindow: restoring to %dx%d", window->pos_x, window->pos_y); + xdg_surface_set_window_geometry(window->xdg_surface, + window->pos_x, + window->pos_y, + window->width, + window->height); + NSRect rect = NSMakeRect(0, 0, + window->width, window->height); + [window->instance flushwindowrect:rect :window->window_id]; + + xdg_surface_set_minimized(window->xdg_surface); + + wl_display_dispatch_pending(window->wlconfig->display); + wl_display_flush(window->wlconfig->display); + + window->is_out = 0; + } +} + +- (void) movewindow: (NSPoint)loc : (int) win +{ + NSDebugLog(@"movewindow"); +} + + +- (NSRect) _OSFrameToWFrame: (NSRect)o for: (void*)win +{ + struct window *window = (struct window *)win; + NSRect x; + + x.size.width = o.size.width; + x.size.height = o.size.height; + x.origin.x = o.origin.x; + x.origin.y = o.origin.y + o.size.height; + x.origin.y = window->output->height - x.origin.y; + return x; +} + +- (void) placewindow: (NSRect)rect : (int) win +{ + NSDebugLog(@"placewindow: %d %@", win, NSStringFromRect(rect)); + struct window *window = get_window_with_id(wlconfig, win); + WaylandConfig *wlconfig = window->wlconfig; + + if (0 && wlconfig->pointer.serial && wlconfig->pointer.focus && + wlconfig->pointer.focus->window_id == win) { + NSEvent *event; + NSEventType eventType; + NSPoint eventLocation; + NSGraphicsContext *gcontext; + unsigned int eventFlags; + float deltaX = 0.0; + float deltaY = 0.0; + int tick; + + gcontext = GSCurrentContext(); + eventLocation = NSMakePoint(wlconfig->pointer.x, + window->height - wlconfig->pointer.y); + eventFlags = 0; + eventType = NSLeftMouseUp; + + tick = 0; + + NSDebugLog(@"sending pointer event at: %fx%f, window=%d", wlconfig->pointer.x, wlconfig->pointer.y, window->window_id); + + event = [NSEvent mouseEventWithType: eventType + location: eventLocation + modifierFlags: eventFlags + timestamp: (NSTimeInterval) 0 + windowNumber: (int)window->window_id + context: gcontext + eventNumber: tick + clickCount: 1 + pressure: 1.0 + buttonNumber: 0 /* FIXME */ + deltaX: deltaX + deltaY: deltaY + deltaZ: 0.]; + + [GSCurrentServer() postEvent: event atStart: NO]; + + xdg_surface_move(window->xdg_surface, + wlconfig->seat, + wlconfig->pointer.serial); + } else { + NSDebugLog(@"placewindow: oldpos=%fx%f", window->pos_x, window->pos_y); + NSDebugLog(@"placewindow: oldsize=%fx%f", window->width, window->height); + NSRect frame; + NSRect wframe; + BOOL resize = NO; + BOOL move = NO; + + frame = [(GSWindowWithNumber(window->window_id)) frame]; + if (NSEqualRects(rect, frame) == YES) + return; + if (NSEqualSizes(rect.size, frame.size) == NO) { + resize = YES; + move = YES; + } + if (NSEqualPoints(rect.origin, frame.origin) == NO) { + move = YES; + } + + wframe = [self _OSFrameToWFrame: rect for: window]; + + if (wlconfig->pointer.focus && + wlconfig->pointer.focus->window_id == window->window_id) { + wlconfig->pointer.y -= (wframe.origin.y - window->pos_y); + wlconfig->pointer.x -= (wframe.origin.x - window->pos_x); + } + + window->width = wframe.size.width; + window->height = wframe.size.height; + window->pos_x = wframe.origin.x; + window->pos_y = wframe.origin.y; + + xdg_surface_set_window_geometry(window->xdg_surface, + window->pos_x, + window->pos_y, + window->width, + window->height); + + NSRect flushRect = NSMakeRect(0, 0, + window->width, window->height); + [window->instance flushwindowrect:rect :window->window_id]; + + wl_display_dispatch_pending(window->wlconfig->display); + wl_display_flush(window->wlconfig->display); + + if (resize == YES) { + NSEvent *ev = [NSEvent otherEventWithType: NSAppKitDefined + location: rect.origin + modifierFlags: 0 + timestamp: 0 + windowNumber: win + context: GSCurrentContext() + subtype: GSAppKitWindowResized + data1: rect.size.width + data2: rect.size.height]; + [(GSWindowWithNumber(window->window_id)) sendEvent: ev]; + NSDebugLog(@"placewindow notify resized=%fx%f", rect.size.width, rect.size.height); + } else if (move == YES) { + NSEvent *ev = [NSEvent otherEventWithType: NSAppKitDefined + location: NSZeroPoint + modifierFlags: 0 + timestamp: 0 + windowNumber: (int)window->window_id + context: GSCurrentContext() + subtype: GSAppKitWindowMoved + data1: rect.origin.x + data2: rect.origin.y]; + [(GSWindowWithNumber(window->window_id)) sendEvent: ev]; + NSDebugLog(@"placewindow notify moved=%fx%f", rect.origin.x, rect.origin.y); + } + + NSDebugLog(@"placewindow: newpos=%fx%f", window->pos_x, window->pos_y); + NSDebugLog(@"placewindow: newsize=%fx%f", window->width, window->height); + } +} + +- (NSRect) windowbounds: (int) win +{ + struct window *window = get_window_with_id(wlconfig, win); + NSDebugLog(@"windowbounds: win=%d, pos=%dx%d size=%dx%d", + window->window_id, window->pos_x, window->pos_y, + window->width, window->height); + + return NSMakeRect(window->pos_x, window->output->height - window->pos_y, + window->width, window->height); +} + +- (void) setwindowlevel: (int) level : (int) win +{ + NSDebugLog(@"setwindowlevel: level=%d win=%d", level, win); +} + +- (int) windowlevel: (int) win +{ + NSDebugLog(@"windowlevel: %d", win); + return 0; +} + +/** Backends can override this method to return an array of window numbers + ordered front to back. The front most window being the first object + in the array. + The default implementation returns the visible windows in an + unspecified order. + */ +- (NSArray *) windowlist +{ + NSMutableArray *list = [NSMutableArray arrayWithArray:[NSApp windows]]; + int c = [list count]; + + while (c-- > 0) + { + if (![[list objectAtIndex:c] isVisible]) + { + [list removeObjectAtIndex:c]; + } + } + return [list valueForKey:@"windowNumber"]; +} + +- (int) windowdepth: (int) win +{ + NSDebugLog(@"windowdepth"); + return 0; +} + +- (void) setmaxsize: (NSSize)size : (int) win +{ + NSDebugLog(@"setmaxsize"); +} + +- (void) setminsize: (NSSize)size : (int) win +{ + NSDebugLog(@"setminsize"); +} + +- (void) setresizeincrements: (NSSize)size : (int) win +{ + NSDebugLog(@"setresizeincrements"); +} + +- (void) flushwindowrect: (NSRect)rect : (int) win +{ + NSDebugLog(@"flushwindowrect: %d %fx%f", win, NSWidth(rect), NSHeight(rect)); + struct window *window = get_window_with_id(wlconfig, win); + + [[GSCurrentContext() class] handleExposeRect: rect forDriver: window->wcs]; +} + +- (void) styleoffsets: (float*) l : (float*) r : (float*) t : (float*) b + : (unsigned int) style +{ + NSDebugLog(@"styleoffsets"); + /* XXX - Assume we don't decorations */ + *l = *r = *t = *b = 0.0; +} + +- (void) docedited: (int) edited : (int) win +{ + NSDebugLog(@"docedited"); +} + +- (void) setinputstate: (int)state : (int)win +{ + NSDebugLog(@"setinputstate"); +} + +- (void) setinputfocus: (int) win +{ + NSDebugLog(@"setinputfocus"); +} + +- (void) setalpha: (float)alpha : (int) win +{ + NSDebugLog(@"setalpha"); +} + +- (void) setShadow: (BOOL)hasShadow : (int)win +{ + NSDebugLog(@"setshadow"); +} + +- (NSPoint) mouselocation +{ + NSDebugLog(@"mouselocation"); + return NSZeroPoint; +} + +- (NSPoint) mouseLocationOnScreen: (int)aScreen window: (int *)win +{ + NSDebugLog(@"mouseLocationOnScreen: %d %fx%f", win, + wlconfig->pointer.x, wlconfig->pointer.y); + struct window *window = wlconfig->pointer.focus; + struct output *output; + float x; + float y; + + /*if (wlconfig->pointer.serial) { + NSDebugLog(@"captured"); + x = wlconfig->pointer.captured_x; + y = wlconfig->pointer.captured_y; + } else*/ { + NSDebugLog(@"NOT captured"); + x = wlconfig->pointer.x; + y = wlconfig->pointer.y; + + if (window) { + x += window->pos_x; + y += window->pos_y; + win = &window->window_id; + } + } + + wl_list_for_each(output, &wlconfig->output_list, link) { + if (output->server_output_id == aScreen) { + y = output->height - y; + break; + } + } + + NSDebugLog(@"mouseLocationOnScreen: returning %fx%f", x, y); + + return NSMakePoint(x, y); +} + +- (BOOL) capturemouse: (int) win +{ + NSDebugLog(@"capturemouse: %d", win); + return NO; +} + +- (void) releasemouse +{ + NSDebugLog(@"releasemouse"); +} + +- (void) setMouseLocation: (NSPoint)mouseLocation onScreen: (int)aScreen +{ + NSDebugLog(@"setMouseLocation"); +} + +- (void) hidecursor +{ + NSDebugLog(@"hidecursor"); +} + +- (void) showcursor +{ + NSDebugLog(@"showcursor"); +} + +- (void) standardcursor: (int) style : (void**) cid +{ + NSDebugLog(@"standardcursor"); +} + +- (void) imagecursor: (NSPoint)hotp : (NSImage *) image : (void**) cid +{ + NSDebugLog(@"imagecursor"); +} + +- (void) setcursorcolor: (NSColor *)fg : (NSColor *)bg : (void*) cid +{ + NSLog(@"Call to obsolete method -setcursorcolor:::"); + [self recolorcursor: fg : bg : cid]; + [self setcursor: cid]; +} + +- (void) recolorcursor: (NSColor *)fg : (NSColor *)bg : (void*) cid +{ + NSDebugLog(@"recolorcursor"); +} + +- (void) setcursor: (void*) cid +{ + NSDebugLog(@"setcursor"); +} + +- (void) freecursor: (void*) cid +{ + NSDebugLog(@"freecursor"); +} + +- (void) setParentWindow: (int)parentWin + forChildWindow: (int)childWin +{ + NSDebugLog(@"setParentWindow: parent=%d child=%d", parentWin, childWin); + struct window *parent = get_window_with_id(wlconfig, parentWin); + struct window *child = get_window_with_id(wlconfig, childWin); + + if (parent) { + xdg_surface_set_parent(child->xdg_surface, parent->xdg_surface); + } else { + xdg_surface_set_parent(child->xdg_surface, NULL); + } + xdg_surface_set_minimized(child->xdg_surface); + wl_display_dispatch_pending(wlconfig->display); + wl_display_flush(wlconfig->display); +} + +- (void) setIgnoreMouse: (BOOL)ignoreMouse : (int)win +{ + NSDebugLog(@"setIgnoreMouse"); +} + +@end diff --git a/Source/wayland/xdg-shell-unstable-v5-protocol.c b/Source/wayland/xdg-shell-unstable-v5-protocol.c new file mode 100644 index 00000000..8599ba38 --- /dev/null +++ b/Source/wayland/xdg-shell-unstable-v5-protocol.c @@ -0,0 +1,129 @@ +/* + * Copyright © 2008-2013 Kristian Høgsberg + * Copyright © 2013 Rafael Antognolli + * Copyright © 2013 Jasper St. Pierre + * Copyright © 2010-2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface xdg_popup_interface; +extern const struct wl_interface xdg_surface_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &xdg_surface_interface, + &wl_surface_interface, + &xdg_surface_interface, + &wl_surface_interface, + NULL, + &xdg_popup_interface, + &wl_surface_interface, + &wl_surface_interface, + &wl_seat_interface, + NULL, + NULL, + NULL, + &xdg_surface_interface, + &wl_seat_interface, + NULL, + NULL, + NULL, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_output_interface, +}; + +static const struct wl_message xdg_shell_requests[] = { + { "destroy", "", types + 0 }, + { "use_unstable_version", "i", types + 0 }, + { "get_xdg_surface", "no", types + 6 }, + { "get_xdg_surface_special", "nou", types + 8 }, + { "get_xdg_popup", "nooouii", types + 11 }, + { "pong", "u", types + 0 }, +}; + +static const struct wl_message xdg_shell_events[] = { + { "ping", "u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface xdg_shell_interface = { + "xdg_shell", 1, + 6, xdg_shell_requests, + 1, xdg_shell_events, +}; + +static const struct wl_message xdg_surface_requests[] = { + { "destroy", "", types + 0 }, + { "set_parent", "?o", types + 18 }, + { "set_title", "s", types + 0 }, + { "set_app_id", "s", types + 0 }, + { "show_window_menu", "ouii", types + 19 }, + { "move", "ou", types + 23 }, + { "resize", "ouu", types + 25 }, + { "ack_configure", "u", types + 0 }, + { "set_window_geometry", "iiii", types + 0 }, + { "set_maximized", "", types + 0 }, + { "unset_maximized", "", types + 0 }, + { "set_fullscreen", "?o", types + 28 }, + { "unset_fullscreen", "", types + 0 }, + { "set_minimized", "", types + 0 }, +}; + +static const struct wl_message xdg_surface_events[] = { + { "configure", "iiiiau", types + 0 }, + { "close", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface xdg_surface_interface = { + "xdg_surface", 1, + 14, xdg_surface_requests, + 2, xdg_surface_events, +}; + +static const struct wl_message xdg_popup_requests[] = { + { "destroy", "", types + 0 }, +}; + +static const struct wl_message xdg_popup_events[] = { + { "popup_done", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface xdg_popup_interface = { + "xdg_popup", 1, + 1, xdg_popup_requests, + 1, xdg_popup_events, +}; + diff --git a/config.h.in b/config.h.in index 2ddb486e..9cb108de 100644 --- a/config.h.in +++ b/config.h.in @@ -3,6 +3,7 @@ #define SERVER_x11 1 #define SERVER_win32 2 +#define SERVER_wayland 3 #define GRAPHICS_xdps 0 #define GRAPHICS_art 1 #define GRAPHICS_xlib 2 diff --git a/configure.ac b/configure.ac index ec708899..60d7ef87 100644 --- a/configure.ac +++ b/configure.ac @@ -565,7 +565,7 @@ case $target_os in esac AC_ARG_ENABLE(server, - [ --enable-server=SRV Build server type: x11, win32],, + [ --enable-server=SRV Build server type: x11, win32, wayland],, enable_server=$BUILD_SERVER) AC_ARG_ENABLE(graphics, [ --enable-graphics=GPH Build graphics: xlib, xdps, winlib, art, cairo, opal],, @@ -584,6 +584,8 @@ if test x"$BUILD_GRAPHICS" = "xcairo"; then AC_MSG_WARN([can't find freetype, required for graphics=cairo]) if test $BUILD_SERVER = win32; then BUILD_GRAPHICS=winlib + elif test $BUILD_SERVER = wayland; then + AC_MSG_ERROR([wayland backend requires cairo]) else BUILD_GRAPHICS=xlib fi @@ -592,6 +594,8 @@ if test x"$BUILD_GRAPHICS" = "xcairo"; then AC_MSG_WARN([can't find cairo, required for graphics=cairo!]) if test $BUILD_SERVER = win32; then BUILD_GRAPHICS=winlib + elif test $BUILD_SERVER = wayland; then + AC_MSG_ERROR([wayland backend requires cairo]) else BUILD_GRAPHICS=art fi @@ -642,6 +646,9 @@ if test x"$BUILD_GRAPHICS" = "xcairo"; then CAIRO_LIBS="$CAIRO_LIBS $CAIRO_XLIB_LIBS $XFT_LIBS" CAIRO_CFLAGS="$CAIRO_CFLAGS $CAIRO_XLIB_CFLAGS" AC_MSG_RESULT(xlib) + elif test $BUILD_SERVER = wayland; then + CAIRO_LIBS="$CAIRO_LIBS $XFT_LIBS" + CAIRO_CFLAGS="$CAIRO_CFLAGS" else AC_MSG_ERROR([Invalid Cairo installation]) fi @@ -743,6 +750,7 @@ fi AH_TOP([ #define SERVER_x11 1 #define SERVER_win32 2 +#define SERVER_wayland 3 #define GRAPHICS_xdps 0 #define GRAPHICS_art 1 #define GRAPHICS_xlib 2 From 05f362d528aeb714134e0fc335703cdbe4c6791a Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Sat, 3 Feb 2018 15:46:46 +0000 Subject: [PATCH 02/23] wayland: Add wayland integration and use stable protocol. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit non functional, all changes just make it compile again. Configure changes by Ivan Vučica. --- Headers/wayland/WaylandServer.h | 6 +- Headers/wayland/xdg-shell-client-protocol.h | 1842 +++++++++++++++++ .../xdg-shell-unstable-v5-client-protocol.h | 559 ----- Source/wayland/GNUmakefile | 2 +- Source/wayland/WaylandServer.m | 48 +- ...ble-v5-protocol.c => xdg-shell-protocol.c} | 117 +- configure | 146 +- configure.ac | 9 + 8 files changed, 2094 insertions(+), 635 deletions(-) create mode 100644 Headers/wayland/xdg-shell-client-protocol.h delete mode 100644 Headers/wayland/xdg-shell-unstable-v5-client-protocol.h rename Source/wayland/{xdg-shell-unstable-v5-protocol.c => xdg-shell-protocol.c} (58%) diff --git a/Headers/wayland/WaylandServer.h b/Headers/wayland/WaylandServer.h index 5c656f63..b63b1a63 100644 --- a/Headers/wayland/WaylandServer.h +++ b/Headers/wayland/WaylandServer.h @@ -16,7 +16,7 @@ #include #include "cairo/WaylandCairoSurface.h" -#include "wayland/xdg-shell-unstable-v5-client-protocol.h" +#include "wayland/xdg-shell-client-protocol.h" struct pointer { struct wl_pointer *wlpointer; @@ -36,14 +36,14 @@ typedef struct _WaylandConfig { struct wl_registry *registry; struct wl_compositor *compositor; struct wl_shell *shell; - struct xdg_shell *xdg_shell; + struct xdg_wm_base *wm_base; struct wl_shm *shm; struct wl_seat *seat; struct wl_keyboard *keyboard; struct wl_surface *surface; struct wl_shell_surface *shell_surface; struct wl_buffer *buffer; - + struct wl_list output_list; int output_count; struct wl_list window_list; diff --git a/Headers/wayland/xdg-shell-client-protocol.h b/Headers/wayland/xdg-shell-client-protocol.h new file mode 100644 index 00000000..1f4bfb5d --- /dev/null +++ b/Headers/wayland/xdg-shell-client-protocol.h @@ -0,0 +1,1842 @@ +/* Generated by wayland-scanner 1.17.0 */ + +#ifndef XDG_SHELL_CLIENT_PROTOCOL_H +#define XDG_SHELL_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; + +/** + * @page page_iface_xdg_wm_base xdg_wm_base + * @section page_iface_xdg_wm_base_desc Description + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + */ +extern const struct wl_interface xdg_wm_base_interface; +/** + * @page page_iface_xdg_positioner xdg_positioner + * @section page_iface_xdg_positioner_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an error. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an error. + */ +extern const struct wl_interface xdg_positioner_interface; +/** + * @page page_iface_xdg_surface xdg_surface + * @section page_iface_xdg_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed. + */ +extern const struct wl_interface xdg_surface_interface; +/** + * @page page_iface_xdg_toplevel xdg_toplevel + * @section page_iface_xdg_toplevel_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. + * + * Attaching a null buffer to a toplevel unmaps the surface. + */ +extern const struct wl_interface xdg_toplevel_interface; +/** + * @page page_iface_xdg_popup xdg_popup + * @section page_iface_xdg_popup_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The x and y arguments passed when creating the popup object specify + * where the top left of the popup should be placed, relative to the + * local surface coordinates of the parent surface. See + * xdg_surface.get_popup. An xdg_popup must intersect with or be at least + * partially adjacent to its parent surface. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The x and y arguments passed when creating the popup object specify + * where the top left of the popup should be placed, relative to the + * local surface coordinates of the parent surface. See + * xdg_surface.get_popup. An xdg_popup must intersect with or be at least + * partially adjacent to its parent surface. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface xdg_popup_interface; + +#ifndef XDG_WM_BASE_ERROR_ENUM +#define XDG_WM_BASE_ERROR_ENUM +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, +}; +#endif /* XDG_WM_BASE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_listener + */ +struct xdg_wm_base_listener { + /** + * check if the client is alive + * + * The ping event asks the client if it's still alive. Pass the + * serial specified in the event back to the compositor by sending + * a "pong" request back with the specified serial. See + * xdg_wm_base.pong. + * + * Compositors can use this to determine if the client is still + * alive. It's unspecified what will happen if the client doesn't + * respond to the ping request, or in what timeframe. Clients + * should try to respond in a reasonable amount of time. + * + * A compositor is free to ping in any way it wants, but a client + * must always respond to any xdg_wm_base object it created. + * @param serial pass this to the pong request + */ + void (*ping)(void *data, + struct xdg_wm_base *xdg_wm_base, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_wm_base + */ +static inline int +xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base, + const struct xdg_wm_base_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base, + (void (**)(void)) listener, data); +} + +#define XDG_WM_BASE_DESTROY 0 +#define XDG_WM_BASE_CREATE_POSITIONER 1 +#define XDG_WM_BASE_GET_XDG_SURFACE 2 +#define XDG_WM_BASE_PONG 3 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** @ingroup iface_xdg_wm_base */ +static inline void +xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data); +} + +/** @ingroup iface_xdg_wm_base */ +static inline void * +xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base); +} + +static inline uint32_t +xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * Destroying a bound xdg_wm_base object while there are surfaces + * still alive created by this xdg_wm_base object instance is illegal + * and will result in a protocol error. + */ +static inline void +xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_wm_base); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Create a positioner object. A positioner object is used to position + * surfaces relative to some parent surface. See the interface description + * and xdg_surface.get_popup for details. + */ +static inline struct xdg_positioner * +xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, NULL); + + return (struct xdg_positioner *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * This creates an xdg_surface for the given surface. While xdg_surface + * itself is not a role, the corresponding surface may only be assigned + * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. + * + * This creates an xdg_surface for the given surface. An xdg_surface is + * used as basis to define a role to a given surface, such as xdg_toplevel + * or xdg_popup. It also manages functionality shared between xdg_surface + * based surface roles. + * + * See the documentation of xdg_surface for more details about what an + * xdg_surface is and how it is used. + */ +static inline struct xdg_surface * +xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, NULL, surface); + + return (struct xdg_surface *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_wm_base.ping. + */ +static inline void +xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_PONG, serial); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * vertically resize the surface + * + * Resize the surface vertically so that it is completely unconstrained. + */ +enum xdg_positioner_constraint_adjustment { + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ + +#define XDG_POSITIONER_DESTROY 0 +#define XDG_POSITIONER_SET_SIZE 1 +#define XDG_POSITIONER_SET_ANCHOR_RECT 2 +#define XDG_POSITIONER_SET_ANCHOR 3 +#define XDG_POSITIONER_SET_GRAVITY 4 +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5 +#define XDG_POSITIONER_SET_OFFSET 6 + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 + +/** @ingroup iface_xdg_positioner */ +static inline void +xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data); +} + +/** @ingroup iface_xdg_positioner */ +static inline void * +xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner); +} + +static inline uint32_t +xdg_positioner_get_version(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_positioner); +} + +/** + * @ingroup iface_xdg_positioner + * + * Notify the compositor that the xdg_positioner will no longer be used. + */ +static inline void +xdg_positioner_destroy(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_positioner); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the size of the surface that is to be positioned with the positioner + * object. The size is in surface-local coordinates and corresponds to the + * window geometry. See xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_SIZE, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the anchor rectangle within the parent surface that the child + * surface will be placed relative to. The rectangle is relative to the + * window geometry as defined by xdg_surface.set_window_geometry of the + * parent surface. + * + * When the xdg_positioner object is used to position a child surface, the + * anchor rectangle may not extend outside the window geometry of the + * positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR_RECT, x, y, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines the anchor point for the anchor rectangle. The specified anchor + * is used derive an anchor point that the child surface will be + * positioned relative to. If a corner anchor is set (e.g. 'top_left' or + * 'bottom_right'), the anchor point will be at the specified corner; + * otherwise, the derived anchor point will be centered on the specified + * edge, or in the center of the anchor rectangle if no edge is specified. + */ +static inline void +xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR, anchor); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines in what direction a surface should be positioned, relative to + * the anchor point of the parent surface. If a corner gravity is + * specified (e.g. 'bottom_right' or 'top_left'), then the child surface + * will be placed towards the specified gravity; otherwise, the child + * surface will be centered over the anchor point on any axis that had no + * gravity specified. + */ +static inline void +xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_GRAVITY, gravity); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify how the window should be positioned if the originally intended + * position caused the surface to be constrained, meaning at least + * partially outside positioning boundaries set by the compositor. The + * adjustment is set by constructing a bitmask describing the adjustment to + * be made when the surface is constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that the child + * surface should not change its position on that axis when constrained. + * + * If more than one bit for one axis is set, the order of how adjustments + * are applied is specified in the corresponding adjustment descriptions. + * + * The default adjustment is none. + */ +static inline void +xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, constraint_adjustment); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the surface position offset relative to the position of the + * anchor on the anchor rectangle and the anchor on the surface. For + * example if the anchor of the anchor rectangle is at (x, y), the surface + * has the gravity bottom|right, and the offset is (ox, oy), the calculated + * surface position will be (x + ox, y + oy). The offset position of the + * surface is the one used for constraint testing. See + * set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user interface + * element, while aligning the user interface element of the parent surface + * with some user interface element placed somewhere in the popup surface. + */ +static inline void +xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_OFFSET, x, y); +} + +#ifndef XDG_SURFACE_ERROR_ENUM +#define XDG_SURFACE_ERROR_ENUM +enum xdg_surface_error { + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, +}; +#endif /* XDG_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_listener + */ +struct xdg_surface_listener { + /** + * suggest a surface change + * + * The configure event marks the end of a configure sequence. A + * configure sequence is a set of one or more events configuring + * the state of the xdg_surface, including the final + * xdg_surface.configure event. + * + * Where applicable, xdg_surface surface roles will during a + * configure sequence extend this event as a latched state sent as + * events before the xdg_surface.configure event. Such events + * should be considered to make up a set of atomically applied + * configuration states, where the xdg_surface.configure commits + * the accumulated state. + * + * Clients should arrange their surface for the new states, and + * then send an ack_configure request with the serial sent in this + * configure event at some point before committing the new surface. + * + * If the client receives multiple configure events before it can + * respond to one, it is free to discard all but the last event it + * received. + * @param serial serial of the configure event + */ + void (*configure)(void *data, + struct xdg_surface *xdg_surface, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_surface + */ +static inline int +xdg_surface_add_listener(struct xdg_surface *xdg_surface, + const struct xdg_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, + (void (**)(void)) listener, data); +} + +#define XDG_SURFACE_DESTROY 0 +#define XDG_SURFACE_GET_TOPLEVEL 1 +#define XDG_SURFACE_GET_POPUP 2 +#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3 +#define XDG_SURFACE_ACK_CONFIGURE 4 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** @ingroup iface_xdg_surface */ +static inline void +xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); +} + +/** @ingroup iface_xdg_surface */ +static inline void * +xdg_surface_get_user_data(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); +} + +static inline uint32_t +xdg_surface_get_version(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_surface); +} + +/** + * @ingroup iface_xdg_surface + * + * Destroy the xdg_surface object. An xdg_surface must only be destroyed + * after its role object has been destroyed. + */ +static inline void +xdg_surface_destroy(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_surface); +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_toplevel object for the given xdg_surface and gives + * the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about what an + * xdg_toplevel is and how it is used. + */ +static inline struct xdg_toplevel * +xdg_surface_get_toplevel(struct xdg_surface *xdg_surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, NULL); + + return (struct xdg_toplevel *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_popup object for the given xdg_surface and gives + * the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be specified using + * some other protocol, before committing the initial state. + * + * See the documentation of xdg_popup for more details about what an + * xdg_popup is and how it is used. + */ +static inline struct xdg_popup * +xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_POPUP, &xdg_popup_interface, NULL, parent, positioner); + + return (struct xdg_popup *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * The window geometry of a surface is its "visible bounds" from the + * user's perspective. Client-side decorations often have invisible + * portions like drop-shadows which should be ignored for the + * purposes of aligning, placing and constraining windows. + * + * The window geometry is double buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * When maintaining a position, the compositor should treat the (x, y) + * coordinate of the window geometry as the top left corner of the window. + * A client changing the (x, y) window geometry coordinate should in + * general not alter the position of the window. + * + * Once the window geometry of the surface is set, it is not possible to + * unset it, and it will remain the same until set_window_geometry is + * called again, even if a new subsurface or buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface. + * + * The width and height must be greater than zero. Setting an invalid size + * will raise an error. When applied, the effective window geometry will be + * the set window geometry clamped to the bounding rectangle of the + * combined geometry of the surface of the xdg_surface and the associated + * subsurfaces. + */ +static inline void +xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_WINDOW_GEOMETRY, x, y, width, height); +} + +/** + * @ingroup iface_xdg_surface + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client + * must make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use this + * information to move a surface to the top left only when the client has + * drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it + * can respond to one, it only has to ack the last configure event. + * + * A client is not required to commit immediately after sending + * an ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before committing, but + * only the last request sent before a commit indicates which configure + * event the client really is responding to. + */ +static inline void +xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_ACK_CONFIGURE, serial); +} + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * the surface is tiled + * + * The window is currently in a tiled layout and the bottom edge is + * considered to be adjacent to another part of the tiling grid. + */ +enum xdg_toplevel_state { + /** + * the surface is maximized + */ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + */ + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + */ + XDG_TOPLEVEL_STATE_RESIZING = 3, + /** + * the surface is now activated + */ + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + /** + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + /** + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + /** + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + /** + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, +}; +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +#endif /* XDG_TOPLEVEL_STATE_ENUM */ + +/** + * @ingroup iface_xdg_toplevel + * @struct xdg_toplevel_listener + */ +struct xdg_toplevel_listener { + /** + * suggest a surface change + * + * This configure event asks the client to resize its toplevel + * surface or to change its state. The configured state should not + * be applied immediately. See xdg_surface.configure for details. + * + * The width and height arguments specify a hint to the window + * about how its surface should be resized in window geometry + * coordinates. See set_window_geometry. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. This may happen when the + * compositor needs to configure the state of the surface but + * doesn't have any information about any previous or expected + * dimension. + * + * The states listed in the event specify how the width/height + * arguments should be interpreted, and possibly how it should be + * drawn. + * + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + */ + void (*configure)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states); + /** + * surface wants to be closed + * + * The close event is sent by the compositor when the user wants + * the surface to be closed. This should be equivalent to the user + * clicking the close button in client-side decorations, if your + * application has any. + * + * This is only a request that the user intends to close the + * window. The client may choose to ignore this request, or show a + * dialog to ask the user to save their data, etc. + */ + void (*close)(void *data, + struct xdg_toplevel *xdg_toplevel); +}; + +/** + * @ingroup iface_xdg_toplevel + */ +static inline int +xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, + const struct xdg_toplevel_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel, + (void (**)(void)) listener, data); +} + +#define XDG_TOPLEVEL_DESTROY 0 +#define XDG_TOPLEVEL_SET_PARENT 1 +#define XDG_TOPLEVEL_SET_TITLE 2 +#define XDG_TOPLEVEL_SET_APP_ID 3 +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4 +#define XDG_TOPLEVEL_MOVE 5 +#define XDG_TOPLEVEL_RESIZE 6 +#define XDG_TOPLEVEL_SET_MAX_SIZE 7 +#define XDG_TOPLEVEL_SET_MIN_SIZE 8 +#define XDG_TOPLEVEL_SET_MAXIMIZED 9 +#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10 +#define XDG_TOPLEVEL_SET_FULLSCREEN 11 +#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12 +#define XDG_TOPLEVEL_SET_MINIMIZED 13 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** @ingroup iface_xdg_toplevel */ +static inline void +xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data); +} + +/** @ingroup iface_xdg_toplevel */ +static inline void * +xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel); +} + +static inline uint32_t +xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel); +} + +/** + * @ingroup iface_xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ +static inline void +xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_toplevel); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set the "parent" of this surface. This surface should be stacked + * above the parent surface and all other ancestor surfaces. + * + * Parent windows should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the dialog + * is raised. + * + * Setting a null parent for a child window removes any parent-child + * relationship for the child. Setting a null parent for a window which + * currently has no parent is a no-op. + * + * If the parent is unmapped then its children are managed as + * though the parent of the now-unmapped parent has become the + * parent of this surface. If no parent exists for the now-unmapped + * parent then the children are managed as though they have no + * parent surface. + */ +static inline void +xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_PARENT, parent); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ +static inline void +xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_TITLE, title); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group multiple + * surfaces together, or to determine how to launch a new application. + * + * For D-Bus activatable applications, the app ID is used as the D-Bus + * service name. + * + * The compositor shell will try to group application surfaces together + * by their app ID. As a best practice, it is suggested to select app + * ID's that match the basename of the application's .desktop file. + * For example, "org.freedesktop.FooViewer" where the .desktop file is + * "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after the + * xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] http://standards.freedesktop.org/desktop-entry-spec/ + */ +static inline void +xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_APP_ID, app_id); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Clients implementing client-side decorations might want to show + * a context menu when right-clicking on the decorations, giving the + * user a menu that they can use to maximize or minimize the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu items + * the window menu contains. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. + */ +static inline void +xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SHOW_WINDOW_MENU, seat, serial, x, y); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive move (touch, + * pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed serial + * is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, such as + * updating a pointer cursor, during the move. There is no guarantee + * that the device focus will return when the move is completed. + */ +static inline void +xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_MOVE, seat, serial); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive resize (touch, + * pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the "resize" + * enum value for more details about what is required. The client + * must also acknowledge configure events using "ack_configure". After + * the resize is completed, the client will receive another "configure" + * event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is no + * guarantee that the device focus will return when the resize is + * completed. + * + * The edges parameter specifies how the surface should be resized, + * and is one of the values of the resize_edge enum. The compositor + * may use this information to update the surface position for + * example when dragging the top left corner. The compositor may also + * use this information to adapt its behavior, e.g. choose an + * appropriate cursor image. + */ +static inline void +xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_RESIZE, seat, serial, edges); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor does + * not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered. They will get applied + * on the next commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. + * As a result, a client wishing to reset the maximum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in a protocol error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in a + * protocol error. + */ +static inline void +xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAX_SIZE, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor does + * not try to configure the window below this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered. They will get applied + * on the next commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. + * As a result, a client wishing to reset the minimum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in a protocol error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in a + * protocol error. + */ +static inline void +xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MIN_SIZE, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the compositor + * will respond by emitting a configure event. Whether this configure + * actually sets the window maximized is subject to compositor policies. + * The client must then update its content, drawing in the configured + * state. The client must also acknowledge the configure when committing + * the new content (see ack_configure). + * + * It is up to the compositor to decide how and where to maximize the + * surface, for example which output and what region of the screen should + * be used. + * + * If the surface was already maximized, the compositor will still emit + * a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAXIMIZED); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the compositor + * will respond by emitting a configure event. Whether this actually + * un-maximizes the window is subject to compositor policies. + * If available and applicable, the compositor will include the window + * geometry dimensions the window had prior to being maximized in the + * configure event. The client must then update its content, drawing it in + * the configured state. The client must also acknowledge the configure + * when committing the new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before maximizing, if + * applicable. + * + * If the surface was already not maximized, the compositor will still + * emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_MAXIMIZED); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether the + * client is actually put into a fullscreen state is subject to compositor + * policies. The client must also acknowledge the configure when + * committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's preference as + * to which display it should be set fullscreen on. If this value is NULL, + * it's up to the compositor to choose which display will be used to map + * this surface. + * + * If the surface doesn't cover the whole output, the compositor will + * position the surface in the center of the output and compensate with + * with border fill covering the rest of the output. The content of the + * border fill is undefined, but should be assumed to be in some way that + * attempts to blend into the surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + */ +static inline void +xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_FULLSCREEN, output); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. + * Whether this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based on the following: + * * the state(s) it may have had before becoming fullscreen + * * any state(s) decided by the compositor + * * any state(s) requested by the client while the surface was fullscreen + * + * The compositor may include the previous window geometry dimensions in + * the configure event, if applicable. + * + * The client must also acknowledge the configure when committing the new + * content (see ack_configure). + */ +static inline void +xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_FULLSCREEN); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ +static inline void +xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MINIMIZED); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +#endif /* XDG_POPUP_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_listener + */ +struct xdg_popup_listener { + /** + * configure the popup surface + * + * This event asks the popup surface to configure itself given + * the configuration. The configured state should not be applied + * immediately. See xdg_surface.configure for details. + * + * The x and y arguments represent the position the popup was + * placed at given the xdg_positioner rule, relative to the upper + * left corner of the window geometry of the parent surface. + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ + void (*configure)(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup is dismissed by + * the compositor. The client should destroy the xdg_popup object + * at this point. + */ + void (*popup_done)(void *data, + struct xdg_popup *xdg_popup); +}; + +/** + * @ingroup iface_xdg_popup + */ +static inline int +xdg_popup_add_listener(struct xdg_popup *xdg_popup, + const struct xdg_popup_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, + (void (**)(void)) listener, data); +} + +#define XDG_POPUP_DESTROY 0 +#define XDG_POPUP_GRAB 1 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 + +/** @ingroup iface_xdg_popup */ +static inline void +xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); +} + +/** @ingroup iface_xdg_popup */ +static inline void * +xdg_popup_get_user_data(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); +} + +static inline uint32_t +xdg_popup_get_version(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_popup); +} + +/** + * @ingroup iface_xdg_popup + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, a protocol error + * will be sent. + */ +static inline void +xdg_popup_destroy(struct xdg_popup *xdg_popup) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_popup); +} + +/** + * @ingroup iface_xdg_popup + * + * This request makes the created popup take an explicit grab. An explicit + * grab will be dismissed when the user dismisses the popup, or when the + * client destroys the xdg_popup. This can be done by the user clicking + * outside the surface, using the keyboard, or even locking the screen + * through closing the lid or a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user action like a + * button press, key press, or touch down event. The serial number of the + * event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel surface or + * another xdg_popup with an explicit grab. If the parent is another + * xdg_popup it means that the popups are nested, with this popup now being + * the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were created + * in, e.g. the only popup you are allowed to destroy at all times is the + * topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss every + * nested grabbing popup as well. When a compositor dismisses popups, it + * will follow the same dismissing order as required from the client. + * + * The parent of a grabbing popup must either be another xdg_popup with an + * active explicit grab, or an xdg_popup or xdg_toplevel, if there are no + * explicit grabs already taken. + * + * If the topmost grabbing popup is destroyed, the grab will be returned to + * the parent of the popup, if that parent previously had an explicit grab. + * + * If the parent is a grabbing popup which has already been dismissed, this + * popup will be immediately dismissed. If the parent is a popup that did + * not take an explicit grab, an error will be raised. + * + * During a popup grab, the client owning the grab will receive pointer + * and touch events for all their surfaces as normal (similar to an + * "owner-events" grab in X11 parlance), while the top most grabbing popup + * will always have keyboard focus. + */ +static inline void +xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_GRAB, seat, serial); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Headers/wayland/xdg-shell-unstable-v5-client-protocol.h b/Headers/wayland/xdg-shell-unstable-v5-client-protocol.h deleted file mode 100644 index 74f198d6..00000000 --- a/Headers/wayland/xdg-shell-unstable-v5-client-protocol.h +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright © 2008-2013 Kristian Høgsberg - * Copyright © 2013 Rafael Antognolli - * Copyright © 2013 Jasper St. Pierre - * Copyright © 2010-2013 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifndef XDG_SHELL_UNSTABLE_V5_CLIENT_PROTOCOL_H -#define XDG_SHELL_UNSTABLE_V5_CLIENT_PROTOCOL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include "wayland-client.h" - -struct wl_client; -struct wl_resource; - -struct wl_output; -struct wl_seat; -struct wl_surface; -struct xdg_popup; -struct xdg_shell; -struct xdg_surface; - -extern const struct wl_interface xdg_shell_interface; -extern const struct wl_interface xdg_surface_interface; -extern const struct wl_interface xdg_popup_interface; - -#ifndef XDG_SHELL_VERSION_ENUM -#define XDG_SHELL_VERSION_ENUM -/** - * xdg_shell_version - latest protocol version - * @XDG_SHELL_VERSION_CURRENT: Always the latest version - * - * The 'current' member of this enum gives the version of the protocol. - * Implementations can compare this to the version they implement using - * static_assert to ensure the protocol and implementation versions match. - */ -enum xdg_shell_version { - XDG_SHELL_VERSION_CURRENT = 5, -}; -#endif /* XDG_SHELL_VERSION_ENUM */ - -#ifndef XDG_SHELL_ERROR_ENUM -#define XDG_SHELL_ERROR_ENUM -enum xdg_shell_error { - XDG_SHELL_ERROR_ROLE = 0, - XDG_SHELL_ERROR_DEFUNCT_SURFACES = 1, - XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP = 2, - XDG_SHELL_ERROR_INVALID_POPUP_PARENT = 3, -}; -#endif /* XDG_SHELL_ERROR_ENUM */ - -/** - * xdg_shell - create desktop-style surfaces - * @ping: check if the client is alive - * - * xdg_shell allows clients to turn a wl_surface into a "real window" - * which can be dragged, resized, stacked, and moved around by the user. - * Everything about this interface is suited towards traditional desktop - * environments. - */ -struct xdg_shell_listener { - /** - * ping - check if the client is alive - * @serial: pass this to the pong request - * - * The ping event asks the client if it's still alive. Pass the - * serial specified in the event back to the compositor by sending - * a "pong" request back with the specified serial. - * - * Compositors can use this to determine if the client is still - * alive. It's unspecified what will happen if the client doesn't - * respond to the ping request, or in what timeframe. Clients - * should try to respond in a reasonable amount of time. - * - * A compositor is free to ping in any way it wants, but a client - * must always respond to any xdg_shell object it created. - */ - void (*ping)(void *data, - struct xdg_shell *xdg_shell, - uint32_t serial); -}; - -static inline int -xdg_shell_add_listener(struct xdg_shell *xdg_shell, - const struct xdg_shell_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_shell, - (void (**)(void)) listener, data); -} - -#define XDG_SHELL_DESTROY 0 -#define XDG_SHELL_USE_UNSTABLE_VERSION 1 -#define XDG_SHELL_GET_XDG_SURFACE 2 -#define XDG_SHELL_GET_XDG_SURFACE_SPECIAL 3 -#define XDG_SHELL_GET_XDG_POPUP 4 -#define XDG_SHELL_PONG 5 - -static inline void -xdg_shell_set_user_data(struct xdg_shell *xdg_shell, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_shell, user_data); -} - -static inline void * -xdg_shell_get_user_data(struct xdg_shell *xdg_shell) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_shell); -} - -static inline void -xdg_shell_destroy(struct xdg_shell *xdg_shell) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_shell, - XDG_SHELL_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) xdg_shell); -} - -static inline void -xdg_shell_use_unstable_version(struct xdg_shell *xdg_shell, int32_t version) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_shell, - XDG_SHELL_USE_UNSTABLE_VERSION, version); -} - -static inline struct xdg_surface * -xdg_shell_get_xdg_surface(struct xdg_shell *xdg_shell, struct wl_surface *surface) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell, - XDG_SHELL_GET_XDG_SURFACE, &xdg_surface_interface, NULL, surface); - - return (struct xdg_surface *) id; -} - -static inline struct xdg_surface * -xdg_shell_get_xdg_surface_special(struct xdg_shell *xdg_shell, struct wl_surface *surface, uint32_t type) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell, - XDG_SHELL_GET_XDG_SURFACE_SPECIAL, &xdg_surface_interface, NULL, surface, type); - - return (struct xdg_surface *) id; -} - -static inline struct xdg_popup * -xdg_shell_get_xdg_popup(struct xdg_shell *xdg_shell, struct wl_surface *surface, struct wl_surface *parent, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_shell, - XDG_SHELL_GET_XDG_POPUP, &xdg_popup_interface, NULL, surface, parent, seat, serial, x, y); - - return (struct xdg_popup *) id; -} - -static inline void -xdg_shell_pong(struct xdg_shell *xdg_shell, uint32_t serial) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_shell, - XDG_SHELL_PONG, serial); -} - -#ifndef XDG_SURFACE_RESIZE_EDGE_ENUM -#define XDG_SURFACE_RESIZE_EDGE_ENUM -/** - * xdg_surface_resize_edge - edge values for resizing - * @XDG_SURFACE_RESIZE_EDGE_NONE: (none) - * @XDG_SURFACE_RESIZE_EDGE_TOP: (none) - * @XDG_SURFACE_RESIZE_EDGE_BOTTOM: (none) - * @XDG_SURFACE_RESIZE_EDGE_LEFT: (none) - * @XDG_SURFACE_RESIZE_EDGE_TOP_LEFT: (none) - * @XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT: (none) - * @XDG_SURFACE_RESIZE_EDGE_RIGHT: (none) - * @XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT: (none) - * @XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT: (none) - * - * These values are used to indicate which edge of a surface is being - * dragged in a resize operation. - */ -enum xdg_surface_resize_edge { - XDG_SURFACE_RESIZE_EDGE_NONE = 0, - XDG_SURFACE_RESIZE_EDGE_TOP = 1, - XDG_SURFACE_RESIZE_EDGE_BOTTOM = 2, - XDG_SURFACE_RESIZE_EDGE_LEFT = 4, - XDG_SURFACE_RESIZE_EDGE_TOP_LEFT = 5, - XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT = 6, - XDG_SURFACE_RESIZE_EDGE_RIGHT = 8, - XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT = 9, - XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT = 10, -}; -#endif /* XDG_SURFACE_RESIZE_EDGE_ENUM */ - -#ifndef XDG_SURFACE_STATE_ENUM -#define XDG_SURFACE_STATE_ENUM -/** - * xdg_surface_state - the surface is now activated - * @XDG_SURFACE_STATE_MAXIMIZED: the surface is maximized - * @XDG_SURFACE_STATE_FULLSCREEN: the surface is fullscreen - * @XDG_SURFACE_STATE_RESIZING: the surface is being resized - * @XDG_SURFACE_STATE_ACTIVATED: the surface is now activated - * - * Client window decorations should be painted as if the window is - * active. Do not assume this means that the window actually has keyboard - * or pointer focus. - */ -enum xdg_surface_state { - XDG_SURFACE_STATE_MAXIMIZED = 1, - XDG_SURFACE_STATE_FULLSCREEN = 2, - XDG_SURFACE_STATE_RESIZING = 3, - XDG_SURFACE_STATE_ACTIVATED = 4, -}; -#endif /* XDG_SURFACE_STATE_ENUM */ - -/** - * xdg_surface - A desktop window - * @configure: suggest a surface change - * @close: surface wants to be closed - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides requests to treat surfaces like windows, allowing to set - * properties like maximized, fullscreen, minimized, and to move and resize - * them, and associate metadata like title and app id. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_surface state to take effect. Prior to committing the new - * state, it can set up initial configuration, such as maximizing or - * setting a window geometry. - * - * Even without attaching a buffer the compositor must respond to initial - * committed configuration, for instance sending a configure event with - * expected window geometry if the client maximized its surface during - * initialization. - * - * For a surface to be mapped by the compositor the client must have - * committed both an xdg_surface state and a buffer. - */ -struct xdg_surface_listener { - /** - * configure - suggest a surface change - * @x: (none) - * @y: (none) - * @width: (none) - * @height: (none) - * @states: (none) - * @serial: (none) - * - * The configure event asks the client to resize its surface or - * to change its state. - * - * The width and height arguments specify a hint to the window - * about how its surface should be resized in window geometry - * coordinates. See set_window_geometry. - * - * If the width or height arguments are zero, it means the client - * should decide its own window dimension. This may happen when the - * compositor need to configure the state of the surface but - * doesn't have any information about any previous or expected - * dimension. - * - * The states listed in the event specify how the width/height - * arguments should be interpreted, and possibly how it should be - * drawn. - * - * Clients should arrange their surface for the new size and - * states, and then send a ack_configure request with the serial - * sent in this configure event at some point before committing the - * new surface. - * - * If the client receives multiple configure events before it can - * respond to one, it is free to discard all but the last event it - * received. - */ - void (*configure)(void *data, - struct xdg_surface *xdg_surface, - int32_t x, - int32_t y, - int32_t width, - int32_t height, - struct wl_array *states, - uint32_t serial); - /** - * close - surface wants to be closed - * - * The close event is sent by the compositor when the user wants - * the surface to be closed. This should be equivalent to the user - * clicking the close button in client-side decorations, if your - * application has any... - * - * This is only a request that the user intends to close your - * window. The client may choose to ignore this request, or show a - * dialog to ask the user to save their data... - */ - void (*close)(void *data, - struct xdg_surface *xdg_surface); -}; - -static inline int -xdg_surface_add_listener(struct xdg_surface *xdg_surface, - const struct xdg_surface_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, - (void (**)(void)) listener, data); -} - -#define XDG_SURFACE_DESTROY 0 -#define XDG_SURFACE_SET_PARENT 1 -#define XDG_SURFACE_SET_TITLE 2 -#define XDG_SURFACE_SET_APP_ID 3 -#define XDG_SURFACE_SHOW_WINDOW_MENU 4 -#define XDG_SURFACE_MOVE 5 -#define XDG_SURFACE_RESIZE 6 -#define XDG_SURFACE_ACK_CONFIGURE 7 -#define XDG_SURFACE_SET_WINDOW_GEOMETRY 8 -#define XDG_SURFACE_SET_MAXIMIZED 9 -#define XDG_SURFACE_UNSET_MAXIMIZED 10 -#define XDG_SURFACE_SET_FULLSCREEN 11 -#define XDG_SURFACE_UNSET_FULLSCREEN 12 -#define XDG_SURFACE_SET_MINIMIZED 13 - -static inline void -xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); -} - -static inline void * -xdg_surface_get_user_data(struct xdg_surface *xdg_surface) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); -} - -static inline void -xdg_surface_destroy(struct xdg_surface *xdg_surface) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) xdg_surface); -} - -static inline void -xdg_surface_set_parent(struct xdg_surface *xdg_surface, struct xdg_surface *parent) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_PARENT, parent); -} - -static inline void -xdg_surface_set_title(struct xdg_surface *xdg_surface, const char *title) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_TITLE, title); -} - -static inline void -xdg_surface_set_app_id(struct xdg_surface *xdg_surface, const char *app_id) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_APP_ID, app_id); -} - -static inline void -xdg_surface_show_window_menu(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SHOW_WINDOW_MENU, seat, serial, x, y); -} - -static inline void -xdg_surface_move(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_MOVE, seat, serial); -} - -static inline void -xdg_surface_resize(struct xdg_surface *xdg_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_RESIZE, seat, serial, edges); -} - -static inline void -xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_ACK_CONFIGURE, serial); -} - -static inline void -xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_WINDOW_GEOMETRY, x, y, width, height); -} - -static inline void -xdg_surface_set_maximized(struct xdg_surface *xdg_surface) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_MAXIMIZED); -} - -static inline void -xdg_surface_unset_maximized(struct xdg_surface *xdg_surface) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_UNSET_MAXIMIZED); -} - -static inline void -xdg_surface_set_fullscreen(struct xdg_surface *xdg_surface, struct wl_output *output) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_FULLSCREEN, output); -} - -static inline void -xdg_surface_unset_fullscreen(struct xdg_surface *xdg_surface) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_UNSET_FULLSCREEN); -} - -static inline void -xdg_surface_set_minimized(struct xdg_surface *xdg_surface) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_surface, - XDG_SURFACE_SET_MINIMIZED); -} - -/** - * xdg_popup - short-lived, popup surfaces for menus - * @popup_done: popup interaction is done - * - * A popup surface is a short-lived, temporary surface that can be used - * to implement menus. It takes an explicit grab on the surface that will - * be dismissed when the user dismisses the popup. This can be done by the - * user clicking outside the surface, using the keyboard, or even locking - * the screen through closing the lid or a timeout. - * - * When the popup is dismissed, a popup_done event will be sent out, and at - * the same time the surface will be unmapped. The xdg_popup object is now - * inert and cannot be reactivated, so clients should destroy it. - * Explicitly destroying the xdg_popup object will also dismiss the popup - * and unmap the surface. - * - * Clients will receive events for all their surfaces during this grab - * (which is an "owner-events" grab in X11 parlance). This is done so that - * users can navigate through submenus and other "nested" popup windows - * without having to dismiss the topmost popup. - * - * Clients that want to dismiss the popup when another surface of their own - * is clicked should dismiss the popup using the destroy request. - * - * The parent surface must have either an xdg_surface or xdg_popup role. - * - * Specifying an xdg_popup for the parent means that the popups are nested, - * with this popup now being the topmost popup. Nested popups must be - * destroyed in the reverse order they were created in, e.g. the only popup - * you are allowed to destroy at all times is the topmost one. - * - * If there is an existing popup when creating a new popup, the parent must - * be the current topmost popup. - * - * A parent surface must be mapped before the new popup is mapped. - * - * When compositors choose to dismiss a popup, they will likely dismiss - * every nested popup as well. When a compositor dismisses popups, it will - * follow the same dismissing order as required from the client. - * - * The x and y arguments passed when creating the popup object specify - * where the top left of the popup should be placed, relative to the local - * surface coordinates of the parent surface. See xdg_shell.get_xdg_popup. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_popup state to take effect. - * - * For a surface to be mapped by the compositor the client must have - * committed both the xdg_popup state and a buffer. - */ -struct xdg_popup_listener { - /** - * popup_done - popup interaction is done - * - * The popup_done event is sent out when a popup is dismissed by - * the compositor. The client should destroy the xdg_popup object - * at this point. - */ - void (*popup_done)(void *data, - struct xdg_popup *xdg_popup); -}; - -static inline int -xdg_popup_add_listener(struct xdg_popup *xdg_popup, - const struct xdg_popup_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, - (void (**)(void)) listener, data); -} - -#define XDG_POPUP_DESTROY 0 - -static inline void -xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); -} - -static inline void * -xdg_popup_get_user_data(struct xdg_popup *xdg_popup) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); -} - -static inline void -xdg_popup_destroy(struct xdg_popup *xdg_popup) -{ - wl_proxy_marshal((struct wl_proxy *) xdg_popup, - XDG_POPUP_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) xdg_popup); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Source/wayland/GNUmakefile b/Source/wayland/GNUmakefile index 264cc7fc..186411bd 100644 --- a/Source/wayland/GNUmakefile +++ b/Source/wayland/GNUmakefile @@ -37,7 +37,7 @@ wayland_LOCALIZED_RESOURCE_FILES = \ # The C source files to be compiled wayland_C_FILES = \ -xdg-shell-unstable-v5-protocol.c \ +xdg-shell-protocol.c \ # The Objective-C source files to be compiled wayland_OBJC_FILES = \ diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index cb4a7e04..f0b8d40a 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -623,24 +623,22 @@ }; static void -xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial) +xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) { WaylandConfig *wlconfig = data; - xdg_shell_pong(shell, serial); + xdg_wm_base_pong(shell, serial); wl_display_dispatch_pending(wlconfig->display); wl_display_flush(wlconfig->display); } -static const struct xdg_shell_listener xdg_shell_listener = { - xdg_shell_ping, +static const struct xdg_wm_base_listener wm_base_listener = { + xdg_wm_base_ping, }; static void handle_surface_configure(void *data, struct xdg_surface *xdg_surface, - int32_t x, int32_t y, - int32_t width, int32_t height, - struct wl_array *states, uint32_t serial) + uint32_t serial) { struct window *window = data; WaylandConfig *wlconfig = window->wlconfig; @@ -706,15 +704,8 @@ #endif } -static void -handle_surface_delete(void *data, struct xdg_surface *xdg_surface) -{ - NSDebugLog(@"handle_surface_delete"); -} - static const struct xdg_surface_listener xdg_surface_listener = { handle_surface_configure, - handle_surface_delete, }; static void @@ -734,11 +725,10 @@ &wl_shell_interface, 1); */ } else if (strcmp(interface, "xdg_shell") == 0) { - wlconfig->xdg_shell = wl_registry_bind(registry, name, - &xdg_shell_interface, 1); - xdg_shell_use_unstable_version(wlconfig->xdg_shell, 5); - xdg_shell_add_listener(wlconfig->xdg_shell, - &xdg_shell_listener, wlconfig); + wlconfig->wm_base = wl_registry_bind(registry, name, + &xdg_wm_base_interface, 1); + xdg_shell_add_listener(wlconfig->wm_base, + &wm_base_listener, wlconfig); } else if (strcmp(interface, "wl_shm") == 0) { wlconfig->shm = wl_registry_bind(wlconfig->registry, name, &wl_shm_interface, 1); @@ -982,6 +972,7 @@ - (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style window->height = height = NSHeight(frame); window->pos_x = frame.origin.x; window->pos_y = NSToWayland(window, frame.origin.y); + window->window_id = wlconfig->last_window_id; wlsurface = wl_compositor_create_surface(wlconfig->compositor); if (wlsurface == NULL) { @@ -1001,18 +992,17 @@ - (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style } */ + window->xdg_surface = xdg_wm_base_get_xdg_surface(wlconfig->wm_base, + wlsurface); + // TODO: xdg_shell_get_xdg_surface_special() no longer exists, + // so we need to find another way if (style & NSMainMenuWindowMask) { - window->xdg_surface = - xdg_shell_get_xdg_surface_special(wlconfig->xdg_shell, wlsurface, 2); - NSDebugLog(@"window id=%d will be a panel", wlconfig->last_window_id); + NSDebugLog(@"window id=%d will be a panel", window->window_id); + } else if (style & NSBackgroundWindowMask) { + NSDebugLog(@"window id=%d will be a ?", window->window_id); + } else { + NSDebugLog(@"window id=%d will be ordinary", window->window_id); } - else if (style & NSBackgroundWindowMask) - window->xdg_surface = - xdg_shell_get_xdg_surface_special(wlconfig->xdg_shell, wlsurface, 1); - else - window->xdg_surface = - xdg_shell_get_xdg_surface_special(wlconfig->xdg_shell, wlsurface, 0); - xdg_surface_set_user_data(window->xdg_surface, window); xdg_surface_add_listener(window->xdg_surface, diff --git a/Source/wayland/xdg-shell-unstable-v5-protocol.c b/Source/wayland/xdg-shell-protocol.c similarity index 58% rename from Source/wayland/xdg-shell-unstable-v5-protocol.c rename to Source/wayland/xdg-shell-protocol.c index 8599ba38..a50fb44c 100644 --- a/Source/wayland/xdg-shell-unstable-v5-protocol.c +++ b/Source/wayland/xdg-shell-protocol.c @@ -1,20 +1,24 @@ -/* +/* Generated by wayland-scanner 1.17.0 */ + +/* * Copyright © 2008-2013 Kristian Høgsberg * Copyright © 2013 Rafael Antognolli * Copyright © 2013 Jasper St. Pierre * Copyright © 2010-2013 Intel Corporation - * + * Copyright © 2015-2017 Samsung Electronics Co., Ltd + * Copyright © 2015-2017 Red Hat Inc. + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -32,28 +36,23 @@ extern const struct wl_interface wl_output_interface; extern const struct wl_interface wl_seat_interface; extern const struct wl_interface wl_surface_interface; extern const struct wl_interface xdg_popup_interface; +extern const struct wl_interface xdg_positioner_interface; extern const struct wl_interface xdg_surface_interface; +extern const struct wl_interface xdg_toplevel_interface; static const struct wl_interface *types[] = { NULL, NULL, NULL, NULL, - NULL, - NULL, - &xdg_surface_interface, - &wl_surface_interface, + &xdg_positioner_interface, &xdg_surface_interface, &wl_surface_interface, - NULL, + &xdg_toplevel_interface, &xdg_popup_interface, - &wl_surface_interface, - &wl_surface_interface, - &wl_seat_interface, - NULL, - NULL, - NULL, &xdg_surface_interface, + &xdg_positioner_interface, + &xdg_toplevel_interface, &wl_seat_interface, NULL, NULL, @@ -64,66 +63,102 @@ static const struct wl_interface *types[] = { NULL, NULL, &wl_output_interface, + &wl_seat_interface, + NULL, }; -static const struct wl_message xdg_shell_requests[] = { +static const struct wl_message xdg_wm_base_requests[] = { { "destroy", "", types + 0 }, - { "use_unstable_version", "i", types + 0 }, - { "get_xdg_surface", "no", types + 6 }, - { "get_xdg_surface_special", "nou", types + 8 }, - { "get_xdg_popup", "nooouii", types + 11 }, + { "create_positioner", "n", types + 4 }, + { "get_xdg_surface", "no", types + 5 }, { "pong", "u", types + 0 }, }; -static const struct wl_message xdg_shell_events[] = { +static const struct wl_message xdg_wm_base_events[] = { { "ping", "u", types + 0 }, }; -WL_EXPORT const struct wl_interface xdg_shell_interface = { - "xdg_shell", 1, - 6, xdg_shell_requests, - 1, xdg_shell_events, +WL_EXPORT const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", 2, + 4, xdg_wm_base_requests, + 1, xdg_wm_base_events, +}; + +static const struct wl_message xdg_positioner_requests[] = { + { "destroy", "", types + 0 }, + { "set_size", "ii", types + 0 }, + { "set_anchor_rect", "iiii", types + 0 }, + { "set_anchor", "u", types + 0 }, + { "set_gravity", "u", types + 0 }, + { "set_constraint_adjustment", "u", types + 0 }, + { "set_offset", "ii", types + 0 }, +}; + +WL_EXPORT const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", 2, + 7, xdg_positioner_requests, + 0, NULL, }; static const struct wl_message xdg_surface_requests[] = { { "destroy", "", types + 0 }, - { "set_parent", "?o", types + 18 }, + { "get_toplevel", "n", types + 7 }, + { "get_popup", "n?oo", types + 8 }, + { "set_window_geometry", "iiii", types + 0 }, + { "ack_configure", "u", types + 0 }, +}; + +static const struct wl_message xdg_surface_events[] = { + { "configure", "u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface xdg_surface_interface = { + "xdg_surface", 2, + 5, xdg_surface_requests, + 1, xdg_surface_events, +}; + +static const struct wl_message xdg_toplevel_requests[] = { + { "destroy", "", types + 0 }, + { "set_parent", "?o", types + 11 }, { "set_title", "s", types + 0 }, { "set_app_id", "s", types + 0 }, - { "show_window_menu", "ouii", types + 19 }, - { "move", "ou", types + 23 }, - { "resize", "ouu", types + 25 }, - { "ack_configure", "u", types + 0 }, - { "set_window_geometry", "iiii", types + 0 }, + { "show_window_menu", "ouii", types + 12 }, + { "move", "ou", types + 16 }, + { "resize", "ouu", types + 18 }, + { "set_max_size", "ii", types + 0 }, + { "set_min_size", "ii", types + 0 }, { "set_maximized", "", types + 0 }, { "unset_maximized", "", types + 0 }, - { "set_fullscreen", "?o", types + 28 }, + { "set_fullscreen", "?o", types + 21 }, { "unset_fullscreen", "", types + 0 }, { "set_minimized", "", types + 0 }, }; -static const struct wl_message xdg_surface_events[] = { - { "configure", "iiiiau", types + 0 }, +static const struct wl_message xdg_toplevel_events[] = { + { "configure", "iia", types + 0 }, { "close", "", types + 0 }, }; -WL_EXPORT const struct wl_interface xdg_surface_interface = { - "xdg_surface", 1, - 14, xdg_surface_requests, - 2, xdg_surface_events, +WL_EXPORT const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", 2, + 14, xdg_toplevel_requests, + 2, xdg_toplevel_events, }; static const struct wl_message xdg_popup_requests[] = { { "destroy", "", types + 0 }, + { "grab", "ou", types + 22 }, }; static const struct wl_message xdg_popup_events[] = { + { "configure", "iiii", types + 0 }, { "popup_done", "", types + 0 }, }; WL_EXPORT const struct wl_interface xdg_popup_interface = { - "xdg_popup", 1, - 1, xdg_popup_requests, - 1, xdg_popup_events, + "xdg_popup", 2, + 2, xdg_popup_requests, + 2, xdg_popup_events, }; diff --git a/configure b/configure index 80b7e15e..be75c259 100755 --- a/configure +++ b/configure @@ -707,6 +707,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -819,6 +820,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' @@ -1071,6 +1073,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1208,7 +1219,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1361,6 +1372,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1401,7 +1413,7 @@ Optional Features: --disable-xim Disable XIM support --disable-wgl Disable WGL support --enable-glitz Enable Glitz support - --enable-server=SRV Build server type: x11, win32 + --enable-server=SRV Build server type: x11, win32, wayland --enable-graphics=GPH Build graphics: xlib, xdps, winlib, art, cairo, opal Optional Packages: @@ -7159,6 +7171,8 @@ if test x"$BUILD_GRAPHICS" = "xcairo"; then $as_echo "$as_me: WARNING: can't find freetype, required for graphics=cairo" >&2;} if test $BUILD_SERVER = win32; then BUILD_GRAPHICS=winlib + elif test $BUILD_SERVER = wayland; then + as_fn_error $? "wayland backend requires cairo" "$LINENO" 5 else BUILD_GRAPHICS=xlib fi @@ -7169,6 +7183,8 @@ $as_echo "$as_me: Switching to $BUILD_GRAPHICS" >&6;} $as_echo "$as_me: WARNING: can't find cairo, required for graphics=cairo!" >&2;} if test $BUILD_SERVER = win32; then BUILD_GRAPHICS=winlib + elif test $BUILD_SERVER = wayland; then + as_fn_error $? "wayland backend requires cairo" "$LINENO" 5 else BUILD_GRAPHICS=art fi @@ -7232,6 +7248,132 @@ $as_echo "winlib" >&6; } CAIRO_CFLAGS="$CAIRO_CFLAGS $CAIRO_XLIB_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: xlib" >&5 $as_echo "xlib" >&6; } + elif test $BUILD_SERVER = wayland; then + for ac_header in wayland-util.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "wayland-util.h" "ac_cv_header_wayland_util_h" "$ac_includes_default" +if test "x$ac_cv_header_wayland_util_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WAYLAND_UTIL_H 1 +_ACEOF + +else + as_fn_error $? "**** No wayland-util.h. Install libwayland-dev or equivalent." "$LINENO" 5 +fi + +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wl_display_flush in -lwayland-client" >&5 +$as_echo_n "checking for wl_display_flush in -lwayland-client... " >&6; } +if ${ac_cv_lib_wayland_client_wl_display_flush+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lwayland-client $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char wl_display_flush (); +int +main () +{ +return wl_display_flush (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_wayland_client_wl_display_flush=yes +else + ac_cv_lib_wayland_client_wl_display_flush=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wayland_client_wl_display_flush" >&5 +$as_echo "$ac_cv_lib_wayland_client_wl_display_flush" >&6; } +if test "x$ac_cv_lib_wayland_client_wl_display_flush" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBWAYLAND_CLIENT 1 +_ACEOF + + LIBS="-lwayland-client $LIBS" + +else + as_fn_error $? "**** No wl_display_flush in libwayland-client. Install correct version of libwayland-dev or equivalent." "$LINENO" 5 +fi + + for ac_header in xkbcommon/xkbcommon.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "xkbcommon/xkbcommon.h" "ac_cv_header_xkbcommon_xkbcommon_h" "$ac_includes_default" +if test "x$ac_cv_header_xkbcommon_xkbcommon_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_XKBCOMMON_XKBCOMMON_H 1 +_ACEOF + +else + as_fn_error $? "**** No xkbcommon/xkbcommon.h. Required for wayland. Install libxkbcommon-dev or equivalent." "$LINENO" 5 +fi + +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for xkb_context_new in -lxkbcommon" >&5 +$as_echo_n "checking for xkb_context_new in -lxkbcommon... " >&6; } +if ${ac_cv_lib_xkbcommon_xkb_context_new+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lxkbcommon $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char xkb_context_new (); +int +main () +{ +return xkb_context_new (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_xkbcommon_xkb_context_new=yes +else + ac_cv_lib_xkbcommon_xkb_context_new=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xkbcommon_xkb_context_new" >&5 +$as_echo "$ac_cv_lib_xkbcommon_xkb_context_new" >&6; } +if test "x$ac_cv_lib_xkbcommon_xkb_context_new" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBXKBCOMMON 1 +_ACEOF + + LIBS="-lxkbcommon $LIBS" + +else + as_fn_error $? "**** No xkb_context_new in libxkbcommon. Install correct version of libxkbcommon-dev or equivalent." "$LINENO" 5 +fi + + CAIRO_LIBS="$CAIRO_LIBS $XFT_LIBS" + CAIRO_CFLAGS="$CAIRO_CFLAGS" + LIBS="-lwayland-client -lxkbcommon $LIBS" else as_fn_error $? "Invalid Cairo installation" "$LINENO" 5 fi diff --git a/configure.ac b/configure.ac index 60d7ef87..a384e68e 100644 --- a/configure.ac +++ b/configure.ac @@ -647,8 +647,17 @@ if test x"$BUILD_GRAPHICS" = "xcairo"; then CAIRO_CFLAGS="$CAIRO_CFLAGS $CAIRO_XLIB_CFLAGS" AC_MSG_RESULT(xlib) elif test $BUILD_SERVER = wayland; then + AC_CHECK_HEADERS(wayland-util.h,, + [AC_MSG_ERROR([**** No wayland-util.h. Install libwayland-dev or equivalent.])]) + AC_CHECK_LIB(wayland-client, wl_display_flush,, + [AC_MSG_ERROR([**** No wl_display_flush in libwayland-client. Install correct version of libwayland-dev or equivalent.])]) + AC_CHECK_HEADERS(xkbcommon/xkbcommon.h,, + [AC_MSG_ERROR([**** No xkbcommon/xkbcommon.h. Required for wayland. Install libxkbcommon-dev or equivalent.])]) + AC_CHECK_LIB(xkbcommon, xkb_context_new,, + [AC_MSG_ERROR([**** No xkb_context_new in libxkbcommon. Install correct version of libxkbcommon-dev or equivalent.])]) CAIRO_LIBS="$CAIRO_LIBS $XFT_LIBS" CAIRO_CFLAGS="$CAIRO_CFLAGS" + LIBS="-lwayland-client -lxkbcommon $LIBS" else AC_MSG_ERROR([Invalid Cairo installation]) fi From e805a4a6c0b075bf5590a86a117226cccf8b700c Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Fri, 4 Oct 2019 22:04:58 +0200 Subject: [PATCH 03/23] wayland: Whitespace fixes --- Source/cairo/WaylandCairoSurface.m | 22 ++++---- Source/wayland/WaylandServer.m | 90 +++++++++++++++--------------- 2 files changed, 54 insertions(+), 58 deletions(-) diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index a27a55ad..d7d87d01 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -53,7 +53,7 @@ fd = set_cloexec_or_close(fd); unlink(tmpname); } - + return fd; } @@ -92,7 +92,7 @@ errno = ret; return -1; } - + return fd; } @@ -121,7 +121,7 @@ } pool = wl_shm_create_pool(window->wlconfig->shm, fd, size); - + surface = cairo_image_surface_create_for_data(window->data, CAIRO_FORMAT_ARGB32, window->width, @@ -133,9 +133,9 @@ window->width, window->height, stride, WL_SHM_FORMAT_ARGB8888); wl_shm_pool_destroy(pool); - + close(fd); - + return surface; } @@ -154,18 +154,18 @@ - (id) initWithDevice: (void*)device NSDebugLog(@"can't create cairo surface"); return 0; } - + wl_surface_attach(window->surface, window->buffer, 0, 0); window->wcs = self; - + return self; } - (void) dealloc { struct window *window = (struct window*) gsDevice; - NSDebugLog(@"WaylandCairoSurface: dealloc win=%d", window->window_id); + NSDebugLog(@"WaylandCairoSurface: dealloc win=%d", window->window_id); [super dealloc]; } @@ -213,7 +213,6 @@ - (void) handleExposeRect: (NSRect)rect cairo_surface = _surface; cairo_surface_get_device_offset(cairo_surface, &backupOffsetX, &backupOffsetY); cairo_surface_set_device_offset(cairo_surface, 0, 0); - cairo_t *cr = cairo_create(cairo_surface); if (width != window->width && 0) { @@ -223,7 +222,7 @@ - (void) handleExposeRect: (NSRect)rect cairo_rectangle(cr, 0, 0, width, height); cairo_set_source_rgba(cr, 0, 0, 0, 0.8); cairo_fill(cr); - + cairo_rectangle(cr, 10, 10, width - 20, height - 20); cairo_set_source_rgba(cr, 1.0, 0, 0, 1); cairo_fill(cr); @@ -244,7 +243,7 @@ - (void) handleExposeRect: (NSRect)rect cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); } - + cairo_destroy(cr); cairo_surface_set_device_offset(_surface, backupOffsetX, backupOffsetY); @@ -259,4 +258,3 @@ - (void) handleExposeRect: (NSRect)rect } @end - diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index f0b8d40a..dfe55338 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -114,7 +114,7 @@ output->server_output_id = id; wl_list_insert(wlconfig->output_list.prev, &output->link); (wlconfig->output_count)++; - + wl_output_add_listener(output->output, &output_listener, output); } @@ -157,12 +157,12 @@ NSDebugLog(@"no surface"); return; } - + WaylandConfig *wlconfig = data; struct window *window = wl_surface_get_user_data(surface); float sx = wl_fixed_to_double(sx_w); float sy = wl_fixed_to_double(sy_w); - + wlconfig->pointer.x = sx; wlconfig->pointer.y = sy; wlconfig->pointer.focus = window; @@ -210,14 +210,14 @@ NSDebugLog(@"obtaining locations: wayland=%fx%f pointer=%fx%f", sx, sy, window->wlconfig->pointer.x, window->wlconfig->pointer.y); - + gcontext = GSCurrentContext(); eventLocation = NSMakePoint(sx, window->height - sy); eventFlags = 0; eventType = NSLeftMouseDragged; - + tick = 0; @@ -236,7 +236,7 @@ deltaX: deltaX deltaY: deltaY deltaZ: 0.]; - + [GSCurrentServer() postEvent: event atStart: NO]; } @@ -280,7 +280,7 @@ wlconfig->pointer.last_click_time = time; wlconfig->pointer.last_click_x = wlconfig->pointer.x; wlconfig->pointer.last_click_y = wlconfig->pointer.y; - } + } switch (button) { case BTN_LEFT: @@ -306,7 +306,7 @@ tick = serial; NSDebugLog(@"sending pointer event at: %fx%f, window=%d", wlconfig->pointer.x, wlconfig->pointer.y, window->window_id); - + event = [NSEvent mouseEventWithType: eventType location: eventLocation modifierFlags: eventFlags @@ -388,7 +388,7 @@ xkb_keymap_unref(keymap); return; } - + xkb_keymap_unref(wlconfig->xkb.keymap); xkb_state_unref(wlconfig->xkb.state); wlconfig->xkb.keymap = keymap; @@ -400,7 +400,6 @@ 1 << xkb_keymap_mod_get_index(wlconfig->xkb.keymap, "Mod1"); wlconfig->xkb.shift_mask = 1 << xkb_keymap_mod_get_index(wlconfig->xkb.keymap, "Shift"); - } static void @@ -445,7 +444,6 @@ wlconfig->modifiers |= NSAlternateKeyMask; if (mask & wlconfig->xkb.shift_mask) wlconfig->modifiers |= NSShiftKeyMask; - } static void @@ -472,9 +470,9 @@ sym = NSDeleteCharacter; } else { code = key + 8; - + num_syms = xkb_state_key_get_syms(wlconfig->xkb.state, code, &syms); - + sym = XKB_KEY_NoSymbol; if (num_syms == 1) sym = syms[0]; @@ -482,7 +480,7 @@ NSString *s = [NSString stringWithUTF8String: &sym]; NSEventType eventType; - + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { eventType = NSKeyDown; } else { @@ -499,7 +497,7 @@ charactersIgnoringModifiers: s isARepeat: NO keyCode: code]; - + [GSCurrentServer() postEvent: ev atStart: NO]; NSDebugLog(@"keyboard_handle_key: %@", s); @@ -643,7 +641,7 @@ struct window *window = data; WaylandConfig *wlconfig = window->wlconfig; NSDebugLog(@"handle_surface_configure: win=%d", window->window_id); - + NSEvent *ev = nil; NSWindow *nswindow = GSWindowWithNumber(window->window_id); @@ -658,7 +656,7 @@ subtype: GSAppKitWindowFocusIn data1: 0 data2: 0]; - + [nswindow sendEvent: ev]; } @@ -675,7 +673,7 @@ window->pos_y = y; moved = 1; } - + xdg_surface_ack_configure(window->xdg_surface, serial); NSRect rect = NSMakeRect(0, 0, window->width, window->height); @@ -688,7 +686,7 @@ NSDebugLog(@"window moved, notifying AppKit"); NSEvent *ev = nil; NSWindow *nswindow = GSWindowWithNumber(window->window_id); - + ev = [NSEvent otherEventWithType: NSAppKitDefined location: NSZeroPoint modifierFlags: 0 @@ -718,7 +716,7 @@ wlconfig->compositor = wl_registry_bind(wlconfig->registry, name, &wl_compositor_interface, 1); - /* + /* } else if (strcmp(interface, "wl_shell") == 0) { wlconfig->shell = wl_registry_bind(registry, name, @@ -791,7 +789,7 @@ - (id) _initWaylandContext wlconfig->last_window_id = 1; wl_list_init(&wlconfig->output_list); wl_list_init(&wlconfig->window_list); - + wlconfig->display = wl_display_connect(NULL); if (!wlconfig->display) { [NSException raise: NSWindowServerCommunicationException @@ -803,7 +801,7 @@ - (id) _initWaylandContext ®istry_listener, wlconfig); wl_display_dispatch(wlconfig->display); wl_display_roundtrip(wlconfig->display); - + return self; } @@ -825,7 +823,7 @@ - (void) setupRunLoopInputSourcesForMode: (NSString*)mode { NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; int fdWaylandHandle = wl_display_get_fd(wlconfig->display); - + [currentRunLoop addEvent: (void*)fdWaylandHandle type: ET_RDESC watcher: (id)self @@ -838,10 +836,10 @@ - (id) initWithAttributes: (NSDictionary *)info [super initWithAttributes: info]; [self _initWaylandContext]; - [self setupRunLoopInputSourcesForMode: NSDefaultRunLoopMode]; - [self setupRunLoopInputSourcesForMode: NSConnectionReplyMode]; - [self setupRunLoopInputSourcesForMode: NSModalPanelRunLoopMode]; - [self setupRunLoopInputSourcesForMode: NSEventTrackingRunLoopMode]; + [self setupRunLoopInputSourcesForMode: NSDefaultRunLoopMode]; + [self setupRunLoopInputSourcesForMode: NSConnectionReplyMode]; + [self setupRunLoopInputSourcesForMode: NSModalPanelRunLoopMode]; + [self setupRunLoopInputSourcesForMode: NSEventTrackingRunLoopMode]; return self; } @@ -902,7 +900,7 @@ - (NSArray *) screenList output->alloc_x, output->alloc_y, output->width, output->height); } - + return screens; } @@ -1079,7 +1077,7 @@ - (void) termwindow: (int) win - (int) nativeWindow: (void *)winref : (NSRect*)frame - : (NSBackingStoreType*)type + : (NSBackingStoreType*)type : (unsigned int*)style : (int*)screen { @@ -1207,17 +1205,17 @@ - (void) placewindow: (NSRect)rect : (int) win float deltaX = 0.0; float deltaY = 0.0; int tick; - + gcontext = GSCurrentContext(); eventLocation = NSMakePoint(wlconfig->pointer.x, window->height - wlconfig->pointer.y); eventFlags = 0; eventType = NSLeftMouseUp; - + tick = 0; - + NSDebugLog(@"sending pointer event at: %fx%f, window=%d", wlconfig->pointer.x, wlconfig->pointer.y, window->window_id); - + event = [NSEvent mouseEventWithType: eventType location: eventLocation modifierFlags: eventFlags @@ -1263,9 +1261,9 @@ - (void) placewindow: (NSRect)rect : (int) win wlconfig->pointer.y -= (wframe.origin.y - window->pos_y); wlconfig->pointer.x -= (wframe.origin.x - window->pos_x); } - + window->width = wframe.size.width; - window->height = wframe.size.height; + window->height = wframe.size.height; window->pos_x = wframe.origin.x; window->pos_y = wframe.origin.y; @@ -1278,7 +1276,7 @@ - (void) placewindow: (NSRect)rect : (int) win NSRect flushRect = NSMakeRect(0, 0, window->width, window->height); [window->instance flushwindowrect:rect :window->window_id]; - + wl_display_dispatch_pending(window->wlconfig->display); wl_display_flush(window->wlconfig->display); @@ -1307,7 +1305,7 @@ - (void) placewindow: (NSRect)rect : (int) win [(GSWindowWithNumber(window->window_id)) sendEvent: ev]; NSDebugLog(@"placewindow notify moved=%fx%f", rect.origin.x, rect.origin.y); } - + NSDebugLog(@"placewindow: newpos=%fx%f", window->pos_x, window->pos_y); NSDebugLog(@"placewindow: newsize=%fx%f", window->width, window->height); } @@ -1319,7 +1317,7 @@ - (NSRect) windowbounds: (int) win NSDebugLog(@"windowbounds: win=%d, pos=%dx%d size=%dx%d", window->window_id, window->pos_x, window->pos_y, window->width, window->height); - + return NSMakeRect(window->pos_x, window->output->height - window->pos_y, window->width, window->height); } @@ -1335,9 +1333,9 @@ - (int) windowlevel: (int) win return 0; } -/** Backends can override this method to return an array of window numbers +/** Backends can override this method to return an array of window numbers ordered front to back. The front most window being the first object - in the array. + in the array. The default implementation returns the visible windows in an unspecified order. */ @@ -1385,7 +1383,7 @@ - (void) flushwindowrect: (NSRect)rect : (int) win [[GSCurrentContext() class] handleExposeRect: rect forDriver: window->wcs]; } -- (void) styleoffsets: (float*) l : (float*) r : (float*) t : (float*) b +- (void) styleoffsets: (float*) l : (float*) r : (float*) t : (float*) b : (unsigned int) style { NSDebugLog(@"styleoffsets"); @@ -1441,12 +1439,12 @@ - (NSPoint) mouseLocationOnScreen: (int)aScreen window: (int *)win NSDebugLog(@"NOT captured"); x = wlconfig->pointer.x; y = wlconfig->pointer.y; - + if (window) { x += window->pos_x; y += window->pos_y; win = &window->window_id; - } + } } wl_list_for_each(output, &wlconfig->output_list, link) { @@ -1457,13 +1455,13 @@ - (NSPoint) mouseLocationOnScreen: (int)aScreen window: (int *)win } NSDebugLog(@"mouseLocationOnScreen: returning %fx%f", x, y); - + return NSMakePoint(x, y); } - (BOOL) capturemouse: (int) win { - NSDebugLog(@"capturemouse: %d", win); + NSDebugLog(@"capturemouse: %d", win); return NO; } @@ -1519,7 +1517,7 @@ - (void) freecursor: (void*) cid NSDebugLog(@"freecursor"); } -- (void) setParentWindow: (int)parentWin +- (void) setParentWindow: (int)parentWin forChildWindow: (int)childWin { NSDebugLog(@"setParentWindow: parent=%d child=%d", parentWin, childWin); From 4311a8191b7b596d5061b824d51aa6a850160969 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Fri, 4 Oct 2019 22:16:54 +0200 Subject: [PATCH 04/23] wayland: Use memfd_create --- Source/cairo/WaylandCairoSurface.m | 54 +++--------------------------- 1 file changed, 5 insertions(+), 49 deletions(-) diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index d7d87d01..ea37e9c7 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -2,6 +2,8 @@ Copyright (C) 2016 Sergio L. Pascual */ +#define _GNU_SOURCE + #include "wayland/WaylandServer.h" #include "cairo/WaylandCairoSurface.h" #include @@ -11,60 +13,16 @@ #include #include - #define GSWINDEVICE ((struct window *)gsDevice) - -int -os_fd_set_cloexec(int fd) -{ - long flags; - - if (fd == -1) - return -1; - - flags = fcntl(fd, F_GETFD); - if (flags == -1) - return -1; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) - return -1; - - return 0; -} - +/* Linux specific version */ static int -set_cloexec_or_close(int fd) -{ - if (os_fd_set_cloexec(fd) != 0) { - close(fd); - return -1; - } - return fd; -} - -static int -create_tmpfile_cloexec(char *tmpname) -{ - int fd; - - fd = mkstemp(tmpname); - if (fd >= 0) { - fd = set_cloexec_or_close(fd); - unlink(tmpname); - } - - return fd; -} - -int os_create_anonymous_file(off_t size) { static const char template[] = "/weston-shared-XXXXXX"; const char *path; char *name; int fd; - int ret; path = getenv("XDG_RUNTIME_DIR"); if (!path) { @@ -79,17 +37,15 @@ strcpy(name, path); strcat(name, template); - fd = create_tmpfile_cloexec(name); + fd = memfd_create(name, MFD_CLOEXEC); free(name); if (fd < 0) return -1; - ret = posix_fallocate(fd, 0, size); - if (ret != 0) { + if (ftruncate(fd, size) != 0) { close(fd); - errno = ret; return -1; } From c1cce2ad67acd2b5ba3ec03b41bfeb8c5f1704a8 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Sun, 29 Dec 2019 18:30:48 +0100 Subject: [PATCH 05/23] wayland: WIP --- Headers/wayland/WaylandServer.h | 14 +- Source/cairo/WaylandCairoSurface.m | 28 +-- Source/wayland/WaylandServer.m | 317 ++++++++++++----------------- 3 files changed, 139 insertions(+), 220 deletions(-) diff --git a/Headers/wayland/WaylandServer.h b/Headers/wayland/WaylandServer.h index b63b1a63..82233112 100644 --- a/Headers/wayland/WaylandServer.h +++ b/Headers/wayland/WaylandServer.h @@ -36,13 +36,10 @@ typedef struct _WaylandConfig { struct wl_registry *registry; struct wl_compositor *compositor; struct wl_shell *shell; - struct xdg_wm_base *wm_base; struct wl_shm *shm; struct wl_seat *seat; struct wl_keyboard *keyboard; - struct wl_surface *surface; - struct wl_shell_surface *shell_surface; - struct wl_buffer *buffer; + struct xdg_wm_base *wm_base; struct wl_list output_list; int output_count; @@ -78,7 +75,6 @@ struct output { char *make; char *model; - //display_output_handler_t destroy_handler; void *user_data; }; @@ -97,18 +93,16 @@ struct window { int is_out; unsigned char *data; - struct wl_surface *surface; struct wl_buffer *buffer; - struct wl_shell_surface *shell_surface; + struct wl_surface *surface; struct xdg_surface *xdg_surface; + struct xdg_toplevel *toplevel; + struct output *output; WaylandCairoSurface *wcs; }; -cairo_surface_t * -create_shm_buffer(struct window *window); - @interface WaylandServer : GSDisplayServer { WaylandConfig *wlconfig; diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index ea37e9c7..d6cecaec 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -52,7 +52,7 @@ return fd; } -cairo_surface_t * +static cairo_surface_t * create_shm_buffer(struct window *window) { struct wl_shm_pool *pool; @@ -62,6 +62,7 @@ stride = window->width * 4; size = stride * window->height; + NSDebugLog(@"WaylandCairoSurface: creating shm buffer of %d bytes", size); fd = os_create_anonymous_file(size); if (fd < 0) { NSLog(@"creating a buffer file for surface failed"); @@ -104,7 +105,6 @@ - (id) initWithDevice: (void*)device gsDevice = device; - //_surface = window->main_surface->cairo_surface; _surface = create_shm_buffer(window); if (_surface == NULL) { NSDebugLog(@"can't create cairo surface"); @@ -112,7 +112,6 @@ - (id) initWithDevice: (void*)device } wl_surface_attach(window->surface, window->buffer, 0, 0); - window->wcs = self; return self; @@ -142,8 +141,7 @@ - (void) handleExposeRect: (NSRect)rect { NSDebugLog(@"handleExposeRect"); struct window *window = (struct window*) gsDevice; - struct wl_surface *wlsurface = window->surface; - cairo_surface_t *cairo_surface; + cairo_surface_t *cairo_surface = _surface; double backupOffsetX = 0; double backupOffsetY = 0; int x = NSMinX(rect); @@ -153,20 +151,12 @@ - (void) handleExposeRect: (NSRect)rect NSDebugLog(@"updating region: %dx%d %dx%d", x, y, width, height); - if (cairo_surface_status(_surface) != CAIRO_STATUS_SUCCESS) + if (cairo_surface_status(cairo_surface) != CAIRO_STATUS_SUCCESS) { NSWarnMLog(@"cairo initial window error status: %s\n", cairo_status_to_string(cairo_surface_status(_surface))); } - /* - cairo_surface = create_shm_buffer(window); - if (cairo_surface == NULL) { - NSDebugLog(@"can't create cairo surface"); - return; - } - */ - cairo_surface = _surface; cairo_surface_get_device_offset(cairo_surface, &backupOffsetX, &backupOffsetY); cairo_surface_set_device_offset(cairo_surface, 0, 0); @@ -202,14 +192,12 @@ - (void) handleExposeRect: (NSRect)rect cairo_destroy(cr); - cairo_surface_set_device_offset(_surface, backupOffsetX, backupOffsetY); - - wl_surface_attach(wlsurface, window->buffer, 0, 0); - wl_surface_damage(wlsurface, 0, 0, window->width, window->height); - wl_surface_commit(wlsurface); - + wl_surface_commit(window->surface); wl_display_dispatch_pending(window->wlconfig->display); wl_display_flush(window->wlconfig->display); + + cairo_surface_set_device_offset(_surface, backupOffsetX, backupOffsetY); + NSDebugLog(@"handleExposeRect exit"); } diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index dfe55338..ba9cb7b4 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -97,42 +98,7 @@ handle_done, handle_scale }; - -static void -add_output(WaylandConfig *wlconfig, uint32_t id) -{ - NSDebugLog(@"add_output"); - - struct output *output; - - output = (struct output *) malloc(sizeof(struct output)); - memset(output, 0, sizeof(struct output)); - output->wlconfig = wlconfig; - output->scale = 1; - output->output = - wl_registry_bind(wlconfig->registry, id, &wl_output_interface, 2); - output->server_output_id = id; - wl_list_insert(wlconfig->output_list.prev, &output->link); - (wlconfig->output_count)++; - - wl_output_add_listener(output->output, &output_listener, output); -} - -static void -output_destroy(struct output *output) -{ - NSDebugLog(@"output_destroy"); - - /* XXX - Should we implement this? - if (output->destroy_handler) - (*output->destroy_handler)(output, output->user_data); - */ - - wl_output_destroy(output->output); - wl_list_remove(&output->link); - free(output); -} - +/* static void destroy_output(WaylandConfig *wlconfig, uint32_t id) { @@ -140,13 +106,15 @@ wl_list_for_each(output, &wlconfig->output_list, link) { if (output->server_output_id == id) { - output_destroy(output); - (wlconfig->output_count)--; + wl_output_destroy(output->output); + wl_list_remove(&output->link); + free(output); + wlconfig->output_count--; break; } } } - +*/ static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, @@ -204,7 +172,6 @@ NSPoint eventLocation; NSGraphicsContext *gcontext; unsigned int eventFlags; - int tick; float deltaX = sx - window->wlconfig->pointer.x; float deltaY = sy - window->wlconfig->pointer.y; @@ -218,9 +185,6 @@ eventFlags = 0; eventType = NSLeftMouseDragged; - tick = 0; - - NSDebugLog(@"sending pointer delta: %fx%f, window=%d", deltaX, deltaY, window->window_id); event = [NSEvent mouseEventWithType: eventType @@ -316,7 +280,7 @@ eventNumber: tick clickCount: clickCount pressure: 1.0 - buttonNumber: 0 /* FIXME */ + buttonNumber: 0 /* FIXME */ deltaX: deltaX deltaY: deltaY deltaZ: 0.]; @@ -425,7 +389,6 @@ { NSDebugLog(@"keyboard_handle_modifiers"); WaylandConfig *wlconfig = data; - struct input *input = data; xkb_mod_mask_t mask; /* If we're not using a keymap, then we don't handle PC-style modifiers */ @@ -457,13 +420,12 @@ enum wl_keyboard_key_state state = state_w; const xkb_keysym_t *syms; xkb_keysym_t sym; - struct itimerspec its; struct window *window = wlconfig->pointer.focus; - if (!window) { + if (!window) return; - } + code = 0; if (key == 28) { sym = NSCarriageReturnCharacter; } else if (key == 14) { @@ -494,7 +456,7 @@ windowNumber: window->window_id context: GSCurrentContext() characters: s - charactersIgnoringModifiers: s + charactersIgnoringModifiers: s isARepeat: NO keyCode: code]; @@ -573,16 +535,6 @@ seat_handle_capabilities, }; -static void -add_seat(WaylandConfig *wlconfig, uint32_t name, uint32_t version) -{ - wlconfig->pointer.wlpointer = NULL; - wlconfig->seat_version = version; - wlconfig->seat = wl_registry_bind(wlconfig->registry, name, - &wl_seat_interface, 1); - wl_seat_add_listener(wlconfig->seat, &seat_listener, wlconfig); -} - static void shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) { @@ -592,55 +544,16 @@ shm_format }; -static void -handle_ping(void *data, struct wl_shell_surface *shell_surface, - uint32_t serial) -{ - NSDebugLog(@"handle_ping"); - struct window *window = (struct window *) data; - wl_shell_surface_pong(shell_surface, serial); - wl_display_dispatch_pending(window->wlconfig->display); - wl_display_flush(window->wlconfig->display); -} - -static void -handle_configure(void *data, struct wl_shell_surface *shell_surface, - uint32_t edges, int32_t width, int32_t height) -{ -} - -static void -handle_popup_done(void *data, struct wl_shell_surface *shell_surface) -{ -} - -static const struct wl_shell_surface_listener shell_surface_listener = { - handle_ping, - handle_configure, - handle_popup_done -}; - -static void -xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) -{ - WaylandConfig *wlconfig = data; - xdg_wm_base_pong(shell, serial); - wl_display_dispatch_pending(wlconfig->display); - wl_display_flush(wlconfig->display); - -} - -static const struct xdg_wm_base_listener wm_base_listener = { - xdg_wm_base_ping, -}; +#define XDG_SHELL +#ifdef XDG_SHELL static void -handle_surface_configure(void *data, struct xdg_surface *xdg_surface, +xdg_surface_on_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) { struct window *window = data; WaylandConfig *wlconfig = window->wlconfig; - NSDebugLog(@"handle_surface_configure: win=%d", window->window_id); + NSDebugLog(@"xdg_surface_on_configure: win=%d", window->window_id); NSEvent *ev = nil; NSWindow *nswindow = GSWindowWithNumber(window->window_id); @@ -651,11 +564,11 @@ location: NSZeroPoint modifierFlags: 0 timestamp: 0 - windowNumber: (int)window->window_id + windowNumber: (int)window->window_id context: GSCurrentContext() subtype: GSAppKitWindowFocusIn data1: 0 - data2: 0]; + data2: 0]; [nswindow sendEvent: ev]; } @@ -700,11 +613,40 @@ [nswindow sendEvent: ev]; } #endif +// xdg_surface_ack_configure(xdg_surface, serial); } static const struct xdg_surface_listener xdg_surface_listener = { - handle_surface_configure, + xdg_surface_on_configure, +}; + +#else +static void +wl_shell_surface_on_ping(void *data, struct wl_shell_surface *shell_surface, + uint32_t serial) +{ + wl_shell_surface_pong(shell_surface, serial); +} + +static void +wl_shell_surface_on_configure(void *data, + struct wl_shell_surface *shell_surface, + uint32_t edges, int32_t width, int32_t height) +{ +} + +static void +wl_shell_surface_on_popup_done(void *data, + struct wl_shell_surface *shell_surface) +{ +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + wl_shell_surface_on_ping, + wl_shell_surface_on_configure, + wl_shell_surface_on_popup_done, }; +#endif static void handle_global(void *data, struct wl_registry *registry, @@ -712,29 +654,35 @@ { WaylandConfig *wlconfig = data; - if (strcmp(interface, "wl_compositor") == 0) { - wlconfig->compositor = - wl_registry_bind(wlconfig->registry, name, - &wl_compositor_interface, 1); - /* - } else if (strcmp(interface, "wl_shell") == 0) { - wlconfig->shell = - wl_registry_bind(registry, name, - &wl_shell_interface, 1); - */ - } else if (strcmp(interface, "xdg_shell") == 0) { + if (strcmp(interface, xdg_wm_base_interface.name) == 0) { wlconfig->wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); - xdg_shell_add_listener(wlconfig->wm_base, - &wm_base_listener, wlconfig); - } else if (strcmp(interface, "wl_shm") == 0) { - wlconfig->shm = wl_registry_bind(wlconfig->registry, name, + } else if (strcmp(interface, wl_shell_interface.name) == 0) { + wlconfig->shell = wl_registry_bind(registry, name, + &wl_shell_interface, 1); + } else if (strcmp(interface, wl_compositor_interface.name) == 0) { + wlconfig->compositor = wl_registry_bind(registry, name, + &wl_compositor_interface, 1); + } else if (strcmp(interface, wl_shm_interface.name) == 0) { + wlconfig->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); wl_shm_add_listener(wlconfig->shm, &shm_listener, wlconfig); - } else if (strcmp(interface, "wl_output") == 0) { - add_output(wlconfig, name); - } else if (strcmp(interface, "wl_seat") == 0) { - add_seat(wlconfig, name, version); + } else if (strcmp(interface, wl_output_interface.name) == 0) { + struct output *output = (struct output *)malloc(sizeof(struct output)); + memset(output, 0, sizeof(struct output)); + output->wlconfig = wlconfig; + output->scale = 1; + output->output = wl_registry_bind(registry, name, &wl_output_interface, 2); + output->server_output_id = name; + wl_list_insert(wlconfig->output_list.prev, &output->link); + wlconfig->output_count++; + wl_output_add_listener(output->output, &output_listener, output); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + wlconfig->pointer.wlpointer = NULL; + wlconfig->seat_version = version; + wlconfig->seat = wl_registry_bind(wlconfig->registry, name, + &wl_seat_interface, 1); + wl_seat_add_listener(wlconfig->seat, &seat_listener, wlconfig); } } @@ -797,11 +745,22 @@ - (id) _initWaylandContext } wlconfig->registry = wl_display_get_registry(wlconfig->display); + if (!wlconfig->registry) { + [NSException raise: NSWindowServerCommunicationException + format: @"Unable to get global registry"]; + } wl_registry_add_listener(wlconfig->registry, ®istry_listener, wlconfig); + wl_display_dispatch(wlconfig->display); wl_display_roundtrip(wlconfig->display); + if (!wlconfig->compositor || !wlconfig->wm_base) { + [NSException raise: NSWindowServerCommunicationException + format: @"Unable to get compositor"]; + + } + return self; } @@ -810,8 +769,8 @@ - (void) receivedEvent: (void*)data extra: (void*)extra forMode: (NSString*)mode { - NSDebugLog(@"receivedEvent"); if (type == ET_RDESC){ + NSDebugLog(@"receivedEvent ET_RDESC"); if (wl_display_dispatch(wlconfig->display) == -1) { [NSException raise: NSWindowServerCommunicationException format: @"Connection to Wayland Server lost"]; @@ -822,7 +781,7 @@ - (void) receivedEvent: (void*)data - (void) setupRunLoopInputSourcesForMode: (NSString*)mode { NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; - int fdWaylandHandle = wl_display_get_fd(wlconfig->display); + long fdWaylandHandle = wl_display_get_fd(wlconfig->display); [currentRunLoop addEvent: (void*)fdWaylandHandle type: ET_RDESC @@ -932,17 +891,13 @@ - (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style NSDebugLog(@"window: screen=%d frame=%@", screen, NSStringFromRect(frame)); struct window *window; struct output *output; - struct wl_surface *wlsurface; - cairo_surface_t *cairo_surface; - cairo_t *cr; int width; int height; int altered = 0; - int window_type = 0; /* We're not allowed to create a zero rect window */ if (NSWidth(frame) <= 0 || NSHeight(frame) <= 0) { - NSDebugLog(@"trying try create a zero rect window"); + NSDebugLog(@"trying to create a zero rect window"); frame.size.width = 2; frame.size.height = 2; } @@ -971,29 +926,19 @@ - (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style window->pos_x = frame.origin.x; window->pos_y = NSToWayland(window, frame.origin.y); window->window_id = wlconfig->last_window_id; - - wlsurface = wl_compositor_create_surface(wlconfig->compositor); - if (wlsurface == NULL) { + window->surface = wl_compositor_create_surface(wlconfig->compositor); + if (!window->surface) { NSDebugLog(@"can't create wayland surface"); return 0; } - /* - window->shell_surface = wl_shell_get_shell_surface(wlconfig->shell, - wlsurface); - if (window->shell_surface) { - NSDebugLog(@"shell surface is present"); - wl_shell_surface_add_listener(window->shell_surface, - &shell_surface_listener, window); - wl_shell_surface_set_toplevel(window->shell_surface); - } else { - NSDebugLog(@"shell surface is missing"); - } - */ + wl_surface_set_user_data(window->surface, window); - window->xdg_surface = xdg_wm_base_get_xdg_surface(wlconfig->wm_base, - wlsurface); + window->xdg_surface = + xdg_wm_base_get_xdg_surface(wlconfig->wm_base, window->surface); + +#if 0 // TODO: xdg_shell_get_xdg_surface_special() no longer exists, - // so we need to find another way + // so we need to find another way, see *get_popup for menus if (style & NSMainMenuWindowMask) { NSDebugLog(@"window id=%d will be a panel", window->window_id); } else if (style & NSBackgroundWindowMask) { @@ -1001,6 +946,9 @@ - (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style } else { NSDebugLog(@"window id=%d will be ordinary", window->window_id); } +#endif + + window->toplevel = xdg_surface_get_toplevel(window->xdg_surface); xdg_surface_set_user_data(window->xdg_surface, window); xdg_surface_add_listener(window->xdg_surface, @@ -1026,18 +974,12 @@ - (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style window->pos_y, window->width, window->height); - wl_surface_commit(wlsurface); - - wl_surface_set_user_data(wlsurface, window); - window->surface = wlsurface; + wl_surface_commit(window->surface); + wl_display_flush(wlconfig->display); - window->window_id = wlconfig->last_window_id; wl_list_insert(wlconfig->window_list.prev, &window->link); - (wlconfig->last_window_id)++; - (wlconfig->window_count)++; - - wl_display_dispatch_pending(wlconfig->display); - wl_display_flush(wlconfig->display); + wlconfig->last_window_id++; + wlconfig->window_count++; [self _setWindowOwnedByServer: (int)window->window_id]; @@ -1064,11 +1006,7 @@ - (void) termwindow: (int) win NSDebugLog(@"termwindow: win=%d", win); struct window *window = get_window_with_id(wlconfig, win); - if (window->xdg_surface) { - xdg_surface_destroy(window->xdg_surface); - } - - wl_surface_destroy(window->surface); + xdg_surface_destroy(window->xdg_surface); wl_buffer_destroy(window->buffer); wl_list_remove(&window->link); @@ -1105,7 +1043,7 @@ - (void) titlewindow: (NSString *) window_title : (int) win struct window *window = get_window_with_id(wlconfig, win); const char *cString = [window_title UTF8String]; - xdg_surface_set_title(window->xdg_surface, cString); + xdg_toplevel_set_title(window->toplevel, cString); } - (void) miniwindow: (int) win @@ -1133,8 +1071,6 @@ - (void) orderwindow: (int) op : (int) otherWin : (int) win if (op == NSWindowOut) { NSDebugLog(@"orderwindow: NSWindowOut"); - //window->pos_x += 32000; - //window->pos_y += 32000; window->is_out = 1; xdg_surface_set_window_geometry(window->xdg_surface, window->pos_x + 32000, @@ -1145,13 +1081,12 @@ - (void) orderwindow: (int) op : (int) otherWin : (int) win window->width, window->height); [window->instance flushwindowrect:rect :window->window_id]; + xdg_toplevel_set_minimized(window->toplevel); + wl_display_dispatch_pending(window->wlconfig->display); wl_display_flush(window->wlconfig->display); - - - //xdg_surface_set_minimized(window->xdg_surface); } else /*if (window->is_out)*/ { - NSDebugLog(@"orderwindow: restoring to %dx%d", window->pos_x, window->pos_y); + NSDebugLog(@"orderwindow: restoring to %fx%f", window->pos_x, window->pos_y); xdg_surface_set_window_geometry(window->xdg_surface, window->pos_x, window->pos_y, @@ -1161,7 +1096,8 @@ - (void) orderwindow: (int) op : (int) otherWin : (int) win window->width, window->height); [window->instance flushwindowrect:rect :window->window_id]; - xdg_surface_set_minimized(window->xdg_surface); +// xdg_toplevel_set_minimized(window->toplevel); +// xdg_toplevel_set_fullscreen(window->toplevel, window->output); wl_display_dispatch_pending(window->wlconfig->display); wl_display_flush(window->wlconfig->display); @@ -1193,10 +1129,10 @@ - (void) placewindow: (NSRect)rect : (int) win { NSDebugLog(@"placewindow: %d %@", win, NSStringFromRect(rect)); struct window *window = get_window_with_id(wlconfig, win); - WaylandConfig *wlconfig = window->wlconfig; + WaylandConfig *config = window->wlconfig; - if (0 && wlconfig->pointer.serial && wlconfig->pointer.focus && - wlconfig->pointer.focus->window_id == win) { + if (0 && config->pointer.serial && config->pointer.focus && + config->pointer.focus->window_id == win) { NSEvent *event; NSEventType eventType; NSPoint eventLocation; @@ -1207,14 +1143,14 @@ - (void) placewindow: (NSRect)rect : (int) win int tick; gcontext = GSCurrentContext(); - eventLocation = NSMakePoint(wlconfig->pointer.x, - window->height - wlconfig->pointer.y); + eventLocation = NSMakePoint(config->pointer.x, + window->height - config->pointer.y); eventFlags = 0; eventType = NSLeftMouseUp; tick = 0; - NSDebugLog(@"sending pointer event at: %fx%f, window=%d", wlconfig->pointer.x, wlconfig->pointer.y, window->window_id); + NSDebugLog(@"sending pointer event at: %fx%f, window=%d", config->pointer.x, config->pointer.y, window->window_id); event = [NSEvent mouseEventWithType: eventType location: eventLocation @@ -1232,9 +1168,9 @@ - (void) placewindow: (NSRect)rect : (int) win [GSCurrentServer() postEvent: event atStart: NO]; - xdg_surface_move(window->xdg_surface, - wlconfig->seat, - wlconfig->pointer.serial); + xdg_toplevel_move(window->toplevel, + config->seat, + config->pointer.serial); } else { NSDebugLog(@"placewindow: oldpos=%fx%f", window->pos_x, window->pos_y); NSDebugLog(@"placewindow: oldsize=%fx%f", window->width, window->height); @@ -1256,10 +1192,10 @@ - (void) placewindow: (NSRect)rect : (int) win wframe = [self _OSFrameToWFrame: rect for: window]; - if (wlconfig->pointer.focus && - wlconfig->pointer.focus->window_id == window->window_id) { - wlconfig->pointer.y -= (wframe.origin.y - window->pos_y); - wlconfig->pointer.x -= (wframe.origin.x - window->pos_x); + if (config->pointer.focus && + config->pointer.focus->window_id == window->window_id) { + config->pointer.y -= (wframe.origin.y - window->pos_y); + config->pointer.x -= (wframe.origin.x - window->pos_x); } window->width = wframe.size.width; @@ -1272,9 +1208,10 @@ - (void) placewindow: (NSRect)rect : (int) win window->pos_y, window->width, window->height); - +/* NSRect flushRect = NSMakeRect(0, 0, window->width, window->height); +*/ [window->instance flushwindowrect:rect :window->window_id]; wl_display_dispatch_pending(window->wlconfig->display); @@ -1387,7 +1324,7 @@ - (void) styleoffsets: (float*) l : (float*) r : (float*) t : (float*) b : (unsigned int) style { NSDebugLog(@"styleoffsets"); - /* XXX - Assume we don't decorations */ + /* XXX - Assume we don't decorate */ *l = *r = *t = *b = 0.0; } @@ -1525,11 +1462,11 @@ - (void) setParentWindow: (int)parentWin struct window *child = get_window_with_id(wlconfig, childWin); if (parent) { - xdg_surface_set_parent(child->xdg_surface, parent->xdg_surface); + xdg_toplevel_set_parent(child->toplevel, parent->toplevel); } else { - xdg_surface_set_parent(child->xdg_surface, NULL); + xdg_toplevel_set_parent(child->toplevel, NULL); } - xdg_surface_set_minimized(child->xdg_surface); + xdg_toplevel_set_minimized(child->toplevel); wl_display_dispatch_pending(wlconfig->display); wl_display_flush(wlconfig->display); } From 3db7a6fbd4ff451253b98f047e0549fc69486f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sun, 26 Jan 2020 21:42:35 +0000 Subject: [PATCH 06/23] wayland: Split the check for compositor and wm_base into two checks. --- Source/wayland/WaylandServer.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index ba9cb7b4..e999e906 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -755,10 +755,13 @@ - (id) _initWaylandContext wl_display_dispatch(wlconfig->display); wl_display_roundtrip(wlconfig->display); - if (!wlconfig->compositor || !wlconfig->wm_base) { + if (!wlconfig->compositor) { [NSException raise: NSWindowServerCommunicationException format: @"Unable to get compositor"]; - + } + if (!wlconfig->wm_base) { + [NSException raise: NSWindowServerCommunicationException + format: @"Unable to get xdg-shell / xdg_wm_base"]; } return self; From 24cbc5a1988a2935da2b416f7bc17cdb55637cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sun, 26 Jan 2020 22:05:38 +0000 Subject: [PATCH 07/23] wayland: Include a script for regenerating protocol headers/source. --- wayland-regenerate.sh | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100755 wayland-regenerate.sh diff --git a/wayland-regenerate.sh b/wayland-regenerate.sh new file mode 100755 index 00000000..1aa006e4 --- /dev/null +++ b/wayland-regenerate.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# This script is used to regenerate xdg-shell-protocol public code and headers +# from the XML specification. + +wayland-scanner public-code /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml Source/wayland/xdg-shell-protocol.c +wayland-scanner client-header /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml Headers/wayland/xdg-shell-client-protocol.h From e8e615548a3c02b677ceec66cca9358e6c1961b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Wed, 15 Apr 2020 00:19:53 +0100 Subject: [PATCH 08/23] wayland: Update license headers and copyright statement. For contributions, we generally ask that copyright is assigned to FSF. I believe this has been done by Sergio. --- Headers/cairo/WaylandCairoSurface.h | 26 ++++++++++++++++++++++++-- Headers/wayland/WaylandServer.h | 23 ++++++++++++++++++++++- Source/wayland/WaylandServer.m | 26 ++++++++++++++++++++++++-- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Headers/cairo/WaylandCairoSurface.h b/Headers/cairo/WaylandCairoSurface.h index 71e32921..5bca4e62 100644 --- a/Headers/cairo/WaylandCairoSurface.h +++ b/Headers/cairo/WaylandCairoSurface.h @@ -1,5 +1,28 @@ /* - Copyright (C) 2016 Sergio L. Pascual + WaylandCairoSurface.h + + Copyright (C) 2020 Free Software Foundation, Inc. + + Author: Sergio L. Pascual + Date: February 2016 + + This file is part of GNUstep. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ #ifndef WaylandCairoSurface_h @@ -12,5 +35,4 @@ } @end - #endif diff --git a/Headers/wayland/WaylandServer.h b/Headers/wayland/WaylandServer.h index 82233112..2e696a5b 100644 --- a/Headers/wayland/WaylandServer.h +++ b/Headers/wayland/WaylandServer.h @@ -2,7 +2,28 @@ Backend server using Wayland. - Copyright (C) 2016 Sergio L. Pascual + Copyright (C) 2020 Free Software Foundation, Inc. + + Author: Sergio L. Pascual + Date: February 2016 + + This file is part of the GNUstep Backend. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ #ifndef _WaylandServer_h_INCLUDE diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index e999e906..b757dff0 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -1,6 +1,28 @@ -/* WaylandServer - Wayland Server Class +/* -*- mode:ObjC -*- + WaylandServer - Wayland Server Class - Copyright (C) 2016 Sergio L. Pascual + Copyright (C) 2020 Free Software Foundation, Inc. + + Author: Sergio L. Pascual + Date: February 2016 + + This file is part of the GNU Objective C User Interface Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ #include "config.h" From 80cc4121aede288ab3b242d604edd46861b65351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Wed, 15 Apr 2020 00:35:47 +0100 Subject: [PATCH 09/23] wayland: Additional license header fixes noticed during PR. --- Source/wayland/GNUmakefile | 6 ++++-- Source/wayland/GNUmakefile.preamble | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/wayland/GNUmakefile b/Source/wayland/GNUmakefile index 186411bd..237e13c7 100644 --- a/Source/wayland/GNUmakefile +++ b/Source/wayland/GNUmakefile @@ -1,9 +1,11 @@ # -# Main makefile for GNUstep Backend win32 +# Main makefile for GNUstep Backend wayland # -# Copyright (C) 2002 Free Software Foundation, Inc. +# Copyright (C) 2020 Free Software Foundation, Inc. # # Author: Adam Fedor +# Author: Sergio L. Pascual +# Author: Ladislav Michl # # This file is part of the GNUstep Backend. # diff --git a/Source/wayland/GNUmakefile.preamble b/Source/wayland/GNUmakefile.preamble index d7461719..8cde639f 100644 --- a/Source/wayland/GNUmakefile.preamble +++ b/Source/wayland/GNUmakefile.preamble @@ -1,9 +1,10 @@ - +# # GNUmakefile.preamble # -# Copyright (C) 2002 Free Software Foundation, Inc. +# Copyright (C) 2020 Free Software Foundation, Inc. # # Author: Adam Fedor +# Author: Sergio L. Pascual # # This file is part of the GNUstep Backend. # From 36eefc981e2efede517bcbf01187f3f0cc37c1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Wed, 15 Apr 2020 00:36:37 +0100 Subject: [PATCH 10/23] wayland: Assortment of fixes noticed during code review. Rearranging order of the code, freeing some memory, writing a note that additional work is required, returning a value through pointer passed as argument, etc. --- Source/cairo/CairoContext.m | 4 ++-- Source/cairo/WaylandCairoSurface.m | 5 +++++ Source/wayland/WaylandServer.m | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Source/cairo/CairoContext.m b/Source/cairo/CairoContext.m index a67839ba..4b7437a2 100644 --- a/Source/cairo/CairoContext.m +++ b/Source/cairo/CairoContext.m @@ -72,10 +72,10 @@ # endif /* USE_GLITZ */ #elif BUILD_SERVER == SERVER_wayland # include "wayland/WaylandServer.h" -# define _CAIRO_GSTATE_CLASSNAME CairoGState # include "cairo/CairoGState.h" -# define _CAIRO_SURFACE_CLASSNAME WaylandCairoSurface # include "cairo/WaylandCairoSurface.h" +# define _CAIRO_GSTATE_CLASSNAME CairoGState +# define _CAIRO_SURFACE_CLASSNAME WaylandCairoSurface #else # error Invalid server for Cairo backend : non implemented #endif /* BUILD_SERVER */ diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index d6cecaec..2fd4a385 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -121,6 +121,10 @@ - (void) dealloc { struct window *window = (struct window*) gsDevice; NSDebugLog(@"WaylandCairoSurface: dealloc win=%d", window->window_id); + + // FIXME: This is leaking memory. We need to implement counterpart to + // create_shm_buffer. + [super dealloc]; } @@ -162,6 +166,7 @@ - (void) handleExposeRect: (NSRect)rect cairo_t *cr = cairo_create(cairo_surface); if (width != window->width && 0) { + // FIXME: remove this dead fake-drawing branch. NSDebugLog(@"fake drawing"); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index b757dff0..e6e21e40 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -954,6 +954,7 @@ - (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style window->surface = wl_compositor_create_surface(wlconfig->compositor); if (!window->surface) { NSDebugLog(@"can't create wayland surface"); + free(window); return 0; } wl_surface_set_user_data(window->surface, window); @@ -1405,7 +1406,9 @@ - (NSPoint) mouseLocationOnScreen: (int)aScreen window: (int *)win if (window) { x += window->pos_x; y += window->pos_y; - win = &window->window_id; + if (win) { + *win = &window->window_id; + } } } From 41b2d294ed7393a5331c3aefa205fad41fabd502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Fri, 17 Apr 2020 01:17:00 +0100 Subject: [PATCH 11/23] wayland: Checking whether the surface is configured before committing. This now results in windows being painted on the screen. However, input is still ending up in all the wrong places, and there is a lot of garbage content being painted outside the actual windows. Right clicking on a window seems to trigger rotate behavior, which needs to be evaluated and likely removed (or prevented, if this is done by Weston). Interestingly, checking for ->configured on first surface commit also seems to break the backend. --- Headers/wayland/WaylandServer.h | 1 + Source/cairo/WaylandCairoSurface.m | 5 ++++- Source/wayland/WaylandServer.m | 15 ++++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Headers/wayland/WaylandServer.h b/Headers/wayland/WaylandServer.h index 2e696a5b..f36c6132 100644 --- a/Headers/wayland/WaylandServer.h +++ b/Headers/wayland/WaylandServer.h @@ -104,6 +104,7 @@ struct window { id instance; int window_id; struct wl_list link; + BOOL configured; // surface has been configured once float pos_x; float pos_y; diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index 2fd4a385..9cdf5f6b 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -197,7 +197,10 @@ - (void) handleExposeRect: (NSRect)rect cairo_destroy(cr); - wl_surface_commit(window->surface); + NSDebugLog(@"trying to commit cairo surface for window %d", window->window_id); + if (window->configured) + wl_surface_commit(window->surface); + NSDebugLog(@"done trying to commit cairo surface for window %d", window->window_id); wl_display_dispatch_pending(window->wlconfig->display); wl_display_flush(window->wlconfig->display); diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index e6e21e40..9981b293 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -580,6 +580,20 @@ NSEvent *ev = nil; NSWindow *nswindow = GSWindowWithNumber(window->window_id); + NSDebugLog(@"Acknowledging surface configure %p %d (window_id=%d)", xdg_surface, serial, window->window_id); + xdg_surface_ack_configure(xdg_surface, serial); + window->configured = YES; + + // TODO: do we need to check that the surface has been painted to? + if (window->surface) + { + // TODO: is this ever going to be null when we get here? + wl_surface_commit(window->surface); + wl_display_dispatch_pending(window->wlconfig->display); + wl_display_flush(window->wlconfig->display); + } + + if (wlconfig->pointer.focus && wlconfig->pointer.focus->window_id == window->window_id) { ev = [NSEvent otherEventWithType: NSAppKitDefined @@ -635,7 +649,6 @@ [nswindow sendEvent: ev]; } #endif -// xdg_surface_ack_configure(xdg_surface, serial); } static const struct xdg_surface_listener xdg_surface_listener = { From 359aa9e639db545bda3649262904f23ed720803b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 16:14:07 +0100 Subject: [PATCH 12/23] wayland: Additional clean up for license headers. --- Source/cairo/WaylandCairoSurface.m | 27 +++++++++++++++++++++++++-- Source/wayland/WaylandServer.m | 2 +- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index 9cdf5f6b..8d2bf836 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -1,5 +1,28 @@ -/* - Copyright (C) 2016 Sergio L. Pascual +/* -*- mode:ObjC -*- + WaylandCairoSurface - Draw with Cairo onto Wayland surfaces + + Copyright (C) 2020 Free Software Foundation, Inc. + + Author: Sergio L. Pascual + Date: February 2016 + + This file is part of the GNU Objective C Backend Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ #define _GNU_SOURCE diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index 9981b293..a35d8009 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -6,7 +6,7 @@ Author: Sergio L. Pascual Date: February 2016 - This file is part of the GNU Objective C User Interface Library. + This file is part of the GNU Objective C Backend Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public From 84f71f5c3e660156d46d7693c1cf99450543982a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 16:14:51 +0100 Subject: [PATCH 13/23] wayland: Additional interface registration NSDebugLog() output. --- Source/wayland/WaylandServer.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index a35d8009..6dcc2845 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -689,18 +689,23 @@ { WaylandConfig *wlconfig = data; + NSDebugLog(@"wayland: registering interface '%s'", interface); if (strcmp(interface, xdg_wm_base_interface.name) == 0) { wlconfig->wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + NSDebugLog(@"wayland: found wm_base interface"); } else if (strcmp(interface, wl_shell_interface.name) == 0) { wlconfig->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1); + NSDebugLog(@"wayland: found shell interface"); } else if (strcmp(interface, wl_compositor_interface.name) == 0) { wlconfig->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); + NSDebugLog(@"wayland: found compositor interface"); } else if (strcmp(interface, wl_shm_interface.name) == 0) { wlconfig->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); + NSDebugLog(@"wayland: found shm interface"); wl_shm_add_listener(wlconfig->shm, &shm_listener, wlconfig); } else if (strcmp(interface, wl_output_interface.name) == 0) { struct output *output = (struct output *)malloc(sizeof(struct output)); @@ -709,6 +714,7 @@ output->scale = 1; output->output = wl_registry_bind(registry, name, &wl_output_interface, 2); output->server_output_id = name; + NSDebugLog(@"wayland: found output interface"); wl_list_insert(wlconfig->output_list.prev, &output->link); wlconfig->output_count++; wl_output_add_listener(output->output, &output_listener, output); @@ -717,6 +723,7 @@ wlconfig->seat_version = version; wlconfig->seat = wl_registry_bind(wlconfig->registry, name, &wl_seat_interface, 1); + NSDebugLog(@"wayland: found seat interface"); wl_seat_add_listener(wlconfig->seat, &seat_listener, wlconfig); } } From b294b7f1b9b34de8ef32de83431d435a9055c2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 16:18:00 +0100 Subject: [PATCH 14/23] wayland: In case *stable* XDG Shell protocol isn't supported, be more informative. The exception was not very informative about why exactly the error message may occur. Weston in Debian buster doesn't support the stable XDG Shell protocol, for instance, and triaging this took some effort. --- Source/wayland/WaylandServer.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index 6dcc2845..d2497529 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -802,8 +802,12 @@ - (id) _initWaylandContext format: @"Unable to get compositor"]; } if (!wlconfig->wm_base) { + /* Note: this was merged into Weston only as of Feb 2019, and is + probably in Weston only as of 6.0 release, therefore not in Weston + 5.x present in Debian buster (current stable). See Weston merge request + !103. */ [NSException raise: NSWindowServerCommunicationException - format: @"Unable to get xdg-shell / xdg_wm_base"]; + format: @"Unable to get xdg-shell / xdg_wm_base - your Wayland compositor must support the stable XDG Shell protocol"]; } return self; From de9a8b36c3e680ac3217b4218898b6364fe8c12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 16:40:07 +0100 Subject: [PATCH 15/23] wayland: Performed some investigation into freeing WaylandCairoSurface memory. --- Source/cairo/WaylandCairoSurface.m | 31 ++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index 8d2bf836..bb05c3ab 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -75,6 +75,18 @@ return fd; } +static inline size_t +shm_buffer_stride(struct window *window) +{ + return window->width * 4; +} + +static inline size_t +shm_buffer_size(struct window *window) +{ + return shm_buffer_stride(window) * window->height; +} + static cairo_surface_t * create_shm_buffer(struct window *window) { @@ -82,8 +94,8 @@ cairo_surface_t *surface; int fd, size, stride; - stride = window->width * 4; - size = stride * window->height; + stride = shm_buffer_stride(window); + size = shm_buffer_size(window); NSDebugLog(@"WaylandCairoSurface: creating shm buffer of %d bytes", size); fd = os_create_anonymous_file(size); @@ -145,8 +157,19 @@ - (void) dealloc struct window *window = (struct window*) gsDevice; NSDebugLog(@"WaylandCairoSurface: dealloc win=%d", window->window_id); - // FIXME: This is leaking memory. We need to implement counterpart to - // create_shm_buffer. + // FIXME: This is leaking memory. We need to *correctly* implement + // the counterpart to create_shm_buffer. + // + // For instance, this is the wrong place to destroy the cairo surface: + // cairo_surface_destroy(window->surface); + // window->surface = NULL; + // and likely to unmap the data, and destroy/release the buffer. + // "Destroying the wl_buffer after wl_buffer.release does not change + // the surface contents. However, if the client destroys the wl_buffer + // before receiving the wl_buffer.release event, the surface contents + // become undefined immediately." + // Hence also skipping: + // munmap(window->data, shm_buffer_size(window)); [super dealloc]; } From 12f1d4877299ef4125d42fe941a90c8ccbf396d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 16:42:59 +0100 Subject: [PATCH 16/23] wayland: Remove the 'fake drawing' branch. --- Source/cairo/WaylandCairoSurface.m | 35 +++++------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index bb05c3ab..0b871af4 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -211,35 +211,12 @@ - (void) handleExposeRect: (NSRect)rect cairo_surface_set_device_offset(cairo_surface, 0, 0); cairo_t *cr = cairo_create(cairo_surface); - if (width != window->width && 0) { - // FIXME: remove this dead fake-drawing branch. - NSDebugLog(@"fake drawing"); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - - cairo_rectangle(cr, 0, 0, width, height); - cairo_set_source_rgba(cr, 0, 0, 0, 0.8); - cairo_fill(cr); - - cairo_rectangle(cr, 10, 10, width - 20, height - 20); - cairo_set_source_rgba(cr, 1.0, 0, 0, 1); - cairo_fill(cr); - - cairo_select_font_face(cr, "sans", - CAIRO_FONT_SLANT_NORMAL, - CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, 12); - cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); - cairo_move_to(cr, 30, 30); - cairo_show_text(cr, "Hello, world!"); - } else { - NSDebugLog(@"real drawing"); - - cairo_rectangle(cr, x, y, width, height); - cairo_clip(cr); - cairo_set_source_surface(cr, cairo_surface, 0, 0); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_paint(cr); - } + + cairo_rectangle(cr, x, y, width, height); + cairo_clip(cr); + cairo_set_source_surface(cr, cairo_surface, 0, 0); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); cairo_destroy(cr); From c6e9ee857fb1759dcbe88540608d1fe43aa556d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 17:41:23 +0100 Subject: [PATCH 17/23] wayland: Support mouse middle click and smooth scroll wheel events. --- Headers/wayland/WaylandServer.h | 4 + Source/wayland/WaylandServer.m | 135 +++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 4 deletions(-) diff --git a/Headers/wayland/WaylandServer.h b/Headers/wayland/WaylandServer.h index f36c6132..c8e6ed39 100644 --- a/Headers/wayland/WaylandServer.h +++ b/Headers/wayland/WaylandServer.h @@ -80,6 +80,8 @@ typedef struct _WaylandConfig { int modifiers; int seat_version; + + float mouse_scroll_multiplier; } WaylandConfig; struct output { @@ -128,6 +130,8 @@ struct window { @interface WaylandServer : GSDisplayServer { WaylandConfig *wlconfig; + + BOOL _mouseInitialized; } @end diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index d2497529..9fd44563 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -152,10 +152,13 @@ struct window *window = wl_surface_get_user_data(surface); float sx = wl_fixed_to_double(sx_w); float sy = wl_fixed_to_double(sy_w); + [GSCurrentServer() initializeMouseIfRequired]; wlconfig->pointer.x = sx; wlconfig->pointer.y = sy; wlconfig->pointer.focus = window; + + // FIXME: Send NSMouseEntered event. } static void @@ -170,11 +173,14 @@ WaylandConfig *wlconfig = data; struct window *window = wl_surface_get_user_data(surface); + [GSCurrentServer() initializeMouseIfRequired]; if (wlconfig->pointer.focus->window_id == window->window_id) { wlconfig->pointer.focus = NULL; wlconfig->pointer.serial = 0; } + + // FIXME: Send NSMouseExited event. } static void @@ -187,6 +193,8 @@ float sy = wl_fixed_to_double(sy_w); NSDebugLog(@"pointer_handle_motion: %fx%f", sx, sy); + [GSCurrentServer() initializeMouseIfRequired]; + if (wlconfig->pointer.focus && wlconfig->pointer.serial) { window = wlconfig->pointer.focus; NSEvent *event; @@ -245,13 +253,17 @@ float deltaY = 0.0; int clickCount = 1; int tick; + int buttonNumber; enum wl_pointer_button_state state = state_w; struct window *window = wlconfig->pointer.focus; + [GSCurrentServer() initializeMouseIfRequired]; + gcontext = GSCurrentContext(); eventLocation = NSMakePoint(wlconfig->pointer.x, window->height - wlconfig->pointer.y); eventFlags = 0; + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { if (button == wlconfig->pointer.last_click_button && time - wlconfig->pointer.last_click_time < 300 && @@ -275,9 +287,16 @@ case BTN_RIGHT: eventType = NSRightMouseDown; break; + case BTN_MIDDLE: + eventType = NSOtherMouseDown; + break; + // TODO: handle BTN_SIDE, BTN_EXTRA, BTN_FORWARD, BTN_BACK and other + // constants in libinput. + // We may just want to send NSOtherMouseDown and populate buttonNumber + // with the libinput constant? } wlconfig->pointer.serial = serial; - } else { + } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) { switch (button) { case BTN_LEFT: eventType = NSLeftMouseUp; @@ -285,14 +304,33 @@ case BTN_RIGHT: eventType = NSRightMouseUp; break; + case BTN_MIDDLE: + eventType = NSOtherMouseUp; + break; } wlconfig->pointer.serial = 0; + } else { + NSDebugLog(@"unhandled wayland pointer state 0x%02x", state); + return; } + /* FIXME: unlike in _motion and _axis handlers, the argument used in _button + is the "serial" of the event, not passed and unavailable in _motion and + _axis handlers. Is it allowed to pass "serial" as the eventNumber: in + _button handler, but "time" as the eventNumber: in the _motion and _axis + handlers? */ tick = serial; NSDebugLog(@"sending pointer event at: %fx%f, window=%d", wlconfig->pointer.x, wlconfig->pointer.y, window->window_id); + /* FIXME: X11 backend uses the XGetPointerMapping()-returned values from + its map_return argument as constants for buttonNumber. As the variant + with buttonNumber: seems to be a GNUstep extension, and the value + internal, it might be ok to just provide libinput constant as we're doing + here. If this is truly correct, please update this comment to document + the correctness of doing so. */ + buttonNumber = button; + event = [NSEvent mouseEventWithType: eventType location: eventLocation modifierFlags: eventFlags @@ -302,9 +340,9 @@ eventNumber: tick clickCount: clickCount pressure: 1.0 - buttonNumber: 0 /* FIXME */ - deltaX: deltaX - deltaY: deltaY + buttonNumber: buttonNumber + deltaX: deltaX /* FIXME unused */ + deltaY: deltaY /* FIXME unused */ deltaZ: 0.]; [GSCurrentServer() postEvent: event atStart: NO]; @@ -314,6 +352,65 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { + NSDebugLog(@"pointer_handle_axis: axis=%d value=%g", axis, wl_fixed_to_double(value)); + WaylandConfig *wlconfig = data; + NSEvent *event; + NSEventType eventType; + NSPoint eventLocation; + NSGraphicsContext *gcontext; + unsigned int eventFlags; + float deltaX = 0.0; + float deltaY = 0.0; + int clickCount = 1; + int buttonNumber; + + struct window *window = wlconfig->pointer.focus; + + [GSCurrentServer() initializeMouseIfRequired]; + + gcontext = GSCurrentContext(); + eventLocation = NSMakePoint(wlconfig->pointer.x, + window->height - wlconfig->pointer.y); + eventFlags = 0; + + float mouse_scroll_multiplier = wlconfig->mouse_scroll_multiplier; + /* For smooth-scroll events, we're not doing any cross-event or delta + calculations, as is done in button event handling. */ + switch(axis) + { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + eventType = NSScrollWheel; + deltaY = wl_fixed_to_double(value) * wlconfig->mouse_scroll_multiplier; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + eventType = NSScrollWheel; + deltaX = wl_fixed_to_double(value) * wlconfig->mouse_scroll_multiplier; + } + + NSDebugLog(@"sending pointer scroll at: %fx%f, value %fx%f, window=%d", wlconfig->pointer.x, wlconfig->pointer.y, deltaX, deltaY, window->window_id); + + /* FIXME: X11 backend uses the XGetPointerMapping()-returned values from + its map_return argument as constants for buttonNumber. As the variant + with buttonNumber: seems to be a GNUstep extension, and the value + internal, it might be ok to just not provide any value here. + If this is truly correct, please update this comment to document + the correctness of doing so. */ + buttonNumber = 0; + + event = [NSEvent mouseEventWithType: eventType + location: eventLocation + modifierFlags: eventFlags + timestamp: (NSTimeInterval) time / 1000.0 + windowNumber: (int)window->window_id + context: gcontext + eventNumber: time + clickCount: clickCount + pressure: 1.0 + buttonNumber: buttonNumber + deltaX: deltaX + deltaY: deltaY + deltaZ: 0.]; + + [GSCurrentServer() postEvent: event atStart: NO]; } static const struct wl_pointer_listener pointer_listener = { @@ -777,6 +874,7 @@ - (id) _initWaylandContext wlconfig = (WaylandConfig *) malloc(sizeof(WaylandConfig)); memset(wlconfig, 0, sizeof(WaylandConfig)); wlconfig->last_window_id = 1; + wlconfig->mouse_scroll_multiplier = 1.0f; wl_list_init(&wlconfig->output_list); wl_list_init(&wlconfig->window_list); @@ -1183,6 +1281,7 @@ - (void) placewindow: (NSRect)rect : (int) win if (0 && config->pointer.serial && config->pointer.focus && config->pointer.focus->window_id == win) { + // FIXME: remove dead branch NSEvent *event; NSEventType eventType; NSPoint eventLocation; @@ -1528,4 +1627,32 @@ - (void) setIgnoreMouse: (BOOL)ignoreMouse : (int)win NSDebugLog(@"setIgnoreMouse"); } +- (void) initializeMouseIfRequired +{ + if (!_mouseInitialized) + [self initializeMouse]; +} + +- (void) initializeMouse +{ + _mouseInitialized = YES; + + [self mouseOptionsChanged: nil]; + [[NSDistributedNotificationCenter defaultCenter] + addObserver: self + selector: @selector(mouseOptionsChanged:) + name: NSUserDefaultsDidChangeNotification + object: nil]; +} + +- (void) mouseOptionsChanged: (NSNotification *)aNotif +{ + NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; + + wlconfig->mouse_scroll_multiplier = [defs integerForKey:@"GSMouseScrollMultiplier"]; + if (wlconfig->mouse_scroll_multiplier < 0.0001f) + wlconfig->mouse_scroll_multiplier = 1.0f; +} + + @end From 67e352b83e377aa87719cac5a2f17901f83d4ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 17:45:11 +0100 Subject: [PATCH 18/23] wayland: Deleted the useless override of -[GSDisplayServer windowlist]. --- Source/wayland/WaylandServer.m | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index 9fd44563..fc2d398a 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -1419,27 +1419,6 @@ - (int) windowlevel: (int) win return 0; } -/** Backends can override this method to return an array of window numbers - ordered front to back. The front most window being the first object - in the array. - The default implementation returns the visible windows in an - unspecified order. - */ -- (NSArray *) windowlist -{ - NSMutableArray *list = [NSMutableArray arrayWithArray:[NSApp windows]]; - int c = [list count]; - - while (c-- > 0) - { - if (![[list objectAtIndex:c] isVisible]) - { - [list removeObjectAtIndex:c]; - } - } - return [list valueForKey:@"windowNumber"]; -} - - (int) windowdepth: (int) win { NSDebugLog(@"windowdepth"); From f8b8609e708a45667a998cca721a4fcbf4cafd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 18:04:50 +0100 Subject: [PATCH 19/23] wayland: Implement -[WaylandServer mouselocation]. --- Source/wayland/WaylandServer.m | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index fc2d398a..a5e48681 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -1483,8 +1483,21 @@ - (void) setShadow: (BOOL)hasShadow : (int)win - (NSPoint) mouselocation { - NSDebugLog(@"mouselocation"); + int aScreen = -1; + struct output *output; + + NSDebugLog(@"mouselocation"); + + // FIXME: find a cleaner way to get the first element of a wl_list + wl_list_for_each(output, &wlconfig->output_list, link) { + aScreen = output->server_output_id; + break; + } + if (aScreen < 0) + // No outputs in the wl_list. return NSZeroPoint; + + return [self mouseLocationOnScreen: aScreen window: NULL]; } - (NSPoint) mouseLocationOnScreen: (int)aScreen window: (int *)win From 8f0cc1b0caec1449e4c249e37f8f076d75f03fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 18:05:43 +0100 Subject: [PATCH 20/23] wayland: Write down TODOs for cairo_surface doublebuffering to itself and for mouse wheel axis_source. --- Source/cairo/WaylandCairoSurface.m | 2 ++ Source/wayland/WaylandServer.m | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index 0b871af4..c6bd101b 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -210,6 +210,8 @@ - (void) handleExposeRect: (NSRect)rect cairo_surface_get_device_offset(cairo_surface, &backupOffsetX, &backupOffsetY); cairo_surface_set_device_offset(cairo_surface, 0, 0); + // FIXME: This seems to be creating a context to paint into cairo_surface, + // and then copies back into the same cairo_surface. cairo_t *cr = cairo_create(cairo_surface); cairo_rectangle(cr, x, y, width, height); diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index a5e48681..748c1102 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -373,6 +373,14 @@ window->height - wlconfig->pointer.y); eventFlags = 0; + /* FIXME: we should get axis_source out of wl_pointer; however, the wl_pointer + is not defined in wayland-client.h. How does one get the axis_source out of + it to confirm the source is the physical mouse wheel? */ +#if 0 + if (pointer->axis_source != WL_POINTER_AXIS_SOURCE_WHEEL) + return; +#endif + float mouse_scroll_multiplier = wlconfig->mouse_scroll_multiplier; /* For smooth-scroll events, we're not doing any cross-event or delta calculations, as is done in button event handling. */ From 2bbcb043efbddf1f80510f5c982a0fb459cc6e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 18:12:11 +0100 Subject: [PATCH 21/23] wayland: Update the changelog for the merge. --- ChangeLog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ChangeLog b/ChangeLog index 31dc830e..bb20170c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2020-04-25 Ivan Vucica + + * Source/GSBackend.m: + * Source/cairo/GNUmakefile: + * Source/cairo/CairoContext.m: + * Source/cairo/WaylandCairoSurface.m: + * Source/wayland/GNUmakefile: + * Source/wayland/GNUmakefile.preamble: + * Source/wayland/WaylandServer.m: + * Source/wayland/xdg-shell-protocol.c: + * Headers/cairo/WaylandCairoSurface.h: + * Headers/wayland/WaylandServer.h: + * Headers/wayland/xdg-shell-client-protocol.h: + * wayland-regenerate.h: + * configure: + * configure.ac: + Initial merge of the Wayland backend into the master branch. + 2020-04-13 Ivan Vucica * Documentation/announce.texi: From bf4efe9d3602bf6c8bd41c58afa586af018562ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 18:23:49 +0100 Subject: [PATCH 22/23] wayland: Added a small readme noting some backend-specific information. --- Source/wayland/README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Source/wayland/README.md diff --git a/Source/wayland/README.md b/Source/wayland/README.md new file mode 100644 index 00000000..4ddc49df --- /dev/null +++ b/Source/wayland/README.md @@ -0,0 +1,37 @@ +# Wayland backend for GNUstep + +This directory (along with `Headers/wayland/`, and a file in `Source/cairo/` +and `Headers/cairo`) contains the Wayland backend for GNUstep GUI. This +display server backend depends on Cairo graphics backend; it will currently +not work with any other combination. + +As of April 2020, it is incomplete and broken. Help getting it functional will +be appreciated. + +## Known issues + +Last updated 25 April 2020: + +* Under Weston, some backing Cairo surfaces, which should not be visible in + the compositor, are nonetheless drawn randomly onto the screen. +* Backing view surfaces may never get blitted onto the main window. +* After a while, Weston assumes that the application is not responding (there + is a spinner when hovering over the windows, and the surfaces can be + rotated by holding the right mouse button). Some events still get + delivered, visible in the debug output, but otherwise the application + appears frozen. + +## Use on Debian + +As of April 2020, it requires the stable XDG Shell protocol to be available in +the compositor you may be using. Weston included in Debian buster does _not_ +include the stable XDG Shell protocol; this was only checked into Weston in +February 2019, and seemingly released with Weston 6, which does not ship in +Debian buster. + +## Regenerating protocol files + +To regenerate protocol sources from protocol IDLs in XML format, please use +`wayland-regenerate.sh`. Paths to the XML files are hardcoded to the values on +a Debian testing system. + From 4ab5a69383fca271331c32eea2c249cf272fc216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vu=C4=8Dica?= Date: Sat, 25 Apr 2020 18:25:08 +0100 Subject: [PATCH 23/23] wayland: Mention the new README in the changelog. --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index bb20170c..3d71a2da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,7 @@ * Source/wayland/GNUmakefile.preamble: * Source/wayland/WaylandServer.m: * Source/wayland/xdg-shell-protocol.c: + * Source/wayland/README.md: * Headers/cairo/WaylandCairoSurface.h: * Headers/wayland/WaylandServer.h: * Headers/wayland/xdg-shell-client-protocol.h: