SDL 2.0
SDL_x11events.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../../SDL_internal.h"
22
23#if SDL_VIDEO_DRIVER_X11
24
25#include <sys/types.h>
26#include <sys/time.h>
27#include <signal.h>
28#include <unistd.h>
29#include <limits.h> /* For INT_MAX */
30
31#include "SDL_x11video.h"
32#include "SDL_x11touch.h"
33#include "SDL_x11xinput2.h"
34#include "../../core/unix/SDL_poll.h"
35#include "../../events/SDL_events_c.h"
36#include "../../events/SDL_mouse_c.h"
37#include "../../events/SDL_touch_c.h"
38
39#include "SDL_hints.h"
40#include "SDL_timer.h"
41#include "SDL_syswm.h"
42#include "SDL_assert.h"
43
44#include <stdio.h>
45
46/*#define DEBUG_XEVENTS*/
47
48#ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT
49#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
50#endif
51
52#ifndef _NET_WM_MOVERESIZE_SIZE_TOP
53#define _NET_WM_MOVERESIZE_SIZE_TOP 1
54#endif
55
56#ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT
57#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
58#endif
59
60#ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT
61#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
62#endif
63
64#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
65#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
66#endif
67
68#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM
69#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
70#endif
71
72#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
73#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
74#endif
75
76#ifndef _NET_WM_MOVERESIZE_SIZE_LEFT
77#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
78#endif
79
80#ifndef _NET_WM_MOVERESIZE_MOVE
81#define _NET_WM_MOVERESIZE_MOVE 8
82#endif
83
84typedef struct {
85 unsigned char *data;
86 int format, count;
87 Atom type;
88} SDL_x11Prop;
89
90/* Reads property
91 Must call X11_XFree on results
92 */
93static void X11_ReadProperty(SDL_x11Prop *p, Display *disp, Window w, Atom prop)
94{
95 unsigned char *ret=NULL;
96 Atom type;
97 int fmt;
98 unsigned long count;
99 unsigned long bytes_left;
100 int bytes_fetch = 0;
101
102 do {
103 if (ret != 0) X11_XFree(ret);
104 X11_XGetWindowProperty(disp, w, prop, 0, bytes_fetch, False, AnyPropertyType, &type, &fmt, &count, &bytes_left, &ret);
105 bytes_fetch += bytes_left;
106 } while (bytes_left != 0);
107
108 p->data=ret;
109 p->format=fmt;
110 p->count=count;
111 p->type=type;
112}
113
114/* Find text-uri-list in a list of targets and return it's atom
115 if available, else return None */
116static Atom X11_PickTarget(Display *disp, Atom list[], int list_count)
117{
118 Atom request = None;
119 char *name;
120 int i;
121 for (i=0; i < list_count && request == None; i++) {
122 name = X11_XGetAtomName(disp, list[i]);
123 if ((SDL_strcmp("text/uri-list", name) == 0) || (SDL_strcmp("text/plain", name) == 0)) {
124 request = list[i];
125 }
126 X11_XFree(name);
127 }
128 return request;
129}
130
131/* Wrapper for X11_PickTarget for a maximum of three targets, a special
132 case in the Xdnd protocol */
133static Atom X11_PickTargetFromAtoms(Display *disp, Atom a0, Atom a1, Atom a2)
134{
135 int count=0;
136 Atom atom[3];
137 if (a0 != None) atom[count++] = a0;
138 if (a1 != None) atom[count++] = a1;
139 if (a2 != None) atom[count++] = a2;
140 return X11_PickTarget(disp, atom, count);
141}
142
143struct KeyRepeatCheckData
144{
145 XEvent *event;
146 SDL_bool found;
147};
148
149static Bool X11_KeyRepeatCheckIfEvent(Display *display, XEvent *chkev,
150 XPointer arg)
151{
152 struct KeyRepeatCheckData *d = (struct KeyRepeatCheckData *) arg;
153 if (chkev->type == KeyPress &&
154 chkev->xkey.keycode == d->event->xkey.keycode &&
155 chkev->xkey.time - d->event->xkey.time < 2)
156 d->found = SDL_TRUE;
157 return False;
158}
159
160/* Check to see if this is a repeated key.
161 (idea shamelessly lifted from GII -- thanks guys! :)
162 */
163static SDL_bool X11_KeyRepeat(Display *display, XEvent *event)
164{
165 XEvent dummyev;
166 struct KeyRepeatCheckData d;
167 d.event = event;
168 d.found = SDL_FALSE;
169 if (X11_XPending(display))
170 X11_XCheckIfEvent(display, &dummyev, X11_KeyRepeatCheckIfEvent,
171 (XPointer) &d);
172 return d.found;
173}
174
175static SDL_bool
176X11_IsWheelEvent(Display * display,XEvent * event,int * xticks,int * yticks)
177{
178 /* according to the xlib docs, no specific mouse wheel events exist.
179 However, the defacto standard is that the vertical wheel is X buttons
180 4 (up) and 5 (down) and a horizontal wheel is 6 (left) and 7 (right). */
181
182 /* Xlib defines "Button1" through 5, so we just use literals here. */
183 switch (event->xbutton.button) {
184 case 4: *yticks = 1; return SDL_TRUE;
185 case 5: *yticks = -1; return SDL_TRUE;
186 case 6: *xticks = 1; return SDL_TRUE;
187 case 7: *xticks = -1; return SDL_TRUE;
188 default: break;
189 }
190 return SDL_FALSE;
191}
192
193/* Decodes URI escape sequences in string buf of len bytes
194 (excluding the terminating NULL byte) in-place. Since
195 URI-encoded characters take three times the space of
196 normal characters, this should not be an issue.
197
198 Returns the number of decoded bytes that wound up in
199 the buffer, excluding the terminating NULL byte.
200
201 The buffer is guaranteed to be NULL-terminated but
202 may contain embedded NULL bytes.
203
204 On error, -1 is returned.
205 */
206static int X11_URIDecode(char *buf, int len) {
207 int ri, wi, di;
208 char decode = '\0';
209 if (buf == NULL || len < 0) {
210 errno = EINVAL;
211 return -1;
212 }
213 if (len == 0) {
214 len = SDL_strlen(buf);
215 }
216 for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) {
217 if (di == 0) {
218 /* start decoding */
219 if (buf[ri] == '%') {
220 decode = '\0';
221 di += 1;
222 continue;
223 }
224 /* normal write */
225 buf[wi] = buf[ri];
226 wi += 1;
227 continue;
228 } else if (di == 1 || di == 2) {
229 char off = '\0';
230 char isa = buf[ri] >= 'a' && buf[ri] <= 'f';
231 char isA = buf[ri] >= 'A' && buf[ri] <= 'F';
232 char isn = buf[ri] >= '0' && buf[ri] <= '9';
233 if (!(isa || isA || isn)) {
234 /* not a hexadecimal */
235 int sri;
236 for (sri = ri - di; sri <= ri; sri += 1) {
237 buf[wi] = buf[sri];
238 wi += 1;
239 }
240 di = 0;
241 continue;
242 }
243 /* itsy bitsy magicsy */
244 if (isn) {
245 off = 0 - '0';
246 } else if (isa) {
247 off = 10 - 'a';
248 } else if (isA) {
249 off = 10 - 'A';
250 }
251 decode |= (buf[ri] + off) << (2 - di) * 4;
252 if (di == 2) {
253 buf[wi] = decode;
254 wi += 1;
255 di = 0;
256 } else {
257 di += 1;
258 }
259 continue;
260 }
261 }
262 buf[wi] = '\0';
263 return wi;
264}
265
266/* Convert URI to local filename
267 return filename if possible, else NULL
268*/
269static char* X11_URIToLocal(char* uri) {
270 char *file = NULL;
271 SDL_bool local;
272
273 if (memcmp(uri,"file:/",6) == 0) uri += 6; /* local file? */
274 else if (strstr(uri,":/") != NULL) return file; /* wrong scheme */
275
276 local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/');
277
278 /* got a hostname? */
279 if (!local && uri[0] == '/' && uri[2] != '/') {
280 char* hostname_end = strchr(uri+1, '/');
281 if (hostname_end != NULL) {
282 char hostname[ 257 ];
283 if (gethostname(hostname, 255) == 0) {
284 hostname[ 256 ] = '\0';
285 if (memcmp(uri+1, hostname, hostname_end - (uri+1)) == 0) {
286 uri = hostname_end + 1;
287 local = SDL_TRUE;
288 }
289 }
290 }
291 }
292 if (local) {
293 file = uri;
294 /* Convert URI escape sequences to real characters */
295 X11_URIDecode(file, 0);
296 if (uri[1] == '/') {
297 file++;
298 } else {
299 file--;
300 }
301 }
302 return file;
303}
304
305#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
306static void X11_HandleGenericEvent(SDL_VideoData *videodata, XEvent *xev)
307{
308 /* event is a union, so cookie == &event, but this is type safe. */
309 XGenericEventCookie *cookie = &xev->xcookie;
310 if (X11_XGetEventData(videodata->display, cookie)) {
311 X11_HandleXinput2Event(videodata, cookie);
312
313 /* Send a SDL_SYSWMEVENT if the application wants them.
314 * Since event data is only available until XFreeEventData is called,
315 * the *only* way for an application to access it is to register an event filter/watcher
316 * and do all the processing on the SDL_SYSWMEVENT inside the callback. */
318 SDL_SysWMmsg wmmsg;
319
320 SDL_VERSION(&wmmsg.version);
321 wmmsg.subsystem = SDL_SYSWM_X11;
322 wmmsg.msg.x11.event = *xev;
323 SDL_SendSysWMEvent(&wmmsg);
324 }
325
326 X11_XFreeEventData(videodata->display, cookie);
327 }
328}
329#endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */
330
331static unsigned
332X11_GetNumLockModifierMask(_THIS)
333{
335 Display *display = viddata->display;
336 unsigned num_mask = 0;
337 int i, j;
338 XModifierKeymap *xmods;
339 unsigned n;
340
341 xmods = X11_XGetModifierMapping(display);
342 n = xmods->max_keypermod;
343 for(i = 3; i < 8; i++) {
344 for(j = 0; j < n; j++) {
345 KeyCode kc = xmods->modifiermap[i * n + j];
346 if (viddata->key_layout[kc] == SDL_SCANCODE_NUMLOCKCLEAR) {
347 num_mask = 1 << i;
348 break;
349 }
350 }
351 }
352 X11_XFreeModifiermap(xmods);
353
354 return num_mask;
355}
356
357static void
358X11_ReconcileKeyboardState(_THIS)
359{
361 Display *display = viddata->display;
362 char keys[32];
363 int keycode;
364 Window junk_window;
365 int x, y;
366 unsigned int mask;
367 const Uint8 *keyboardState;
368
369 X11_XQueryKeymap(display, keys);
370
371 /* Sync up the keyboard modifier state */
372 if (X11_XQueryPointer(display, DefaultRootWindow(display), &junk_window, &junk_window, &x, &y, &x, &y, &mask)) {
373 SDL_ToggleModState(KMOD_CAPS, (mask & LockMask) != 0);
374 SDL_ToggleModState(KMOD_NUM, (mask & X11_GetNumLockModifierMask(_this)) != 0);
375 }
376
377 keyboardState = SDL_GetKeyboardState(0);
378 for (keycode = 0; keycode < 256; ++keycode) {
379 SDL_Scancode scancode = viddata->key_layout[keycode];
380 SDL_bool x11KeyPressed = (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
381 SDL_bool sdlKeyPressed = keyboardState[scancode] == SDL_PRESSED;
382
383 if (x11KeyPressed && !sdlKeyPressed) {
385 } else if (!x11KeyPressed && sdlKeyPressed) {
387 }
388 }
389}
390
391
392static void
393X11_DispatchFocusIn(_THIS, SDL_WindowData *data)
394{
395#ifdef DEBUG_XEVENTS
396 printf("window %p: Dispatching FocusIn\n", data);
397#endif
398 SDL_SetKeyboardFocus(data->window);
399 X11_ReconcileKeyboardState(_this);
400#ifdef X_HAVE_UTF8_STRING
401 if (data->ic) {
402 X11_XSetICFocus(data->ic);
403 }
404#endif
405#ifdef SDL_USE_IME
407#endif
408}
409
410static void
411X11_DispatchFocusOut(_THIS, SDL_WindowData *data)
412{
413#ifdef DEBUG_XEVENTS
414 printf("window %p: Dispatching FocusOut\n", data);
415#endif
416 /* If another window has already processed a focus in, then don't try to
417 * remove focus here. Doing so will incorrectly remove focus from that
418 * window, and the focus lost event for this window will have already
419 * been dispatched anyway. */
420 if (data->window == SDL_GetKeyboardFocus()) {
422 }
423#ifdef X_HAVE_UTF8_STRING
424 if (data->ic) {
425 X11_XUnsetICFocus(data->ic);
426 }
427#endif
428#ifdef SDL_USE_IME
430#endif
431}
432
433static void
434X11_DispatchMapNotify(SDL_WindowData *data)
435{
438}
439
440static void
441X11_DispatchUnmapNotify(SDL_WindowData *data)
442{
445}
446
447static void
448InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point)
449{
451 SDL_Window* window = data->window;
452 Display *display = viddata->display;
453 XEvent evt;
454
455 /* !!! FIXME: we need to regrab this if necessary when the drag is done. */
456 X11_XUngrabPointer(display, 0L);
457 X11_XFlush(display);
458
459 evt.xclient.type = ClientMessage;
460 evt.xclient.window = data->xwindow;
461 evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
462 evt.xclient.format = 32;
463 evt.xclient.data.l[0] = window->x + point->x;
464 evt.xclient.data.l[1] = window->y + point->y;
465 evt.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
466 evt.xclient.data.l[3] = Button1;
467 evt.xclient.data.l[4] = 0;
468 X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt);
469
470 X11_XSync(display, 0);
471}
472
473static void
474InitiateWindowResize(_THIS, const SDL_WindowData *data, const SDL_Point *point, int direction)
475{
477 SDL_Window* window = data->window;
478 Display *display = viddata->display;
479 XEvent evt;
480
481 if (direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT || direction > _NET_WM_MOVERESIZE_SIZE_LEFT)
482 return;
483
484 /* !!! FIXME: we need to regrab this if necessary when the drag is done. */
485 X11_XUngrabPointer(display, 0L);
486 X11_XFlush(display);
487
488 evt.xclient.type = ClientMessage;
489 evt.xclient.window = data->xwindow;
490 evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
491 evt.xclient.format = 32;
492 evt.xclient.data.l[0] = window->x + point->x;
493 evt.xclient.data.l[1] = window->y + point->y;
494 evt.xclient.data.l[2] = direction;
495 evt.xclient.data.l[3] = Button1;
496 evt.xclient.data.l[4] = 0;
497 X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt);
498
499 X11_XSync(display, 0);
500}
501
502static SDL_bool
503ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev)
504{
505 SDL_Window *window = data->window;
506
507 if (window->hit_test) {
508 const SDL_Point point = { xev->xbutton.x, xev->xbutton.y };
509 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
510 static const int directions[] = {
511 _NET_WM_MOVERESIZE_SIZE_TOPLEFT, _NET_WM_MOVERESIZE_SIZE_TOP,
512 _NET_WM_MOVERESIZE_SIZE_TOPRIGHT, _NET_WM_MOVERESIZE_SIZE_RIGHT,
513 _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT, _NET_WM_MOVERESIZE_SIZE_BOTTOM,
514 _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT, _NET_WM_MOVERESIZE_SIZE_LEFT
515 };
516
517 switch (rc) {
519 InitiateWindowMove(_this, data, &point);
520 return SDL_TRUE;
521
530 InitiateWindowResize(_this, data, &point, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
531 return SDL_TRUE;
532
533 default: return SDL_FALSE;
534 }
535 }
536
537 return SDL_FALSE;
538}
539
540static void
541X11_UpdateUserTime(SDL_WindowData *data, const unsigned long latest)
542{
543 if (latest && (latest != data->user_time)) {
544 SDL_VideoData *videodata = data->videodata;
545 Display *display = videodata->display;
546 X11_XChangeProperty(display, data->xwindow, videodata->_NET_WM_USER_TIME,
547 XA_CARDINAL, 32, PropModeReplace,
548 (const unsigned char *) &latest, 1);
549#ifdef DEBUG_XEVENTS
550 printf("window %p: updating _NET_WM_USER_TIME to %lu\n", data, latest);
551#endif
552 data->user_time = latest;
553 }
554}
555
556static void
557X11_HandleClipboardEvent(_THIS, const XEvent *xevent)
558{
560 Display *display = videodata->display;
561
562 SDL_assert(videodata->clipboard_window != None);
563 SDL_assert(xevent->xany.window == videodata->clipboard_window);
564
565 switch (xevent->type) {
566 /* Copy the selection from our own CUTBUFFER to the requested property */
567 case SelectionRequest: {
568 const XSelectionRequestEvent *req = &xevent->xselectionrequest;
569 XEvent sevent;
570 int seln_format;
571 unsigned long nbytes;
572 unsigned long overflow;
573 unsigned char *seln_data;
574
575#ifdef DEBUG_XEVENTS
576 printf("window CLIPBOARD: SelectionRequest (requestor = %ld, target = %ld)\n",
577 req->requestor, req->target);
578#endif
579
580 SDL_zero(sevent);
581 sevent.xany.type = SelectionNotify;
582 sevent.xselection.selection = req->selection;
583 sevent.xselection.target = None;
584 sevent.xselection.property = None; /* tell them no by default */
585 sevent.xselection.requestor = req->requestor;
586 sevent.xselection.time = req->time;
587
588 /* !!! FIXME: We were probably storing this on the root window
589 because an SDL window might go away...? but we don't have to do
590 this now (or ever, really). */
591 if (X11_XGetWindowProperty(display, DefaultRootWindow(display),
592 X11_GetSDLCutBufferClipboardType(display), 0, INT_MAX/4, False, req->target,
593 &sevent.xselection.target, &seln_format, &nbytes,
594 &overflow, &seln_data) == Success) {
595 /* !!! FIXME: cache atoms */
596 Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
597 if (sevent.xselection.target == req->target) {
598 X11_XChangeProperty(display, req->requestor, req->property,
599 sevent.xselection.target, seln_format, PropModeReplace,
600 seln_data, nbytes);
601 sevent.xselection.property = req->property;
602 } else if (XA_TARGETS == req->target) {
603 Atom SupportedFormats[] = { XA_TARGETS, sevent.xselection.target };
604 X11_XChangeProperty(display, req->requestor, req->property,
605 XA_ATOM, 32, PropModeReplace,
606 (unsigned char*)SupportedFormats,
607 SDL_arraysize(SupportedFormats));
608 sevent.xselection.property = req->property;
609 sevent.xselection.target = XA_TARGETS;
610 }
611 X11_XFree(seln_data);
612 }
613 X11_XSendEvent(display, req->requestor, False, 0, &sevent);
614 X11_XSync(display, False);
615 }
616 break;
617
618 case SelectionNotify: {
619#ifdef DEBUG_XEVENTS
620 printf("window CLIPBOARD: SelectionNotify (requestor = %ld, target = %ld)\n",
621 xevent->xselection.requestor, xevent->xselection.target);
622#endif
623 videodata->selection_waiting = SDL_FALSE;
624 }
625 break;
626
627 case SelectionClear: {
628 /* !!! FIXME: cache atoms */
629 Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
630
631#ifdef DEBUG_XEVENTS
632 printf("window CLIPBOARD: SelectionClear (requestor = %ld, target = %ld)\n",
633 xevent->xselection.requestor, xevent->xselection.target);
634#endif
635
636 if (xevent->xselectionclear.selection == XA_PRIMARY ||
637 (XA_CLIPBOARD != None && xevent->xselectionclear.selection == XA_CLIPBOARD)) {
639 }
640 }
641 break;
642 }
643}
644
645
646static void
647X11_DispatchEvent(_THIS)
648{
650 Display *display;
652 XEvent xevent;
653 int orig_event_type;
654 KeyCode orig_keycode;
655 XClientMessageEvent m;
656 int i;
657
658 if (!videodata) {
659 return;
660 }
661 display = videodata->display;
662
663 SDL_zero(xevent); /* valgrind fix. --ryan. */
664 X11_XNextEvent(display, &xevent);
665
666 /* Save the original keycode for dead keys, which are filtered out by
667 the XFilterEvent() call below.
668 */
669 orig_event_type = xevent.type;
670 if (orig_event_type == KeyPress || orig_event_type == KeyRelease) {
671 orig_keycode = xevent.xkey.keycode;
672 } else {
673 orig_keycode = 0;
674 }
675
676 /* filter events catchs XIM events and sends them to the correct handler */
677 if (X11_XFilterEvent(&xevent, None) == True) {
678#if 0
679 printf("Filtered event type = %d display = %d window = %d\n",
680 xevent.type, xevent.xany.display, xevent.xany.window);
681#endif
682 /* Make sure dead key press/release events are sent */
683 /* But only if we're using one of the DBus IMEs, otherwise
684 some XIM IMEs will generate duplicate events */
685 if (orig_keycode) {
686#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
687 SDL_Scancode scancode = videodata->key_layout[orig_keycode];
688 videodata->filter_code = orig_keycode;
689 videodata->filter_time = xevent.xkey.time;
690
691 if (orig_event_type == KeyPress) {
693 } else {
695 }
696#endif
697 }
698 return;
699 }
700
701#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
702 if(xevent.type == GenericEvent) {
703 X11_HandleGenericEvent(videodata, &xevent);
704 return;
705 }
706#endif
707
708 /* Send a SDL_SYSWMEVENT if the application wants them */
710 SDL_SysWMmsg wmmsg;
711
712 SDL_VERSION(&wmmsg.version);
713 wmmsg.subsystem = SDL_SYSWM_X11;
714 wmmsg.msg.x11.event = xevent;
715 SDL_SendSysWMEvent(&wmmsg);
716 }
717
718#if 0
719 printf("type = %d display = %d window = %d\n",
720 xevent.type, xevent.xany.display, xevent.xany.window);
721#endif
722
723 if ((videodata->clipboard_window != None) &&
724 (videodata->clipboard_window == xevent.xany.window)) {
725 X11_HandleClipboardEvent(_this, &xevent);
726 return;
727 }
728
729 data = NULL;
730 if (videodata && videodata->windowlist) {
731 for (i = 0; i < videodata->numwindows; ++i) {
732 if ((videodata->windowlist[i] != NULL) &&
733 (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
734 data = videodata->windowlist[i];
735 break;
736 }
737 }
738 }
739 if (!data) {
740 /* The window for KeymapNotify, etc events is 0 */
741 if (xevent.type == KeymapNotify) {
742 if (SDL_GetKeyboardFocus() != NULL) {
743 X11_ReconcileKeyboardState(_this);
744 }
745 } else if (xevent.type == MappingNotify) {
746 /* Has the keyboard layout changed? */
747 const int request = xevent.xmapping.request;
748
749#ifdef DEBUG_XEVENTS
750 printf("window %p: MappingNotify!\n", data);
751#endif
752 if ((request == MappingKeyboard) || (request == MappingModifier)) {
753 X11_XRefreshKeyboardMapping(&xevent.xmapping);
754 }
755
758 }
759 return;
760 }
761
762 switch (xevent.type) {
763
764 /* Gaining mouse coverage? */
765 case EnterNotify:{
766 SDL_Mouse *mouse = SDL_GetMouse();
767#ifdef DEBUG_XEVENTS
768 printf("window %p: EnterNotify! (%d,%d,%d)\n", data,
769 xevent.xcrossing.x,
770 xevent.xcrossing.y,
771 xevent.xcrossing.mode);
772 if (xevent.xcrossing.mode == NotifyGrab)
773 printf("Mode: NotifyGrab\n");
774 if (xevent.xcrossing.mode == NotifyUngrab)
775 printf("Mode: NotifyUngrab\n");
776#endif
777 SDL_SetMouseFocus(data->window);
778
779 mouse->last_x = xevent.xcrossing.x;
780 mouse->last_y = xevent.xcrossing.y;
781
782 if (!mouse->relative_mode) {
783 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
784 }
785 }
786 break;
787 /* Losing mouse coverage? */
788 case LeaveNotify:{
789#ifdef DEBUG_XEVENTS
790 printf("window %p: LeaveNotify! (%d,%d,%d)\n", data,
791 xevent.xcrossing.x,
792 xevent.xcrossing.y,
793 xevent.xcrossing.mode);
794 if (xevent.xcrossing.mode == NotifyGrab)
795 printf("Mode: NotifyGrab\n");
796 if (xevent.xcrossing.mode == NotifyUngrab)
797 printf("Mode: NotifyUngrab\n");
798#endif
799 if (!SDL_GetMouse()->relative_mode) {
800 SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
801 }
802
803 if (xevent.xcrossing.mode != NotifyGrab &&
804 xevent.xcrossing.mode != NotifyUngrab &&
805 xevent.xcrossing.detail != NotifyInferior) {
807 }
808 }
809 break;
810
811 /* Gaining input focus? */
812 case FocusIn:{
813 if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
814 /* Someone is handling a global hotkey, ignore it */
815#ifdef DEBUG_XEVENTS
816 printf("window %p: FocusIn (NotifyGrab/NotifyUngrab, ignoring)\n", data);
817#endif
818 break;
819 }
820
821 if (xevent.xfocus.detail == NotifyInferior) {
822#ifdef DEBUG_XEVENTS
823 printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data);
824#endif
825 break;
826 }
827#ifdef DEBUG_XEVENTS
828 printf("window %p: FocusIn!\n", data);
829#endif
830 if (!videodata->last_mode_change_deadline) /* no recent mode changes */
831 {
832 data->pending_focus = PENDING_FOCUS_NONE;
833 data->pending_focus_time = 0;
834 X11_DispatchFocusIn(_this, data);
835 }
836 else
837 {
838 data->pending_focus = PENDING_FOCUS_IN;
839 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME;
840 }
841 data->last_focus_event_time = SDL_GetTicks();
842 }
843 break;
844
845 /* Losing input focus? */
846 case FocusOut:{
847 if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
848 /* Someone is handling a global hotkey, ignore it */
849#ifdef DEBUG_XEVENTS
850 printf("window %p: FocusOut (NotifyGrab/NotifyUngrab, ignoring)\n", data);
851#endif
852 break;
853 }
854 if (xevent.xfocus.detail == NotifyInferior) {
855 /* We still have focus if a child gets focus */
856#ifdef DEBUG_XEVENTS
857 printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data);
858#endif
859 break;
860 }
861#ifdef DEBUG_XEVENTS
862 printf("window %p: FocusOut!\n", data);
863#endif
864 if (!videodata->last_mode_change_deadline) /* no recent mode changes */
865 {
866 data->pending_focus = PENDING_FOCUS_NONE;
867 data->pending_focus_time = 0;
868 X11_DispatchFocusOut(_this, data);
869 }
870 else
871 {
872 data->pending_focus = PENDING_FOCUS_OUT;
873 data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME;
874 }
875 }
876 break;
877
878 /* Key press? */
879 case KeyPress:{
880 KeyCode keycode = xevent.xkey.keycode;
881 KeySym keysym = NoSymbol;
883 Status status = 0;
884 SDL_bool handled_by_ime = SDL_FALSE;
885
886#ifdef DEBUG_XEVENTS
887 printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
888#endif
889#if 1
890 if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
891 int min_keycode, max_keycode;
892 X11_XDisplayKeycodes(display, &min_keycode, &max_keycode);
893 keysym = X11_KeyCodeToSym(_this, keycode, xevent.xkey.state >> 13);
894 fprintf(stderr,
895 "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",
896 keycode, keycode - min_keycode, keysym,
897 X11_XKeysymToString(keysym));
898 }
899#endif
900 /* */
901 SDL_zero(text);
902#ifdef X_HAVE_UTF8_STRING
903 if (data->ic) {
904 X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
905 &keysym, &status);
906 } else {
907 X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
908 }
909#else
910 X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
911#endif
912
913#ifdef SDL_USE_IME
915 handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode);
916 }
917#endif
918 if (!handled_by_ime) {
919 /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
920 if (xevent.xkey.keycode != videodata->filter_code || xevent.xkey.time != videodata->filter_time) {
921 SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
922 }
923 if(*text) {
925 }
926 }
927
928 X11_UpdateUserTime(data, xevent.xkey.time);
929 }
930 break;
931
932 /* Key release? */
933 case KeyRelease:{
934 KeyCode keycode = xevent.xkey.keycode;
935
936#ifdef DEBUG_XEVENTS
937 printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
938#endif
939 if (X11_KeyRepeat(display, &xevent)) {
940 /* We're about to get a repeated key down, ignore the key up */
941 break;
942 }
943 SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
944 }
945 break;
946
947 /* Have we been iconified? */
948 case UnmapNotify:{
949#ifdef DEBUG_XEVENTS
950 printf("window %p: UnmapNotify!\n", data);
951#endif
952 X11_DispatchUnmapNotify(data);
953 }
954 break;
955
956 /* Have we been restored? */
957 case MapNotify:{
958#ifdef DEBUG_XEVENTS
959 printf("window %p: MapNotify!\n", data);
960#endif
961 X11_DispatchMapNotify(data);
962 }
963 break;
964
965 /* Have we been resized or moved? */
966 case ConfigureNotify:{
967#ifdef DEBUG_XEVENTS
968 printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
969 xevent.xconfigure.x, xevent.xconfigure.y,
970 xevent.xconfigure.width, xevent.xconfigure.height);
971#endif
972 /* Real configure notify events are relative to the parent, synthetic events are absolute. */
973 if (!xevent.xconfigure.send_event) {
974 unsigned int NumChildren;
975 Window ChildReturn, Root, Parent;
976 Window * Children;
977 /* Translate these coodinates back to relative to root */
978 X11_XQueryTree(data->videodata->display, xevent.xconfigure.window, &Root, &Parent, &Children, &NumChildren);
979 X11_XTranslateCoordinates(xevent.xconfigure.display,
980 Parent, DefaultRootWindow(xevent.xconfigure.display),
981 xevent.xconfigure.x, xevent.xconfigure.y,
982 &xevent.xconfigure.x, &xevent.xconfigure.y,
983 &ChildReturn);
984 }
985
986 if (xevent.xconfigure.x != data->last_xconfigure.x ||
987 xevent.xconfigure.y != data->last_xconfigure.y) {
989 xevent.xconfigure.x, xevent.xconfigure.y);
990#ifdef SDL_USE_IME
992 /* Update IME candidate list position */
994 }
995#endif
996 }
997 if (xevent.xconfigure.width != data->last_xconfigure.width ||
998 xevent.xconfigure.height != data->last_xconfigure.height) {
1000 xevent.xconfigure.width,
1001 xevent.xconfigure.height);
1002 }
1003 data->last_xconfigure = xevent.xconfigure;
1004 }
1005 break;
1006
1007 /* Have we been requested to quit (or another client message?) */
1008 case ClientMessage:{
1009
1010 static int xdnd_version=0;
1011
1012 if (xevent.xclient.message_type == videodata->XdndEnter) {
1013
1014 SDL_bool use_list = xevent.xclient.data.l[1] & 1;
1015 data->xdnd_source = xevent.xclient.data.l[0];
1016 xdnd_version = (xevent.xclient.data.l[1] >> 24);
1017#ifdef DEBUG_XEVENTS
1018 printf("XID of source window : %ld\n", data->xdnd_source);
1019 printf("Protocol version to use : %d\n", xdnd_version);
1020 printf("More then 3 data types : %d\n", (int) use_list);
1021#endif
1022
1023 if (use_list) {
1024 /* fetch conversion targets */
1025 SDL_x11Prop p;
1026 X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList);
1027 /* pick one */
1028 data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count);
1029 X11_XFree(p.data);
1030 } else {
1031 /* pick from list of three */
1032 data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]);
1033 }
1034 }
1035 else if (xevent.xclient.message_type == videodata->XdndPosition) {
1036
1037#ifdef DEBUG_XEVENTS
1038 Atom act= videodata->XdndActionCopy;
1039 if(xdnd_version >= 2) {
1040 act = xevent.xclient.data.l[4];
1041 }
1042 printf("Action requested by user is : %s\n", X11_XGetAtomName(display , act));
1043#endif
1044
1045
1046 /* reply with status */
1047 memset(&m, 0, sizeof(XClientMessageEvent));
1048 m.type = ClientMessage;
1049 m.display = xevent.xclient.display;
1050 m.window = xevent.xclient.data.l[0];
1051 m.message_type = videodata->XdndStatus;
1052 m.format=32;
1053 m.data.l[0] = data->xwindow;
1054 m.data.l[1] = (data->xdnd_req != None);
1055 m.data.l[2] = 0; /* specify an empty rectangle */
1056 m.data.l[3] = 0;
1057 m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */
1058
1059 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
1060 X11_XFlush(display);
1061 }
1062 else if(xevent.xclient.message_type == videodata->XdndDrop) {
1063 if (data->xdnd_req == None) {
1064 /* say again - not interested! */
1065 memset(&m, 0, sizeof(XClientMessageEvent));
1066 m.type = ClientMessage;
1067 m.display = xevent.xclient.display;
1068 m.window = xevent.xclient.data.l[0];
1069 m.message_type = videodata->XdndFinished;
1070 m.format=32;
1071 m.data.l[0] = data->xwindow;
1072 m.data.l[1] = 0;
1073 m.data.l[2] = None; /* fail! */
1074 X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
1075 } else {
1076 /* convert */
1077 if(xdnd_version >= 1) {
1078 X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]);
1079 } else {
1080 X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime);
1081 }
1082 }
1083 }
1084 else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
1085 (xevent.xclient.format == 32) &&
1086 (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
1087 Window root = DefaultRootWindow(display);
1088
1089#ifdef DEBUG_XEVENTS
1090 printf("window %p: _NET_WM_PING\n", data);
1091#endif
1092 xevent.xclient.window = root;
1093 X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
1094 break;
1095 }
1096
1097 else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
1098 (xevent.xclient.format == 32) &&
1099 (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
1100
1101#ifdef DEBUG_XEVENTS
1102 printf("window %p: WM_DELETE_WINDOW\n", data);
1103#endif
1105 break;
1106 }
1107 else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
1108 (xevent.xclient.format == 32) &&
1109 (xevent.xclient.data.l[0] == videodata->WM_TAKE_FOCUS)) {
1110
1111#ifdef DEBUG_XEVENTS
1112 printf("window %p: WM_TAKE_FOCUS\n", data);
1113#endif
1115 break;
1116 }
1117 }
1118 break;
1119
1120 /* Do we need to refresh ourselves? */
1121 case Expose:{
1122#ifdef DEBUG_XEVENTS
1123 printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
1124#endif
1126 }
1127 break;
1128
1129 case MotionNotify:{
1130 SDL_Mouse *mouse = SDL_GetMouse();
1131 if(!mouse->relative_mode || mouse->relative_mode_warp) {
1132#ifdef DEBUG_MOTION
1133 printf("window %p: X11 motion: %d,%d\n", data, xevent.xmotion.x, xevent.xmotion.y);
1134#endif
1135
1136 SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y);
1137 }
1138 }
1139 break;
1140
1141 case ButtonPress:{
1142 int xticks = 0, yticks = 0;
1143#ifdef DEBUG_XEVENTS
1144 printf("window %p: ButtonPress (X11 button = %d)\n", data, xevent.xbutton.button);
1145#endif
1146 if (X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) {
1147 SDL_SendMouseWheel(data->window, 0, (float) xticks, (float) yticks, SDL_MOUSEWHEEL_NORMAL);
1148 } else {
1149 SDL_bool ignore_click = SDL_FALSE;
1150 int button = xevent.xbutton.button;
1151 if(button == Button1) {
1152 if (ProcessHitTest(_this, data, &xevent)) {
1154 break; /* don't pass this event on to app. */
1155 }
1156 }
1157 else if(button > 7) {
1158 /* X button values 4-7 are used for scrolling, so X1 is 8, X2 is 9, ...
1159 => subtract (8-SDL_BUTTON_X1) to get value SDL expects */
1160 button -= (8-SDL_BUTTON_X1);
1161 }
1162 if (data->last_focus_event_time) {
1163 const int X11_FOCUS_CLICK_TIMEOUT = 10;
1164 if (!SDL_TICKS_PASSED(SDL_GetTicks(), data->last_focus_event_time + X11_FOCUS_CLICK_TIMEOUT)) {
1166 }
1167 data->last_focus_event_time = 0;
1168 }
1169 if (!ignore_click) {
1171 }
1172 }
1173 X11_UpdateUserTime(data, xevent.xbutton.time);
1174 }
1175 break;
1176
1177 case ButtonRelease:{
1178 int button = xevent.xbutton.button;
1179 /* The X server sends a Release event for each Press for wheels. Ignore them. */
1180 int xticks = 0, yticks = 0;
1181#ifdef DEBUG_XEVENTS
1182 printf("window %p: ButtonRelease (X11 button = %d)\n", data, xevent.xbutton.button);
1183#endif
1184 if (!X11_IsWheelEvent(display, &xevent, &xticks, &yticks)) {
1185 if (button > 7) {
1186 /* see explanation at case ButtonPress */
1187 button -= (8-SDL_BUTTON_X1);
1188 }
1190 }
1191 }
1192 break;
1193
1194 case PropertyNotify:{
1195#ifdef DEBUG_XEVENTS
1196 unsigned char *propdata;
1197 int status, real_format;
1198 Atom real_type;
1199 unsigned long items_read, items_left;
1200
1201 char *name = X11_XGetAtomName(display, xevent.xproperty.atom);
1202 if (name) {
1203 printf("window %p: PropertyNotify: %s %s time=%lu\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent.xproperty.time);
1204 X11_XFree(name);
1205 }
1206
1207 status = X11_XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
1208 if (status == Success && items_read > 0) {
1209 if (real_type == XA_INTEGER) {
1210 int *values = (int *)propdata;
1211
1212 printf("{");
1213 for (i = 0; i < items_read; i++) {
1214 printf(" %d", values[i]);
1215 }
1216 printf(" }\n");
1217 } else if (real_type == XA_CARDINAL) {
1218 if (real_format == 32) {
1219 Uint32 *values = (Uint32 *)propdata;
1220
1221 printf("{");
1222 for (i = 0; i < items_read; i++) {
1223 printf(" %d", values[i]);
1224 }
1225 printf(" }\n");
1226 } else if (real_format == 16) {
1227 Uint16 *values = (Uint16 *)propdata;
1228
1229 printf("{");
1230 for (i = 0; i < items_read; i++) {
1231 printf(" %d", values[i]);
1232 }
1233 printf(" }\n");
1234 } else if (real_format == 8) {
1235 Uint8 *values = (Uint8 *)propdata;
1236
1237 printf("{");
1238 for (i = 0; i < items_read; i++) {
1239 printf(" %d", values[i]);
1240 }
1241 printf(" }\n");
1242 }
1243 } else if (real_type == XA_STRING ||
1244 real_type == videodata->UTF8_STRING) {
1245 printf("{ \"%s\" }\n", propdata);
1246 } else if (real_type == XA_ATOM) {
1247 Atom *atoms = (Atom *)propdata;
1248
1249 printf("{");
1250 for (i = 0; i < items_read; i++) {
1251 char *atomname = X11_XGetAtomName(display, atoms[i]);
1252 if (atomname) {
1253 printf(" %s", atomname);
1254 X11_XFree(atomname);
1255 }
1256 }
1257 printf(" }\n");
1258 } else {
1259 char *atomname = X11_XGetAtomName(display, real_type);
1260 printf("Unknown type: %ld (%s)\n", real_type, atomname ? atomname : "UNKNOWN");
1261 if (atomname) {
1262 X11_XFree(atomname);
1263 }
1264 }
1265 }
1266 if (status == Success) {
1267 X11_XFree(propdata);
1268 }
1269#endif /* DEBUG_XEVENTS */
1270
1271 /* Take advantage of this moment to make sure user_time has a
1272 valid timestamp from the X server, so if we later try to
1273 raise/restore this window, _NET_ACTIVE_WINDOW can have a
1274 non-zero timestamp, even if there's never been a mouse or
1275 key press to this window so far. Note that we don't try to
1276 set _NET_WM_USER_TIME here, though. That's only for legit
1277 user interaction with the window. */
1278 if (!data->user_time) {
1279 data->user_time = xevent.xproperty.time;
1280 }
1281
1282 if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
1283 /* Get the new state from the window manager.
1284 Compositing window managers can alter visibility of windows
1285 without ever mapping / unmapping them, so we handle that here,
1286 because they use the NETWM protocol to notify us of changes.
1287 */
1288 const Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
1289 const Uint32 changed = flags ^ data->window->flags;
1290
1291 if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) {
1292 if (flags & SDL_WINDOW_HIDDEN) {
1293 X11_DispatchUnmapNotify(data);
1294 } else {
1295 X11_DispatchMapNotify(data);
1296 }
1297 }
1298
1299 if (changed & SDL_WINDOW_MAXIMIZED) {
1302 } else {
1304 }
1305 }
1306 } else if (xevent.xproperty.atom == videodata->XKLAVIER_STATE) {
1307 /* Hack for Ubuntu 12.04 (etc) that doesn't send MappingNotify
1308 events when the keyboard layout changes (for example,
1309 changing from English to French on the menubar's keyboard
1310 icon). Since it changes the XKLAVIER_STATE property, we
1311 notice and reinit our keymap here. This might not be the
1312 right approach, but it seems to work. */
1315 } else if (xevent.xproperty.atom == videodata->_NET_FRAME_EXTENTS) {
1316 Atom type;
1317 int format;
1318 unsigned long nitems, bytes_after;
1319 unsigned char *property;
1320 if (X11_XGetWindowProperty(display, data->xwindow, videodata->_NET_FRAME_EXTENTS, 0, 16, 0, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &property) == Success) {
1321 if (type != None && nitems == 4) {
1322 data->border_left = (int) ((long*)property)[0];
1323 data->border_right = (int) ((long*)property)[1];
1324 data->border_top = (int) ((long*)property)[2];
1325 data->border_bottom = (int) ((long*)property)[3];
1326 }
1327 X11_XFree(property);
1328
1329 #ifdef DEBUG_XEVENTS
1330 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);
1331 #endif
1332 }
1333 }
1334 }
1335 break;
1336
1337 case SelectionNotify: {
1338 Atom target = xevent.xselection.target;
1339#ifdef DEBUG_XEVENTS
1340 printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
1341 xevent.xselection.requestor, xevent.xselection.target);
1342#endif
1343 if (target == data->xdnd_req) {
1344 /* read data */
1345 SDL_x11Prop p;
1346 X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY);
1347
1348 if (p.format == 8) {
1349 /* !!! FIXME: don't use strtok here. It's not reentrant and not in SDL_stdinc. */
1350 char* name = X11_XGetAtomName(display, target);
1351 char *token = strtok((char *) p.data, "\r\n");
1352 while (token != NULL) {
1353 if (SDL_strcmp("text/plain", name)==0) {
1354 SDL_SendDropText(data->window, token);
1355 } else if (SDL_strcmp("text/uri-list", name)==0) {
1356 char *fn = X11_URIToLocal(token);
1357 if (fn) {
1358 SDL_SendDropFile(data->window, fn);
1359 }
1360 }
1361 token = strtok(NULL, "\r\n");
1362 }
1363 SDL_SendDropComplete(data->window);
1364 }
1365 X11_XFree(p.data);
1366
1367 /* send reply */
1368 SDL_memset(&m, 0, sizeof(XClientMessageEvent));
1369 m.type = ClientMessage;
1370 m.display = display;
1371 m.window = data->xdnd_source;
1372 m.message_type = videodata->XdndFinished;
1373 m.format = 32;
1374 m.data.l[0] = data->xwindow;
1375 m.data.l[1] = 1;
1376 m.data.l[2] = videodata->XdndActionCopy;
1377 X11_XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m);
1378
1379 X11_XSync(display, False);
1380 }
1381 }
1382 break;
1383
1384 default:{
1385#ifdef DEBUG_XEVENTS
1386 printf("window %p: Unhandled event %d\n", data, xevent.type);
1387#endif
1388 }
1389 break;
1390 }
1391}
1392
1393static void
1394X11_HandleFocusChanges(_THIS)
1395{
1396 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
1397 int i;
1398
1399 if (videodata && videodata->windowlist) {
1400 for (i = 0; i < videodata->numwindows; ++i) {
1401 SDL_WindowData *data = videodata->windowlist[i];
1402 if (data && data->pending_focus != PENDING_FOCUS_NONE) {
1403 Uint32 now = SDL_GetTicks();
1404 if (SDL_TICKS_PASSED(now, data->pending_focus_time)) {
1405 if (data->pending_focus == PENDING_FOCUS_IN) {
1406 X11_DispatchFocusIn(_this, data);
1407 } else {
1408 X11_DispatchFocusOut(_this, data);
1409 }
1410 data->pending_focus = PENDING_FOCUS_NONE;
1411 }
1412 }
1413 }
1414 }
1415}
1416/* Ack! X11_XPending() actually performs a blocking read if no events available */
1417static int
1418X11_Pending(Display * display)
1419{
1420 /* Flush the display connection and look to see if events are queued */
1421 X11_XFlush(display);
1422 if (X11_XEventsQueued(display, QueuedAlready)) {
1423 return (1);
1424 }
1425
1426 /* More drastic measures are required -- see if X is ready to talk */
1427 if (SDL_IOReady(ConnectionNumber(display), SDL_FALSE, 0)) {
1428 return (X11_XPending(display));
1429 }
1430
1431 /* Oh well, nothing is ready .. */
1432 return (0);
1433}
1434
1435void
1437{
1439
1440 if (data->last_mode_change_deadline) {
1441 if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) {
1442 data->last_mode_change_deadline = 0; /* assume we're done. */
1443 }
1444 }
1445
1446 /* Update activity every 30 seconds to prevent screensaver */
1448 const Uint32 now = SDL_GetTicks();
1449 if (!data->screensaver_activity ||
1450 SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
1451 X11_XResetScreenSaver(data->display);
1452
1453#if SDL_USE_LIBDBUS
1454 SDL_DBus_ScreensaverTickle();
1455#endif
1456
1457 data->screensaver_activity = now;
1458 }
1459 }
1460
1461 /* Keep processing pending events */
1462 while (X11_Pending(data->display)) {
1463 X11_DispatchEvent(_this);
1464 }
1465
1466#ifdef SDL_USE_IME
1469 }
1470#endif
1471
1472 /* FIXME: Only need to do this when there are pending focus changes */
1473 X11_HandleFocusChanges(_this);
1474}
1475
1476
1477void
1479{
1480#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
1482 int dummy;
1483 int major_version, minor_version;
1484#endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
1485
1486#if SDL_USE_LIBDBUS
1487 if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) {
1488 return;
1489 }
1490
1492 SDL_DBus_ScreensaverTickle();
1493 }
1494#endif
1495
1496#if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
1497 if (SDL_X11_HAVE_XSS) {
1498 /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
1499 if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
1500 !X11_XScreenSaverQueryVersion(data->display,
1501 &major_version, &minor_version) ||
1502 major_version < 1 || (major_version == 1 && minor_version < 1)) {
1503 return;
1504 }
1505
1506 X11_XScreenSaverSuspend(data->display, _this->suspend_screensaver);
1507 X11_XResetScreenSaver(data->display);
1508 }
1509#endif
1510}
1511
1512#endif /* SDL_VIDEO_DRIVER_X11 */
1513
1514/* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_assert(condition)
Definition: SDL_assert.h:169
int SDL_SendClipboardUpdate(void)
int SDL_SendDropText(SDL_Window *window, const char *text)
int SDL_SendDropFile(SDL_Window *window, const char *file)
int SDL_SendDropComplete(SDL_Window *window)
#define SDL_memset
#define SDL_GetKeyboardFocus
#define SDL_strlen
#define SDL_GetKeyboardState
#define SDL_strcmp
#define SDL_GetHintBoolean
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
int SDL_SendKeymapChangedEvent(void)
Definition: SDL_events.c:996
int SDL_SendSysWMEvent(SDL_SysWMmsg *message)
Definition: SDL_events.c:979
@ SDL_TEXTINPUT
Definition: SDL_events.h:99
@ SDL_SYSWMEVENT
Definition: SDL_events.h:93
#define SDL_TEXTINPUTEVENT_TEXT_SIZE
Definition: SDL_events.h:238
#define SDL_GetEventState(type)
Definition: SDL_events.h:772
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_ENABLE
Definition: SDL_events.h:759
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
Allow mouse click events when clicking to focus an SDL window.
Definition: SDL_hints.h:305
void SDL_IME_PumpEvents()
Definition: SDL_ime.c:146
void SDL_IME_UpdateTextRect(SDL_Rect *rect)
Definition: SDL_ime.c:139
void SDL_IME_SetFocus(SDL_bool focused)
Definition: SDL_ime.c:116
SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
Definition: SDL_ime.c:130
void SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
Definition: SDL_keyboard.c:865
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:789
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:679
@ KMOD_CAPS
Definition: SDL_keycode.h:337
@ KMOD_NUM
Definition: SDL_keycode.h:336
#define memset
Definition: SDL_malloc.c:627
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:605
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:211
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:178
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:611
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:301
#define SDL_BUTTON_X1
Definition: SDL_mouse.h:285
@ SDL_MOUSEWHEEL_NORMAL
Definition: SDL_mouse.h:68
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
struct _cl_event * event
const GLfloat * m
GLenum GLsizei len
GLenum GLsizei GLsizei GLint * values
GLuint const GLchar * name
GLenum GLuint GLenum GLsizei const GLchar * buf
GLfloat GLfloat p
GLbitfield flags
GLdouble n
GLenum GLint GLuint mask
GLenum target
GLubyte GLubyte GLubyte GLubyte w
int SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS)
Definition: SDL_poll.c:38
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:44
@ SDL_SCANCODE_NUMLOCKCLEAR
Definition: SDL_scancode.h:181
@ SDL_SCANCODE_UNKNOWN
Definition: SDL_scancode.h:45
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
uint32_t Uint32
Definition: SDL_stdinc.h:203
uint16_t Uint16
Definition: SDL_stdinc.h:191
uint8_t Uint8
Definition: SDL_stdinc.h:179
@ SDL_SYSWM_X11
Definition: SDL_syswm.h:123
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
Definition: SDL_version.h:79
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
SDL_HitTestResult
Possible return values from the SDL_HitTest callback.
Definition: SDL_video.h:1021
@ SDL_HITTEST_DRAGGABLE
Definition: SDL_video.h:1023
@ SDL_HITTEST_RESIZE_LEFT
Definition: SDL_video.h:1031
@ SDL_HITTEST_RESIZE_TOP
Definition: SDL_video.h:1025
@ SDL_HITTEST_RESIZE_TOPRIGHT
Definition: SDL_video.h:1026
@ SDL_HITTEST_RESIZE_BOTTOM
Definition: SDL_video.h:1029
@ SDL_HITTEST_RESIZE_BOTTOMRIGHT
Definition: SDL_video.h:1028
@ SDL_HITTEST_RESIZE_BOTTOMLEFT
Definition: SDL_video.h:1030
@ SDL_HITTEST_RESIZE_RIGHT
Definition: SDL_video.h:1027
@ SDL_HITTEST_RESIZE_TOPLEFT
Definition: SDL_video.h:1024
@ SDL_WINDOW_FULLSCREEN
Definition: SDL_video.h:100
@ SDL_WINDOW_MAXIMIZED
Definition: SDL_video.h:107
@ SDL_WINDOW_HIDDEN
Definition: SDL_video.h:103
@ SDL_WINDOWEVENT_HIDDEN
Definition: SDL_video.h:150
@ SDL_WINDOWEVENT_CLOSE
Definition: SDL_video.h:167
@ SDL_WINDOWEVENT_RESIZED
Definition: SDL_video.h:155
@ SDL_WINDOWEVENT_HIT_TEST
Definition: SDL_video.h:169
@ SDL_WINDOWEVENT_SHOWN
Definition: SDL_video.h:149
@ SDL_WINDOWEVENT_MOVED
Definition: SDL_video.h:153
@ SDL_WINDOWEVENT_TAKE_FOCUS
Definition: SDL_video.h:168
@ SDL_WINDOWEVENT_MINIMIZED
Definition: SDL_video.h:159
@ SDL_WINDOWEVENT_MAXIMIZED
Definition: SDL_video.h:160
@ SDL_WINDOWEVENT_RESTORED
Definition: SDL_video.h:161
@ SDL_WINDOWEVENT_EXPOSED
Definition: SDL_video.h:151
#define INT_MAX
Definition: SDL_wave.c:31
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
Atom X11_GetSDLCutBufferClipboardType(Display *display)
void X11_SuspendScreenSaver(_THIS)
void X11_PumpEvents(_THIS)
void X11_UpdateKeymap(_THIS)
KeySym X11_KeyCodeToSym(_THIS, KeyCode, unsigned char group)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
@ PENDING_FOCUS_NONE
Definition: SDL_x11window.h:38
@ PENDING_FOCUS_OUT
Definition: SDL_x11window.h:40
@ PENDING_FOCUS_IN
Definition: SDL_x11window.h:39
#define PENDING_FOCUS_TIME
Definition: SDL_x11window.h:30
Uint32 X11_GetNetWMState(_THIS, Window xwindow)
int X11_HandleXinput2Event(SDL_VideoData *videodata, XGenericEventCookie *cookie)
struct XGenericEventCookie XGenericEventCookie
#define NULL
Definition: begin_code.h:167
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
int last_y
Definition: SDL_mouse_c.h:82
SDL_bool relative_mode
Definition: SDL_mouse_c.h:87
int last_x
Definition: SDL_mouse_c.h:82
SDL_bool relative_mode_warp
Definition: SDL_mouse_c.h:88
The structure that defines a point (integer)
Definition: SDL_rect.h:49
int x
Definition: SDL_rect.h:50
int y
Definition: SDL_rect.h:51
struct SDL_SysWMmsg::@15::@16 x11
union SDL_SysWMmsg::@15 msg
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:141
SDL_version version
Definition: SDL_syswm.h:140
XEvent event
Definition: SDL_syswm.h:154
Window clipboard_window
Definition: SDL_x11video.h:86
Atom _NET_WM_USER_TIME
Definition: SDL_x11video.h:111
Atom WM_DELETE_WINDOW
Definition: SDL_x11video.h:93
Atom _NET_FRAME_EXTENTS
Definition: SDL_x11video.h:113
SDL_bool selection_waiting
Definition: SDL_x11video.h:127
SDL_WindowData ** windowlist
Definition: SDL_x11video.h:83
Uint32 last_mode_change_deadline
Definition: SDL_x11video.h:131
KeyCode filter_code
Definition: SDL_x11video.h:141
Atom WM_TAKE_FOCUS
Definition: SDL_x11video.h:94
struct wl_display * display
SDL_bool suspend_screensaver
Definition: SDL_sysvideo.h:314
The type used to identify a window.
Definition: SDL_sysvideo.h:74
SDL_Texture * button
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47