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