[client] wm/wayland: implement grab mode for capture

This commit is contained in:
Tudor Brindus 2021-01-11 18:52:42 -05:00 committed by Geoffrey McRae
parent 1040a7c168
commit c21f502414
4 changed files with 229 additions and 3 deletions

View File

@ -88,7 +88,7 @@ struct AppParams params = { 0 };
static void setGrab(bool enable);
static void setGrabQuiet(bool enable);
static void handleMouseGrabbed(double ex, double ey);
void handleMouseGrabbed(double ex, double ey);
static void handleMouseNormal(double ex, double ey);
static void lgInit()
@ -883,7 +883,7 @@ static void cursorToInt(double ex, double ey, int *x, int *y)
*y = (int)ey;
}
static void handleMouseGrabbed(double ex, double ey)
void handleMouseGrabbed(double ex, double ey)
{
int x, y;
@ -1469,7 +1469,12 @@ int eventFilter(void * userdata, SDL_Event * event)
g_cursor.pos.y = event->motion.y;
if (g_cursor.grab)
handleMouseGrabbed(event->motion.xrel, event->motion.yrel);
{
// On Wayland, wm.c calls handleMouseGrabbed, bypassing the SDL event
// loop.
if (g_state.wminfo.subsystem != SDL_SYSWM_WAYLAND)
handleMouseGrabbed(event->motion.xrel, event->motion.yrel);
}
else
handleMouseNormal(event->motion.xrel, event->motion.yrel);
break;
@ -2046,6 +2051,8 @@ static int lg_run()
// the end of the output
lgWaitEvent(e_startup, TIMEOUT_INFINITE);
wmInit();
LGMP_STATUS status;
while(g_state.state == APP_STATE_RUNNING)
@ -2237,7 +2244,10 @@ static void lg_shutdown()
}
if (g_state.window)
{
wmFree();
SDL_DestroyWindow(g_state.window);
}
if (cursor)
SDL_FreeCursor(cursor);

View File

@ -235,3 +235,5 @@ struct CursorState
// forwards
extern struct AppState g_state;
extern struct AppParams params;
void handleMouseGrabbed(double, double);

View File

@ -23,16 +23,54 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdbool.h>
#include <SDL2/SDL.h>
#include <wayland-client.h>
#include "common/debug.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
struct WMState
{
bool pointerGrabbed;
bool keyboardGrabbed;
void * opaque;
};
static struct WMState g_wmState;
static void wmWaylandInit();
static void wmWaylandFree();
static void wmWaylandGrabPointer();
static void wmWaylandUngrabPointer();
void wmInit()
{
switch (g_state.wminfo.subsystem)
{
case SDL_SYSWM_WAYLAND:
wmWaylandInit();
break;
default:
break;
}
}
void wmFree()
{
switch (g_state.wminfo.subsystem)
{
case SDL_SYSWM_WAYLAND:
wmWaylandFree();
break;
default:
break;
}
}
void wmGrabPointer()
{
switch(g_state.wminfo.subsystem)
@ -50,6 +88,10 @@ void wmGrabPointer()
CurrentTime);
break;
case SDL_SYSWM_WAYLAND:
wmWaylandGrabPointer();
break;
default:
SDL_SetWindowGrab(g_state.window, SDL_TRUE);
break;
@ -66,6 +108,10 @@ void wmUngrabPointer()
XUngrabPointer(g_state.wminfo.info.x11.display, CurrentTime);
break;
case SDL_SYSWM_WAYLAND:
wmWaylandUngrabPointer();
break;
default:
SDL_SetWindowGrab(g_state.window, SDL_FALSE);
break;
@ -161,3 +207,169 @@ void wmWarpMouse(int x, int y)
break;
}
}
// Wayland support.
struct WMDataWayland
{
struct wl_display * display;
struct wl_surface * surface;
struct wl_registry * registry;
struct wl_seat * seat;
uint32_t capabilities;
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;
};
// Registry-handling listeners.
static void registryGlobalHandler(void * data, struct wl_registry * registry,
uint32_t name, const char * interface, uint32_t version)
{
struct WMDataWayland * wm = data;
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, zwp_relative_pointer_manager_v1_interface.name))
wm->relativePointerManager = wl_registry_bind(wm->registry, name,
&zwp_relative_pointer_manager_v1_interface, 1);
else if (!strcmp(interface, zwp_pointer_constraints_v1_interface.name))
wm->pointerConstraints = wl_registry_bind(wm->registry, name,
&zwp_pointer_constraints_v1_interface, 1);
}
static void registryGlobalRemoveHandler(void * data,
struct wl_registry * registry, uint32_t name)
{
// Do nothing.
}
static const struct wl_registry_listener registryListener = {
.global = registryGlobalHandler,
.global_remove = registryGlobalRemoveHandler,
};
// Seat-handling listeners.
static void handlePointerCapability(struct WMDataWayland * wm,
uint32_t capabilities)
{
bool hasPointer = capabilities & WL_SEAT_CAPABILITY_POINTER;
if (!hasPointer && wm->pointer)
{
wl_pointer_destroy(wm->pointer);
wm->pointer = NULL;
}
else if (hasPointer && !wm->pointer)
wm->pointer = wl_seat_get_pointer(wm->seat);
}
static void seatCapabilitiesHandler(void * data, struct wl_seat * seat,
uint32_t capabilities)
{
struct WMDataWayland * wm = data;
wm->capabilities = capabilities;
handlePointerCapability(wm, capabilities);
}
static void seatNameHandler(void * data, struct wl_seat * seat,
const char * name)
{
// Do nothing.
}
static const struct wl_seat_listener seatListener = {
.capabilities = seatCapabilitiesHandler,
.name = seatNameHandler,
};
void wmWaylandInit()
{
struct WMDataWayland * wm = malloc(sizeof(struct WMDataWayland));
memset(wm, 0, sizeof(struct WMDataWayland));
wm->display = g_state.wminfo.info.wl.display;
wm->surface = g_state.wminfo.info.wl.surface;
wm->registry = wl_display_get_registry(wm->display);
wl_registry_add_listener(wm->registry, &registryListener, wm);
wl_display_roundtrip(wm->display);
wl_seat_add_listener(wm->seat, &seatListener, wm);
wl_display_roundtrip(wm->display);
g_wmState.opaque = wm;
}
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,
wl_fixed_t dyUnaccelW)
{
double dxUnaccel = wl_fixed_to_double(dxUnaccelW);
double dyUnaccel = wl_fixed_to_double(dyUnaccelW);
handleMouseGrabbed(dxUnaccel, dyUnaccel);
}
static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
.relative_motion = relativePointerMotionHandler,
};
static void wmWaylandGrabPointer()
{
struct WMDataWayland * wm = g_wmState.opaque;
if (!wm->relativePointer)
{
wm->relativePointer =
zwp_relative_pointer_manager_v1_get_relative_pointer(
wm->relativePointerManager, wm->pointer);
zwp_relative_pointer_v1_add_listener(wm->relativePointer,
&relativePointerListener, wm);
}
if (!wm->confinedPointer)
{
wm->confinedPointer = zwp_pointer_constraints_v1_confine_pointer(
wm->pointerConstraints, wm->surface, wm->pointer, NULL,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
static void wmWaylandUngrabPointer()
{
struct WMDataWayland * wm = g_wmState.opaque;
if (wm->relativePointer)
{
zwp_relative_pointer_v1_destroy(wm->relativePointer);
wm->relativePointer = NULL;
}
if (wm->confinedPointer)
{
zwp_confined_pointer_v1_destroy(wm->confinedPointer);
wm->confinedPointer = NULL;
}
}
static void wmWaylandFree()
{
struct WMDataWayland * wm = g_wmState.opaque;
wmWaylandUngrabPointer();
// TODO: these also need to be freed, but are currently owned by SDL.
// wl_display_destroy(wm->display);
// wl_surface_destroy(wm->surface);
wl_pointer_destroy(wm->pointer);
wl_seat_destroy(wm->seat);
wl_registry_destroy(wm->registry);
free(g_wmState.opaque);
}

View File

@ -17,6 +17,8 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
void wmInit();
void wmFree();
void wmGrabPointer();
void wmUngrabPointer();
void wmGrabKeyboard();