2015-06-21 17:33:46 +02:00
/*
Simple DirectMedia Layer
2017-01-02 03:33:28 +01:00
Copyright ( C ) 1997 - 2017 Sam Lantinga < slouken @ libsdl . org >
2015-06-21 17:33:46 +02:00
This software is provided ' as - is ' , without any express or implied
warranty . In no event will the authors be held liable for any damages
arising from the use of this software .
Permission is granted to anyone to use this software for any purpose ,
including commercial applications , and to alter it and redistribute it
freely , subject to the following restrictions :
1. The origin of this software must not be misrepresented ; you must not
claim that you wrote the original software . If you use this software
in a product , an acknowledgment in the product documentation would be
appreciated but is not required .
2. Altered source versions must be plainly marked as such , and must not be
misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
*/
# include "../../SDL_internal.h"
# if SDL_VIDEO_DRIVER_X11
# include <sys/types.h>
# include <sys/time.h>
# include <signal.h>
# include <unistd.h>
# include <limits.h> /* For INT_MAX */
# include "SDL_x11video.h"
# include "SDL_x11touch.h"
# include "SDL_x11xinput2.h"
# include "../../events/SDL_events_c.h"
# include "../../events/SDL_mouse_c.h"
# include "../../events/SDL_touch_c.h"
2016-09-30 01:05:29 +02:00
# include "SDL_hints.h"
2015-06-21 17:33:46 +02:00
# include "SDL_timer.h"
# include "SDL_syswm.h"
# include <stdio.h>
/*#define DEBUG_XEVENTS*/
# ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT
# define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
# endif
# ifndef _NET_WM_MOVERESIZE_SIZE_TOP
# define _NET_WM_MOVERESIZE_SIZE_TOP 1
# endif
# ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT
# define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
# endif
# ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT
# define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
# endif
# ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
# define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
# endif
# ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM
# define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
# endif
# ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
# define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
# endif
# ifndef _NET_WM_MOVERESIZE_SIZE_LEFT
# define _NET_WM_MOVERESIZE_SIZE_LEFT 7
# endif
# ifndef _NET_WM_MOVERESIZE_MOVE
# define _NET_WM_MOVERESIZE_MOVE 8
# endif
typedef struct {
unsigned char * data ;
int format , count ;
Atom type ;
} SDL_x11Prop ;
/* Reads property
Must call X11_XFree on results
*/
static void X11_ReadProperty ( SDL_x11Prop * p , Display * disp , Window w , Atom prop )
{
unsigned char * ret = NULL ;
Atom type ;
int fmt ;
unsigned long count ;
unsigned long bytes_left ;
int bytes_fetch = 0 ;
do {
if ( ret ! = 0 ) X11_XFree ( ret ) ;
X11_XGetWindowProperty ( disp , w , prop , 0 , bytes_fetch , False , AnyPropertyType , & type , & fmt , & count , & bytes_left , & ret ) ;
bytes_fetch + = bytes_left ;
} while ( bytes_left ! = 0 ) ;
p - > data = ret ;
p - > format = fmt ;
p - > count = count ;
p - > type = type ;
}
/* Find text-uri-list in a list of targets and return it's atom
if available , else return None */
static Atom X11_PickTarget ( Display * disp , Atom list [ ] , int list_count )
{
Atom request = None ;
char * name ;
int i ;
for ( i = 0 ; i < list_count & & request = = None ; i + + ) {
name = X11_XGetAtomName ( disp , list [ i ] ) ;
2016-01-05 08:26:45 +01:00
if ( ( SDL_strcmp ( " text/uri-list " , name ) = = 0 ) | | ( SDL_strcmp ( " text/plain " , name ) = = 0 ) ) {
request = list [ i ] ;
}
2015-06-21 17:33:46 +02:00
X11_XFree ( name ) ;
}
return request ;
}
/* Wrapper for X11_PickTarget for a maximum of three targets, a special
case in the Xdnd protocol */
static Atom X11_PickTargetFromAtoms ( Display * disp , Atom a0 , Atom a1 , Atom a2 )
{
int count = 0 ;
Atom atom [ 3 ] ;
if ( a0 ! = None ) atom [ count + + ] = a0 ;
if ( a1 ! = None ) atom [ count + + ] = a1 ;
if ( a2 ! = None ) atom [ count + + ] = a2 ;
return X11_PickTarget ( disp , atom , count ) ;
}
struct KeyRepeatCheckData
{
XEvent * event ;
SDL_bool found ;
} ;
static Bool X11_KeyRepeatCheckIfEvent ( Display * display , XEvent * chkev ,
XPointer arg )
{
struct KeyRepeatCheckData * d = ( struct KeyRepeatCheckData * ) arg ;
if ( chkev - > type = = KeyPress & &
chkev - > xkey . keycode = = d - > event - > xkey . keycode & &
chkev - > xkey . time - d - > event - > xkey . time < 2 )
d - > found = SDL_TRUE ;
return False ;
}
/* Check to see if this is a repeated key.
( idea shamelessly lifted from GII - - thanks guys ! : )
*/
static SDL_bool X11_KeyRepeat ( Display * display , XEvent * event )
{
XEvent dummyev ;
struct KeyRepeatCheckData d ;
d . event = event ;
d . found = SDL_FALSE ;
if ( X11_XPending ( display ) )
X11_XCheckIfEvent ( display , & dummyev , X11_KeyRepeatCheckIfEvent ,
( XPointer ) & d ) ;
return d . found ;
}
2015-08-13 23:40:28 +02:00
static SDL_bool
X11_IsWheelEvent ( Display * display , XEvent * event , int * xticks , int * yticks )
2015-06-21 17:33:46 +02:00
{
2015-08-13 23:40:28 +02:00
/* according to the xlib docs, no specific mouse wheel events exist.
However , the defacto standard is that the vertical wheel is X buttons
4 ( up ) and 5 ( down ) and a horizontal wheel is 6 ( left ) and 7 ( right ) . */
/* Xlib defines "Button1" through 5, so we just use literals here. */
switch ( event - > xbutton . button ) {
case 4 : * yticks = 1 ; return SDL_TRUE ;
case 5 : * yticks = - 1 ; return SDL_TRUE ;
case 6 : * xticks = 1 ; return SDL_TRUE ;
case 7 : * xticks = - 1 ; return SDL_TRUE ;
default : break ;
2015-06-21 17:33:46 +02:00
}
return SDL_FALSE ;
}
/* Decodes URI escape sequences in string buf of len bytes
( excluding the terminating NULL byte ) in - place . Since
URI - encoded characters take three times the space of
normal characters , this should not be an issue .
Returns the number of decoded bytes that wound up in
the buffer , excluding the terminating NULL byte .
The buffer is guaranteed to be NULL - terminated but
may contain embedded NULL bytes .
On error , - 1 is returned .
*/
2016-11-14 07:57:41 +01:00
static int X11_URIDecode ( char * buf , int len ) {
2015-06-21 17:33:46 +02:00
int ri , wi , di ;
char decode = ' \0 ' ;
if ( buf = = NULL | | len < 0 ) {
errno = EINVAL ;
return - 1 ;
}
if ( len = = 0 ) {
len = SDL_strlen ( buf ) ;
}
for ( ri = 0 , wi = 0 , di = 0 ; ri < len & & wi < len ; ri + = 1 ) {
if ( di = = 0 ) {
/* start decoding */
if ( buf [ ri ] = = ' % ' ) {
decode = ' \0 ' ;
di + = 1 ;
continue ;
}
/* normal write */
buf [ wi ] = buf [ ri ] ;
wi + = 1 ;
continue ;
} else if ( di = = 1 | | di = = 2 ) {
char off = ' \0 ' ;
char isa = buf [ ri ] > = ' a ' & & buf [ ri ] < = ' f ' ;
char isA = buf [ ri ] > = ' A ' & & buf [ ri ] < = ' F ' ;
char isn = buf [ ri ] > = ' 0 ' & & buf [ ri ] < = ' 9 ' ;
if ( ! ( isa | | isA | | isn ) ) {
/* not a hexadecimal */
int sri ;
for ( sri = ri - di ; sri < = ri ; sri + = 1 ) {
buf [ wi ] = buf [ sri ] ;
wi + = 1 ;
}
di = 0 ;
continue ;
}
/* itsy bitsy magicsy */
if ( isn ) {
off = 0 - ' 0 ' ;
} else if ( isa ) {
off = 10 - ' a ' ;
} else if ( isA ) {
off = 10 - ' A ' ;
}
decode | = ( buf [ ri ] + off ) < < ( 2 - di ) * 4 ;
if ( di = = 2 ) {
buf [ wi ] = decode ;
wi + = 1 ;
di = 0 ;
} else {
di + = 1 ;
}
continue ;
}
}
buf [ wi ] = ' \0 ' ;
return wi ;
}
/* Convert URI to local filename
return filename if possible , else NULL
*/
static char * X11_URIToLocal ( char * uri ) {
char * file = NULL ;
SDL_bool local ;
if ( memcmp ( uri , " file:/ " , 6 ) = = 0 ) uri + = 6 ; /* local file? */
else if ( strstr ( uri , " :/ " ) ! = NULL ) return file ; /* wrong scheme */
local = uri [ 0 ] ! = ' / ' | | ( uri [ 0 ] ! = ' \0 ' & & uri [ 1 ] = = ' / ' ) ;
/* got a hostname? */
if ( ! local & & uri [ 0 ] = = ' / ' & & uri [ 2 ] ! = ' / ' ) {
char * hostname_end = strchr ( uri + 1 , ' / ' ) ;
if ( hostname_end ! = NULL ) {
char hostname [ 257 ] ;
if ( gethostname ( hostname , 255 ) = = 0 ) {
hostname [ 256 ] = ' \0 ' ;
if ( memcmp ( uri + 1 , hostname , hostname_end - ( uri + 1 ) ) = = 0 ) {
uri = hostname_end + 1 ;
local = SDL_TRUE ;
}
}
}
}
if ( local ) {
file = uri ;
/* Convert URI escape sequences to real characters */
X11_URIDecode ( file , 0 ) ;
if ( uri [ 1 ] = = ' / ' ) {
file + + ;
} else {
file - - ;
}
}
return file ;
}
# if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
static void X11_HandleGenericEvent ( SDL_VideoData * videodata , XEvent event )
{
/* event is a union, so cookie == &event, but this is type safe. */
XGenericEventCookie * cookie = & event . xcookie ;
if ( X11_XGetEventData ( videodata - > display , cookie ) ) {
X11_HandleXinput2Event ( videodata , cookie ) ;
X11_XFreeEventData ( videodata - > display , cookie ) ;
}
}
# endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */
static unsigned
X11_GetNumLockModifierMask ( _THIS )
{
SDL_VideoData * viddata = ( SDL_VideoData * ) _this - > driverdata ;
Display * display = viddata - > display ;
unsigned num_mask = 0 ;
int i , j ;
XModifierKeymap * xmods ;
unsigned n ;
xmods = X11_XGetModifierMapping ( display ) ;
n = xmods - > max_keypermod ;
for ( i = 3 ; i < 8 ; i + + ) {
for ( j = 0 ; j < n ; j + + ) {
KeyCode kc = xmods - > modifiermap [ i * n + j ] ;
if ( viddata - > key_layout [ kc ] = = SDL_SCANCODE_NUMLOCKCLEAR ) {
num_mask = 1 < < i ;
break ;
}
}
}
X11_XFreeModifiermap ( xmods ) ;
return num_mask ;
}
static void
X11_ReconcileKeyboardState ( _THIS )
{
SDL_VideoData * viddata = ( SDL_VideoData * ) _this - > driverdata ;
Display * display = viddata - > display ;
char keys [ 32 ] ;
int keycode ;
Window junk_window ;
int x , y ;
unsigned int mask ;
X11_XQueryKeymap ( display , keys ) ;
2015-12-28 19:07:44 +01:00
/* Sync up the keyboard modifier state */
2015-06-21 17:33:46 +02:00
if ( X11_XQueryPointer ( display , DefaultRootWindow ( display ) , & junk_window , & junk_window , & x , & y , & x , & y , & mask ) ) {
2015-12-28 19:07:44 +01:00
SDL_ToggleModState ( KMOD_CAPS , ( mask & LockMask ) ! = 0 ) ;
SDL_ToggleModState ( KMOD_NUM , ( mask & X11_GetNumLockModifierMask ( _this ) ) ! = 0 ) ;
2015-06-21 17:33:46 +02:00
}
for ( keycode = 0 ; keycode < 256 ; + + keycode ) {
if ( keys [ keycode / 8 ] & ( 1 < < ( keycode % 8 ) ) ) {
SDL_SendKeyboardKey ( SDL_PRESSED , viddata - > key_layout [ keycode ] ) ;
} else {
SDL_SendKeyboardKey ( SDL_RELEASED , viddata - > key_layout [ keycode ] ) ;
}
}
}
static void
X11_DispatchFocusIn ( _THIS , SDL_WindowData * data )
{
# ifdef DEBUG_XEVENTS
printf ( " window %p: Dispatching FocusIn \n " , data ) ;
# endif
SDL_SetKeyboardFocus ( data - > window ) ;
X11_ReconcileKeyboardState ( _this ) ;
# ifdef X_HAVE_UTF8_STRING
if ( data - > ic ) {
X11_XSetICFocus ( data - > ic ) ;
}
# endif
2016-10-08 03:57:40 +02:00
# ifdef SDL_USE_IME
SDL_IME_SetFocus ( SDL_TRUE ) ;
2015-06-21 17:33:46 +02:00
# endif
}
static void
X11_DispatchFocusOut ( _THIS , SDL_WindowData * data )
{
# ifdef DEBUG_XEVENTS
printf ( " window %p: Dispatching FocusOut \n " , data ) ;
# endif
/* If another window has already processed a focus in, then don't try to
* remove focus here . Doing so will incorrectly remove focus from that
* window , and the focus lost event for this window will have already
* been dispatched anyway . */
if ( data - > window = = SDL_GetKeyboardFocus ( ) ) {
SDL_SetKeyboardFocus ( NULL ) ;
}
# ifdef X_HAVE_UTF8_STRING
if ( data - > ic ) {
X11_XUnsetICFocus ( data - > ic ) ;
}
# endif
2016-10-08 03:57:40 +02:00
# ifdef SDL_USE_IME
SDL_IME_SetFocus ( SDL_FALSE ) ;
2015-06-21 17:33:46 +02:00
# endif
}
static void
X11_DispatchMapNotify ( SDL_WindowData * data )
{
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_SHOWN , 0 , 0 ) ;
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_RESTORED , 0 , 0 ) ;
}
static void
X11_DispatchUnmapNotify ( SDL_WindowData * data )
{
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_HIDDEN , 0 , 0 ) ;
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_MINIMIZED , 0 , 0 ) ;
}
static void
InitiateWindowMove ( _THIS , const SDL_WindowData * data , const SDL_Point * point )
{
SDL_VideoData * viddata = ( SDL_VideoData * ) _this - > driverdata ;
SDL_Window * window = data - > window ;
Display * display = viddata - > display ;
XEvent evt ;
/* !!! FIXME: we need to regrab this if necessary when the drag is done. */
X11_XUngrabPointer ( display , 0L ) ;
X11_XFlush ( display ) ;
evt . xclient . type = ClientMessage ;
evt . xclient . window = data - > xwindow ;
evt . xclient . message_type = X11_XInternAtom ( display , " _NET_WM_MOVERESIZE " , True ) ;
evt . xclient . format = 32 ;
evt . xclient . data . l [ 0 ] = window - > x + point - > x ;
evt . xclient . data . l [ 1 ] = window - > y + point - > y ;
evt . xclient . data . l [ 2 ] = _NET_WM_MOVERESIZE_MOVE ;
evt . xclient . data . l [ 3 ] = Button1 ;
evt . xclient . data . l [ 4 ] = 0 ;
X11_XSendEvent ( display , DefaultRootWindow ( display ) , False , SubstructureRedirectMask | SubstructureNotifyMask , & evt ) ;
X11_XSync ( display , 0 ) ;
}
static void
InitiateWindowResize ( _THIS , const SDL_WindowData * data , const SDL_Point * point , int direction )
{
SDL_VideoData * viddata = ( SDL_VideoData * ) _this - > driverdata ;
SDL_Window * window = data - > window ;
Display * display = viddata - > display ;
XEvent evt ;
if ( direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT | | direction > _NET_WM_MOVERESIZE_SIZE_LEFT )
return ;
/* !!! FIXME: we need to regrab this if necessary when the drag is done. */
X11_XUngrabPointer ( display , 0L ) ;
X11_XFlush ( display ) ;
evt . xclient . type = ClientMessage ;
evt . xclient . window = data - > xwindow ;
evt . xclient . message_type = X11_XInternAtom ( display , " _NET_WM_MOVERESIZE " , True ) ;
evt . xclient . format = 32 ;
evt . xclient . data . l [ 0 ] = window - > x + point - > x ;
evt . xclient . data . l [ 1 ] = window - > y + point - > y ;
evt . xclient . data . l [ 2 ] = direction ;
evt . xclient . data . l [ 3 ] = Button1 ;
evt . xclient . data . l [ 4 ] = 0 ;
X11_XSendEvent ( display , DefaultRootWindow ( display ) , False , SubstructureRedirectMask | SubstructureNotifyMask , & evt ) ;
X11_XSync ( display , 0 ) ;
}
static SDL_bool
ProcessHitTest ( _THIS , const SDL_WindowData * data , const XEvent * xev )
{
SDL_Window * window = data - > window ;
if ( window - > hit_test ) {
const SDL_Point point = { xev - > xbutton . x , xev - > xbutton . y } ;
const SDL_HitTestResult rc = window - > hit_test ( window , & point , window - > hit_test_data ) ;
static const int directions [ ] = {
_NET_WM_MOVERESIZE_SIZE_TOPLEFT , _NET_WM_MOVERESIZE_SIZE_TOP ,
_NET_WM_MOVERESIZE_SIZE_TOPRIGHT , _NET_WM_MOVERESIZE_SIZE_RIGHT ,
_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT , _NET_WM_MOVERESIZE_SIZE_BOTTOM ,
_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT , _NET_WM_MOVERESIZE_SIZE_LEFT
} ;
switch ( rc ) {
case SDL_HITTEST_DRAGGABLE :
InitiateWindowMove ( _this , data , & point ) ;
return SDL_TRUE ;
case SDL_HITTEST_RESIZE_TOPLEFT :
case SDL_HITTEST_RESIZE_TOP :
case SDL_HITTEST_RESIZE_TOPRIGHT :
case SDL_HITTEST_RESIZE_RIGHT :
case SDL_HITTEST_RESIZE_BOTTOMRIGHT :
case SDL_HITTEST_RESIZE_BOTTOM :
case SDL_HITTEST_RESIZE_BOTTOMLEFT :
case SDL_HITTEST_RESIZE_LEFT :
InitiateWindowResize ( _this , data , & point , directions [ rc - SDL_HITTEST_RESIZE_TOPLEFT ] ) ;
return SDL_TRUE ;
default : return SDL_FALSE ;
}
}
return SDL_FALSE ;
}
2016-01-04 22:25:27 +01:00
static void
X11_UpdateUserTime ( SDL_WindowData * data , const unsigned long latest )
{
if ( latest & & ( latest ! = data - > user_time ) ) {
SDL_VideoData * videodata = data - > videodata ;
Display * display = videodata - > display ;
X11_XChangeProperty ( display , data - > xwindow , videodata - > _NET_WM_USER_TIME ,
XA_CARDINAL , 32 , PropModeReplace ,
( const unsigned char * ) & latest , 1 ) ;
2016-09-30 01:05:29 +02:00
# ifdef DEBUG_XEVENTS
2016-01-04 22:25:27 +01:00
printf ( " window %p: updating _NET_WM_USER_TIME to %lu \n " , data , latest ) ;
2016-09-30 01:05:29 +02:00
# endif
2016-01-04 22:25:27 +01:00
data - > user_time = latest ;
}
}
2015-06-21 17:33:46 +02:00
static void
X11_DispatchEvent ( _THIS )
{
SDL_VideoData * videodata = ( SDL_VideoData * ) _this - > driverdata ;
2016-10-08 02:26:25 +02:00
Display * display ;
2015-06-21 17:33:46 +02:00
SDL_WindowData * data ;
XEvent xevent ;
int orig_event_type ;
KeyCode orig_keycode ;
XClientMessageEvent m ;
int i ;
2016-10-08 02:26:25 +02:00
if ( ! videodata ) {
return ;
}
display = videodata - > display ;
2015-06-21 17:33:46 +02:00
SDL_zero ( xevent ) ; /* valgrind fix. --ryan. */
X11_XNextEvent ( display , & xevent ) ;
/* Save the original keycode for dead keys, which are filtered out by
the XFilterEvent ( ) call below .
*/
orig_event_type = xevent . type ;
if ( orig_event_type = = KeyPress | | orig_event_type = = KeyRelease ) {
orig_keycode = xevent . xkey . keycode ;
} else {
orig_keycode = 0 ;
}
/* filter events catchs XIM events and sends them to the correct handler */
if ( X11_XFilterEvent ( & xevent , None ) = = True ) {
#if 0
printf ( " Filtered event type = %d display = %d window = %d \n " ,
xevent . type , xevent . xany . display , xevent . xany . window ) ;
# endif
2016-10-28 02:28:58 +02:00
/* Make sure dead key press/release events are sent */
/* But only if we're using one of the DBus IMEs, otherwise
some XIM IMEs will generate duplicate events */
2015-06-21 17:33:46 +02:00
if ( orig_keycode ) {
2016-10-28 02:28:58 +02:00
# if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
2015-06-21 17:33:46 +02:00
SDL_Scancode scancode = videodata - > key_layout [ orig_keycode ] ;
2016-11-01 18:38:05 +01:00
videodata - > filter_code = orig_keycode ;
videodata - > filter_time = xevent . xkey . time ;
2015-06-21 17:33:46 +02:00
if ( orig_event_type = = KeyPress ) {
SDL_SendKeyboardKey ( SDL_PRESSED , scancode ) ;
} else {
SDL_SendKeyboardKey ( SDL_RELEASED , scancode ) ;
}
2016-10-28 02:28:58 +02:00
# endif
2015-06-21 17:33:46 +02:00
}
return ;
}
/* Send a SDL_SYSWMEVENT if the application wants them */
if ( SDL_GetEventState ( SDL_SYSWMEVENT ) = = SDL_ENABLE ) {
SDL_SysWMmsg wmmsg ;
SDL_VERSION ( & wmmsg . version ) ;
wmmsg . subsystem = SDL_SYSWM_X11 ;
wmmsg . msg . x11 . event = xevent ;
SDL_SendSysWMEvent ( & wmmsg ) ;
}
# if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
if ( xevent . type = = GenericEvent ) {
X11_HandleGenericEvent ( videodata , xevent ) ;
return ;
}
# endif
#if 0
printf ( " type = %d display = %d window = %d \n " ,
xevent . type , xevent . xany . display , xevent . xany . window ) ;
# endif
data = NULL ;
if ( videodata & & videodata - > windowlist ) {
for ( i = 0 ; i < videodata - > numwindows ; + + i ) {
if ( ( videodata - > windowlist [ i ] ! = NULL ) & &
( videodata - > windowlist [ i ] - > xwindow = = xevent . xany . window ) ) {
data = videodata - > windowlist [ i ] ;
break ;
}
}
}
if ( ! data ) {
2015-06-30 20:39:39 +02:00
/* The window for KeymapNotify, etc events is 0 */
2015-06-21 17:33:46 +02:00
if ( xevent . type = = KeymapNotify ) {
if ( SDL_GetKeyboardFocus ( ) ! = NULL ) {
X11_ReconcileKeyboardState ( _this ) ;
}
2015-06-30 20:39:39 +02:00
} else if ( xevent . type = = MappingNotify ) {
/* Has the keyboard layout changed? */
2015-06-30 20:41:17 +02:00
const int request = xevent . xmapping . request ;
2015-06-30 20:39:39 +02:00
# ifdef DEBUG_XEVENTS
printf ( " window %p: MappingNotify! \n " , data ) ;
# endif
2015-06-30 20:41:17 +02:00
if ( ( request = = MappingKeyboard ) | | ( request = = MappingModifier ) ) {
X11_XRefreshKeyboardMapping ( & xevent . xmapping ) ;
}
2015-06-30 20:39:39 +02:00
X11_UpdateKeymap ( _this ) ;
2015-10-27 19:17:32 +01:00
SDL_SendKeymapChangedEvent ( ) ;
2015-06-21 17:33:46 +02:00
}
return ;
}
switch ( xevent . type ) {
/* Gaining mouse coverage? */
case EnterNotify : {
2016-01-08 01:58:00 +01:00
SDL_Mouse * mouse = SDL_GetMouse ( ) ;
2015-06-21 17:33:46 +02:00
# ifdef DEBUG_XEVENTS
printf ( " window %p: EnterNotify! (%d,%d,%d) \n " , data ,
xevent . xcrossing . x ,
xevent . xcrossing . y ,
xevent . xcrossing . mode ) ;
if ( xevent . xcrossing . mode = = NotifyGrab )
printf ( " Mode: NotifyGrab \n " ) ;
if ( xevent . xcrossing . mode = = NotifyUngrab )
printf ( " Mode: NotifyUngrab \n " ) ;
# endif
SDL_SetMouseFocus ( data - > window ) ;
2016-01-08 01:58:00 +01:00
mouse - > last_x = xevent . xcrossing . x ;
mouse - > last_y = xevent . xcrossing . y ;
if ( ! mouse - > relative_mode ) {
2015-06-21 17:33:46 +02:00
SDL_SendMouseMotion ( data - > window , 0 , 0 , xevent . xcrossing . x , xevent . xcrossing . y ) ;
}
}
break ;
/* Losing mouse coverage? */
case LeaveNotify : {
# ifdef DEBUG_XEVENTS
printf ( " window %p: LeaveNotify! (%d,%d,%d) \n " , data ,
xevent . xcrossing . x ,
xevent . xcrossing . y ,
xevent . xcrossing . mode ) ;
if ( xevent . xcrossing . mode = = NotifyGrab )
printf ( " Mode: NotifyGrab \n " ) ;
if ( xevent . xcrossing . mode = = NotifyUngrab )
printf ( " Mode: NotifyUngrab \n " ) ;
# endif
if ( ! SDL_GetMouse ( ) - > relative_mode ) {
SDL_SendMouseMotion ( data - > window , 0 , 0 , xevent . xcrossing . x , xevent . xcrossing . y ) ;
}
if ( xevent . xcrossing . mode ! = NotifyGrab & &
xevent . xcrossing . mode ! = NotifyUngrab & &
xevent . xcrossing . detail ! = NotifyInferior ) {
SDL_SetMouseFocus ( NULL ) ;
}
}
break ;
/* Gaining input focus? */
case FocusIn : {
if ( xevent . xfocus . mode = = NotifyGrab | | xevent . xfocus . mode = = NotifyUngrab ) {
/* Someone is handling a global hotkey, ignore it */
# ifdef DEBUG_XEVENTS
printf ( " window %p: FocusIn (NotifyGrab/NotifyUngrab, ignoring) \n " , data ) ;
# endif
break ;
}
if ( xevent . xfocus . detail = = NotifyInferior ) {
# ifdef DEBUG_XEVENTS
printf ( " window %p: FocusIn (NotifierInferior, ignoring) \n " , data ) ;
# endif
break ;
}
# ifdef DEBUG_XEVENTS
printf ( " window %p: FocusIn! \n " , data ) ;
# endif
if ( ! videodata - > last_mode_change_deadline ) /* no recent mode changes */
{
data - > pending_focus = PENDING_FOCUS_NONE ;
data - > pending_focus_time = 0 ;
X11_DispatchFocusIn ( _this , data ) ;
}
else
{
data - > pending_focus = PENDING_FOCUS_IN ;
data - > pending_focus_time = SDL_GetTicks ( ) + PENDING_FOCUS_TIME ;
}
2016-09-30 01:05:29 +02:00
data - > last_focus_event_time = SDL_GetTicks ( ) ;
2015-06-21 17:33:46 +02:00
}
break ;
/* Losing input focus? */
case FocusOut : {
if ( xevent . xfocus . mode = = NotifyGrab | | xevent . xfocus . mode = = NotifyUngrab ) {
/* Someone is handling a global hotkey, ignore it */
# ifdef DEBUG_XEVENTS
printf ( " window %p: FocusOut (NotifyGrab/NotifyUngrab, ignoring) \n " , data ) ;
# endif
break ;
}
if ( xevent . xfocus . detail = = NotifyInferior ) {
/* We still have focus if a child gets focus */
# ifdef DEBUG_XEVENTS
printf ( " window %p: FocusOut (NotifierInferior, ignoring) \n " , data ) ;
# endif
break ;
}
# ifdef DEBUG_XEVENTS
printf ( " window %p: FocusOut! \n " , data ) ;
# endif
if ( ! videodata - > last_mode_change_deadline ) /* no recent mode changes */
{
data - > pending_focus = PENDING_FOCUS_NONE ;
data - > pending_focus_time = 0 ;
X11_DispatchFocusOut ( _this , data ) ;
}
else
{
data - > pending_focus = PENDING_FOCUS_OUT ;
data - > pending_focus_time = SDL_GetTicks ( ) + PENDING_FOCUS_TIME ;
}
}
break ;
/* Key press? */
case KeyPress : {
KeyCode keycode = xevent . xkey . keycode ;
KeySym keysym = NoSymbol ;
char text [ SDL_TEXTINPUTEVENT_TEXT_SIZE ] ;
Status status = 0 ;
SDL_bool handled_by_ime = SDL_FALSE ;
# ifdef DEBUG_XEVENTS
printf ( " window %p: KeyPress (X11 keycode = 0x%X) \n " , data , xevent . xkey . keycode ) ;
# endif
# if 1
if ( videodata - > key_layout [ keycode ] = = SDL_SCANCODE_UNKNOWN & & keycode ) {
int min_keycode , max_keycode ;
X11_XDisplayKeycodes ( display , & min_keycode , & max_keycode ) ;
2016-10-03 12:35:34 +02:00
keysym = X11_KeyCodeToSym ( _this , keycode , xevent . xkey . state > > 13 ) ;
2015-06-21 17:33:46 +02:00
fprintf ( stderr ,
" The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list <sdl@libsdl.org> X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s). \n " ,
keycode , keycode - min_keycode , keysym ,
X11_XKeysymToString ( keysym ) ) ;
}
# endif
/* */
SDL_zero ( text ) ;
# ifdef X_HAVE_UTF8_STRING
if ( data - > ic ) {
X11_Xutf8LookupString ( data - > ic , & xevent . xkey , text , sizeof ( text ) ,
& keysym , & status ) ;
2015-09-30 05:16:09 +02:00
} else {
X11_XLookupString ( & xevent . xkey , text , sizeof ( text ) , & keysym , NULL ) ;
2015-06-21 17:33:46 +02:00
}
# else
2015-07-11 06:59:56 +02:00
X11_XLookupString ( & xevent . xkey , text , sizeof ( text ) , & keysym , NULL ) ;
2015-06-21 17:33:46 +02:00
# endif
2016-10-08 03:57:40 +02:00
# ifdef SDL_USE_IME
2015-06-21 17:33:46 +02:00
if ( SDL_GetEventState ( SDL_TEXTINPUT ) = = SDL_ENABLE ) {
2016-10-08 03:57:40 +02:00
handled_by_ime = SDL_IME_ProcessKeyEvent ( keysym , keycode ) ;
2015-06-21 17:33:46 +02:00
}
# endif
if ( ! handled_by_ime ) {
2016-11-02 10:56:54 +01:00
/* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
if ( xevent . xkey . keycode ! = videodata - > filter_code | | xevent . xkey . time ! = videodata - > filter_time ) {
SDL_SendKeyboardKey ( SDL_PRESSED , videodata - > key_layout [ keycode ] ) ;
}
2015-06-21 17:33:46 +02:00
if ( * text ) {
SDL_SendKeyboardText ( text ) ;
}
}
2016-01-04 22:25:27 +01:00
X11_UpdateUserTime ( data , xevent . xkey . time ) ;
2015-06-21 17:33:46 +02:00
}
break ;
/* Key release? */
case KeyRelease : {
KeyCode keycode = xevent . xkey . keycode ;
# ifdef DEBUG_XEVENTS
printf ( " window %p: KeyRelease (X11 keycode = 0x%X) \n " , data , xevent . xkey . keycode ) ;
# endif
if ( X11_KeyRepeat ( display , & xevent ) ) {
/* We're about to get a repeated key down, ignore the key up */
break ;
}
SDL_SendKeyboardKey ( SDL_RELEASED , videodata - > key_layout [ keycode ] ) ;
}
break ;
/* Have we been iconified? */
case UnmapNotify : {
# ifdef DEBUG_XEVENTS
printf ( " window %p: UnmapNotify! \n " , data ) ;
# endif
X11_DispatchUnmapNotify ( data ) ;
}
break ;
/* Have we been restored? */
case MapNotify : {
# ifdef DEBUG_XEVENTS
printf ( " window %p: MapNotify! \n " , data ) ;
# endif
X11_DispatchMapNotify ( data ) ;
}
break ;
/* Have we been resized or moved? */
case ConfigureNotify : {
# ifdef DEBUG_XEVENTS
printf ( " window %p: ConfigureNotify! (position: %d,%d, size: %dx%d) \n " , data ,
xevent . xconfigure . x , xevent . xconfigure . y ,
xevent . xconfigure . width , xevent . xconfigure . height ) ;
# endif
2016-09-30 05:01:43 +02:00
/* Real configure notify events are relative to the parent, synthetic events are absolute. */
if ( ! xevent . xconfigure . send_event ) {
unsigned int NumChildren ;
Window ChildReturn , Root , Parent ;
Window * Children ;
/* Translate these coodinates back to relative to root */
X11_XQueryTree ( data - > videodata - > display , xevent . xconfigure . window , & Root , & Parent , & Children , & NumChildren ) ;
X11_XTranslateCoordinates ( xevent . xconfigure . display ,
Parent , DefaultRootWindow ( xevent . xconfigure . display ) ,
xevent . xconfigure . x , xevent . xconfigure . y ,
& xevent . xconfigure . x , & xevent . xconfigure . y ,
& ChildReturn ) ;
}
2015-06-21 17:33:46 +02:00
if ( xevent . xconfigure . x ! = data - > last_xconfigure . x | |
xevent . xconfigure . y ! = data - > last_xconfigure . y ) {
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_MOVED ,
2016-03-05 00:47:19 +01:00
xevent . xconfigure . x , xevent . xconfigure . y ) ;
2016-10-08 03:57:40 +02:00
# ifdef SDL_USE_IME
2015-06-21 17:33:46 +02:00
if ( SDL_GetEventState ( SDL_TEXTINPUT ) = = SDL_ENABLE ) {
2016-10-08 03:57:40 +02:00
/* Update IME candidate list position */
SDL_IME_UpdateTextRect ( NULL ) ;
2015-06-21 17:33:46 +02:00
}
# endif
}
if ( xevent . xconfigure . width ! = data - > last_xconfigure . width | |
xevent . xconfigure . height ! = data - > last_xconfigure . height ) {
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_RESIZED ,
xevent . xconfigure . width ,
xevent . xconfigure . height ) ;
}
data - > last_xconfigure = xevent . xconfigure ;
}
break ;
/* Have we been requested to quit (or another client message?) */
case ClientMessage : {
static int xdnd_version = 0 ;
if ( xevent . xclient . message_type = = videodata - > XdndEnter ) {
SDL_bool use_list = xevent . xclient . data . l [ 1 ] & 1 ;
data - > xdnd_source = xevent . xclient . data . l [ 0 ] ;
xdnd_version = ( xevent . xclient . data . l [ 1 ] > > 24 ) ;
# ifdef DEBUG_XEVENTS
printf ( " XID of source window : %ld \n " , data - > xdnd_source ) ;
printf ( " Protocol version to use : %d \n " , xdnd_version ) ;
printf ( " More then 3 data types : %d \n " , ( int ) use_list ) ;
# endif
if ( use_list ) {
/* fetch conversion targets */
SDL_x11Prop p ;
X11_ReadProperty ( & p , display , data - > xdnd_source , videodata - > XdndTypeList ) ;
/* pick one */
data - > xdnd_req = X11_PickTarget ( display , ( Atom * ) p . data , p . count ) ;
X11_XFree ( p . data ) ;
} else {
/* pick from list of three */
data - > xdnd_req = X11_PickTargetFromAtoms ( display , xevent . xclient . data . l [ 2 ] , xevent . xclient . data . l [ 3 ] , xevent . xclient . data . l [ 4 ] ) ;
}
}
else if ( xevent . xclient . message_type = = videodata - > XdndPosition ) {
# ifdef DEBUG_XEVENTS
Atom act = videodata - > XdndActionCopy ;
if ( xdnd_version > = 2 ) {
act = xevent . xclient . data . l [ 4 ] ;
}
printf ( " Action requested by user is : %s \n " , X11_XGetAtomName ( display , act ) ) ;
# endif
/* reply with status */
memset ( & m , 0 , sizeof ( XClientMessageEvent ) ) ;
m . type = ClientMessage ;
m . display = xevent . xclient . display ;
m . window = xevent . xclient . data . l [ 0 ] ;
m . message_type = videodata - > XdndStatus ;
m . format = 32 ;
m . data . l [ 0 ] = data - > xwindow ;
m . data . l [ 1 ] = ( data - > xdnd_req ! = None ) ;
m . data . l [ 2 ] = 0 ; /* specify an empty rectangle */
m . data . l [ 3 ] = 0 ;
m . data . l [ 4 ] = videodata - > XdndActionCopy ; /* we only accept copying anyway */
X11_XSendEvent ( display , xevent . xclient . data . l [ 0 ] , False , NoEventMask , ( XEvent * ) & m ) ;
X11_XFlush ( display ) ;
}
else if ( xevent . xclient . message_type = = videodata - > XdndDrop ) {
if ( data - > xdnd_req = = None ) {
/* say again - not interested! */
memset ( & m , 0 , sizeof ( XClientMessageEvent ) ) ;
m . type = ClientMessage ;
m . display = xevent . xclient . display ;
m . window = xevent . xclient . data . l [ 0 ] ;
m . message_type = videodata - > XdndFinished ;
m . format = 32 ;
m . data . l [ 0 ] = data - > xwindow ;
m . data . l [ 1 ] = 0 ;
m . data . l [ 2 ] = None ; /* fail! */
X11_XSendEvent ( display , xevent . xclient . data . l [ 0 ] , False , NoEventMask , ( XEvent * ) & m ) ;
} else {
/* convert */
if ( xdnd_version > = 1 ) {
X11_XConvertSelection ( display , videodata - > XdndSelection , data - > xdnd_req , videodata - > PRIMARY , data - > xwindow , xevent . xclient . data . l [ 2 ] ) ;
} else {
X11_XConvertSelection ( display , videodata - > XdndSelection , data - > xdnd_req , videodata - > PRIMARY , data - > xwindow , CurrentTime ) ;
}
}
}
else if ( ( xevent . xclient . message_type = = videodata - > WM_PROTOCOLS ) & &
( xevent . xclient . format = = 32 ) & &
( xevent . xclient . data . l [ 0 ] = = videodata - > _NET_WM_PING ) ) {
Window root = DefaultRootWindow ( display ) ;
# ifdef DEBUG_XEVENTS
printf ( " window %p: _NET_WM_PING \n " , data ) ;
# endif
xevent . xclient . window = root ;
X11_XSendEvent ( display , root , False , SubstructureRedirectMask | SubstructureNotifyMask , & xevent ) ;
break ;
}
else if ( ( xevent . xclient . message_type = = videodata - > WM_PROTOCOLS ) & &
( xevent . xclient . format = = 32 ) & &
( xevent . xclient . data . l [ 0 ] = = videodata - > WM_DELETE_WINDOW ) ) {
# ifdef DEBUG_XEVENTS
printf ( " window %p: WM_DELETE_WINDOW \n " , data ) ;
# endif
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_CLOSE , 0 , 0 ) ;
break ;
}
2016-01-05 08:27:50 +01:00
else if ( ( xevent . xclient . message_type = = videodata - > WM_PROTOCOLS ) & &
( xevent . xclient . format = = 32 ) & &
( xevent . xclient . data . l [ 0 ] = = videodata - > WM_TAKE_FOCUS ) ) {
# ifdef DEBUG_XEVENTS
printf ( " window %p: WM_TAKE_FOCUS \n " , data ) ;
# endif
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_TAKE_FOCUS , 0 , 0 ) ;
break ;
}
2015-06-21 17:33:46 +02:00
}
break ;
/* Do we need to refresh ourselves? */
case Expose : {
# ifdef DEBUG_XEVENTS
printf ( " window %p: Expose (count = %d) \n " , data , xevent . xexpose . count ) ;
# endif
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_EXPOSED , 0 , 0 ) ;
}
break ;
case MotionNotify : {
SDL_Mouse * mouse = SDL_GetMouse ( ) ;
if ( ! mouse - > relative_mode | | mouse - > relative_mode_warp ) {
# ifdef DEBUG_MOTION
2016-09-30 01:05:29 +02:00
printf ( " window %p: X11 motion: %d,%d \n " , data , xevent . xmotion . x , xevent . xmotion . y ) ;
2015-06-21 17:33:46 +02:00
# endif
SDL_SendMouseMotion ( data - > window , 0 , 0 , xevent . xmotion . x , xevent . xmotion . y ) ;
}
}
break ;
case ButtonPress : {
int xticks = 0 , yticks = 0 ;
2016-09-30 01:05:29 +02:00
# ifdef DEBUG_XEVENTS
printf ( " window %p: ButtonPress (X11 button = %d) \n " , data , xevent . xbutton . button ) ;
# endif
2015-06-21 17:33:46 +02:00
if ( X11_IsWheelEvent ( display , & xevent , & xticks , & yticks ) ) {
SDL_SendMouseWheel ( data - > window , 0 , xticks , yticks , SDL_MOUSEWHEEL_NORMAL ) ;
} else {
2016-09-30 01:05:29 +02:00
SDL_bool ignore_click = SDL_FALSE ;
2015-06-21 17:33:46 +02:00
int button = xevent . xbutton . button ;
if ( button = = Button1 ) {
if ( ProcessHitTest ( _this , data , & xevent ) ) {
2015-04-21 16:10:59 +02:00
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_HIT_TEST , 0 , 0 ) ;
2015-06-21 17:33:46 +02:00
break ; /* don't pass this event on to app. */
}
}
else if ( button > 7 ) {
/* X button values 4-7 are used for scrolling, so X1 is 8, X2 is 9, ...
= > subtract ( 8 - SDL_BUTTON_X1 ) to get value SDL expects */
button - = ( 8 - SDL_BUTTON_X1 ) ;
}
2016-09-30 01:05:29 +02:00
if ( data - > last_focus_event_time ) {
const int X11_FOCUS_CLICK_TIMEOUT = 10 ;
if ( ! SDL_TICKS_PASSED ( SDL_GetTicks ( ) , data - > last_focus_event_time + X11_FOCUS_CLICK_TIMEOUT ) ) {
2016-10-08 08:40:44 +02:00
ignore_click = ! SDL_GetHintBoolean ( SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH , SDL_FALSE ) ;
2016-09-30 01:05:29 +02:00
}
data - > last_focus_event_time = 0 ;
}
if ( ! ignore_click ) {
SDL_SendMouseButton ( data - > window , 0 , SDL_PRESSED , button ) ;
}
2015-06-21 17:33:46 +02:00
}
2016-01-04 22:25:27 +01:00
X11_UpdateUserTime ( data , xevent . xbutton . time ) ;
2015-06-21 17:33:46 +02:00
}
break ;
case ButtonRelease : {
int button = xevent . xbutton . button ;
2015-08-13 23:40:28 +02:00
/* The X server sends a Release event for each Press for wheels. Ignore them. */
int xticks = 0 , yticks = 0 ;
2016-09-30 01:05:29 +02:00
# ifdef DEBUG_XEVENTS
printf ( " window %p: ButtonRelease (X11 button = %d) \n " , data , xevent . xbutton . button ) ;
# endif
if ( ! X11_IsWheelEvent ( display , & xevent , & xticks , & yticks ) ) {
2015-08-13 23:40:28 +02:00
if ( button > 7 ) {
/* see explanation at case ButtonPress */
button - = ( 8 - SDL_BUTTON_X1 ) ;
}
2015-08-14 03:40:32 +02:00
SDL_SendMouseButton ( data - > window , 0 , SDL_RELEASED , button ) ;
2015-06-21 17:33:46 +02:00
}
}
break ;
case PropertyNotify : {
# ifdef DEBUG_XEVENTS
unsigned char * propdata ;
int status , real_format ;
Atom real_type ;
unsigned long items_read , items_left ;
char * name = X11_XGetAtomName ( display , xevent . xproperty . atom ) ;
if ( name ) {
2016-01-04 22:25:27 +01:00
printf ( " window %p: PropertyNotify: %s %s time=%lu \n " , data , name , ( xevent . xproperty . state = = PropertyDelete ) ? " deleted " : " changed " , xevent . xproperty . time ) ;
2015-06-21 17:33:46 +02:00
X11_XFree ( name ) ;
}
status = X11_XGetWindowProperty ( display , data - > xwindow , xevent . xproperty . atom , 0L , 8192L , False , AnyPropertyType , & real_type , & real_format , & items_read , & items_left , & propdata ) ;
if ( status = = Success & & items_read > 0 ) {
if ( real_type = = XA_INTEGER ) {
int * values = ( int * ) propdata ;
printf ( " { " ) ;
for ( i = 0 ; i < items_read ; i + + ) {
printf ( " %d " , values [ i ] ) ;
}
printf ( " } \n " ) ;
} else if ( real_type = = XA_CARDINAL ) {
if ( real_format = = 32 ) {
Uint32 * values = ( Uint32 * ) propdata ;
printf ( " { " ) ;
for ( i = 0 ; i < items_read ; i + + ) {
printf ( " %d " , values [ i ] ) ;
}
printf ( " } \n " ) ;
} else if ( real_format = = 16 ) {
Uint16 * values = ( Uint16 * ) propdata ;
printf ( " { " ) ;
for ( i = 0 ; i < items_read ; i + + ) {
printf ( " %d " , values [ i ] ) ;
}
printf ( " } \n " ) ;
} else if ( real_format = = 8 ) {
Uint8 * values = ( Uint8 * ) propdata ;
printf ( " { " ) ;
for ( i = 0 ; i < items_read ; i + + ) {
printf ( " %d " , values [ i ] ) ;
}
printf ( " } \n " ) ;
}
} else if ( real_type = = XA_STRING | |
real_type = = videodata - > UTF8_STRING ) {
printf ( " { \" %s \" } \n " , propdata ) ;
} else if ( real_type = = XA_ATOM ) {
Atom * atoms = ( Atom * ) propdata ;
printf ( " { " ) ;
for ( i = 0 ; i < items_read ; i + + ) {
char * atomname = X11_XGetAtomName ( display , atoms [ i ] ) ;
if ( atomname ) {
printf ( " %s " , atomname ) ;
X11_XFree ( atomname ) ;
}
}
printf ( " } \n " ) ;
} else {
char * atomname = X11_XGetAtomName ( display , real_type ) ;
printf ( " Unknown type: %ld (%s) \n " , real_type , atomname ? atomname : " UNKNOWN " ) ;
if ( atomname ) {
X11_XFree ( atomname ) ;
}
}
}
if ( status = = Success ) {
X11_XFree ( propdata ) ;
}
# endif /* DEBUG_XEVENTS */
2016-01-04 22:25:27 +01:00
/* Take advantage of this moment to make sure user_time has a
valid timestamp from the X server , so if we later try to
raise / restore this window , _NET_ACTIVE_WINDOW can have a
non - zero timestamp , even if there ' s never been a mouse or
key press to this window so far . Note that we don ' t try to
set _NET_WM_USER_TIME here , though . That ' s only for legit
user interaction with the window . */
if ( ! data - > user_time ) {
data - > user_time = xevent . xproperty . time ;
}
2015-06-21 17:33:46 +02:00
if ( xevent . xproperty . atom = = data - > videodata - > _NET_WM_STATE ) {
/* Get the new state from the window manager.
Compositing window managers can alter visibility of windows
without ever mapping / unmapping them , so we handle that here ,
because they use the NETWM protocol to notify us of changes .
*/
const Uint32 flags = X11_GetNetWMState ( _this , xevent . xproperty . window ) ;
const Uint32 changed = flags ^ data - > window - > flags ;
if ( ( changed & SDL_WINDOW_HIDDEN ) | | ( changed & SDL_WINDOW_FULLSCREEN ) ) {
if ( flags & SDL_WINDOW_HIDDEN ) {
X11_DispatchUnmapNotify ( data ) ;
} else {
X11_DispatchMapNotify ( data ) ;
}
}
if ( changed & SDL_WINDOW_MAXIMIZED ) {
if ( flags & SDL_WINDOW_MAXIMIZED ) {
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_MAXIMIZED , 0 , 0 ) ;
} else {
SDL_SendWindowEvent ( data - > window , SDL_WINDOWEVENT_RESTORED , 0 , 0 ) ;
}
2015-08-15 06:36:39 +02:00
}
} else if ( xevent . xproperty . atom = = videodata - > XKLAVIER_STATE ) {
/* Hack for Ubuntu 12.04 (etc) that doesn't send MappingNotify
events when the keyboard layout changes ( for example ,
changing from English to French on the menubar ' s keyboard
icon ) . Since it changes the XKLAVIER_STATE property , we
notice and reinit our keymap here . This might not be the
right approach , but it seems to work . */
X11_UpdateKeymap ( _this ) ;
2015-10-27 19:17:32 +01:00
SDL_SendKeymapChangedEvent ( ) ;
2016-03-05 00:47:19 +01:00
} else if ( xevent . xproperty . atom = = videodata - > _NET_FRAME_EXTENTS ) {
Atom type ;
int format ;
unsigned long nitems , bytes_after ;
unsigned char * property ;
if ( X11_XGetWindowProperty ( display , data - > xwindow , videodata - > _NET_FRAME_EXTENTS , 0 , 16 , 0 , XA_CARDINAL , & type , & format , & nitems , & bytes_after , & property ) = = Success ) {
if ( type ! = None & & nitems = = 4 ) {
data - > border_left = ( int ) ( ( long * ) property ) [ 0 ] ;
data - > border_right = ( int ) ( ( long * ) property ) [ 1 ] ;
data - > border_top = ( int ) ( ( long * ) property ) [ 2 ] ;
data - > border_bottom = ( int ) ( ( long * ) property ) [ 3 ] ;
}
X11_XFree ( property ) ;
# ifdef DEBUG_XEVENTS
printf ( " New _NET_FRAME_EXTENTS: left=%d right=%d, top=%d, bottom=%d \n " , data - > border_left , data - > border_right , data - > border_top , data - > border_bottom ) ;
# endif
}
2015-06-21 17:33:46 +02:00
}
}
break ;
/* Copy the selection from our own CUTBUFFER to the requested property */
case SelectionRequest : {
XSelectionRequestEvent * req ;
XEvent sevent ;
int seln_format ;
unsigned long nbytes ;
unsigned long overflow ;
unsigned char * seln_data ;
req = & xevent . xselectionrequest ;
# ifdef DEBUG_XEVENTS
printf ( " window %p: SelectionRequest (requestor = %ld, target = %ld) \n " , data ,
req - > requestor , req - > target ) ;
# endif
SDL_zero ( sevent ) ;
sevent . xany . type = SelectionNotify ;
sevent . xselection . selection = req - > selection ;
sevent . xselection . target = None ;
sevent . xselection . property = None ;
sevent . xselection . requestor = req - > requestor ;
sevent . xselection . time = req - > time ;
if ( X11_XGetWindowProperty ( display , DefaultRootWindow ( display ) ,
X11_GetSDLCutBufferClipboardType ( display ) , 0 , INT_MAX / 4 , False , req - > target ,
& sevent . xselection . target , & seln_format , & nbytes ,
& overflow , & seln_data ) = = Success ) {
Atom XA_TARGETS = X11_XInternAtom ( display , " TARGETS " , 0 ) ;
if ( sevent . xselection . target = = req - > target ) {
X11_XChangeProperty ( display , req - > requestor , req - > property ,
sevent . xselection . target , seln_format , PropModeReplace ,
seln_data , nbytes ) ;
sevent . xselection . property = req - > property ;
} else if ( XA_TARGETS = = req - > target ) {
Atom SupportedFormats [ ] = { XA_TARGETS , sevent . xselection . target } ;
X11_XChangeProperty ( display , req - > requestor , req - > property ,
XA_ATOM , 32 , PropModeReplace ,
( unsigned char * ) SupportedFormats ,
SDL_arraysize ( SupportedFormats ) ) ;
sevent . xselection . property = req - > property ;
sevent . xselection . target = XA_TARGETS ;
}
X11_XFree ( seln_data ) ;
}
X11_XSendEvent ( display , req - > requestor , False , 0 , & sevent ) ;
X11_XSync ( display , False ) ;
}
break ;
case SelectionNotify : {
2016-02-12 06:27:21 +01:00
Atom target = xevent . xselection . target ;
2015-06-21 17:33:46 +02:00
# ifdef DEBUG_XEVENTS
printf ( " window %p: SelectionNotify (requestor = %ld, target = %ld) \n " , data ,
xevent . xselection . requestor , xevent . xselection . target ) ;
# endif
if ( target = = data - > xdnd_req ) {
/* read data */
SDL_x11Prop p ;
X11_ReadProperty ( & p , display , data - > xwindow , videodata - > PRIMARY ) ;
if ( p . format = = 8 ) {
2016-01-05 08:26:45 +01:00
/* !!! FIXME: don't use strtok here. It's not reentrant and not in SDL_stdinc. */
char * name = X11_XGetAtomName ( display , target ) ;
char * token = strtok ( ( char * ) p . data , " \r \n " ) ;
while ( token ! = NULL ) {
if ( SDL_strcmp ( " text/plain " , name ) = = 0 ) {
2016-01-05 07:42:00 +01:00
SDL_SendDropText ( data - > window , token ) ;
2016-01-05 08:26:45 +01:00
} else if ( SDL_strcmp ( " text/uri-list " , name ) = = 0 ) {
char * fn = X11_URIToLocal ( token ) ;
if ( fn ) {
2016-01-05 07:42:00 +01:00
SDL_SendDropFile ( data - > window , fn ) ;
2015-06-21 17:33:46 +02:00
}
}
2016-01-05 08:26:45 +01:00
token = strtok ( NULL , " \r \n " ) ;
2015-06-21 17:33:46 +02:00
}
2016-01-05 07:42:00 +01:00
SDL_SendDropComplete ( data - > window ) ;
2015-06-21 17:33:46 +02:00
}
X11_XFree ( p . data ) ;
/* send reply */
SDL_memset ( & m , 0 , sizeof ( XClientMessageEvent ) ) ;
m . type = ClientMessage ;
m . display = display ;
m . window = data - > xdnd_source ;
m . message_type = videodata - > XdndFinished ;
m . format = 32 ;
m . data . l [ 0 ] = data - > xwindow ;
m . data . l [ 1 ] = 1 ;
m . data . l [ 2 ] = videodata - > XdndActionCopy ;
X11_XSendEvent ( display , data - > xdnd_source , False , NoEventMask , ( XEvent * ) & m ) ;
X11_XSync ( display , False ) ;
} else {
videodata - > selection_waiting = SDL_FALSE ;
}
}
break ;
case SelectionClear : {
Atom XA_CLIPBOARD = X11_XInternAtom ( display , " CLIPBOARD " , 0 ) ;
if ( xevent . xselectionclear . selection = = XA_PRIMARY | |
( XA_CLIPBOARD ! = None & & xevent . xselectionclear . selection = = XA_CLIPBOARD ) ) {
SDL_SendClipboardUpdate ( ) ;
}
}
break ;
default : {
# ifdef DEBUG_XEVENTS
printf ( " window %p: Unhandled event %d \n " , data , xevent . type ) ;
# endif
}
break ;
}
}
static void
X11_HandleFocusChanges ( _THIS )
{
SDL_VideoData * videodata = ( SDL_VideoData * ) _this - > driverdata ;
int i ;
if ( videodata & & videodata - > windowlist ) {
for ( i = 0 ; i < videodata - > numwindows ; + + i ) {
SDL_WindowData * data = videodata - > windowlist [ i ] ;
if ( data & & data - > pending_focus ! = PENDING_FOCUS_NONE ) {
Uint32 now = SDL_GetTicks ( ) ;
if ( SDL_TICKS_PASSED ( now , data - > pending_focus_time ) ) {
if ( data - > pending_focus = = PENDING_FOCUS_IN ) {
X11_DispatchFocusIn ( _this , data ) ;
} else {
X11_DispatchFocusOut ( _this , data ) ;
}
data - > pending_focus = PENDING_FOCUS_NONE ;
}
}
}
}
}
/* Ack! X11_XPending() actually performs a blocking read if no events available */
static int
X11_Pending ( Display * display )
{
/* Flush the display connection and look to see if events are queued */
X11_XFlush ( display ) ;
if ( X11_XEventsQueued ( display , QueuedAlready ) ) {
return ( 1 ) ;
}
/* More drastic measures are required -- see if X is ready to talk */
{
static struct timeval zero_time ; /* static == 0 */
int x11_fd ;
fd_set fdset ;
x11_fd = ConnectionNumber ( display ) ;
FD_ZERO ( & fdset ) ;
FD_SET ( x11_fd , & fdset ) ;
if ( select ( x11_fd + 1 , & fdset , NULL , NULL , & zero_time ) = = 1 ) {
return ( X11_XPending ( display ) ) ;
}
}
/* Oh well, nothing is ready .. */
return ( 0 ) ;
}
void
X11_PumpEvents ( _THIS )
{
SDL_VideoData * data = ( SDL_VideoData * ) _this - > driverdata ;
if ( data - > last_mode_change_deadline ) {
if ( SDL_TICKS_PASSED ( SDL_GetTicks ( ) , data - > last_mode_change_deadline ) ) {
data - > last_mode_change_deadline = 0 ; /* assume we're done. */
}
}
/* Update activity every 30 seconds to prevent screensaver */
if ( _this - > suspend_screensaver ) {
const Uint32 now = SDL_GetTicks ( ) ;
if ( ! data - > screensaver_activity | |
SDL_TICKS_PASSED ( now , data - > screensaver_activity + 30000 ) ) {
X11_XResetScreenSaver ( data - > display ) ;
# if SDL_USE_LIBDBUS
SDL_DBus_ScreensaverTickle ( ) ;
# endif
data - > screensaver_activity = now ;
}
}
/* Keep processing pending events */
while ( X11_Pending ( data - > display ) ) {
X11_DispatchEvent ( _this ) ;
}
2016-10-08 03:57:40 +02:00
# ifdef SDL_USE_IME
2015-06-21 17:33:46 +02:00
if ( SDL_GetEventState ( SDL_TEXTINPUT ) = = SDL_ENABLE ) {
2016-10-08 03:57:40 +02:00
SDL_IME_PumpEvents ( ) ;
2015-06-21 17:33:46 +02:00
}
# endif
/* FIXME: Only need to do this when there are pending focus changes */
X11_HandleFocusChanges ( _this ) ;
}
void
X11_SuspendScreenSaver ( _THIS )
{
# if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
SDL_VideoData * data = ( SDL_VideoData * ) _this - > driverdata ;
int dummy ;
int major_version , minor_version ;
# endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
# if SDL_USE_LIBDBUS
if ( SDL_DBus_ScreensaverInhibit ( _this - > suspend_screensaver ) ) {
return ;
}
if ( _this - > suspend_screensaver ) {
SDL_DBus_ScreensaverTickle ( ) ;
}
# endif
# if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
if ( SDL_X11_HAVE_XSS ) {
/* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
if ( ! X11_XScreenSaverQueryExtension ( data - > display , & dummy , & dummy ) | |
! X11_XScreenSaverQueryVersion ( data - > display ,
& major_version , & minor_version ) | |
major_version < 1 | | ( major_version = = 1 & & minor_version < 1 ) ) {
return ;
}
X11_XScreenSaverSuspend ( data - > display , _this - > suspend_screensaver ) ;
X11_XResetScreenSaver ( data - > display ) ;
}
# endif
}
# endif /* SDL_VIDEO_DRIVER_X11 */
/* vi: set ts=4 sw=4 expandtab: */