mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-01-08 21:33:57 +00:00
[client] wayland: implement window creation for egl
This commit implements window creation and resize logic, allowing the desktop to be drawn.
This commit is contained in:
parent
f4c1927f56
commit
9f0b99dac0
8 changed files with 248 additions and 54 deletions
|
@ -229,6 +229,11 @@ static EGLNativeWindowType sdlGetEGLNativeWindow(void)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdlEGLSwapBuffers(EGLDisplay display, EGLSurface surface)
|
||||
{
|
||||
eglSwapBuffers(display, surface);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void sdlSwapBuffers(void)
|
||||
|
@ -470,6 +475,7 @@ struct LG_DisplayServerOps LGDS_SDL =
|
|||
#ifdef ENABLE_EGL
|
||||
.getEGLDisplay = sdlGetEGLDisplay,
|
||||
.getEGLNativeWindow = sdlGetEGLNativeWindow,
|
||||
.eglSwapBuffers = sdlEGLSwapBuffers,
|
||||
#endif
|
||||
|
||||
.glSwapBuffers = sdlSwapBuffers,
|
||||
|
|
|
@ -46,6 +46,9 @@ endmacro()
|
|||
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/wayland")
|
||||
include_directories("${CMAKE_BINARY_DIR}/wayland")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-shell-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-relative-pointer-unstable-v1-client-protocol")
|
||||
|
|
|
@ -25,13 +25,21 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/input.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#ifdef ENABLE_EGL
|
||||
# include <wayland-egl.h>
|
||||
# include "egl_dynprocs.h"
|
||||
# include <EGL/eglext.h>
|
||||
#endif
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#include "wayland-xdg-shell-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"
|
||||
|
@ -46,6 +54,19 @@ struct WaylandDSState
|
|||
struct wl_surface * surface;
|
||||
struct wl_registry * registry;
|
||||
struct wl_seat * seat;
|
||||
struct wl_compositor * compositor;
|
||||
|
||||
int32_t width, height;
|
||||
uint32_t resizeSerial;
|
||||
bool configured;
|
||||
|
||||
#ifdef ENABLE_EGL
|
||||
struct wl_egl_window * eglWindow;
|
||||
#endif
|
||||
|
||||
struct xdg_wm_base * xdgWmBase;
|
||||
struct xdg_surface * xdgSurface;
|
||||
struct xdg_toplevel * xdgToplevel;
|
||||
|
||||
struct wl_data_device_manager * dataDeviceManager;
|
||||
struct wl_data_device * dataDevice;
|
||||
|
@ -90,6 +111,17 @@ struct WCBState
|
|||
static struct WaylandDSState wm;
|
||||
static struct WCBState wcb;
|
||||
|
||||
// XDG WM base listeners.
|
||||
|
||||
static void xdgWmBasePing(void * data, struct xdg_wm_base * xdgWmBase, uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(xdgWmBase, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdgWmBaseListener = {
|
||||
.ping = xdgWmBasePing,
|
||||
};
|
||||
|
||||
// Registry-handling listeners.
|
||||
|
||||
static void registryGlobalHandler(void * data, struct wl_registry * registry,
|
||||
|
@ -97,6 +129,10 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
|
|||
{
|
||||
if (!strcmp(interface, wl_seat_interface.name) && !wm.seat)
|
||||
wm.seat = wl_registry_bind(wm.registry, name, &wl_seat_interface, 1);
|
||||
else if (!strcmp(interface, wl_compositor_interface.name))
|
||||
wm.compositor = wl_registry_bind(wm.registry, name, &wl_compositor_interface, 4);
|
||||
else if (!strcmp(interface, xdg_wm_base_interface.name))
|
||||
wm.xdgWmBase = wl_registry_bind(wm.registry, name, &xdg_wm_base_interface, 1);
|
||||
else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name))
|
||||
wm.relativePointerManager = wl_registry_bind(wm.registry, name,
|
||||
&zwp_relative_pointer_manager_v1_interface, 1);
|
||||
|
@ -321,19 +357,37 @@ static const struct wl_seat_listener seatListener = {
|
|||
.name = seatNameHandler,
|
||||
};
|
||||
|
||||
// Surface-handling listeners.
|
||||
|
||||
static void xdgSurfaceConfigure(void * data, struct xdg_surface * xdgSurface,
|
||||
uint32_t serial)
|
||||
{
|
||||
if (wm.configured)
|
||||
wm.resizeSerial = serial;
|
||||
else
|
||||
{
|
||||
xdg_surface_ack_configure(xdgSurface, serial);
|
||||
wm.configured = true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdgSurfaceListener = {
|
||||
.configure = xdgSurfaceConfigure,
|
||||
};
|
||||
|
||||
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
|
||||
int32_t width, int32_t height, struct wl_array * states)
|
||||
{
|
||||
wm.width = width;
|
||||
wm.height = height;
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdgToplevelListener = {
|
||||
.configure = xdgToplevelConfigure,
|
||||
};
|
||||
|
||||
static bool waylandEarlyInit(void)
|
||||
{
|
||||
if (!getenv("SDL_VIDEODRIVER"))
|
||||
{
|
||||
int err = setenv("SDL_VIDEODRIVER", "wayland", 1);
|
||||
if (err < 0)
|
||||
{
|
||||
DEBUG_ERROR("Unable to set the env variable SDL_VIDEODRIVER: %d", err);
|
||||
return false;
|
||||
}
|
||||
DEBUG_INFO("SDL_VIDEODRIVER has been set to wayland");
|
||||
}
|
||||
|
||||
// Request to receive EPIPE instead of SIGPIPE when one end of a pipe
|
||||
// disconnects while a write is pending. This is useful to the Wayland
|
||||
// clipboard backend, where an arbitrary application is on the other end of
|
||||
|
@ -352,14 +406,13 @@ static bool waylandInit(const LG_DSInitParams params)
|
|||
{
|
||||
memset(&wm, 0, sizeof(wm));
|
||||
|
||||
wm.display = info->info.wl.display;
|
||||
wm.surface = info->info.wl.surface;
|
||||
wm.display = wl_display_connect(NULL);
|
||||
wm.registry = wl_display_get_registry(wm.display);
|
||||
|
||||
wl_registry_add_listener(wm.registry, ®istryListener, NULL);
|
||||
wl_display_roundtrip(wm.display);
|
||||
|
||||
if (!wm.seat || !wm.dataDeviceManager)
|
||||
if (!wm.seat || !wm.dataDeviceManager || !wm.compositor || !wm.xdgWmBase)
|
||||
{
|
||||
DEBUG_ERROR("Compositor missing a required interface, will not proceed");
|
||||
return false;
|
||||
|
@ -379,11 +432,30 @@ static bool waylandInit(const LG_DSInitParams params)
|
|||
"not be able to suppress idle states");
|
||||
|
||||
wl_seat_add_listener(wm.seat, &seatListener, NULL);
|
||||
xdg_wm_base_add_listener(wm.xdgWmBase, &xdgWmBaseListener, NULL);
|
||||
wl_display_roundtrip(wm.display);
|
||||
|
||||
wm.dataDevice = wl_data_device_manager_get_data_device(
|
||||
wm.dataDeviceManager, wm.seat);
|
||||
|
||||
wm.surface = wl_compositor_create_surface(wm.compositor);
|
||||
wm.eglWindow = wl_egl_window_create(wm.surface, params.w, params.h);
|
||||
wm.xdgSurface = xdg_wm_base_get_xdg_surface(wm.xdgWmBase, wm.surface);
|
||||
xdg_surface_add_listener(wm.xdgSurface, &xdgSurfaceListener, NULL);
|
||||
|
||||
wm.xdgToplevel = xdg_surface_get_toplevel(wm.xdgSurface);
|
||||
xdg_toplevel_add_listener(wm.xdgToplevel, &xdgToplevelListener, NULL);
|
||||
xdg_toplevel_set_title(wm.xdgToplevel, params.title);
|
||||
xdg_toplevel_set_app_id(wm.xdgToplevel, "looking-glass-client");
|
||||
|
||||
if (params.fullscreen)
|
||||
xdg_toplevel_set_fullscreen(wm.xdgToplevel, NULL);
|
||||
|
||||
wl_surface_commit(wm.surface);
|
||||
|
||||
wm.width = params.w;
|
||||
wm.height = params.h;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -391,6 +463,109 @@ static void waylandStartup(void)
|
|||
{
|
||||
}
|
||||
|
||||
static void waylandShutdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EGL
|
||||
static EGLDisplay waylandGetEGLDisplay(void)
|
||||
{
|
||||
EGLNativeDisplayType native = (EGLNativeDisplayType) wm.display;
|
||||
|
||||
const char *early_exts = eglQueryString(NULL, EGL_EXTENSIONS);
|
||||
|
||||
if (strstr(early_exts, "EGL_KHR_platform_base") != NULL &&
|
||||
g_egl_dynProcs.eglGetPlatformDisplay)
|
||||
{
|
||||
DEBUG_INFO("Using eglGetPlatformDisplay");
|
||||
return g_egl_dynProcs.eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, native, NULL);
|
||||
}
|
||||
|
||||
if (strstr(early_exts, "EGL_EXT_platform_base") != NULL &&
|
||||
g_egl_dynProcs.eglGetPlatformDisplayEXT)
|
||||
{
|
||||
DEBUG_INFO("Using eglGetPlatformDisplayEXT");
|
||||
return g_egl_dynProcs.eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, native, NULL);
|
||||
}
|
||||
|
||||
DEBUG_INFO("Using eglGetDisplay");
|
||||
return eglGetDisplay(native);
|
||||
}
|
||||
|
||||
static EGLNativeWindowType waylandGetEGLNativeWindow(void)
|
||||
{
|
||||
return (EGLNativeWindowType) wm.eglWindow;
|
||||
}
|
||||
|
||||
static void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface)
|
||||
{
|
||||
eglSwapBuffers(display, surface);
|
||||
|
||||
if (wm.resizeSerial)
|
||||
{
|
||||
wl_egl_window_resize(wm.eglWindow, wm.width, wm.height, 0, 0);
|
||||
|
||||
struct wl_region * region = wl_compositor_create_region(wm.compositor);
|
||||
wl_region_add(region, 0, 0, wm.width, wm.height);
|
||||
wl_surface_set_opaque_region(wm.surface, region);
|
||||
wl_region_destroy(region);
|
||||
|
||||
app_handleResizeEvent(wm.width, wm.height, (struct Border) {0, 0, 0, 0});
|
||||
xdg_surface_ack_configure(wm.xdgSurface, wm.resizeSerial);
|
||||
wm.resizeSerial = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void waylandGLSwapBuffers(void)
|
||||
{
|
||||
// FIXME: implement.
|
||||
}
|
||||
|
||||
static void waylandShowPointer(bool show)
|
||||
{
|
||||
// FIXME: implement.
|
||||
}
|
||||
|
||||
static void waylandWait(unsigned int time)
|
||||
{
|
||||
while (wl_display_prepare_read(wm.display))
|
||||
wl_display_dispatch_pending(wm.display);
|
||||
wl_display_flush(wm.display);
|
||||
|
||||
struct pollfd pollfd = {
|
||||
.fd = wl_display_get_fd(wm.display),
|
||||
.events = POLLIN,
|
||||
};
|
||||
|
||||
if (poll(&pollfd, 1, time) == -1 || pollfd.revents & POLLERR)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
DEBUG_INFO("Poll failed: %d\n", errno);
|
||||
wl_display_cancel_read(wm.display);
|
||||
}
|
||||
else
|
||||
wl_display_read_events(wm.display);
|
||||
|
||||
wl_display_dispatch_pending(wm.display);
|
||||
}
|
||||
|
||||
static void waylandSetWindowSize(int x, int y)
|
||||
{
|
||||
// FIXME: implement.
|
||||
}
|
||||
|
||||
static void waylandSetFullscreen(bool fs)
|
||||
{
|
||||
// FIXME: implement.
|
||||
}
|
||||
|
||||
static bool waylandGetFullscreen(void)
|
||||
{
|
||||
// FIXME: implement.
|
||||
return false;
|
||||
}
|
||||
|
||||
static void relativePointerMotionHandler(void * data,
|
||||
struct zwp_relative_pointer_v1 *pointer, uint32_t timeHi, uint32_t timeLo,
|
||||
wl_fixed_t dxW, wl_fixed_t dyW, wl_fixed_t dxUnaccelW,
|
||||
|
@ -479,6 +654,11 @@ static void waylandRealignPointer(void)
|
|||
app_handleMouseBasic();
|
||||
}
|
||||
|
||||
static bool waylandIsValidPointerPos(int x, int y)
|
||||
{
|
||||
return x >= 0 && x < wm.width && y >= 0 && y < wm.height;
|
||||
}
|
||||
|
||||
static void waylandFree(void)
|
||||
{
|
||||
waylandUngrabPointer();
|
||||
|
@ -508,23 +688,6 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool waylandEventFilter(SDL_Event * event)
|
||||
{
|
||||
/* prevent the default processing for the following events */
|
||||
switch(event->type)
|
||||
{
|
||||
case SDL_MOUSEMOTION:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char * textMimetypes[] =
|
||||
{
|
||||
"text/plain",
|
||||
|
@ -862,21 +1025,36 @@ static void waylandCBRelease(void)
|
|||
|
||||
struct LG_DisplayServerOps LGDS_Wayland =
|
||||
{
|
||||
.probe = waylandProbe,
|
||||
.earlyInit = waylandEarlyInit,
|
||||
.init = waylandInit,
|
||||
.startup = waylandStartup,
|
||||
.free = waylandFree,
|
||||
.getProp = waylandGetProp,
|
||||
.eventFilter = waylandEventFilter,
|
||||
.grabPointer = waylandGrabPointer,
|
||||
.ungrabPointer = waylandUngrabPointer,
|
||||
.grabKeyboard = waylandGrabKeyboard,
|
||||
.ungrabKeyboard = waylandUngrabKeyboard,
|
||||
.warpPointer = waylandWarpPointer,
|
||||
.realignPointer = waylandRealignPointer,
|
||||
.inhibitIdle = waylandInhibitIdle,
|
||||
.uninhibitIdle = waylandUninhibitIdle,
|
||||
.probe = waylandProbe,
|
||||
.earlyInit = waylandEarlyInit,
|
||||
.init = waylandInit,
|
||||
.startup = waylandStartup,
|
||||
.shutdown = waylandShutdown,
|
||||
.free = waylandFree,
|
||||
.getProp = waylandGetProp,
|
||||
|
||||
#ifdef ENABLE_EGL
|
||||
.getEGLDisplay = waylandGetEGLDisplay,
|
||||
.getEGLNativeWindow = waylandGetEGLNativeWindow,
|
||||
.eglSwapBuffers = waylandEGLSwapBuffers,
|
||||
#endif
|
||||
|
||||
.glSwapBuffers = waylandGLSwapBuffers,
|
||||
|
||||
.showPointer = waylandShowPointer,
|
||||
.grabPointer = waylandGrabPointer,
|
||||
.ungrabPointer = waylandUngrabPointer,
|
||||
.grabKeyboard = waylandGrabKeyboard,
|
||||
.ungrabKeyboard = waylandUngrabKeyboard,
|
||||
.warpPointer = waylandWarpPointer,
|
||||
.realignPointer = waylandRealignPointer,
|
||||
.isValidPointerPos = waylandIsValidPointerPos,
|
||||
.inhibitIdle = waylandInhibitIdle,
|
||||
.uninhibitIdle = waylandUninhibitIdle,
|
||||
.wait = waylandWait,
|
||||
.setWindowSize = waylandSetWindowSize,
|
||||
.setFullscreen = waylandSetFullscreen,
|
||||
.getFullscreen = waylandGetFullscreen,
|
||||
|
||||
.cbInit = waylandCBInit,
|
||||
.cbNotice = waylandCBNotice,
|
||||
|
|
|
@ -814,6 +814,11 @@ static EGLNativeWindowType x11GetEGLNativeWindow(void)
|
|||
{
|
||||
return (EGLNativeWindowType)x11.window;
|
||||
}
|
||||
|
||||
static void x11EGLSwapBuffers(EGLDisplay display, EGLSurface surface)
|
||||
{
|
||||
eglSwapBuffers(display, surface);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void x11GLSwapBuffers(void)
|
||||
|
@ -1370,6 +1375,7 @@ struct LG_DisplayServerOps LGDS_X11 =
|
|||
#ifdef ENABLE_EGL
|
||||
.getEGLDisplay = x11GetEGLDisplay,
|
||||
.getEGLNativeWindow = x11GetEGLNativeWindow,
|
||||
.eglSwapBuffers = x11EGLSwapBuffers,
|
||||
#endif
|
||||
.glSwapBuffers = x11GLSwapBuffers,
|
||||
.showPointer = x11ShowPointer,
|
||||
|
|
|
@ -60,6 +60,7 @@ bool app_getProp(LG_DSProperty prop, void * ret);
|
|||
|
||||
EGLDisplay app_getEGLDisplay(void);
|
||||
EGLNativeWindowType app_getEGLNativeWindow(void);
|
||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface);
|
||||
void app_glSwapBuffers(void);
|
||||
|
||||
void app_clipboardRelease(void);
|
||||
|
|
|
@ -100,6 +100,7 @@ struct LG_DisplayServerOps
|
|||
/* EGL support */
|
||||
EGLDisplay (*getEGLDisplay)(void);
|
||||
EGLNativeWindowType (*getEGLNativeWindow)(void);
|
||||
void (*eglSwapBuffers)(EGLDisplay display, EGLSurface surface);
|
||||
#endif
|
||||
|
||||
/* opengl platform specific methods */
|
||||
|
@ -152,6 +153,7 @@ struct LG_DisplayServerOps
|
|||
(x)->getProp && \
|
||||
(x)->getEGLDisplay && \
|
||||
(x)->getEGLNativeWindow && \
|
||||
(x)->eglSwapBuffers && \
|
||||
(x)->glSwapBuffers && \
|
||||
(x)->showPointer && \
|
||||
(x)->grabPointer && \
|
||||
|
|
|
@ -164,13 +164,6 @@ void egl_setup(void)
|
|||
|
||||
bool egl_create(void ** opaque, const LG_RendererParams params)
|
||||
{
|
||||
// Fail if running on Wayland so that OpenGL is used instead. Wayland-EGL
|
||||
// is broken (https://github.com/gnif/LookingGlass/issues/306) and isn't
|
||||
// fixable until SDL is dropped entirely. Until then, the OpenGL renderer
|
||||
// "mostly works".
|
||||
if (getenv("WAYLAND_DISPLAY"))
|
||||
return false;
|
||||
|
||||
// check if EGL is even available
|
||||
if (!eglQueryString(EGL_NO_DISPLAY, EGL_VERSION))
|
||||
return false;
|
||||
|
@ -707,7 +700,7 @@ bool egl_render(void * opaque, LG_RendererRotate rotate)
|
|||
}
|
||||
|
||||
egl_fps_render(this->fps, this->screenScaleX, this->screenScaleY);
|
||||
eglSwapBuffers(this->display, this->surface);
|
||||
app_eglSwapBuffers(this->display, this->surface);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -576,6 +576,11 @@ EGLNativeWindowType app_getEGLNativeWindow(void)
|
|||
return g_state.ds->getEGLNativeWindow();
|
||||
}
|
||||
|
||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface)
|
||||
{
|
||||
g_state.ds->eglSwapBuffers(display, surface);
|
||||
}
|
||||
|
||||
void app_glSwapBuffers(void)
|
||||
{
|
||||
g_state.ds->glSwapBuffers();
|
||||
|
|
Loading…
Reference in a new issue