SDL  2.0
SDL_x11events.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 
84 typedef 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  */
93 static 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 */
116 static 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 */
133 static 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 
143 struct KeyRepeatCheckData
144 {
145  XEvent *event;
146  SDL_bool found;
147 };
148 
149 static 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  */
163 static 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 
175 static SDL_bool
176 X11_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  */
206 static 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 */
269 static 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
306 static 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  X11_XFreeEventData(videodata->display, cookie);
313  }
314 }
315 #endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */
316 
317 static unsigned
318 X11_GetNumLockModifierMask(_THIS)
319 {
321  Display *display = viddata->display;
322  unsigned num_mask = 0;
323  int i, j;
324  XModifierKeymap *xmods;
325  unsigned n;
326 
327  xmods = X11_XGetModifierMapping(display);
328  n = xmods->max_keypermod;
329  for(i = 3; i < 8; i++) {
330  for(j = 0; j < n; j++) {
331  KeyCode kc = xmods->modifiermap[i * n + j];
332  if (viddata->key_layout[kc] == SDL_SCANCODE_NUMLOCKCLEAR) {
333  num_mask = 1 << i;
334  break;
335  }
336  }
337  }
338  X11_XFreeModifiermap(xmods);
339 
340  return num_mask;
341 }
342 
343 static void
344 X11_ReconcileKeyboardState(_THIS)
345 {
347  Display *display = viddata->display;
348  char keys[32];
349  int keycode;
350  Window junk_window;
351  int x, y;
352  unsigned int mask;
353  const Uint8 *keyboardState;
354 
355  X11_XQueryKeymap(display, keys);
356 
357  /* Sync up the keyboard modifier state */
358  if (X11_XQueryPointer(display, DefaultRootWindow(display), &junk_window, &junk_window, &x, &y, &x, &y, &mask)) {
359  SDL_ToggleModState(KMOD_CAPS, (mask & LockMask) != 0);
360  SDL_ToggleModState(KMOD_NUM, (mask & X11_GetNumLockModifierMask(_this)) != 0);
361  }
362 
363  keyboardState = SDL_GetKeyboardState(0);
364  for (keycode = 0; keycode < 256; ++keycode) {
365  SDL_Scancode scancode = viddata->key_layout[keycode];
366  SDL_bool x11KeyPressed = (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
367  SDL_bool sdlKeyPressed = keyboardState[scancode] == SDL_PRESSED;
368 
369  if (x11KeyPressed && !sdlKeyPressed) {
370  SDL_SendKeyboardKey(SDL_PRESSED, scancode);
371  } else if (!x11KeyPressed && sdlKeyPressed) {
373  }
374  }
375 }
376 
377 
378 static void
379 X11_DispatchFocusIn(_THIS, SDL_WindowData *data)
380 {
381 #ifdef DEBUG_XEVENTS
382  printf("window %p: Dispatching FocusIn\n", data);
383 #endif
385  X11_ReconcileKeyboardState(_this);
386 #ifdef X_HAVE_UTF8_STRING
387  if (data->ic) {
388  X11_XSetICFocus(data->ic);
389  }
390 #endif
391 #ifdef SDL_USE_IME
393 #endif
394 }
395 
396 static void
397 X11_DispatchFocusOut(_THIS, SDL_WindowData *data)
398 {
399 #ifdef DEBUG_XEVENTS
400  printf("window %p: Dispatching FocusOut\n", data);
401 #endif
402  /* If another window has already processed a focus in, then don't try to
403  * remove focus here. Doing so will incorrectly remove focus from that
404  * window, and the focus lost event for this window will have already
405  * been dispatched anyway. */
406  if (data->window == SDL_GetKeyboardFocus()) {
408  }
409 #ifdef X_HAVE_UTF8_STRING
410  if (data->ic) {
411  X11_XUnsetICFocus(data->ic);
412  }
413 #endif
414 #ifdef SDL_USE_IME
416 #endif
417 }
418 
419 static void
420 X11_DispatchMapNotify(SDL_WindowData *data)
421 {
424 }
425 
426 static void
427 X11_DispatchUnmapNotify(SDL_WindowData *data)
428 {
431 }
432 
433 static void
434 InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point)
435 {
437  SDL_Window* window = data->window;
438  Display *display = viddata->display;
439  XEvent evt;
440 
441  /* !!! FIXME: we need to regrab this if necessary when the drag is done. */
442  X11_XUngrabPointer(display, 0L);
443  X11_XFlush(display);
444 
445  evt.xclient.type = ClientMessage;
446  evt.xclient.window = data->xwindow;
447  evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
448  evt.xclient.format = 32;
449  evt.xclient.data.l[0] = window->x + point->x;
450  evt.xclient.data.l[1] = window->y + point->y;
451  evt.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
452  evt.xclient.data.l[3] = Button1;
453  evt.xclient.data.l[4] = 0;
454  X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt);
455 
456  X11_XSync(display, 0);
457 }
458 
459 static void
460 InitiateWindowResize(_THIS, const SDL_WindowData *data, const SDL_Point *point, int direction)
461 {
463  SDL_Window* window = data->window;
464  Display *display = viddata->display;
465  XEvent evt;
466 
467  if (direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT || direction > _NET_WM_MOVERESIZE_SIZE_LEFT)
468  return;
469 
470  /* !!! FIXME: we need to regrab this if necessary when the drag is done. */
471  X11_XUngrabPointer(display, 0L);
472  X11_XFlush(display);
473 
474  evt.xclient.type = ClientMessage;
475  evt.xclient.window = data->xwindow;
476  evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
477  evt.xclient.format = 32;
478  evt.xclient.data.l[0] = window->x + point->x;
479  evt.xclient.data.l[1] = window->y + point->y;
480  evt.xclient.data.l[2] = direction;
481  evt.xclient.data.l[3] = Button1;
482  evt.xclient.data.l[4] = 0;
483  X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt);
484 
485  X11_XSync(display, 0);
486 }
487 
488 static SDL_bool
489 ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev)
490 {
491  SDL_Window *window = data->window;
492 
493  if (window->hit_test) {
494  const SDL_Point point = { xev->xbutton.x, xev->xbutton.y };
495  const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
496  static const int directions[] = {
497  _NET_WM_MOVERESIZE_SIZE_TOPLEFT, _NET_WM_MOVERESIZE_SIZE_TOP,
498  _NET_WM_MOVERESIZE_SIZE_TOPRIGHT, _NET_WM_MOVERESIZE_SIZE_RIGHT,
499  _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT, _NET_WM_MOVERESIZE_SIZE_BOTTOM,
500  _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT, _NET_WM_MOVERESIZE_SIZE_LEFT
501  };
502 
503  switch (rc) {
505  InitiateWindowMove(_this, data, &point);
506  return SDL_TRUE;
507 
516  InitiateWindowResize(_this, data, &point, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
517  return SDL_TRUE;
518 
519  default: return SDL_FALSE;
520  }
521  }
522 
523  return SDL_FALSE;
524 }
525 
526 static void
527 X11_UpdateUserTime(SDL_WindowData *data, const unsigned long latest)
528 {
529  if (latest && (latest != data->user_time)) {
530  SDL_VideoData *videodata = data->videodata;
531  Display *display = videodata->display;
532  X11_XChangeProperty(display, data->xwindow, videodata->_NET_WM_USER_TIME,
533  XA_CARDINAL, 32, PropModeReplace,
534  (const unsigned char *) &latest, 1);
535 #ifdef DEBUG_XEVENTS
536  printf("window %p: updating _NET_WM_USER_TIME to %lu\n", data, latest);
537 #endif
538  data->user_time = latest;
539  }
540 }
541 
542 static void
543 X11_HandleClipboardEvent(_THIS, const XEvent *xevent)
544 {
545  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
546  Display *display = videodata->display;
547 
548  SDL_assert(videodata->clipboard_window != None);
549  SDL_assert(xevent->xany.window == videodata->clipboard_window);
550 
551  switch (xevent->type) {
552  /* Copy the selection from our own CUTBUFFER to the requested property */
553  case SelectionRequest: {
554  const XSelectionRequestEvent *req = &xevent->xselectionrequest;
555  XEvent sevent;
556  int seln_format;
557  unsigned long nbytes;
558  unsigned long overflow;
559  unsigned char *seln_data;
560 
561 #ifdef DEBUG_XEVENTS
562  printf("window CLIPBOARD: SelectionRequest (requestor = %ld, target = %ld)\n",
563  req->requestor, req->target);
564 #endif
565 
566  SDL_zero(sevent);
567  sevent.xany.type = SelectionNotify;
568  sevent.xselection.selection = req->selection;
569  sevent.xselection.target = None;
570  sevent.xselection.property = None; /* tell them no by default */
571  sevent.xselection.requestor = req->requestor;
572  sevent.xselection.time = req->time;
573 
574  /* !!! FIXME: We were probably storing this on the root window
575  because an SDL window might go away...? but we don't have to do
576  this now (or ever, really). */
577  if (X11_XGetWindowProperty(display, DefaultRootWindow(display),
578  X11_GetSDLCutBufferClipboardType(display), 0, INT_MAX/4, False, req->target,
579  &sevent.xselection.target, &seln_format, &nbytes,
580  &overflow, &seln_data) == Success) {
581  /* !!! FIXME: cache atoms */
582  Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
583  if (sevent.xselection.target == req->target) {
584  X11_XChangeProperty(display, req->requestor, req->property,
585  sevent.xselection.target, seln_format, PropModeReplace,
586  seln_data, nbytes);
587  sevent.xselection.property = req->property;
588  } else if (XA_TARGETS == req->target) {
589  Atom SupportedFormats[] = { XA_TARGETS, sevent.xselection.target };
590  X11_XChangeProperty(display, req->requestor, req->property,
591  XA_ATOM, 32, PropModeReplace,
592  (unsigned char*)SupportedFormats,
593  SDL_arraysize(SupportedFormats));
594  sevent.xselection.property = req->property;
595  sevent.xselection.target = XA_TARGETS;
596  }
597  X11_XFree(seln_data);
598  }
599  X11_XSendEvent(display, req->requestor, False, 0, &sevent);
600  X11_XSync(display, False);
601  }
602  break;
603 
604  case SelectionNotify: {
605 #ifdef DEBUG_XEVENTS
606  printf("window CLIPBOARD: SelectionNotify (requestor = %ld, target = %ld)\n",
607  xevent->xselection.requestor, xevent->xselection.target);
608 #endif
609  videodata->selection_waiting = SDL_FALSE;
610  }
611  break;
612 
613  case SelectionClear: {
614  /* !!! FIXME: cache atoms */
615  Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
616 
617 #ifdef DEBUG_XEVENTS
618  printf("window CLIPBOARD: SelectionClear (requestor = %ld, target = %ld)\n",
619  xevent->xselection.requestor, xevent->xselection.target);
620 #endif
621 
622  if (xevent->xselectionclear.selection == XA_PRIMARY ||
623  (XA_CLIPBOARD != None && xevent->xselectionclear.selection == XA_CLIPBOARD)) {
625  }
626  }
627  break;
628  }
629 }
630 
631 
632 static void
633 X11_DispatchEvent(_THIS)
634 {
635  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
636  Display *display;
637  SDL_WindowData *data;
638  XEvent xevent;
639  int orig_event_type;
640  KeyCode orig_keycode;
641  XClientMessageEvent m;
642  int i;
643 
644  if (!videodata) {
645  return;
646  }
647  display = videodata->display;
648 
649  SDL_zero(xevent); /* valgrind fix. --ryan. */
650  X11_XNextEvent(display, &xevent);
651 
652  /* Save the original keycode for dead keys, which are filtered out by
653  the XFilterEvent() call below.
654  */
655  orig_event_type = xevent.type;
656  if (orig_event_type == KeyPress || orig_event_type == KeyRelease) {
657  orig_keycode = xevent.xkey.keycode;
658  } else {
659  orig_keycode = 0;
660  }
661 
662  /* filter events catchs XIM events and sends them to the correct handler */
663  if (X11_XFilterEvent(&xevent, None) == True) {
664 #if 0
665  printf("Filtered event type = %d display = %d window = %d\n",
666  xevent.type, xevent.xany.display, xevent.xany.window);
667 #endif
668  /* Make sure dead key press/release events are sent */
669  /* But only if we're using one of the DBus IMEs, otherwise
670  some XIM IMEs will generate duplicate events */
671  if (orig_keycode) {
672 #if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
673  SDL_Scancode scancode = videodata->key_layout[orig_keycode];
674  videodata->filter_code = orig_keycode;
675  videodata->filter_time = xevent.xkey.time;
676 
677  if (orig_event_type == KeyPress) {
678  SDL_SendKeyboardKey(SDL_PRESSED, scancode);
679  } else {
681  }
682 #endif
683  }
684  return;
685  }
686 
687  /* Send a SDL_SYSWMEVENT if the application wants them */
689  SDL_SysWMmsg wmmsg;
690 
691  SDL_VERSION(&wmmsg.version);
692  wmmsg.subsystem = SDL_SYSWM_X11;
693  wmmsg.msg.x11.event = xevent;
694  SDL_SendSysWMEvent(&wmmsg);
695  }
696 
697 #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
698  if(xevent.type == GenericEvent) {
699  X11_HandleGenericEvent(videodata, &xevent);
700  return;
701  }
702 #endif
703 
704 #if 0
705  printf("type = %d display = %d window = %d\n",
706  xevent.type, xevent.xany.display, xevent.xany.window);
707 #endif
708 
709  if ((videodata->clipboard_window != None) &&
710  (videodata->clipboard_window == xevent.xany.window)) {
711  X11_HandleClipboardEvent(_this, &xevent);
712  return;
713  }
714 
715  data = NULL;
716  if (videodata && videodata->windowlist) {
717  for (i = 0; i < videodata->numwindows; ++i) {
718  if ((videodata->windowlist[i] != NULL) &&
719  (videodata->windowlist[i]->xwindow == xevent.xany.window)) {
720  data = videodata->windowlist[i];
721  break;
722  }
723  }
724  }
725  if (!data) {
726  /* The window for KeymapNotify, etc events is 0 */
727  if (xevent.type == KeymapNotify) {
728  if (SDL_GetKeyboardFocus() != NULL) {
729  X11_ReconcileKeyboardState(_this);
730  }
731  } else if (xevent.type == MappingNotify) {
732  /* Has the keyboard layout changed? */
733  const int request = xevent.xmapping.request;
734 
735 #ifdef DEBUG_XEVENTS
736  printf("window %p: MappingNotify!\n", data);
737 #endif
738  if ((request == MappingKeyboard) || (request == MappingModifier)) {
739  X11_XRefreshKeyboardMapping(&xevent.xmapping);
740  }
741 
744  }
745  return;
746  }
747 
748  switch (xevent.type) {
749 
750  /* Gaining mouse coverage? */
751  case EnterNotify:{
752  SDL_Mouse *mouse = SDL_GetMouse();
753 #ifdef DEBUG_XEVENTS
754  printf("window %p: EnterNotify! (%d,%d,%d)\n", data,
755  xevent.xcrossing.x,
756  xevent.xcrossing.y,
757  xevent.xcrossing.mode);
758  if (xevent.xcrossing.mode == NotifyGrab)
759  printf("Mode: NotifyGrab\n");
760  if (xevent.xcrossing.mode == NotifyUngrab)
761  printf("Mode: NotifyUngrab\n");
762 #endif
763  SDL_SetMouseFocus(data->window);
764 
765  mouse->last_x = xevent.xcrossing.x;
766  mouse->last_y = xevent.xcrossing.y;
767 
768  if (!mouse->relative_mode) {
769  SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
770  }
771  }
772  break;
773  /* Losing mouse coverage? */
774  case LeaveNotify:{
775 #ifdef DEBUG_XEVENTS
776  printf("window %p: LeaveNotify! (%d,%d,%d)\n", data,
777  xevent.xcrossing.x,
778  xevent.xcrossing.y,
779  xevent.xcrossing.mode);
780  if (xevent.xcrossing.mode == NotifyGrab)
781  printf("Mode: NotifyGrab\n");
782  if (xevent.xcrossing.mode == NotifyUngrab)
783  printf("Mode: NotifyUngrab\n");
784 #endif
785  if (!SDL_GetMouse()->relative_mode) {
786  SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y);
787  }
788 
789  if (xevent.xcrossing.mode != NotifyGrab &&
790  xevent.xcrossing.mode != NotifyUngrab &&
791  xevent.xcrossing.detail != NotifyInferior) {
793  }
794  }
795  break;
796 
797  /* Gaining input focus? */
798  case FocusIn:{
799  if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
800  /* Someone is handling a global hotkey, ignore it */
801 #ifdef DEBUG_XEVENTS
802  printf("window %p: FocusIn (NotifyGrab/NotifyUngrab, ignoring)\n", data);
803 #endif
804  break;
805  }
806 
807  if (xevent.xfocus.detail == NotifyInferior) {
808 #ifdef DEBUG_XEVENTS
809  printf("window %p: FocusIn (NotifierInferior, ignoring)\n", data);
810 #endif
811  break;
812  }
813 #ifdef DEBUG_XEVENTS
814  printf("window %p: FocusIn!\n", data);
815 #endif
816  if (!videodata->last_mode_change_deadline) /* no recent mode changes */
817  {
819  data->pending_focus_time = 0;
820  X11_DispatchFocusIn(_this, data);
821  }
822  else
823  {
826  }
828  }
829  break;
830 
831  /* Losing input focus? */
832  case FocusOut:{
833  if (xevent.xfocus.mode == NotifyGrab || xevent.xfocus.mode == NotifyUngrab) {
834  /* Someone is handling a global hotkey, ignore it */
835 #ifdef DEBUG_XEVENTS
836  printf("window %p: FocusOut (NotifyGrab/NotifyUngrab, ignoring)\n", data);
837 #endif
838  break;
839  }
840  if (xevent.xfocus.detail == NotifyInferior) {
841  /* We still have focus if a child gets focus */
842 #ifdef DEBUG_XEVENTS
843  printf("window %p: FocusOut (NotifierInferior, ignoring)\n", data);
844 #endif
845  break;
846  }
847 #ifdef DEBUG_XEVENTS
848  printf("window %p: FocusOut!\n", data);
849 #endif
850  if (!videodata->last_mode_change_deadline) /* no recent mode changes */
851  {
853  data->pending_focus_time = 0;
854  X11_DispatchFocusOut(_this, data);
855  }
856  else
857  {
860  }
861  }
862  break;
863 
864  /* Key press? */
865  case KeyPress:{
866  KeyCode keycode = xevent.xkey.keycode;
867  KeySym keysym = NoSymbol;
869  Status status = 0;
870  SDL_bool handled_by_ime = SDL_FALSE;
871 
872 #ifdef DEBUG_XEVENTS
873  printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
874 #endif
875 #if 1
876  if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
877  int min_keycode, max_keycode;
878  X11_XDisplayKeycodes(display, &min_keycode, &max_keycode);
879  keysym = X11_KeyCodeToSym(_this, keycode, xevent.xkey.state >> 13);
880  fprintf(stderr,
881  "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",
882  keycode, keycode - min_keycode, keysym,
883  X11_XKeysymToString(keysym));
884  }
885 #endif
886  /* */
887  SDL_zero(text);
888 #ifdef X_HAVE_UTF8_STRING
889  if (data->ic) {
890  X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text),
891  &keysym, &status);
892  } else {
893  X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
894  }
895 #else
896  X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
897 #endif
898 
899 #ifdef SDL_USE_IME
901  handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode);
902  }
903 #endif
904  if (!handled_by_ime) {
905  /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
906  if (xevent.xkey.keycode != videodata->filter_code || xevent.xkey.time != videodata->filter_time) {
907  SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
908  }
909  if(*text) {
910  SDL_SendKeyboardText(text);
911  }
912  }
913 
914  X11_UpdateUserTime(data, xevent.xkey.time);
915  }
916  break;
917 
918  /* Key release? */
919  case KeyRelease:{
920  KeyCode keycode = xevent.xkey.keycode;
921 
922 #ifdef DEBUG_XEVENTS
923  printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
924 #endif
925  if (X11_KeyRepeat(display, &xevent)) {
926  /* We're about to get a repeated key down, ignore the key up */
927  break;
928  }
929  SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
930  }
931  break;
932 
933  /* Have we been iconified? */
934  case UnmapNotify:{
935 #ifdef DEBUG_XEVENTS
936  printf("window %p: UnmapNotify!\n", data);
937 #endif
938  X11_DispatchUnmapNotify(data);
939  }
940  break;
941 
942  /* Have we been restored? */
943  case MapNotify:{
944 #ifdef DEBUG_XEVENTS
945  printf("window %p: MapNotify!\n", data);
946 #endif
947  X11_DispatchMapNotify(data);
948  }
949  break;
950 
951  /* Have we been resized or moved? */
952  case ConfigureNotify:{
953 #ifdef DEBUG_XEVENTS
954  printf("window %p: ConfigureNotify! (position: %d,%d, size: %dx%d)\n", data,
955  xevent.xconfigure.x, xevent.xconfigure.y,
956  xevent.xconfigure.width, xevent.xconfigure.height);
957 #endif
958  /* Real configure notify events are relative to the parent, synthetic events are absolute. */
959  if (!xevent.xconfigure.send_event) {
960  unsigned int NumChildren;
961  Window ChildReturn, Root, Parent;
962  Window * Children;
963  /* Translate these coodinates back to relative to root */
964  X11_XQueryTree(data->videodata->display, xevent.xconfigure.window, &Root, &Parent, &Children, &NumChildren);
965  X11_XTranslateCoordinates(xevent.xconfigure.display,
966  Parent, DefaultRootWindow(xevent.xconfigure.display),
967  xevent.xconfigure.x, xevent.xconfigure.y,
968  &xevent.xconfigure.x, &xevent.xconfigure.y,
969  &ChildReturn);
970  }
971 
972  if (xevent.xconfigure.x != data->last_xconfigure.x ||
973  xevent.xconfigure.y != data->last_xconfigure.y) {
975  xevent.xconfigure.x, xevent.xconfigure.y);
976 #ifdef SDL_USE_IME
978  /* Update IME candidate list position */
980  }
981 #endif
982  }
983  if (xevent.xconfigure.width != data->last_xconfigure.width ||
984  xevent.xconfigure.height != data->last_xconfigure.height) {
986  xevent.xconfigure.width,
987  xevent.xconfigure.height);
988  }
989  data->last_xconfigure = xevent.xconfigure;
990  }
991  break;
992 
993  /* Have we been requested to quit (or another client message?) */
994  case ClientMessage:{
995 
996  static int xdnd_version=0;
997 
998  if (xevent.xclient.message_type == videodata->XdndEnter) {
999 
1000  SDL_bool use_list = xevent.xclient.data.l[1] & 1;
1001  data->xdnd_source = xevent.xclient.data.l[0];
1002  xdnd_version = (xevent.xclient.data.l[1] >> 24);
1003 #ifdef DEBUG_XEVENTS
1004  printf("XID of source window : %ld\n", data->xdnd_source);
1005  printf("Protocol version to use : %d\n", xdnd_version);
1006  printf("More then 3 data types : %d\n", (int) use_list);
1007 #endif
1008 
1009  if (use_list) {
1010  /* fetch conversion targets */
1011  SDL_x11Prop p;
1012  X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList);
1013  /* pick one */
1014  data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count);
1015  X11_XFree(p.data);
1016  } else {
1017  /* pick from list of three */
1018  data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]);
1019  }
1020  }
1021  else if (xevent.xclient.message_type == videodata->XdndPosition) {
1022 
1023 #ifdef DEBUG_XEVENTS
1024  Atom act= videodata->XdndActionCopy;
1025  if(xdnd_version >= 2) {
1026  act = xevent.xclient.data.l[4];
1027  }
1028  printf("Action requested by user is : %s\n", X11_XGetAtomName(display , act));
1029 #endif
1030 
1031 
1032  /* reply with status */
1033  memset(&m, 0, sizeof(XClientMessageEvent));
1034  m.type = ClientMessage;
1035  m.display = xevent.xclient.display;
1036  m.window = xevent.xclient.data.l[0];
1037  m.message_type = videodata->XdndStatus;
1038  m.format=32;
1039  m.data.l[0] = data->xwindow;
1040  m.data.l[1] = (data->xdnd_req != None);
1041  m.data.l[2] = 0; /* specify an empty rectangle */
1042  m.data.l[3] = 0;
1043  m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */
1044 
1045  X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
1046  X11_XFlush(display);
1047  }
1048  else if(xevent.xclient.message_type == videodata->XdndDrop) {
1049  if (data->xdnd_req == None) {
1050  /* say again - not interested! */
1051  memset(&m, 0, sizeof(XClientMessageEvent));
1052  m.type = ClientMessage;
1053  m.display = xevent.xclient.display;
1054  m.window = xevent.xclient.data.l[0];
1055  m.message_type = videodata->XdndFinished;
1056  m.format=32;
1057  m.data.l[0] = data->xwindow;
1058  m.data.l[1] = 0;
1059  m.data.l[2] = None; /* fail! */
1060  X11_XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
1061  } else {
1062  /* convert */
1063  if(xdnd_version >= 1) {
1064  X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]);
1065  } else {
1066  X11_XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime);
1067  }
1068  }
1069  }
1070  else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
1071  (xevent.xclient.format == 32) &&
1072  (xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
1073  Window root = DefaultRootWindow(display);
1074 
1075 #ifdef DEBUG_XEVENTS
1076  printf("window %p: _NET_WM_PING\n", data);
1077 #endif
1078  xevent.xclient.window = root;
1079  X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
1080  break;
1081  }
1082 
1083  else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
1084  (xevent.xclient.format == 32) &&
1085  (xevent.xclient.data.l[0] == videodata->WM_DELETE_WINDOW)) {
1086 
1087 #ifdef DEBUG_XEVENTS
1088  printf("window %p: WM_DELETE_WINDOW\n", data);
1089 #endif
1091  break;
1092  }
1093  else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
1094  (xevent.xclient.format == 32) &&
1095  (xevent.xclient.data.l[0] == videodata->WM_TAKE_FOCUS)) {
1096 
1097 #ifdef DEBUG_XEVENTS
1098  printf("window %p: WM_TAKE_FOCUS\n", data);
1099 #endif
1101  break;
1102  }
1103  }
1104  break;
1105 
1106  /* Do we need to refresh ourselves? */
1107  case Expose:{
1108 #ifdef DEBUG_XEVENTS
1109  printf("window %p: Expose (count = %d)\n", data, xevent.xexpose.count);
1110 #endif
1112  }
1113  break;
1114 
1115  case MotionNotify:{
1116  SDL_Mouse *mouse = SDL_GetMouse();
1117  if(!mouse->relative_mode || mouse->relative_mode_warp) {
1118 #ifdef DEBUG_MOTION
1119  printf("window %p: X11 motion: %d,%d\n", data, xevent.xmotion.x, xevent.xmotion.y);
1120 #endif
1121 
1122  SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y);
1123  }
1124  }
1125  break;
1126 
1127  case ButtonPress:{
1128  int xticks = 0, yticks = 0;
1129 #ifdef DEBUG_XEVENTS
1130  printf("window %p: ButtonPress (X11 button = %d)\n", data, xevent.xbutton.button);
1131 #endif
1132  if (X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) {
1133  SDL_SendMouseWheel(data->window, 0, (float) xticks, (float) yticks, SDL_MOUSEWHEEL_NORMAL);
1134  } else {
1135  SDL_bool ignore_click = SDL_FALSE;
1136  int button = xevent.xbutton.button;
1137  if(button == Button1) {
1138  if (ProcessHitTest(_this, data, &xevent)) {
1140  break; /* don't pass this event on to app. */
1141  }
1142  }
1143  else if(button > 7) {
1144  /* X button values 4-7 are used for scrolling, so X1 is 8, X2 is 9, ...
1145  => subtract (8-SDL_BUTTON_X1) to get value SDL expects */
1146  button -= (8-SDL_BUTTON_X1);
1147  }
1148  if (data->last_focus_event_time) {
1149  const int X11_FOCUS_CLICK_TIMEOUT = 10;
1150  if (!SDL_TICKS_PASSED(SDL_GetTicks(), data->last_focus_event_time + X11_FOCUS_CLICK_TIMEOUT)) {
1152  }
1153  data->last_focus_event_time = 0;
1154  }
1155  if (!ignore_click) {
1156  SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button);
1157  }
1158  }
1159  X11_UpdateUserTime(data, xevent.xbutton.time);
1160  }
1161  break;
1162 
1163  case ButtonRelease:{
1164  int button = xevent.xbutton.button;
1165  /* The X server sends a Release event for each Press for wheels. Ignore them. */
1166  int xticks = 0, yticks = 0;
1167 #ifdef DEBUG_XEVENTS
1168  printf("window %p: ButtonRelease (X11 button = %d)\n", data, xevent.xbutton.button);
1169 #endif
1170  if (!X11_IsWheelEvent(display, &xevent, &xticks, &yticks)) {
1171  if (button > 7) {
1172  /* see explanation at case ButtonPress */
1173  button -= (8-SDL_BUTTON_X1);
1174  }
1175  SDL_SendMouseButton(data->window, 0, SDL_RELEASED, button);
1176  }
1177  }
1178  break;
1179 
1180  case PropertyNotify:{
1181 #ifdef DEBUG_XEVENTS
1182  unsigned char *propdata;
1183  int status, real_format;
1184  Atom real_type;
1185  unsigned long items_read, items_left;
1186 
1187  char *name = X11_XGetAtomName(display, xevent.xproperty.atom);
1188  if (name) {
1189  printf("window %p: PropertyNotify: %s %s time=%lu\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent.xproperty.time);
1190  X11_XFree(name);
1191  }
1192 
1193  status = X11_XGetWindowProperty(display, data->xwindow, xevent.xproperty.atom, 0L, 8192L, False, AnyPropertyType, &real_type, &real_format, &items_read, &items_left, &propdata);
1194  if (status == Success && items_read > 0) {
1195  if (real_type == XA_INTEGER) {
1196  int *values = (int *)propdata;
1197 
1198  printf("{");
1199  for (i = 0; i < items_read; i++) {
1200  printf(" %d", values[i]);
1201  }
1202  printf(" }\n");
1203  } else if (real_type == XA_CARDINAL) {
1204  if (real_format == 32) {
1205  Uint32 *values = (Uint32 *)propdata;
1206 
1207  printf("{");
1208  for (i = 0; i < items_read; i++) {
1209  printf(" %d", values[i]);
1210  }
1211  printf(" }\n");
1212  } else if (real_format == 16) {
1213  Uint16 *values = (Uint16 *)propdata;
1214 
1215  printf("{");
1216  for (i = 0; i < items_read; i++) {
1217  printf(" %d", values[i]);
1218  }
1219  printf(" }\n");
1220  } else if (real_format == 8) {
1221  Uint8 *values = (Uint8 *)propdata;
1222 
1223  printf("{");
1224  for (i = 0; i < items_read; i++) {
1225  printf(" %d", values[i]);
1226  }
1227  printf(" }\n");
1228  }
1229  } else if (real_type == XA_STRING ||
1230  real_type == videodata->UTF8_STRING) {
1231  printf("{ \"%s\" }\n", propdata);
1232  } else if (real_type == XA_ATOM) {
1233  Atom *atoms = (Atom *)propdata;
1234 
1235  printf("{");
1236  for (i = 0; i < items_read; i++) {
1237  char *atomname = X11_XGetAtomName(display, atoms[i]);
1238  if (atomname) {
1239  printf(" %s", atomname);
1240  X11_XFree(atomname);
1241  }
1242  }
1243  printf(" }\n");
1244  } else {
1245  char *atomname = X11_XGetAtomName(display, real_type);
1246  printf("Unknown type: %ld (%s)\n", real_type, atomname ? atomname : "UNKNOWN");
1247  if (atomname) {
1248  X11_XFree(atomname);
1249  }
1250  }
1251  }
1252  if (status == Success) {
1253  X11_XFree(propdata);
1254  }
1255 #endif /* DEBUG_XEVENTS */
1256 
1257  /* Take advantage of this moment to make sure user_time has a
1258  valid timestamp from the X server, so if we later try to
1259  raise/restore this window, _NET_ACTIVE_WINDOW can have a
1260  non-zero timestamp, even if there's never been a mouse or
1261  key press to this window so far. Note that we don't try to
1262  set _NET_WM_USER_TIME here, though. That's only for legit
1263  user interaction with the window. */
1264  if (!data->user_time) {
1265  data->user_time = xevent.xproperty.time;
1266  }
1267 
1268  if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) {
1269  /* Get the new state from the window manager.
1270  Compositing window managers can alter visibility of windows
1271  without ever mapping / unmapping them, so we handle that here,
1272  because they use the NETWM protocol to notify us of changes.
1273  */
1274  const Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window);
1275  const Uint32 changed = flags ^ data->window->flags;
1276 
1277  if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) {
1278  if (flags & SDL_WINDOW_HIDDEN) {
1279  X11_DispatchUnmapNotify(data);
1280  } else {
1281  X11_DispatchMapNotify(data);
1282  }
1283  }
1284 
1285  if (changed & SDL_WINDOW_MAXIMIZED) {
1286  if (flags & SDL_WINDOW_MAXIMIZED) {
1288  } else {
1290  }
1291  }
1292  } else if (xevent.xproperty.atom == videodata->XKLAVIER_STATE) {
1293  /* Hack for Ubuntu 12.04 (etc) that doesn't send MappingNotify
1294  events when the keyboard layout changes (for example,
1295  changing from English to French on the menubar's keyboard
1296  icon). Since it changes the XKLAVIER_STATE property, we
1297  notice and reinit our keymap here. This might not be the
1298  right approach, but it seems to work. */
1301  } else if (xevent.xproperty.atom == videodata->_NET_FRAME_EXTENTS) {
1302  Atom type;
1303  int format;
1304  unsigned long nitems, bytes_after;
1305  unsigned char *property;
1306  if (X11_XGetWindowProperty(display, data->xwindow, videodata->_NET_FRAME_EXTENTS, 0, 16, 0, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &property) == Success) {
1307  if (type != None && nitems == 4) {
1308  data->border_left = (int) ((long*)property)[0];
1309  data->border_right = (int) ((long*)property)[1];
1310  data->border_top = (int) ((long*)property)[2];
1311  data->border_bottom = (int) ((long*)property)[3];
1312  }
1313  X11_XFree(property);
1314 
1315  #ifdef DEBUG_XEVENTS
1316  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);
1317  #endif
1318  }
1319  }
1320  }
1321  break;
1322 
1323  case SelectionNotify: {
1324  Atom target = xevent.xselection.target;
1325 #ifdef DEBUG_XEVENTS
1326  printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
1327  xevent.xselection.requestor, xevent.xselection.target);
1328 #endif
1329  if (target == data->xdnd_req) {
1330  /* read data */
1331  SDL_x11Prop p;
1332  X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY);
1333 
1334  if (p.format == 8) {
1335  /* !!! FIXME: don't use strtok here. It's not reentrant and not in SDL_stdinc. */
1336  char* name = X11_XGetAtomName(display, target);
1337  char *token = strtok((char *) p.data, "\r\n");
1338  while (token != NULL) {
1339  if (SDL_strcmp("text/plain", name)==0) {
1340  SDL_SendDropText(data->window, token);
1341  } else if (SDL_strcmp("text/uri-list", name)==0) {
1342  char *fn = X11_URIToLocal(token);
1343  if (fn) {
1344  SDL_SendDropFile(data->window, fn);
1345  }
1346  }
1347  token = strtok(NULL, "\r\n");
1348  }
1350  }
1351  X11_XFree(p.data);
1352 
1353  /* send reply */
1354  SDL_memset(&m, 0, sizeof(XClientMessageEvent));
1355  m.type = ClientMessage;
1356  m.display = display;
1357  m.window = data->xdnd_source;
1358  m.message_type = videodata->XdndFinished;
1359  m.format = 32;
1360  m.data.l[0] = data->xwindow;
1361  m.data.l[1] = 1;
1362  m.data.l[2] = videodata->XdndActionCopy;
1363  X11_XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m);
1364 
1365  X11_XSync(display, False);
1366  }
1367  }
1368  break;
1369 
1370  default:{
1371 #ifdef DEBUG_XEVENTS
1372  printf("window %p: Unhandled event %d\n", data, xevent.type);
1373 #endif
1374  }
1375  break;
1376  }
1377 }
1378 
1379 static void
1380 X11_HandleFocusChanges(_THIS)
1381 {
1382  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
1383  int i;
1384 
1385  if (videodata && videodata->windowlist) {
1386  for (i = 0; i < videodata->numwindows; ++i) {
1387  SDL_WindowData *data = videodata->windowlist[i];
1388  if (data && data->pending_focus != PENDING_FOCUS_NONE) {
1389  Uint32 now = SDL_GetTicks();
1390  if (SDL_TICKS_PASSED(now, data->pending_focus_time)) {
1391  if (data->pending_focus == PENDING_FOCUS_IN) {
1392  X11_DispatchFocusIn(_this, data);
1393  } else {
1394  X11_DispatchFocusOut(_this, data);
1395  }
1397  }
1398  }
1399  }
1400  }
1401 }
1402 /* Ack! X11_XPending() actually performs a blocking read if no events available */
1403 static int
1404 X11_Pending(Display * display)
1405 {
1406  /* Flush the display connection and look to see if events are queued */
1407  X11_XFlush(display);
1408  if (X11_XEventsQueued(display, QueuedAlready)) {
1409  return (1);
1410  }
1411 
1412  /* More drastic measures are required -- see if X is ready to talk */
1413  if (SDL_IOReady(ConnectionNumber(display), SDL_FALSE, 0)) {
1414  return (X11_XPending(display));
1415  }
1416 
1417  /* Oh well, nothing is ready .. */
1418  return (0);
1419 }
1420 
1421 void
1423 {
1425 
1426  if (data->last_mode_change_deadline) {
1428  data->last_mode_change_deadline = 0; /* assume we're done. */
1429  }
1430  }
1431 
1432  /* Update activity every 30 seconds to prevent screensaver */
1433  if (_this->suspend_screensaver) {
1434  const Uint32 now = SDL_GetTicks();
1435  if (!data->screensaver_activity ||
1436  SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
1437  X11_XResetScreenSaver(data->display);
1438 
1439 #if SDL_USE_LIBDBUS
1440  SDL_DBus_ScreensaverTickle();
1441 #endif
1442 
1443  data->screensaver_activity = now;
1444  }
1445  }
1446 
1447  /* Keep processing pending events */
1448  while (X11_Pending(data->display)) {
1449  X11_DispatchEvent(_this);
1450  }
1451 
1452 #ifdef SDL_USE_IME
1455  }
1456 #endif
1457 
1458  /* FIXME: Only need to do this when there are pending focus changes */
1459  X11_HandleFocusChanges(_this);
1460 }
1461 
1462 
1463 void
1465 {
1466 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
1468  int dummy;
1469  int major_version, minor_version;
1470 #endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
1471 
1472 #if SDL_USE_LIBDBUS
1473  if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) {
1474  return;
1475  }
1476 
1477  if (_this->suspend_screensaver) {
1478  SDL_DBus_ScreensaverTickle();
1479  }
1480 #endif
1481 
1482 #if SDL_VIDEO_DRIVER_X11_XSCRNSAVER
1483  if (SDL_X11_HAVE_XSS) {
1484  /* X11_XScreenSaverSuspend was introduced in MIT-SCREEN-SAVER 1.1 */
1485  if (!X11_XScreenSaverQueryExtension(data->display, &dummy, &dummy) ||
1486  !X11_XScreenSaverQueryVersion(data->display,
1487  &major_version, &minor_version) ||
1488  major_version < 1 || (major_version == 1 && minor_version < 1)) {
1489  return;
1490  }
1491 
1492  X11_XScreenSaverSuspend(data->display, _this->suspend_screensaver);
1493  X11_XResetScreenSaver(data->display);
1494  }
1495 #endif
1496 }
1497 
1498 #endif /* SDL_VIDEO_DRIVER_X11 */
1499 
1500 /* vi: set ts=4 sw=4 expandtab: */
void SDL_IME_SetFocus(SDL_bool focused)
Definition: SDL_ime.c:116
void X11_PumpEvents(_THIS)
SDL_version version
Definition: SDL_syswm.h:137
int last_y
Definition: SDL_mouse_c.h:82
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:112
SDL_Texture * button
int SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS)
Definition: SDL_poll.c:38
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
Uint32 X11_GetNetWMState(_THIS, Window xwindow)
int last_x
Definition: SDL_mouse_c.h:82
void * hit_test_data
Definition: SDL_sysvideo.h:107
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
unsigned long user_time
Definition: SDL_x11window.h:68
SDL_bool relative_mode_warp
Definition: SDL_mouse_c.h:88
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
int SDL_SendDropFile(SDL_Window *window, const char *file)
struct wl_display * display
GLfloat GLfloat p
The structure that defines a point.
Definition: SDL_rect.h:48
const GLfloat * m
void SDL_IME_UpdateTextRect(SDL_Rect *rect)
Definition: SDL_ime.c:139
SDL_WindowData ** windowlist
Definition: SDL_x11video.h:83
#define memset
Definition: SDL_malloc.c:619
#define SDL_ENABLE
Definition: SDL_events.h:722
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
Definition: SDL_ime.c:130
Atom _NET_FRAME_EXTENTS
Definition: SDL_x11video.h:113
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
SDL_Window * window
#define SDL_BUTTON_X1
Definition: SDL_mouse.h:285
KeyCode filter_code
Definition: SDL_x11video.h:141
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:151
#define SDL_GetKeyboardFocus
uint32_t Uint32
Definition: SDL_stdinc.h:181
union SDL_SysWMmsg::@16 msg
GLenum GLsizei len
SDL_bool selection_waiting
Definition: SDL_x11video.h:127
int SDL_SendDropComplete(SDL_Window *window)
int SDL_SendSysWMEvent(SDL_SysWMmsg *message)
Definition: SDL_events.c:933
GLuint const GLchar * name
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:679
#define SDL_GetHintBoolean
Atom _NET_WM_STATE
Definition: SDL_x11video.h:95
#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:121
SDL_HitTestResult
Possible return values from the SDL_HitTest callback.
Definition: SDL_video.h:993
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
int x
Definition: SDL_rect.h:50
GLenum GLsizei GLsizei GLint * values
Atom _NET_WM_USER_TIME
Definition: SDL_x11video.h:111
Uint32 screensaver_activity
Uint32 pending_focus_time
Definition: SDL_x11window.h:65
int SDL_SendDropText(SDL_Window *window, const char *text)
Atom WM_DELETE_WINDOW
Definition: SDL_x11video.h:93
#define SDL_GetEventState(type)
Definition: SDL_events.h:735
#define SDL_GetKeyboardState
void X11_SuspendScreenSaver(_THIS)
KeySym X11_KeyCodeToSym(_THIS, KeyCode, unsigned char group)
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:237
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
int y
Definition: SDL_rect.h:51
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
#define _THIS
struct SDL_VideoData * videodata
int SDL_SendClipboardUpdate(void)
uint8_t Uint8
Definition: SDL_stdinc.h:157
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:789
struct _cl_event * event
SDL_bool relative_mode
Definition: SDL_mouse_c.h:87
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
GLenum GLint GLuint mask
GLubyte GLubyte GLubyte GLubyte w
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
Window clipboard_window
Definition: SDL_x11video.h:86
void X11_UpdateKeymap(_THIS)
GLenum GLuint GLenum GLsizei const GLchar * buf
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
Window xdnd_source
Definition: SDL_x11window.h:70
void SDL_IME_PumpEvents()
Definition: SDL_ime.c:146
void SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
Definition: SDL_keyboard.c:865
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:138
GLenum target
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:512
SDL_HitTest hit_test
Definition: SDL_sysvideo.h:106
Atom X11_GetSDLCutBufferClipboardType(Display *display)
GLbitfield flags
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
struct SDL_SysWMmsg::@16::@17 x11
int SDL_SendKeymapChangedEvent(void)
Definition: SDL_events.c:950
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
#define SDL_strlen
#define PENDING_FOCUS_TIME
Definition: SDL_x11window.h:30
The type used to identify a window.
Definition: SDL_sysvideo.h:73
GLdouble n
uint16_t Uint16
Definition: SDL_stdinc.h:169
XConfigureEvent last_xconfigure
Definition: SDL_x11window.h:66
int X11_HandleXinput2Event(SDL_VideoData *videodata, XGenericEventCookie *cookie)
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
SDL_bool suspend_screensaver
Definition: SDL_sysvideo.h:310
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
Uint32 last_focus_event_time
Definition: SDL_x11window.h:63
#define SDL_TEXTINPUTEVENT_TEXT_SIZE
Definition: SDL_events.h:217
#define SDL_strcmp
Uint32 last_mode_change_deadline
Definition: SDL_x11video.h:131
#define SDL_PRESSED
Definition: SDL_events.h:50
Uint32 flags
Definition: SDL_sysvideo.h:83
#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_RELEASED
Definition: SDL_events.h:49
#define SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
Allow mouse click events when clicking to focus an SDL window.
Definition: SDL_hints.h:295
PendingFocusEnum pending_focus
Definition: SDL_x11window.h:64
struct XGenericEventCookie XGenericEventCookie
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:506
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:43
Atom WM_TAKE_FOCUS
Definition: SDL_x11video.h:94
#define SDL_memset