@ -28,7 +28,6 @@
# include "internal.h"
# include <assert.h>
# include <errno.h>
# include <limits.h>
# include <linux/input.h>
@ -56,765 +55,6 @@
# include "wayland-pointer-constraints-unstable-v1-client-protocol-code.h"
# include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h"
static _GLFWwindow * findWindowFromDecorationSurface ( struct wl_surface * surface ,
int * which )
{
int focus ;
_GLFWwindow * window = _glfw . windowListHead ;
if ( ! which )
which = & focus ;
while ( window )
{
if ( surface = = window - > wl . decorations . top . surface )
{
* which = topDecoration ;
break ;
}
if ( surface = = window - > wl . decorations . left . surface )
{
* which = leftDecoration ;
break ;
}
if ( surface = = window - > wl . decorations . right . surface )
{
* which = rightDecoration ;
break ;
}
if ( surface = = window - > wl . decorations . bottom . surface )
{
* which = bottomDecoration ;
break ;
}
window = window - > next ;
}
return window ;
}
static void pointerHandleEnter ( void * userData ,
struct wl_pointer * pointer ,
uint32_t serial ,
struct wl_surface * surface ,
wl_fixed_t sx ,
wl_fixed_t sy )
{
// Happens in the case we just destroyed the surface.
if ( ! surface )
return ;
int focus = 0 ;
_GLFWwindow * window = wl_surface_get_user_data ( surface ) ;
if ( ! window )
{
window = findWindowFromDecorationSurface ( surface , & focus ) ;
if ( ! window )
return ;
}
window - > wl . decorations . focus = focus ;
_glfw . wl . serial = serial ;
_glfw . wl . pointerEnterSerial = serial ;
_glfw . wl . pointerFocus = window ;
window - > wl . hovered = GLFW_TRUE ;
_glfwSetCursorWayland ( window , window - > wl . currentCursor ) ;
_glfwInputCursorEnter ( window , GLFW_TRUE ) ;
}
static void pointerHandleLeave ( void * userData ,
struct wl_pointer * pointer ,
uint32_t serial ,
struct wl_surface * surface )
{
_GLFWwindow * window = _glfw . wl . pointerFocus ;
if ( ! window )
return ;
window - > wl . hovered = GLFW_FALSE ;
_glfw . wl . serial = serial ;
_glfw . wl . pointerFocus = NULL ;
_glfwInputCursorEnter ( window , GLFW_FALSE ) ;
_glfw . wl . cursorPreviousName = NULL ;
}
static void setCursor ( _GLFWwindow * window , const char * name )
{
struct wl_buffer * buffer ;
struct wl_cursor * cursor ;
struct wl_cursor_image * image ;
struct wl_surface * surface = _glfw . wl . cursorSurface ;
struct wl_cursor_theme * theme = _glfw . wl . cursorTheme ;
int scale = 1 ;
if ( window - > wl . scale > 1 & & _glfw . wl . cursorThemeHiDPI )
{
// We only support up to scale=2 for now, since libwayland-cursor
// requires us to load a different theme for each size.
scale = 2 ;
theme = _glfw . wl . cursorThemeHiDPI ;
}
cursor = wl_cursor_theme_get_cursor ( theme , name ) ;
if ( ! cursor )
{
_glfwInputError ( GLFW_CURSOR_UNAVAILABLE ,
" Wayland: Standard cursor shape unavailable " ) ;
return ;
}
// TODO: handle animated cursors too.
image = cursor - > images [ 0 ] ;
if ( ! image )
return ;
buffer = wl_cursor_image_get_buffer ( image ) ;
if ( ! buffer )
return ;
wl_pointer_set_cursor ( _glfw . wl . pointer , _glfw . wl . pointerEnterSerial ,
surface ,
image - > hotspot_x / scale ,
image - > hotspot_y / scale ) ;
wl_surface_set_buffer_scale ( surface , scale ) ;
wl_surface_attach ( surface , buffer , 0 , 0 ) ;
wl_surface_damage ( surface , 0 , 0 ,
image - > width , image - > height ) ;
wl_surface_commit ( surface ) ;
_glfw . wl . cursorPreviousName = name ;
}
static void pointerHandleMotion ( void * userData ,
struct wl_pointer * pointer ,
uint32_t time ,
wl_fixed_t sx ,
wl_fixed_t sy )
{
_GLFWwindow * window = _glfw . wl . pointerFocus ;
const char * cursorName = NULL ;
double x , y ;
if ( ! window )
return ;
if ( window - > cursorMode = = GLFW_CURSOR_DISABLED )
return ;
x = wl_fixed_to_double ( sx ) ;
y = wl_fixed_to_double ( sy ) ;
window - > wl . cursorPosX = x ;
window - > wl . cursorPosY = y ;
switch ( window - > wl . decorations . focus )
{
case mainWindow :
_glfwInputCursorPos ( window , x , y ) ;
_glfw . wl . cursorPreviousName = NULL ;
return ;
case topDecoration :
if ( y < _GLFW_DECORATION_WIDTH )
cursorName = " n-resize " ;
else
cursorName = " left_ptr " ;
break ;
case leftDecoration :
if ( y < _GLFW_DECORATION_WIDTH )
cursorName = " nw-resize " ;
else
cursorName = " w-resize " ;
break ;
case rightDecoration :
if ( y < _GLFW_DECORATION_WIDTH )
cursorName = " ne-resize " ;
else
cursorName = " e-resize " ;
break ;
case bottomDecoration :
if ( x < _GLFW_DECORATION_WIDTH )
cursorName = " sw-resize " ;
else if ( x > window - > wl . width + _GLFW_DECORATION_WIDTH )
cursorName = " se-resize " ;
else
cursorName = " s-resize " ;
break ;
default :
assert ( 0 ) ;
}
if ( _glfw . wl . cursorPreviousName ! = cursorName )
setCursor ( window , cursorName ) ;
}
static void pointerHandleButton ( void * userData ,
struct wl_pointer * pointer ,
uint32_t serial ,
uint32_t time ,
uint32_t button ,
uint32_t state )
{
_GLFWwindow * window = _glfw . wl . pointerFocus ;
int glfwButton ;
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE ;
if ( ! window )
return ;
if ( button = = BTN_LEFT )
{
switch ( window - > wl . decorations . focus )
{
case mainWindow :
break ;
case topDecoration :
if ( window - > wl . cursorPosY < _GLFW_DECORATION_WIDTH )
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP ;
else
xdg_toplevel_move ( window - > wl . xdg . toplevel , _glfw . wl . seat , serial ) ;
break ;
case leftDecoration :
if ( window - > wl . cursorPosY < _GLFW_DECORATION_WIDTH )
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT ;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT ;
break ;
case rightDecoration :
if ( window - > wl . cursorPosY < _GLFW_DECORATION_WIDTH )
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT ;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT ;
break ;
case bottomDecoration :
if ( window - > wl . cursorPosX < _GLFW_DECORATION_WIDTH )
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT ;
else if ( window - > wl . cursorPosX > window - > wl . width + _GLFW_DECORATION_WIDTH )
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT ;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM ;
break ;
default :
assert ( 0 ) ;
}
if ( edges ! = XDG_TOPLEVEL_RESIZE_EDGE_NONE )
{
xdg_toplevel_resize ( window - > wl . xdg . toplevel , _glfw . wl . seat ,
serial , edges ) ;
return ;
}
}
else if ( button = = BTN_RIGHT )
{
if ( window - > wl . decorations . focus ! = mainWindow & & window - > wl . xdg . toplevel )
{
xdg_toplevel_show_window_menu ( window - > wl . xdg . toplevel ,
_glfw . wl . seat , serial ,
window - > wl . cursorPosX ,
window - > wl . cursorPosY ) ;
return ;
}
}
// Don’t pass the button to the user if it was related to a decoration.
if ( window - > wl . decorations . focus ! = mainWindow )
return ;
_glfw . wl . serial = serial ;
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
* codes . */
glfwButton = button - BTN_LEFT ;
_glfwInputMouseClick ( window ,
glfwButton ,
state = = WL_POINTER_BUTTON_STATE_PRESSED
? GLFW_PRESS
: GLFW_RELEASE ,
_glfw . wl . xkb . modifiers ) ;
}
static void pointerHandleAxis ( void * userData ,
struct wl_pointer * pointer ,
uint32_t time ,
uint32_t axis ,
wl_fixed_t value )
{
_GLFWwindow * window = _glfw . wl . pointerFocus ;
double x = 0.0 , y = 0.0 ;
// Wayland scroll events are in pointer motion coordinate space (think two
// finger scroll). The factor 10 is commonly used to convert to "scroll
// step means 1.0.
const double scrollFactor = 1.0 / 10.0 ;
if ( ! window )
return ;
assert ( axis = = WL_POINTER_AXIS_HORIZONTAL_SCROLL | |
axis = = WL_POINTER_AXIS_VERTICAL_SCROLL ) ;
if ( axis = = WL_POINTER_AXIS_HORIZONTAL_SCROLL )
x = - wl_fixed_to_double ( value ) * scrollFactor ;
else if ( axis = = WL_POINTER_AXIS_VERTICAL_SCROLL )
y = - wl_fixed_to_double ( value ) * scrollFactor ;
_glfwInputScroll ( window , x , y ) ;
}
static const struct wl_pointer_listener pointerListener = {
pointerHandleEnter ,
pointerHandleLeave ,
pointerHandleMotion ,
pointerHandleButton ,
pointerHandleAxis ,
} ;
static void keyboardHandleKeymap ( void * userData ,
struct wl_keyboard * keyboard ,
uint32_t format ,
int fd ,
uint32_t size )
{
struct xkb_keymap * keymap ;
struct xkb_state * state ;
struct xkb_compose_table * composeTable ;
struct xkb_compose_state * composeState ;
char * mapStr ;
const char * locale ;
if ( format ! = WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 )
{
close ( fd ) ;
return ;
}
mapStr = mmap ( NULL , size , PROT_READ , MAP_SHARED , fd , 0 ) ;
if ( mapStr = = MAP_FAILED ) {
close ( fd ) ;
return ;
}
keymap = xkb_keymap_new_from_string ( _glfw . wl . xkb . context ,
mapStr ,
XKB_KEYMAP_FORMAT_TEXT_V1 ,
0 ) ;
munmap ( mapStr , size ) ;
close ( fd ) ;
if ( ! keymap )
{
_glfwInputError ( GLFW_PLATFORM_ERROR ,
" Wayland: Failed to compile keymap " ) ;
return ;
}
state = xkb_state_new ( keymap ) ;
if ( ! state )
{
_glfwInputError ( GLFW_PLATFORM_ERROR ,
" Wayland: Failed to create XKB state " ) ;
xkb_keymap_unref ( keymap ) ;
return ;
}
// Look up the preferred locale, falling back to "C" as default.
locale = getenv ( " LC_ALL " ) ;
if ( ! locale )
locale = getenv ( " LC_CTYPE " ) ;
if ( ! locale )
locale = getenv ( " LANG " ) ;
if ( ! locale )
locale = " C " ;
composeTable =
xkb_compose_table_new_from_locale ( _glfw . wl . xkb . context , locale ,
XKB_COMPOSE_COMPILE_NO_FLAGS ) ;
if ( composeTable )
{
composeState =
xkb_compose_state_new ( composeTable , XKB_COMPOSE_STATE_NO_FLAGS ) ;
xkb_compose_table_unref ( composeTable ) ;
if ( composeState )
_glfw . wl . xkb . composeState = composeState ;
else
_glfwInputError ( GLFW_PLATFORM_ERROR ,
" Wayland: Failed to create XKB compose state " ) ;
}
else
{
_glfwInputError ( GLFW_PLATFORM_ERROR ,
" Wayland: Failed to create XKB compose table " ) ;
}
xkb_keymap_unref ( _glfw . wl . xkb . keymap ) ;
xkb_state_unref ( _glfw . wl . xkb . state ) ;
_glfw . wl . xkb . keymap = keymap ;
_glfw . wl . xkb . state = state ;
_glfw . wl . xkb . controlMask =
1 < < xkb_keymap_mod_get_index ( _glfw . wl . xkb . keymap , " Control " ) ;
_glfw . wl . xkb . altMask =
1 < < xkb_keymap_mod_get_index ( _glfw . wl . xkb . keymap , " Mod1 " ) ;
_glfw . wl . xkb . shiftMask =
1 < < xkb_keymap_mod_get_index ( _glfw . wl . xkb . keymap , " Shift " ) ;
_glfw . wl . xkb . superMask =
1 < < xkb_keymap_mod_get_index ( _glfw . wl . xkb . keymap , " Mod4 " ) ;
_glfw . wl . xkb . capsLockMask =
1 < < xkb_keymap_mod_get_index ( _glfw . wl . xkb . keymap , " Lock " ) ;
_glfw . wl . xkb . numLockMask =
1 < < xkb_keymap_mod_get_index ( _glfw . wl . xkb . keymap , " Mod2 " ) ;
}
static void keyboardHandleEnter ( void * userData ,
struct wl_keyboard * keyboard ,
uint32_t serial ,
struct wl_surface * surface ,
struct wl_array * keys )
{
// Happens in the case we just destroyed the surface.
if ( ! surface )
return ;
_GLFWwindow * window = wl_surface_get_user_data ( surface ) ;
if ( ! window )
{
window = findWindowFromDecorationSurface ( surface , NULL ) ;
if ( ! window )
return ;
}
_glfw . wl . serial = serial ;
_glfw . wl . keyboardFocus = window ;
_glfwInputWindowFocus ( window , GLFW_TRUE ) ;
}
static void keyboardHandleLeave ( void * userData ,
struct wl_keyboard * keyboard ,
uint32_t serial ,
struct wl_surface * surface )
{
_GLFWwindow * window = _glfw . wl . keyboardFocus ;
if ( ! window )
return ;
struct itimerspec timer = { } ;
timerfd_settime ( _glfw . wl . timerfd , 0 , & timer , NULL ) ;
_glfw . wl . serial = serial ;
_glfw . wl . keyboardFocus = NULL ;
_glfwInputWindowFocus ( window , GLFW_FALSE ) ;
}
static int translateKey ( uint32_t scancode )
{
if ( scancode < sizeof ( _glfw . wl . keycodes ) / sizeof ( _glfw . wl . keycodes [ 0 ] ) )
return _glfw . wl . keycodes [ scancode ] ;
return GLFW_KEY_UNKNOWN ;
}
static xkb_keysym_t composeSymbol ( xkb_keysym_t sym )
{
if ( sym = = XKB_KEY_NoSymbol | | ! _glfw . wl . xkb . composeState )
return sym ;
if ( xkb_compose_state_feed ( _glfw . wl . xkb . composeState , sym )
! = XKB_COMPOSE_FEED_ACCEPTED )
return sym ;
switch ( xkb_compose_state_get_status ( _glfw . wl . xkb . composeState ) )
{
case XKB_COMPOSE_COMPOSED :
return xkb_compose_state_get_one_sym ( _glfw . wl . xkb . composeState ) ;
case XKB_COMPOSE_COMPOSING :
case XKB_COMPOSE_CANCELLED :
return XKB_KEY_NoSymbol ;
case XKB_COMPOSE_NOTHING :
default :
return sym ;
}
}
GLFWbool _glfwInputTextWayland ( _GLFWwindow * window , uint32_t scancode )
{
const xkb_keysym_t * keysyms ;
const xkb_keycode_t keycode = scancode + 8 ;
if ( xkb_state_key_get_syms ( _glfw . wl . xkb . state , keycode , & keysyms ) = = 1 )
{
const xkb_keysym_t keysym = composeSymbol ( keysyms [ 0 ] ) ;
const uint32_t codepoint = _glfwKeySym2Unicode ( keysym ) ;
if ( codepoint ! = GLFW_INVALID_CODEPOINT )
{
const int mods = _glfw . wl . xkb . modifiers ;
const int plain = ! ( mods & ( GLFW_MOD_CONTROL | GLFW_MOD_ALT ) ) ;
_glfwInputChar ( window , codepoint , mods , plain ) ;
}
}
return xkb_keymap_key_repeats ( _glfw . wl . xkb . keymap , keycode ) ;
}
static void keyboardHandleKey ( void * userData ,
struct wl_keyboard * keyboard ,
uint32_t serial ,
uint32_t time ,
uint32_t scancode ,
uint32_t state )
{
_GLFWwindow * window = _glfw . wl . keyboardFocus ;
if ( ! window )
return ;
const int key = translateKey ( scancode ) ;
const int action =
state = = WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE ;
_glfw . wl . serial = serial ;
_glfwInputKey ( window , key , scancode , action , _glfw . wl . xkb . modifiers ) ;
struct itimerspec timer = { } ;
if ( action = = GLFW_PRESS )
{
const GLFWbool shouldRepeat = _glfwInputTextWayland ( window , scancode ) ;
if ( shouldRepeat & & _glfw . wl . keyboardRepeatRate > 0 )
{
_glfw . wl . keyboardLastKey = key ;
_glfw . wl . keyboardLastScancode = scancode ;
if ( _glfw . wl . keyboardRepeatRate > 1 )
timer . it_interval . tv_nsec = 1000000000 / _glfw . wl . keyboardRepeatRate ;
else
timer . it_interval . tv_sec = 1 ;
timer . it_value . tv_sec = _glfw . wl . keyboardRepeatDelay / 1000 ;
timer . it_value . tv_nsec = ( _glfw . wl . keyboardRepeatDelay % 1000 ) * 1000000 ;
}
}
timerfd_settime ( _glfw . wl . timerfd , 0 , & timer , NULL ) ;
}
static void keyboardHandleModifiers ( void * userData ,
struct wl_keyboard * keyboard ,
uint32_t serial ,
uint32_t modsDepressed ,
uint32_t modsLatched ,
uint32_t modsLocked ,
uint32_t group )
{
_glfw . wl . serial = serial ;
if ( ! _glfw . wl . xkb . keymap )
return ;
xkb_state_update_mask ( _glfw . wl . xkb . state ,
modsDepressed ,
modsLatched ,
modsLocked ,
0 ,
0 ,
group ) ;
const xkb_mod_mask_t mask =
xkb_state_serialize_mods ( _glfw . wl . xkb . state ,
XKB_STATE_MODS_DEPRESSED |
XKB_STATE_LAYOUT_DEPRESSED |
XKB_STATE_MODS_LATCHED |
XKB_STATE_LAYOUT_LATCHED ) ;
unsigned int mods = 0 ;
if ( mask & _glfw . wl . xkb . controlMask )
mods | = GLFW_MOD_CONTROL ;
if ( mask & _glfw . wl . xkb . altMask )
mods | = GLFW_MOD_ALT ;
if ( mask & _glfw . wl . xkb . shiftMask )
mods | = GLFW_MOD_SHIFT ;
if ( mask & _glfw . wl . xkb . superMask )
mods | = GLFW_MOD_SUPER ;
if ( mask & _glfw . wl . xkb . capsLockMask )
mods | = GLFW_MOD_CAPS_LOCK ;
if ( mask & _glfw . wl . xkb . numLockMask )
mods | = GLFW_MOD_NUM_LOCK ;
_glfw . wl . xkb . modifiers = mods ;
}
# ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
static void keyboardHandleRepeatInfo ( void * userData ,
struct wl_keyboard * keyboard ,
int32_t rate ,
int32_t delay )
{
if ( keyboard ! = _glfw . wl . keyboard )
return ;
_glfw . wl . keyboardRepeatRate = rate ;
_glfw . wl . keyboardRepeatDelay = delay ;
}
# endif
static const struct wl_keyboard_listener keyboardListener = {
keyboardHandleKeymap ,
keyboardHandleEnter ,
keyboardHandleLeave ,
keyboardHandleKey ,
keyboardHandleModifiers ,
# ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
keyboardHandleRepeatInfo ,
# endif
} ;
static void seatHandleCapabilities ( void * userData ,
struct wl_seat * seat ,
enum wl_seat_capability caps )
{
if ( ( caps & WL_SEAT_CAPABILITY_POINTER ) & & ! _glfw . wl . pointer )
{
_glfw . wl . pointer = wl_seat_get_pointer ( seat ) ;
wl_pointer_add_listener ( _glfw . wl . pointer , & pointerListener , NULL ) ;
}
else if ( ! ( caps & WL_SEAT_CAPABILITY_POINTER ) & & _glfw . wl . pointer )
{
wl_pointer_destroy ( _glfw . wl . pointer ) ;
_glfw . wl . pointer = NULL ;
}
if ( ( caps & WL_SEAT_CAPABILITY_KEYBOARD ) & & ! _glfw . wl . keyboard )
{
_glfw . wl . keyboard = wl_seat_get_keyboard ( seat ) ;
wl_keyboard_add_listener ( _glfw . wl . keyboard , & keyboardListener , NULL ) ;
}
else if ( ! ( caps & WL_SEAT_CAPABILITY_KEYBOARD ) & & _glfw . wl . keyboard )
{
wl_keyboard_destroy ( _glfw . wl . keyboard ) ;
_glfw . wl . keyboard = NULL ;
}
}
static void seatHandleName ( void * userData ,
struct wl_seat * seat ,
const char * name )
{
}
static const struct wl_seat_listener seatListener = {
seatHandleCapabilities ,
seatHandleName ,
} ;
static void dataOfferHandleOffer ( void * userData ,
struct wl_data_offer * offer ,
const char * mimeType )
{
for ( unsigned int i = 0 ; i < _glfw . wl . offerCount ; i + + )
{
if ( _glfw . wl . offers [ i ] . offer = = offer )
{
if ( strcmp ( mimeType , " text/plain;charset=utf-8 " ) = = 0 )
_glfw . wl . offers [ i ] . text_plain_utf8 = GLFW_TRUE ;
break ;
}
}
}
static const struct wl_data_offer_listener dataOfferListener = {
dataOfferHandleOffer ,
} ;
static void dataDeviceHandleDataOffer ( void * userData ,
struct wl_data_device * device ,
struct wl_data_offer * offer )
{
_GLFWofferWayland * offers =
_glfw_realloc ( _glfw . wl . offers , _glfw . wl . offerCount + 1 ) ;
if ( ! offers )
{
_glfwInputError ( GLFW_OUT_OF_MEMORY , NULL ) ;
return ;
}
_glfw . wl . offers = offers ;
_glfw . wl . offerCount + + ;
_glfw . wl . offers [ _glfw . wl . offerCount - 1 ] = ( _GLFWofferWayland ) { offer } ;
wl_data_offer_add_listener ( offer , & dataOfferListener , NULL ) ;
}
static void dataDeviceHandleEnter ( void * userData ,
struct wl_data_device * device ,
uint32_t serial ,
struct wl_surface * surface ,
wl_fixed_t x ,
wl_fixed_t y ,
struct wl_data_offer * offer )
{
for ( unsigned int i = 0 ; i < _glfw . wl . offerCount ; i + + )
{
if ( _glfw . wl . offers [ i ] . offer = = offer )
{
_glfw . wl . offers [ i ] = _glfw . wl . offers [ _glfw . wl . offerCount - 1 ] ;
_glfw . wl . offerCount - - ;
// We don't yet handle drag and drop
wl_data_offer_accept ( offer , serial , NULL ) ;
wl_data_offer_destroy ( offer ) ;
break ;
}
}
}
static void dataDeviceHandleLeave ( void * userData ,
struct wl_data_device * device )
{
}
static void dataDeviceHandleMotion ( void * userData ,
struct wl_data_device * device ,
uint32_t time ,
wl_fixed_t x ,
wl_fixed_t y )
{
}
static void dataDeviceHandleDrop ( void * userData ,
struct wl_data_device * device )
{
}
static void dataDeviceHandleSelection ( void * userData ,
struct wl_data_device * device ,
struct wl_data_offer * offer )
{
if ( _glfw . wl . selectionOffer )
{
wl_data_offer_destroy ( _glfw . wl . selectionOffer ) ;
_glfw . wl . selectionOffer = NULL ;
}
for ( unsigned int i = 0 ; i < _glfw . wl . offerCount ; i + + )
{
if ( _glfw . wl . offers [ i ] . offer = = offer )
{
if ( _glfw . wl . offers [ i ] . text_plain_utf8 )
_glfw . wl . selectionOffer = offer ;
else
wl_data_offer_destroy ( offer ) ;
_glfw . wl . offers [ i ] = _glfw . wl . offers [ _glfw . wl . offerCount - 1 ] ;
_glfw . wl . offerCount - - ;
break ;
}
}
}
static const struct wl_data_device_listener dataDeviceListener = {
dataDeviceHandleDataOffer ,
dataDeviceHandleEnter ,
dataDeviceHandleLeave ,
dataDeviceHandleMotion ,
dataDeviceHandleDrop ,
dataDeviceHandleSelection ,
} ;
static void wmBaseHandlePing ( void * userData ,
struct xdg_wm_base * wmBase ,
uint32_t serial )
@ -861,7 +101,7 @@ static void registryHandleGlobal(void* userData,
_glfw . wl . seat =
wl_registry_bind ( registry , name , & wl_seat_interface ,
_glfw . wl . seatVersion ) ;
wl_seat_add_listener ( _glfw . wl . seat , & seatListener , NULL ) ;
_glfwAddSeatListenerWayland ( _glfw . wl . seat ) ;
}
}
else if ( strcmp ( interface , " wl_data_device_manager " ) = = 0 )
@ -1412,7 +652,7 @@ int _glfwInitWayland(void)
_glfw . wl . dataDevice =
wl_data_device_manager_get_data_device ( _glfw . wl . dataDeviceManager ,
_glfw . wl . seat ) ;
wl_data_device_add_listener ( _glfw . wl . dataDevice , & dataDeviceListener , NULL ) ;
_glfwAddDataDeviceListenerWayland ( _glfw . wl . dataDevice ) ;
}
return GLFW_TRUE ;