2021-06-06 01:26:18 +00:00
|
|
|
/**
|
|
|
|
* Looking Glass
|
2022-01-05 08:42:46 +00:00
|
|
|
* Copyright © 2017-2022 The Looking Glass Authors
|
2021-06-06 01:26:18 +00:00
|
|
|
* https://looking-glass.io
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
|
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <wayland-client.h>
|
2021-07-29 21:34:17 +00:00
|
|
|
#include <wayland-cursor.h>
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
|
|
|
|
# include <wayland-egl.h>
|
|
|
|
# include <EGL/egl.h>
|
|
|
|
# include <EGL/eglext.h>
|
2021-07-19 08:01:19 +00:00
|
|
|
# include "eglutil.h"
|
2021-02-20 06:23:48 +00:00
|
|
|
#endif
|
|
|
|
|
2021-07-18 02:57:15 +00:00
|
|
|
#include "app.h"
|
2021-05-11 20:49:39 +00:00
|
|
|
#include "egl_dynprocs.h"
|
2021-02-20 06:23:48 +00:00
|
|
|
#include "common/locking.h"
|
|
|
|
#include "common/countedbuffer.h"
|
2021-07-18 02:57:15 +00:00
|
|
|
#include "common/ringbuffer.h"
|
2021-02-20 06:23:48 +00:00
|
|
|
#include "interface/displayserver.h"
|
|
|
|
|
|
|
|
#include "wayland-xdg-shell-client-protocol.h"
|
2021-05-14 02:51:45 +00:00
|
|
|
#include "wayland-presentation-time-client-protocol.h"
|
2021-08-01 01:56:47 +00:00
|
|
|
#include "wayland-viewporter-client-protocol.h"
|
2021-02-20 06:23:48 +00:00
|
|
|
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
|
|
|
|
#include "wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
|
|
|
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
|
|
|
|
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
|
|
|
|
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
|
2021-08-01 01:56:47 +00:00
|
|
|
#include "wayland-xdg-output-unstable-v1-client-protocol.h"
|
2022-02-06 21:07:29 +00:00
|
|
|
#include "wayland-xdg-activation-v1-client-protocol.h"
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
typedef void (*WaylandPollCallback)(uint32_t events, void * opaque);
|
|
|
|
|
|
|
|
struct WaylandPoll
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
bool removed;
|
|
|
|
WaylandPollCallback callback;
|
|
|
|
void * opaque;
|
|
|
|
struct wl_list link;
|
|
|
|
};
|
|
|
|
|
2021-02-21 03:48:48 +00:00
|
|
|
struct WaylandOutput
|
|
|
|
{
|
|
|
|
uint32_t name;
|
2021-08-01 01:56:47 +00:00
|
|
|
wl_fixed_t scale;
|
|
|
|
int32_t scaleInt;
|
|
|
|
int32_t logicalWidth;
|
|
|
|
int32_t logicalHeight;
|
|
|
|
int32_t modeWidth;
|
|
|
|
int32_t modeHeight;
|
|
|
|
bool modeRotate;
|
2021-02-21 03:48:48 +00:00
|
|
|
struct wl_output * output;
|
2021-08-01 01:56:47 +00:00
|
|
|
struct zxdg_output_v1 * xdgOutput;
|
2021-02-27 02:38:20 +00:00
|
|
|
uint32_t version;
|
2021-02-21 03:48:48 +00:00
|
|
|
struct wl_list link;
|
|
|
|
};
|
|
|
|
|
2021-02-21 05:10:08 +00:00
|
|
|
struct SurfaceOutput
|
|
|
|
{
|
|
|
|
struct wl_output * output;
|
|
|
|
struct wl_list link;
|
|
|
|
};
|
|
|
|
|
2021-05-11 20:49:39 +00:00
|
|
|
enum EGLSwapWithDamageState {
|
|
|
|
SWAP_WITH_DAMAGE_UNKNOWN,
|
|
|
|
SWAP_WITH_DAMAGE_UNSUPPORTED,
|
|
|
|
SWAP_WITH_DAMAGE_KHR,
|
|
|
|
SWAP_WITH_DAMAGE_EXT,
|
|
|
|
};
|
|
|
|
|
2021-08-14 04:20:34 +00:00
|
|
|
struct xkb_context;
|
|
|
|
struct xkb_keymap;
|
|
|
|
struct xkb_state;
|
|
|
|
|
2021-02-20 06:23:48 +00:00
|
|
|
struct WaylandDSState
|
|
|
|
{
|
|
|
|
bool pointerGrabbed;
|
|
|
|
bool keyboardGrabbed;
|
2021-03-06 22:17:11 +00:00
|
|
|
bool pointerInSurface;
|
|
|
|
bool focusedOnSurface;
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
struct wl_display * display;
|
|
|
|
struct wl_surface * surface;
|
|
|
|
struct wl_registry * registry;
|
|
|
|
struct wl_seat * seat;
|
|
|
|
struct wl_shm * shm;
|
|
|
|
struct wl_compositor * compositor;
|
|
|
|
|
2021-08-01 01:56:47 +00:00
|
|
|
int32_t width, height;
|
|
|
|
wl_fixed_t scale;
|
|
|
|
bool fractionalScale;
|
2021-02-21 05:10:08 +00:00
|
|
|
bool needsResize;
|
2021-02-20 06:23:48 +00:00
|
|
|
bool fullscreen;
|
|
|
|
uint32_t resizeSerial;
|
|
|
|
bool configured;
|
|
|
|
bool warpSupport;
|
|
|
|
double cursorX, cursorY;
|
|
|
|
|
2021-05-11 20:49:39 +00:00
|
|
|
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
|
2021-02-20 06:23:48 +00:00
|
|
|
struct wl_egl_window * eglWindow;
|
2021-07-19 08:01:19 +00:00
|
|
|
struct SwapWithDamageData swapWithDamage;
|
2021-02-20 06:23:48 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_OPENGL
|
|
|
|
EGLDisplay glDisplay;
|
|
|
|
EGLConfig glConfig;
|
|
|
|
EGLSurface glSurface;
|
|
|
|
#endif
|
|
|
|
|
2021-05-14 02:51:45 +00:00
|
|
|
struct wp_presentation * presentation;
|
|
|
|
clockid_t clkId;
|
2021-07-18 02:57:15 +00:00
|
|
|
RingBuffer photonTimings;
|
|
|
|
GraphHandle photonGraph;
|
2021-05-14 02:51:45 +00:00
|
|
|
|
2021-03-06 12:09:44 +00:00
|
|
|
#ifdef ENABLE_LIBDECOR
|
|
|
|
struct libdecor * libdecor;
|
|
|
|
struct libdecor_frame * libdecorFrame;
|
|
|
|
#else
|
2021-02-20 06:23:48 +00:00
|
|
|
struct xdg_wm_base * xdgWmBase;
|
|
|
|
struct xdg_surface * xdgSurface;
|
|
|
|
struct xdg_toplevel * xdgToplevel;
|
|
|
|
struct zxdg_decoration_manager_v1 * xdgDecorationManager;
|
|
|
|
struct zxdg_toplevel_decoration_v1 * xdgToplevelDecoration;
|
2021-03-06 12:09:44 +00:00
|
|
|
#endif
|
2021-02-20 06:23:48 +00:00
|
|
|
|
2021-08-14 23:32:33 +00:00
|
|
|
const char * cursorThemeName;
|
|
|
|
int cursorSize;
|
|
|
|
int cursorScale;
|
2021-07-29 21:34:17 +00:00
|
|
|
struct wl_cursor_theme * cursorTheme;
|
|
|
|
struct wl_buffer * cursorSquareBuffer;
|
|
|
|
struct wl_surface * cursors[LG_POINTER_COUNT];
|
|
|
|
struct Point cursorHot[LG_POINTER_COUNT];
|
2021-08-14 23:32:33 +00:00
|
|
|
LG_DSPointer cursorId;
|
2021-07-29 21:34:17 +00:00
|
|
|
struct wl_surface * cursor;
|
|
|
|
int cursorHotX;
|
|
|
|
int cursorHotY;
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
struct wl_data_device_manager * dataDeviceManager;
|
|
|
|
|
|
|
|
uint32_t capabilities;
|
|
|
|
|
|
|
|
struct wl_keyboard * keyboard;
|
|
|
|
struct zwp_keyboard_shortcuts_inhibit_manager_v1 * keyboardInhibitManager;
|
|
|
|
struct zwp_keyboard_shortcuts_inhibitor_v1 * keyboardInhibitor;
|
|
|
|
uint32_t keyboardEnterSerial;
|
2021-08-14 04:20:34 +00:00
|
|
|
struct xkb_context * xkb;
|
|
|
|
struct xkb_state * xkbState;
|
|
|
|
struct xkb_keymap * keymap;
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
struct wl_pointer * pointer;
|
|
|
|
struct zwp_relative_pointer_manager_v1 * relativePointerManager;
|
|
|
|
struct zwp_pointer_constraints_v1 * pointerConstraints;
|
|
|
|
struct zwp_relative_pointer_v1 * relativePointer;
|
|
|
|
struct zwp_confined_pointer_v1 * confinedPointer;
|
2021-05-04 00:37:01 +00:00
|
|
|
struct zwp_locked_pointer_v1 * lockedPointer;
|
2021-02-20 06:23:48 +00:00
|
|
|
bool showPointer;
|
|
|
|
uint32_t pointerEnterSerial;
|
2021-06-06 05:28:22 +00:00
|
|
|
LG_Lock confineLock;
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
struct zwp_idle_inhibit_manager_v1 * idleInhibitManager;
|
|
|
|
struct zwp_idle_inhibitor_v1 * idleInhibitor;
|
|
|
|
|
2022-02-06 21:07:29 +00:00
|
|
|
struct xdg_activation_v1 * xdgActivation;
|
|
|
|
|
2021-08-01 01:56:47 +00:00
|
|
|
struct wp_viewporter * viewporter;
|
|
|
|
struct wp_viewport * viewport;
|
|
|
|
struct zxdg_output_manager_v1 * xdgOutputManager;
|
2021-02-21 03:48:48 +00:00
|
|
|
struct wl_list outputs; // WaylandOutput::link
|
2021-02-21 05:10:08 +00:00
|
|
|
struct wl_list surfaceOutputs; // SurfaceOutput::link
|
2021-08-01 02:57:03 +00:00
|
|
|
bool useFractionalScale;
|
2021-02-21 03:48:48 +00:00
|
|
|
|
2021-08-01 07:06:03 +00:00
|
|
|
LGEvent * frameEvent;
|
|
|
|
|
2021-02-20 06:23:48 +00:00
|
|
|
struct wl_list poll; // WaylandPoll::link
|
|
|
|
struct wl_list pollFree; // WaylandPoll::link
|
|
|
|
LG_Lock pollLock;
|
|
|
|
LG_Lock pollFreeLock;
|
|
|
|
int epollFd;
|
|
|
|
int displayFd;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct WCBTransfer
|
|
|
|
{
|
|
|
|
struct CountedBuffer * data;
|
|
|
|
const char ** mimetypes;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ClipboardRead
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
size_t size;
|
|
|
|
size_t numRead;
|
|
|
|
uint8_t * buf;
|
|
|
|
enum LG_ClipboardData type;
|
|
|
|
struct wl_data_offer * offer;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct WCBState
|
|
|
|
{
|
|
|
|
struct wl_data_device * dataDevice;
|
|
|
|
char lgMimetype[64];
|
|
|
|
|
[client] wayland: offer all supported clipboard formats
This commit restructures the Wayland clipboard handling for host->VM.
Before, we select one clipboard format and buffers the data for it, to
be presented to spice when needed.
Now, we simply offer all clipboard formats supported, and only when spice
asks for the data do we actually read the wl_data_offer. The wl_data_offer
is kept around until a new offer is presented, the offer invalidated, or
when we lose keyboard focus. This is in accordance with the specification
for wl_data_device::selection, which states that:
> The data_offer is valid until a new data_offer or NULL is received or
> until the client loses keyboard focus. The client must destroy the
> previous selection data_offer, if any, upon receiving this event.
We still buffer the entire clipboard data into memory because we have no
knowledge of the clipboard data size in advance and cannot do incremental
transfers.
Furthermore, if the user performs drag-and-drop on our window, we may have
need to handle multiple wl_data_offer objects at the same time. Therefore,
instead of storing state on the global wlCb object, we instead allocate
memory and store it as user_data on the wl_data_offer. As a result, we also
handle drag-and-drop so that we can free the memory.
2021-05-30 23:02:39 +00:00
|
|
|
char * mimetypes[LG_CLIPBOARD_DATA_NONE];
|
|
|
|
struct wl_data_offer * offer;
|
|
|
|
struct wl_data_offer * dndOffer;
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
bool haveRequest;
|
|
|
|
LG_ClipboardData type;
|
|
|
|
|
|
|
|
struct ClipboardRead * currentRead;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern struct WaylandDSState wlWm;
|
|
|
|
extern struct WCBState wlCb;
|
|
|
|
|
2022-02-06 21:07:29 +00:00
|
|
|
// activation module
|
|
|
|
bool waylandActivationInit(void);
|
|
|
|
void waylandActivationFree(void);
|
2022-02-06 21:20:59 +00:00
|
|
|
void waylandActivationRequestActivation(void);
|
2022-02-06 21:07:29 +00:00
|
|
|
|
2021-02-20 06:23:48 +00:00
|
|
|
// clipboard module
|
|
|
|
bool waylandCBInit(void);
|
|
|
|
void waylandCBRequest(LG_ClipboardData type);
|
|
|
|
void waylandCBNotice(LG_ClipboardData type);
|
|
|
|
void waylandCBRelease(void);
|
[client] wayland: offer all supported clipboard formats
This commit restructures the Wayland clipboard handling for host->VM.
Before, we select one clipboard format and buffers the data for it, to
be presented to spice when needed.
Now, we simply offer all clipboard formats supported, and only when spice
asks for the data do we actually read the wl_data_offer. The wl_data_offer
is kept around until a new offer is presented, the offer invalidated, or
when we lose keyboard focus. This is in accordance with the specification
for wl_data_device::selection, which states that:
> The data_offer is valid until a new data_offer or NULL is received or
> until the client loses keyboard focus. The client must destroy the
> previous selection data_offer, if any, upon receiving this event.
We still buffer the entire clipboard data into memory because we have no
knowledge of the clipboard data size in advance and cannot do incremental
transfers.
Furthermore, if the user performs drag-and-drop on our window, we may have
need to handle multiple wl_data_offer objects at the same time. Therefore,
instead of storing state on the global wlCb object, we instead allocate
memory and store it as user_data on the wl_data_offer. As a result, we also
handle drag-and-drop so that we can free the memory.
2021-05-30 23:02:39 +00:00
|
|
|
void waylandCBInvalidate(void);
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
// cursor module
|
|
|
|
bool waylandCursorInit(void);
|
2021-04-06 00:06:49 +00:00
|
|
|
void waylandCursorFree(void);
|
2021-07-29 20:31:07 +00:00
|
|
|
void waylandSetPointer(LG_DSPointer pointer);
|
2021-08-14 23:32:33 +00:00
|
|
|
void waylandCursorScaleChange(void);
|
2021-02-20 06:23:48 +00:00
|
|
|
|
|
|
|
// gl module
|
|
|
|
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
|
|
|
|
bool waylandEGLInit(int w, int h);
|
|
|
|
EGLDisplay waylandGetEGLDisplay(void);
|
2021-05-11 20:49:39 +00:00
|
|
|
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count);
|
2021-02-20 06:23:48 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_EGL
|
|
|
|
EGLNativeWindowType waylandGetEGLNativeWindow(void);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_OPENGL
|
|
|
|
bool waylandOpenGLInit(void);
|
|
|
|
LG_DSGLContext waylandGLCreateContext(void);
|
|
|
|
void waylandGLDeleteContext(LG_DSGLContext context);
|
|
|
|
void waylandGLMakeCurrent(LG_DSGLContext context);
|
|
|
|
void waylandGLSetSwapInterval(int interval);
|
|
|
|
void waylandGLSwapBuffers(void);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// idle module
|
|
|
|
bool waylandIdleInit(void);
|
|
|
|
void waylandIdleFree(void);
|
|
|
|
void waylandInhibitIdle(void);
|
|
|
|
void waylandUninhibitIdle(void);
|
|
|
|
|
|
|
|
// input module
|
|
|
|
bool waylandInputInit(void);
|
|
|
|
void waylandInputFree(void);
|
|
|
|
void waylandGrabKeyboard(void);
|
|
|
|
void waylandGrabPointer(void);
|
|
|
|
void waylandUngrabKeyboard(void);
|
|
|
|
void waylandUngrabPointer(void);
|
2021-05-04 00:16:51 +00:00
|
|
|
void waylandCapturePointer(void);
|
|
|
|
void waylandUncapturePointer(void);
|
2021-02-20 06:23:48 +00:00
|
|
|
void waylandRealignPointer(void);
|
|
|
|
void waylandWarpPointer(int x, int y, bool exiting);
|
2021-05-04 08:53:31 +00:00
|
|
|
void waylandGuestPointerUpdated(double x, double y, double localX, double localY);
|
2021-02-20 06:23:48 +00:00
|
|
|
|
2021-02-21 03:48:48 +00:00
|
|
|
// output module
|
|
|
|
bool waylandOutputInit(void);
|
|
|
|
void waylandOutputFree(void);
|
2021-02-25 00:44:49 +00:00
|
|
|
void waylandOutputBind(uint32_t name, uint32_t version);
|
2021-02-21 03:48:48 +00:00
|
|
|
void waylandOutputTryUnbind(uint32_t name);
|
2021-08-01 01:56:47 +00:00
|
|
|
wl_fixed_t waylandOutputGetScale(struct wl_output * output);
|
2021-02-21 03:48:48 +00:00
|
|
|
|
2021-02-20 06:23:48 +00:00
|
|
|
// poll module
|
|
|
|
bool waylandPollInit(void);
|
|
|
|
void waylandWait(unsigned int time);
|
2021-03-02 04:51:12 +00:00
|
|
|
bool waylandPollRegister(int fd, WaylandPollCallback callback, void * opaque, uint32_t events);
|
|
|
|
bool waylandPollUnregister(int fd);
|
2021-02-20 06:23:48 +00:00
|
|
|
|
2021-05-14 02:51:45 +00:00
|
|
|
// presentation module
|
|
|
|
bool waylandPresentationInit(void);
|
|
|
|
void waylandPresentationFrame(void);
|
|
|
|
void waylandPresentationFree(void);
|
|
|
|
|
2021-02-20 06:23:48 +00:00
|
|
|
// registry module
|
|
|
|
bool waylandRegistryInit(void);
|
|
|
|
void waylandRegistryFree(void);
|
|
|
|
|
2021-03-06 10:20:29 +00:00
|
|
|
// shell module
|
2021-10-04 17:55:18 +00:00
|
|
|
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable);
|
2021-03-06 10:20:29 +00:00
|
|
|
void waylandShellAckConfigureIfNeeded(void);
|
|
|
|
void waylandSetFullscreen(bool fs);
|
|
|
|
bool waylandGetFullscreen(void);
|
2021-05-06 12:25:38 +00:00
|
|
|
void waylandMinimize(void);
|
2021-10-04 17:55:18 +00:00
|
|
|
void waylandShellResize(int w, int h);
|
2021-03-06 10:20:29 +00:00
|
|
|
|
2021-02-20 06:23:48 +00:00
|
|
|
// window module
|
2021-10-04 17:55:18 +00:00
|
|
|
bool waylandWindowInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable);
|
2021-02-20 06:23:48 +00:00
|
|
|
void waylandWindowFree(void);
|
2021-02-22 07:19:03 +00:00
|
|
|
void waylandWindowUpdateScale(void);
|
2021-02-20 06:23:48 +00:00
|
|
|
void waylandSetWindowSize(int x, int y);
|
|
|
|
bool waylandIsValidPointerPos(int x, int y);
|
2021-08-03 21:21:57 +00:00
|
|
|
bool waylandWaitFrame(void);
|
2021-08-01 08:06:35 +00:00
|
|
|
void waylandSkipFrame(void);
|
2021-08-01 09:46:07 +00:00
|
|
|
void waylandStopWaitFrame(void);
|