Modifies WaitEvent and WaitEventTimeout to actually wait instead of polling

When possible use native os functions to make a blocking call waiting for
an incoming event. Previous behavior was to continuously poll the event
queue with a small delay between each poll.

The blocking call uses a new optional video driver event,
WaitEventTimeout, if available. It is called only if an window
already shown is available. If present the window is designated
using the variable wakeup_window to receive a wakeup event if
needed.

The WaitEventTimeout function accept a timeout parameter. If
positive the call will wait for an event or return if the timeout
expired without any event. If the timeout is zero it will
implement a polling behavior. If the timeout is negative the
function will block indefinetely waiting for an event.

To let the main thread sees events sent form a different thread
a "wake-up" signal is sent to the main thread if the main thread
is in a blocking state. The wake-up event is sent to the designated
wakeup_window if present.

The wake-up event is sent only if the PushEvent call is coming
from a different thread. Before sending the wake-up event
the ID of the thread making the blocking call is saved using the
variable blocking_thread_id and it is compared to the current
thread's id to decide if the wake-up event should be sent.

Two new optional video device methods are introduced:

WaitEventTimeout
SendWakeupEvent

in addition the mutex

wakeup_lock

which is defined and initialized but only for the drivers supporting the
methods above.

If the methods are not present the system behaves as previously
performing a periodic polling of the events queue.

The blocking call is disabled if a joystick or sensor is detected
and falls back to previous behavior.
This commit is contained in:
Francesco Abbate 2021-03-12 21:58:20 +01:00 committed by Sam Lantinga
parent 40e5ce7fe5
commit 0dd7024d55
16 changed files with 716 additions and 132 deletions

View file

@ -759,6 +759,80 @@ SDL_PollEvent(SDL_Event * event)
return SDL_WaitEventTimeout(event, 0);
}
static int
SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event, int timeout)
{
/* Release any keys held down from last frame */
SDL_ReleaseAutoReleaseKeys();
for (;;) {
if (!_this->wakeup_lock || SDL_LockMutex(_this->wakeup_lock) == 0) {
int status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
/* If status == 0 we are going to block so wakeup will be needed. */
if (status == 0) {
_this->wakeup_window = wakeup_window;
_this->blocking_thread_id = SDL_ThreadID();
} else {
_this->wakeup_window = NULL;
_this->blocking_thread_id = 0;
}
if (_this->wakeup_lock) {
SDL_UnlockMutex(_this->wakeup_lock);
}
if (status < 0) {
/* Got an error: return */
break;
}
if (status > 0) {
/* There is an event, we can return. */
SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */
return 1;
}
/* No events found in the queue, call WaitEventTimeout to wait for an event. */
status = _this->WaitEventTimeout(_this, timeout);
/* Set wakeup_window to NULL without holding the lock. */
_this->wakeup_window = NULL;
if (status <= 0) {
/* There is either an error or the timeout is elapsed: return */
return 0;
}
/* An event was found and pumped into the SDL events queue. Continue the loop
to let SDL_PeepEvents pick it up .*/
}
}
return 0;
}
static int
SDL_events_need_polling() {
SDL_bool need_polling = SDL_FALSE;
#if !SDL_JOYSTICK_DISABLED
need_polling = \
(!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY)) \
&& (SDL_NumJoysticks() > 0);
#endif
#if !SDL_SENSOR_DISABLED
need_polling = need_polling || (!SDL_disabled_events[SDL_SENSORUPDATE >> 8] && \
(SDL_NumSensors() > 0));
#endif
return need_polling;
}
static SDL_Window *
SDL_find_active_window(SDL_VideoDevice * _this)
{
SDL_Window *window;
for (window = _this->windows; window; window = window->next) {
if (!window->is_destroying) {
return window;
}
}
return NULL;
}
int
SDL_WaitEvent(SDL_Event * event)
{
@ -768,11 +842,24 @@ SDL_WaitEvent(SDL_Event * event)
int
SDL_WaitEventTimeout(SDL_Event * event, int timeout)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
SDL_bool need_polling = SDL_events_need_polling();
SDL_Window *wakeup_window = NULL;
Uint32 expiration = 0;
if (timeout > 0)
expiration = SDL_GetTicks() + timeout;
if (!need_polling && _this) {
/* Look if a shown window is available to send the wakeup event. */
wakeup_window = SDL_find_active_window(_this);
need_polling = (wakeup_window == NULL);
}
if (!need_polling && _this && _this->WaitEventTimeout && _this->SendWakeupEvent) {
return SDL_WaitEventTimeout_Device(_this, wakeup_window, event, timeout);
}
for (;;) {
SDL_PumpEvents();
switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
@ -796,6 +883,24 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout)
}
}
static int
SDL_SendWakeupEvent()
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (!_this || !_this->SendWakeupEvent) {
return 0;
}
if (!_this->wakeup_lock || SDL_LockMutex(_this->wakeup_lock) == 0) {
if (_this->wakeup_window && _this->blocking_thread_id != 0 && _this->blocking_thread_id != SDL_ThreadID()) {
_this->SendWakeupEvent(_this, _this->wakeup_window);
}
if (_this->wakeup_lock) {
SDL_UnlockMutex(_this->wakeup_lock);
}
}
return 0;
}
int
SDL_PushEvent(SDL_Event * event)
{
@ -845,6 +950,7 @@ SDL_PushEvent(SDL_Event * event)
return -1;
}
SDL_SendWakeupEvent();
SDL_GestureProcessEvent(event);
return 1;

View file

@ -290,6 +290,8 @@ struct SDL_VideoDevice
/*
* Event manager functions
*/
int (*WaitEventTimeout) (_THIS, int timeout);
void (*SendWakeupEvent) (_THIS, SDL_Window *window);
void (*PumpEvents) (_THIS);
/* Suspend the screensaver */
@ -324,6 +326,9 @@ struct SDL_VideoDevice
/* Data common to all drivers */
SDL_bool is_dummy;
SDL_bool suspend_screensaver;
SDL_Window *wakeup_window;
SDL_threadID blocking_thread_id;
SDL_mutex *wakeup_lock; /* Initialized only if WaitEventTimeout/SendWakeupEvent are supported */
int num_displays;
SDL_VideoDisplay *displays;
SDL_Window *windows;

View file

@ -25,6 +25,8 @@
extern void Cocoa_RegisterApp(void);
extern void Cocoa_PumpEvents(_THIS);
extern int Cocoa_WaitEventTimeout(_THIS, int timeout);
extern void Cocoa_SendWakeupEvent(_THIS, SDL_Window *window);
extern void Cocoa_SuspendScreenSaver(_THIS);
#endif /* SDL_cocoaevents_h_ */

View file

@ -512,9 +512,8 @@ Cocoa_RegisterApp(void)
}
}}
void
Cocoa_PumpEvents(_THIS)
{ @autoreleasepool
int
Cocoa_PumpEventsUntilDate(_THIS, NSDate *expiration, bool accumulate)
{
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
/* Update activity every 30 seconds to prevent screensaver */
@ -530,9 +529,9 @@ Cocoa_PumpEvents(_THIS)
#endif
for ( ; ; ) {
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES ];
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:expiration inMode:NSDefaultRunLoopMode dequeue:YES ];
if ( event == nil ) {
break;
return 0;
}
if (!s_bShouldHandleEventsInSDLApplication) {
@ -541,7 +540,52 @@ Cocoa_PumpEvents(_THIS)
// Pass events down to SDLApplication to be handled in sendEvent:
[NSApp sendEvent:event];
if ( !accumulate) {
break;
}
}
return 1;
}
int
Cocoa_WaitEventTimeout(_THIS, int timeout)
{ @autoreleasepool
{
if (timeout > 0) {
NSDate *limitDate = [NSDate dateWithTimeIntervalSinceNow: (double) timeout / 1000.0];
return Cocoa_PumpEventsUntilDate(_this, limitDate, false);
} else if (timeout == 0) {
return Cocoa_PumpEventsUntilDate(_this, [NSDate distantPast], false);
} else {
while (Cocoa_PumpEventsUntilDate(_this, [NSDate distantFuture], false) == 0) {
}
}
return 1;
}}
void
Cocoa_PumpEvents(_THIS)
{ @autoreleasepool
{
Cocoa_PumpEventsUntilDate(_this, [NSDate distantPast], true);
}}
void Cocoa_SendWakeupEvent(_THIS, SDL_Window *window)
{ @autoreleasepool
{
NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
NSEvent* event = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
location: NSMakePoint(0,0)
modifierFlags: 0
timestamp: 0.0
windowNumber: nswindow.windowNumber
context: nil
subtype: 0
data1: 0
data2: 0];
[NSApp postEvent: event atStart: YES];
}}
void

View file

@ -38,6 +38,9 @@ static void Cocoa_VideoQuit(_THIS);
static void
Cocoa_DeleteDevice(SDL_VideoDevice * device)
{
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->driverdata);
SDL_free(device);
}
@ -63,6 +66,7 @@ Cocoa_CreateDevice(int devindex)
return NULL;
}
device->driverdata = data;
device->wakeup_lock = SDL_CreateMutex();
/* Set the function pointers */
device->VideoInit = Cocoa_VideoInit;
@ -73,6 +77,8 @@ Cocoa_CreateDevice(int devindex)
device->GetDisplayModes = Cocoa_GetDisplayModes;
device->SetDisplayMode = Cocoa_SetDisplayMode;
device->PumpEvents = Cocoa_PumpEvents;
device->WaitEventTimeout = Cocoa_WaitEventTimeout;
device->SendWakeupEvent = Cocoa_SendWakeupEvent;
device->SuspendScreenSaver = Cocoa_SuspendScreenSaver;
device->CreateSDLWindow = Cocoa_CreateWindow;

View file

@ -1276,6 +1276,45 @@ void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
g_WindowsMessageHookData = userdata;
}
int
WIN_WaitEventTimeout(_THIS, int timeout)
{
MSG msg;
if (g_WindowsEnableMessageLoop) {
BOOL message_result;
UINT_PTR timer_id = 0;
if (timeout > 0) {
timer_id = SetTimer(NULL, 0, timeout, NULL);
message_result = GetMessage(&msg, 0, 0, 0);
KillTimer(NULL, timer_id);
} else if (timeout == 0) {
message_result = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
} else {
message_result = GetMessage(&msg, 0, 0, 0);
}
if (message_result) {
if (msg.message == WM_TIMER && msg.hwnd == NULL && msg.wParam == timer_id) {
return 0;
}
if (g_WindowsMessageHook) {
g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
/* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */
TranslateMessage(&msg);
DispatchMessage(&msg);
return 1;
}
}
return 0;
}
void
WIN_SendWakeupEvent(_THIS, SDL_Window *window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
PostMessage(data->hwnd, data->videodata->_SDL_WAKEUP, 0, 0);
}
void
WIN_PumpEvents(_THIS)
{

View file

@ -31,6 +31,8 @@ extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lP
extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam);
extern void WIN_PumpEvents(_THIS);
extern void WIN_SendWakeupEvent(_THIS, SDL_Window *window);
extern int WIN_WaitEventTimeout(_THIS, int timeout);
#endif /* SDL_windowsevents_h_ */

View file

@ -87,7 +87,9 @@ WIN_DeleteDevice(SDL_VideoDevice * device)
if (data->shcoreDLL) {
SDL_UnloadObject(data->shcoreDLL);
}
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->driverdata);
SDL_free(device);
}
@ -113,6 +115,7 @@ WIN_CreateDevice(int devindex)
return NULL;
}
device->driverdata = data;
device->wakeup_lock = SDL_CreateMutex();
data->userDLL = SDL_LoadObject("USER32.DLL");
if (data->userDLL) {
@ -139,6 +142,8 @@ WIN_CreateDevice(int devindex)
device->GetDisplayModes = WIN_GetDisplayModes;
device->SetDisplayMode = WIN_SetDisplayMode;
device->PumpEvents = WIN_PumpEvents;
device->WaitEventTimeout = WIN_WaitEventTimeout;
device->SendWakeupEvent = WIN_SendWakeupEvent;
device->SuspendScreenSaver = WIN_SuspendScreenSaver;
device->CreateSDLWindow = WIN_CreateWindow;
@ -226,6 +231,8 @@ VideoBootStrap WINDOWS_bootstrap = {
int
WIN_VideoInit(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
if (WIN_InitModes(_this) < 0) {
return -1;
}
@ -236,6 +243,8 @@ WIN_VideoInit(_THIS)
SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL);
SDL_AddHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL);
data->_SDL_WAKEUP = RegisterWindowMessageA("_SDL_WAKEUP");
return 0;
}

View file

@ -190,6 +190,7 @@ typedef struct SDL_VideoData
TSFSink *ime_ippasink;
BYTE pre_hook_key_state[256];
UINT _SDL_WAKEUP;
} SDL_VideoData;
extern SDL_bool g_WindowsEnableMessageLoop;

View file

@ -670,42 +670,35 @@ isReparentNotify(Display *display, XEvent *ev, XPointer arg)
}
static void
X11_DispatchEvent(_THIS)
X11_DispatchEvent(_THIS, XEvent *xevent)
{
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
XkbEvent* xkbEvent = (XkbEvent*) xevent;
Display *display;
SDL_WindowData *data;
XEvent xevent;
XkbEvent* xkbEvent;
int orig_event_type;
KeyCode orig_keycode;
XClientMessageEvent m;
int i;
if (!videodata) {
return;
}
SDL_assert(videodata != NULL);
display = videodata->display;
SDL_zero(xevent); /* valgrind fix. --ryan. */
X11_XNextEvent(display, &xevent);
xkbEvent = (XkbEvent*) &xevent;
/* Save the original keycode for dead keys, which are filtered out by
the XFilterEvent() call below.
*/
orig_event_type = xevent.type;
orig_event_type = xevent->type;
if (orig_event_type == KeyPress || orig_event_type == KeyRelease) {
orig_keycode = xevent.xkey.keycode;
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 (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);
xevent->type, xevent->xany.display, xevent->xany.window);
#endif
/* Make sure dead key press/release events are sent */
/* But only if we're using one of the DBus IMEs, otherwise
@ -714,7 +707,7 @@ X11_DispatchEvent(_THIS)
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX)
SDL_Scancode scancode = videodata->key_layout[orig_keycode];
videodata->filter_code = orig_keycode;
videodata->filter_time = xevent.xkey.time;
videodata->filter_time = xevent->xkey.time;
if (orig_event_type == KeyPress) {
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
@ -727,8 +720,8 @@ X11_DispatchEvent(_THIS)
}
#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
if(xevent.type == GenericEvent) {
X11_HandleGenericEvent(videodata, &xevent);
if(xevent->type == GenericEvent) {
X11_HandleGenericEvent(videodata, xevent);
return;
}
#endif
@ -739,18 +732,18 @@ X11_DispatchEvent(_THIS)
SDL_VERSION(&wmmsg.version);
wmmsg.subsystem = SDL_SYSWM_X11;
wmmsg.msg.x11.event = xevent;
wmmsg.msg.x11.event = *xevent;
SDL_SendSysWMEvent(&wmmsg);
}
#if 0
printf("type = %d display = %d window = %d\n",
xevent.type, xevent.xany.display, xevent.xany.window);
xevent->type, xevent->xany.display, xevent->xany.window);
#endif
if ((videodata->clipboard_window != None) &&
(videodata->clipboard_window == xevent.xany.window)) {
X11_HandleClipboardEvent(_this, &xevent);
(videodata->clipboard_window == xevent->xany.window)) {
X11_HandleClipboardEvent(_this, xevent);
return;
}
@ -758,7 +751,7 @@ X11_DispatchEvent(_THIS)
if (videodata && videodata->windowlist) {
for (i = 0; i < videodata->numwindows; ++i) {
if ((videodata->windowlist[i] != NULL) &&
(videodata->windowlist[i]->xwindow == xevent.xany.window)) {
(videodata->windowlist[i]->xwindow == xevent->xany.window)) {
data = videodata->windowlist[i];
break;
}
@ -766,19 +759,19 @@ X11_DispatchEvent(_THIS)
}
if (!data) {
/* The window for KeymapNotify, etc events is 0 */
if (xevent.type == KeymapNotify) {
if (xevent->type == KeymapNotify) {
if (SDL_GetKeyboardFocus() != NULL) {
X11_ReconcileKeyboardState(_this);
}
} else if (xevent.type == MappingNotify || xkbEvent->any.xkb_type == XkbStateNotify) {
} else if (xevent->type == MappingNotify || xkbEvent->any.xkb_type == XkbStateNotify) {
/* Has the keyboard layout changed? */
const int request = xevent.xmapping.request;
const int request = xevent->xmapping.request;
#ifdef DEBUG_XEVENTS
printf("window %p: MappingNotify!\n", data);
#endif
if ((request == MappingKeyboard) || (request == MappingModifier)) {
X11_XRefreshKeyboardMapping(&xevent.xmapping);
X11_XRefreshKeyboardMapping(&xevent->xmapping);
}
X11_UpdateKeymap(_this);
@ -787,28 +780,28 @@ X11_DispatchEvent(_THIS)
return;
}
switch (xevent.type) {
switch (xevent->type) {
/* Gaining mouse coverage? */
case EnterNotify:{
SDL_Mouse *mouse = SDL_GetMouse();
#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)
xevent->xcrossing.x,
xevent->xcrossing.y,
xevent->xcrossing.mode);
if (xevent->xcrossing.mode == NotifyGrab)
printf("Mode: NotifyGrab\n");
if (xevent.xcrossing.mode == NotifyUngrab)
if (xevent->xcrossing.mode == NotifyUngrab)
printf("Mode: NotifyUngrab\n");
#endif
SDL_SetMouseFocus(data->window);
mouse->last_x = xevent.xcrossing.x;
mouse->last_y = xevent.xcrossing.y;
mouse->last_x = xevent->xcrossing.x;
mouse->last_y = xevent->xcrossing.y;
if (!mouse->relative_mode) {
SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
SDL_SendMouseMotion(data->window, 0, 0, xevent->xcrossing.x, xevent->xcrossing.y);
}
/* We ungrab in LeaveNotify, so we may need to grab again here */
@ -819,21 +812,21 @@ X11_DispatchEvent(_THIS)
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)
xevent->xcrossing.x,
xevent->xcrossing.y,
xevent->xcrossing.mode);
if (xevent->xcrossing.mode == NotifyGrab)
printf("Mode: NotifyGrab\n");
if (xevent.xcrossing.mode == NotifyUngrab)
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);
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) {
if (xevent->xcrossing.mode != NotifyGrab &&
xevent->xcrossing.mode != NotifyUngrab &&
xevent->xcrossing.detail != NotifyInferior) {
/* In order for interaction with the window decorations and menu to work properly
on Mutter, we need to ungrab the keyboard when the the mouse leaves. */
@ -848,7 +841,7 @@ X11_DispatchEvent(_THIS)
/* Gaining input focus? */
case FocusIn:{
if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
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);
@ -856,7 +849,7 @@ X11_DispatchEvent(_THIS)
break;
}
if (xevent.xfocus.detail == NotifyInferior || xevent.xfocus.detail == NotifyPointer) {
if (xevent->xfocus.detail == NotifyInferior || xevent->xfocus.detail == NotifyPointer) {
#ifdef DEBUG_XEVENTS
printf("window %p: FocusIn (NotifyInferior/NotifyPointer, ignoring)\n", data);
#endif
@ -882,14 +875,14 @@ X11_DispatchEvent(_THIS)
/* Losing input focus? */
case FocusOut:{
if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
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 || xevent.xfocus.detail == NotifyPointer) {
if (xevent->xfocus.detail == NotifyInferior || xevent->xfocus.detail == NotifyPointer) {
/* We still have focus if a child gets focus. We also don't
care about the position of the pointer when the keyboard
focus changed. */
@ -917,20 +910,20 @@ X11_DispatchEvent(_THIS)
/* Key press? */
case KeyPress:{
KeyCode keycode = xevent.xkey.keycode;
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);
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);
keysym = X11_KeyCodeToSym(_this, keycode, xevent.xkey.state >> 13);
keysym = X11_KeyCodeToSym(_this, keycode, xevent->xkey.state >> 13);
fprintf(stderr,
"The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL forums/mailing list <https://discourse.libsdl.org/> X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n",
keycode, keycode - min_keycode, keysym,
@ -941,13 +934,13 @@ X11_DispatchEvent(_THIS)
SDL_zeroa(text);
#ifdef X_HAVE_UTF8_STRING
if (data->ic) {
X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
X11_Xutf8LookupString(data->ic, &xevent->xkey, text, sizeof(text),
&keysym, &status);
} else {
X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
X11_XLookupString(&xevent->xkey, text, sizeof(text), &keysym, NULL);
}
#else
X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
X11_XLookupString(&xevent->xkey, text, sizeof(text), &keysym, NULL);
#endif
#ifdef SDL_USE_IME
@ -957,7 +950,7 @@ X11_DispatchEvent(_THIS)
#endif
if (!handled_by_ime) {
/* 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) {
if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) {
SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
}
if(*text) {
@ -965,18 +958,18 @@ X11_DispatchEvent(_THIS)
}
}
X11_UpdateUserTime(data, xevent.xkey.time);
X11_UpdateUserTime(data, xevent->xkey.time);
}
break;
/* Key release? */
case KeyRelease:{
KeyCode keycode = xevent.xkey.keycode;
KeyCode keycode = xevent->xkey.keycode;
#ifdef DEBUG_XEVENTS
printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode);
#endif
if (X11_KeyRepeat(display, &xevent)) {
if (X11_KeyRepeat(display, xevent)) {
/* We're about to get a repeated key down, ignore the key up */
break;
}
@ -992,8 +985,8 @@ X11_DispatchEvent(_THIS)
printf("window %p: UnmapNotify!\n", data);
#endif
if (X11_XCheckIfEvent(display, &ev, &isReparentNotify, (XPointer)&xevent.xunmap)) {
X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&xevent.xunmap);
if (X11_XCheckIfEvent(display, &ev, &isReparentNotify, (XPointer)&xevent->xunmap)) {
X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&xevent->xunmap);
} else {
X11_DispatchUnmapNotify(data);
}
@ -1013,27 +1006,27 @@ X11_DispatchEvent(_THIS)
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);
xevent->xconfigure.x, xevent->xconfigure.y,
xevent->xconfigure.width, xevent->xconfigure.height);
#endif
/* Real configure notify events are relative to the parent, synthetic events are absolute. */
if (!xevent.xconfigure.send_event) {
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,
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);
}
if (xevent.xconfigure.x != data->last_xconfigure.x ||
xevent.xconfigure.y != data->last_xconfigure.y) {
if (xevent->xconfigure.x != data->last_xconfigure.x ||
xevent->xconfigure.y != data->last_xconfigure.y) {
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
xevent.xconfigure.x, xevent.xconfigure.y);
xevent->xconfigure.x, xevent->xconfigure.y);
#ifdef SDL_USE_IME
if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
/* Update IME candidate list position */
@ -1041,13 +1034,13 @@ X11_DispatchEvent(_THIS)
}
#endif
}
if (xevent.xconfigure.width != data->last_xconfigure.width ||
xevent.xconfigure.height != data->last_xconfigure.height) {
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);
xevent->xconfigure.width,
xevent->xconfigure.height);
}
data->last_xconfigure = xevent.xconfigure;
data->last_xconfigure = xevent->xconfigure;
}
break;
@ -1056,11 +1049,11 @@ X11_DispatchEvent(_THIS)
static int xdnd_version=0;
if (xevent.xclient.message_type == videodata->XdndEnter) {
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);
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);
@ -1076,15 +1069,15 @@ X11_DispatchEvent(_THIS)
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]);
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) {
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];
act = xevent->xclient.data.l[4];
}
printf("Action requested by user is : %s\n", X11_XGetAtomName(display , act));
#endif
@ -1093,8 +1086,8 @@ X11_DispatchEvent(_THIS)
/* reply with status */
memset(&m, 0, sizeof(XClientMessageEvent));
m.type = ClientMessage;
m.display = xevent.xclient.display;
m.window = xevent.xclient.data.l[0];
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;
@ -1103,47 +1096,47 @@ X11_DispatchEvent(_THIS)
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_XSendEvent(display, xevent->xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
X11_XFlush(display);
}
else if(xevent.xclient.message_type == videodata->XdndDrop) {
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.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);
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]);
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)) {
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);
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)) {
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);
@ -1151,9 +1144,9 @@ X11_DispatchEvent(_THIS)
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
break;
}
else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
(xevent.xclient.format == 32) &&
(xevent.xclient.data.l[0] == videodata->WM_TAKE_FOCUS)) {
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);
@ -1167,7 +1160,7 @@ X11_DispatchEvent(_THIS)
/* Do we need to refresh ourselves? */
case Expose:{
#ifdef DEBUG_XEVENTS
printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
printf("window %p: Expose (count = %d)\n", data, xevent->xexpose.count);
#endif
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
}
@ -1177,10 +1170,10 @@ X11_DispatchEvent(_THIS)
SDL_Mouse *mouse = SDL_GetMouse();
if(!mouse->relative_mode || mouse->relative_mode_warp) {
#ifdef DEBUG_MOTION
printf("window %p: X11 motion: %d,%d\n", data, xevent.xmotion.x, xevent.xmotion.y);
printf("window %p: X11 motion: %d,%d\n", data, xevent->xmotion.x, xevent->xmotion.y);
#endif
SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y);
SDL_SendMouseMotion(data->window, 0, 0, xevent->xmotion.x, xevent->xmotion.y);
}
}
break;
@ -1188,15 +1181,15 @@ X11_DispatchEvent(_THIS)
case ButtonPress:{
int xticks = 0, yticks = 0;
#ifdef DEBUG_XEVENTS
printf("window %p: ButtonPress (X11 button = %d)\n", data, xevent.xbutton.button);
printf("window %p: ButtonPress (X11 button = %d)\n", data, xevent->xbutton.button);
#endif
if (X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) {
if (X11_IsWheelEvent(display,xevent,&xticks, &yticks)) {
SDL_SendMouseWheel(data->window, 0, (float) xticks, (float) yticks, SDL_MOUSEWHEEL_NORMAL);
} else {
SDL_bool ignore_click = SDL_FALSE;
int button = xevent.xbutton.button;
int button = xevent->xbutton.button;
if(button == Button1) {
if (ProcessHitTest(_this, data, &xevent)) {
if (ProcessHitTest(_this, data, xevent)) {
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0);
break; /* don't pass this event on to app. */
}
@ -1217,18 +1210,18 @@ X11_DispatchEvent(_THIS)
SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button);
}
}
X11_UpdateUserTime(data, xevent.xbutton.time);
X11_UpdateUserTime(data, xevent->xbutton.time);
}
break;
case ButtonRelease:{
int button = xevent.xbutton.button;
int button = xevent->xbutton.button;
/* The X server sends a Release event for each Press for wheels. Ignore them. */
int xticks = 0, yticks = 0;
#ifdef DEBUG_XEVENTS
printf("window %p: ButtonRelease (X11 button = %d)\n", data, xevent.xbutton.button);
printf("window %p: ButtonRelease (X11 button = %d)\n", data, xevent->xbutton.button);
#endif
if (!X11_IsWheelEvent(display, &xevent, &xticks, &yticks)) {
if (!X11_IsWheelEvent(display, xevent, &xticks, &yticks)) {
if (button > 7) {
/* see explanation at case ButtonPress */
button -= (8-SDL_BUTTON_X1);
@ -1245,13 +1238,13 @@ X11_DispatchEvent(_THIS)
Atom real_type;
unsigned long items_read, items_left;
char *name = X11_XGetAtomName(display, xevent.xproperty.atom);
char *name = X11_XGetAtomName(display, xevent->xproperty.atom);
if (name) {
printf("window %p: PropertyNotify: %s %s time=%lu\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent.xproperty.time);
printf("window %p: PropertyNotify: %s %s time=%lu\n", data, name, (xevent->xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent->xproperty.time);
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);
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;
@ -1323,16 +1316,16 @@ X11_DispatchEvent(_THIS)
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;
data->user_time = xevent->xproperty.time;
}
if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
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 flags = X11_GetNetWMState(_this, xevent->xproperty.window);
const Uint32 changed = flags ^ data->window->flags;
if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) {
@ -1350,7 +1343,7 @@ X11_DispatchEvent(_THIS)
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
}
}
} else if (xevent.xproperty.atom == videodata->XKLAVIER_STATE) {
} 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
@ -1359,7 +1352,7 @@ X11_DispatchEvent(_THIS)
right approach, but it seems to work. */
X11_UpdateKeymap(_this);
SDL_SendKeymapChangedEvent();
} else if (xevent.xproperty.atom == videodata->_NET_FRAME_EXTENTS) {
} else if (xevent->xproperty.atom == videodata->_NET_FRAME_EXTENTS) {
Atom type;
int format;
unsigned long nitems, bytes_after;
@ -1382,10 +1375,10 @@ X11_DispatchEvent(_THIS)
break;
case SelectionNotify: {
Atom target = xevent.xselection.target;
Atom target = xevent->xselection.target;
#ifdef DEBUG_XEVENTS
printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
xevent.xselection.requestor, xevent.xselection.target);
xevent->xselection.requestor, xevent->xselection.target);
#endif
if (target == data->xdnd_req) {
/* read data */
@ -1433,7 +1426,7 @@ X11_DispatchEvent(_THIS)
default:{
#ifdef DEBUG_XEVENTS
printf("window %p: Unhandled event %d\n", data, xevent.type);
printf("window %p: Unhandled event %d\n", data, xevent->type);
#endif
}
break;
@ -1482,10 +1475,79 @@ X11_Pending(Display * display)
return (0);
}
void
X11_SendWakeupEvent(_THIS, SDL_Window *window)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
Display *req_display = data->request_display;
Window xwindow = ((SDL_WindowData *) window->driverdata)->xwindow;
XClientMessageEvent event;
memset(&event, 0, sizeof(XClientMessageEvent));
event.type = ClientMessage;
event.display = req_display;
event.send_event = True;
event.message_type = data->_SDL_WAKEUP;
event.format = 8;
X11_XSendEvent(req_display, xwindow, False, NoEventMask, (XEvent *) &event);
/* XSendEvent returns a status and it could be BadValue or BadWindow. If an
error happens it is an SDL's internal error and there is nothing we can do here. */
X11_XFlush(req_display);
}
int
X11_WaitEventTimeout(_THIS, int timeout)
{
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
Display *display;
XEvent xevent;
if (!videodata) {
return 0;
}
display = videodata->display;
SDL_zero(xevent);
if (timeout == 0) {
if (X11_Pending(display)) {
X11_XNextEvent(display, &xevent);
} else {
return 0;
}
} else if (timeout > 0) {
int display_fd = ConnectionNumber(display);
fd_set readset;
struct timeval tv_timeout;
FD_ZERO(&readset);
FD_SET(display_fd, &readset);
tv_timeout.tv_sec = (timeout / 1000);
tv_timeout.tv_usec = (timeout % 1000) * 1000;
if (select(display_fd + 1, &readset, NULL, NULL, &tv_timeout) > 0) {
X11_XNextEvent(display, &xevent);
} else {
return 0;
}
} else {
X11_XNextEvent(display, &xevent);
}
X11_DispatchEvent(_this, &xevent);
#ifdef SDL_USE_IME
if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
SDL_IME_PumpEvents();
}
#endif
return 1;
}
void
X11_PumpEvents(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
XEvent xevent;
if (data->last_mode_change_deadline) {
if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) {
@ -1508,9 +1570,12 @@ X11_PumpEvents(_THIS)
}
}
SDL_zero(xevent);
/* Keep processing pending events */
while (X11_Pending(data->display)) {
X11_DispatchEvent(_this);
X11_XNextEvent(data->display, &xevent);
X11_DispatchEvent(_this, &xevent);
}
#ifdef SDL_USE_IME

View file

@ -24,6 +24,8 @@
#define SDL_x11events_h_
extern void X11_PumpEvents(_THIS);
extern int X11_WaitEventTimeout(_THIS, int timeout);
extern void X11_SendWakeupEvent(_THIS, SDL_Window *window);
extern void X11_SuspendScreenSaver(_THIS);
#endif /* SDL_x11events_h_ */

View file

@ -105,7 +105,13 @@ X11_DeleteDevice(SDL_VideoDevice * device)
X11_XSetErrorHandler(orig_x11_errhandler);
X11_XCloseDisplay(data->display);
}
if (data->request_display) {
X11_XCloseDisplay(data->request_display);
}
SDL_free(data->windowlist);
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->driverdata);
SDL_free(device);
@ -178,10 +184,22 @@ X11_CreateDevice(int devindex)
return NULL;
}
device->driverdata = data;
device->wakeup_lock = SDL_CreateMutex();
data->global_mouse_changed = SDL_TRUE;
data->display = x11_display;
data->request_display = X11_XOpenDisplay(display);
if (data->request_display == NULL) {
X11_XCloseDisplay(data->display);
SDL_free(device->driverdata);
SDL_free(device);
SDL_X11_UnloadSymbols();
return NULL;
}
device->wakeup_lock = SDL_CreateMutex();
#ifdef X11_DEBUG
X11_XSynchronize(data->display, True);
#endif
@ -201,6 +219,8 @@ X11_CreateDevice(int devindex)
device->SetDisplayMode = X11_SetDisplayMode;
device->SuspendScreenSaver = X11_SuspendScreenSaver;
device->PumpEvents = X11_PumpEvents;
device->WaitEventTimeout = X11_WaitEventTimeout;
device->SendWakeupEvent = X11_SendWakeupEvent;
device->CreateSDLWindow = X11_CreateWindow;
device->CreateSDLWindowFrom = X11_CreateWindowFrom;
@ -403,6 +423,7 @@ X11_VideoInit(_THIS)
GET_ATOM(_NET_WM_USER_TIME);
GET_ATOM(_NET_ACTIVE_WINDOW);
GET_ATOM(_NET_FRAME_EXTENTS);
GET_ATOM(_SDL_WAKEUP);
GET_ATOM(UTF8_STRING);
GET_ATOM(PRIMARY);
GET_ATOM(XdndEnter);

View file

@ -75,6 +75,7 @@
typedef struct SDL_VideoData
{
Display *display;
Display *request_display;
char *classname;
pid_t pid;
XIM im;
@ -111,6 +112,7 @@ typedef struct SDL_VideoData
Atom _NET_WM_USER_TIME;
Atom _NET_ACTIVE_WINDOW;
Atom _NET_FRAME_EXTENTS;
Atom _SDL_WAKEUP;
Atom UTF8_STRING;
Atom PRIMARY;
Atom XdndEnter;

View file

@ -20,6 +20,7 @@ add_definitions(-DHAVE_OPENGL)
endif()
add_executable(checkkeys checkkeys.c)
add_executable(checkkeysthreads checkkeysthreads.c)
add_executable(loopwave loopwave.c)
add_executable(loopwavequeue loopwavequeue.c)
add_executable(testresample testresample.c)

View file

@ -9,6 +9,7 @@ LIBS = @LIBS@
TARGETS = \
checkkeys$(EXE) \
checkkeysthreads$(EXE) \
controllermap$(EXE) \
loopwave$(EXE) \
loopwavequeue$(EXE) \
@ -83,6 +84,9 @@ Makefile: $(srcdir)/Makefile.in
checkkeys$(EXE): $(srcdir)/checkkeys.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
checkkeysthreads$(EXE): $(srcdir)/checkkeysthreads.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
loopwave$(EXE): $(srcdir)/loopwave.c
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)

275
test/checkkeysthreads.c Normal file
View file

@ -0,0 +1,275 @@
/*
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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.
*/
/* Simple program: Loop, watching keystrokes
Note that you need to call SDL_PollEvent() or SDL_WaitEvent() to
pump the event loop and catch keystrokes.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
#include "SDL.h"
int done;
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
static void
quit(int rc)
{
SDL_Quit();
exit(rc);
}
static void
print_string(char **text, size_t *maxlen, const char *fmt, ...)
{
int len;
va_list ap;
va_start(ap, fmt);
len = SDL_vsnprintf(*text, *maxlen, fmt, ap);
if (len > 0) {
*text += len;
if ( ((size_t) len) < *maxlen ) {
*maxlen -= (size_t) len;
} else {
*maxlen = 0;
}
}
va_end(ap);
}
static void
print_modifiers(char **text, size_t *maxlen)
{
int mod;
print_string(text, maxlen, " modifiers:");
mod = SDL_GetModState();
if (!mod) {
print_string(text, maxlen, " (none)");
return;
}
if (mod & KMOD_LSHIFT)
print_string(text, maxlen, " LSHIFT");
if (mod & KMOD_RSHIFT)
print_string(text, maxlen, " RSHIFT");
if (mod & KMOD_LCTRL)
print_string(text, maxlen, " LCTRL");
if (mod & KMOD_RCTRL)
print_string(text, maxlen, " RCTRL");
if (mod & KMOD_LALT)
print_string(text, maxlen, " LALT");
if (mod & KMOD_RALT)
print_string(text, maxlen, " RALT");
if (mod & KMOD_LGUI)
print_string(text, maxlen, " LGUI");
if (mod & KMOD_RGUI)
print_string(text, maxlen, " RGUI");
if (mod & KMOD_NUM)
print_string(text, maxlen, " NUM");
if (mod & KMOD_CAPS)
print_string(text, maxlen, " CAPS");
if (mod & KMOD_MODE)
print_string(text, maxlen, " MODE");
}
static void
PrintModifierState()
{
char message[512];
char *spot;
size_t left;
spot = message;
left = sizeof(message);
print_modifiers(&spot, &left);
SDL_Log("Initial state:%s\n", message);
}
static void
PrintKey(SDL_Keysym * sym, SDL_bool pressed, SDL_bool repeat)
{
char message[512];
char *spot;
size_t left;
spot = message;
left = sizeof(message);
/* Print the keycode, name and state */
if (sym->sym) {
print_string(&spot, &left,
"Key %s: scancode %d = %s, keycode 0x%08X = %s ",
pressed ? "pressed " : "released",
sym->scancode,
SDL_GetScancodeName(sym->scancode),
sym->sym, SDL_GetKeyName(sym->sym));
} else {
print_string(&spot, &left,
"Unknown Key (scancode %d = %s) %s ",
sym->scancode,
SDL_GetScancodeName(sym->scancode),
pressed ? "pressed " : "released");
}
print_modifiers(&spot, &left);
if (repeat) {
print_string(&spot, &left, " (repeat)");
}
SDL_Log("%s\n", message);
fflush(stderr);
}
static void
PrintText(char *eventtype, char *text)
{
char *spot, expanded[1024];
expanded[0] = '\0';
for ( spot = text; *spot; ++spot )
{
size_t length = SDL_strlen(expanded);
SDL_snprintf(expanded + length, sizeof(expanded) - length, "\\x%.2x", (unsigned char)*spot);
}
SDL_Log("%s Text (%s): \"%s%s\"\n", eventtype, expanded, *text == '"' ? "\\" : "", text);
}
void
loop()
{
SDL_Event event;
/* Check for events */
/*SDL_WaitEvent(&event); emscripten does not like waiting*/
fprintf(stderr, "starting loop\n"); fflush(stderr);
// while (SDL_PollEvent(&event)) {
while (!done && SDL_WaitEvent(&event)) {
fprintf(stderr, "got event type: %d\n", event.type); fflush(stderr);
switch (event.type) {
case SDL_KEYDOWN:
case SDL_KEYUP:
PrintKey(&event.key.keysym, (event.key.state == SDL_PRESSED) ? SDL_TRUE : SDL_FALSE, (event.key.repeat) ? SDL_TRUE : SDL_FALSE);
break;
case SDL_TEXTEDITING:
PrintText("EDIT", event.text.text);
break;
case SDL_TEXTINPUT:
PrintText("INPUT", event.text.text);
break;
case SDL_MOUSEBUTTONDOWN:
/* Left button quits the app, other buttons toggles text input */
fprintf(stderr, "mouse button down button: %d (LEFT=%d)\n", event.button.button, SDL_BUTTON_LEFT); fflush(stderr);
if (event.button.button == SDL_BUTTON_LEFT) {
done = 1;
} else {
if (SDL_IsTextInputActive()) {
SDL_Log("Stopping text input\n");
SDL_StopTextInput();
} else {
SDL_Log("Starting text input\n");
SDL_StartTextInput();
}
}
break;
case SDL_QUIT:
done = 1;
break;
default:
break;
}
fprintf(stderr, "waiting new event\n"); fflush(stderr);
}
fprintf(stderr, "exiting event loop\n"); fflush(stderr);
#ifdef __EMSCRIPTEN__
if (done) {
emscripten_cancel_main_loop();
}
#endif
}
/* Very simple thread - counts 0 to 9 delaying 50ms between increments */
static int ping_thread(void *ptr)
{
int cnt;
SDL_Event sdlevent;
memset(&sdlevent, 0 , sizeof(SDL_Event));
for (cnt = 0; cnt < 10; ++cnt) {
fprintf(stderr, "sending event (%d/%d) from thread.\n", cnt + 1, 10); fflush(stderr);
sdlevent.type = SDL_KEYDOWN;
sdlevent.key.keysym.sym = SDLK_1;
SDL_PushEvent(&sdlevent);
SDL_Delay(1000 + rand() % 1000);
}
return cnt;
}
int
main(int argc, char *argv[])
{
SDL_Window *window;
/* Enable standard application logging */
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
/* Initialize SDL */
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
return (1);
}
/* Set 640x480 video mode */
window = SDL_CreateWindow("CheckKeys Test",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480, 0);
if (!window) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create 640x480 window: %s\n",
SDL_GetError());
quit(2);
}
#if __IPHONEOS__
/* Creating the context creates the view, which we need to show keyboard */
SDL_GL_CreateContext(window);
#endif
SDL_StartTextInput();
/* Print initial modifier state */
SDL_PumpEvents();
PrintModifierState();
/* Watch keystrokes */
done = 0;
SDL_Thread *thread;
thread = SDL_CreateThread(ping_thread, "PingThread", (void *)NULL);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(loop, 0, 1);
#else
while (!done) {
loop();
}
#endif
SDL_WaitThread(thread, NULL);
SDL_Quit();
return (0);
}
/* vi: set ts=4 sw=4 expandtab: */