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