SDL  2.0
SDL_x11window.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2017 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 "SDL_assert.h"
26 #include "SDL_hints.h"
27 #include "../SDL_sysvideo.h"
28 #include "../SDL_pixels_c.h"
29 #include "../../events/SDL_keyboard_c.h"
30 #include "../../events/SDL_mouse_c.h"
31 
32 #include "SDL_x11video.h"
33 #include "SDL_x11mouse.h"
34 #include "SDL_x11shape.h"
35 #include "SDL_x11xinput2.h"
36 
37 #if SDL_VIDEO_OPENGL_EGL
38 #include "SDL_x11opengles.h"
39 #endif
40 
41 #include "SDL_timer.h"
42 #include "SDL_syswm.h"
43 #include "SDL_log.h"
44 
45 #define _NET_WM_STATE_REMOVE 0l
46 #define _NET_WM_STATE_ADD 1l
47 
48 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
49 {
50  return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
51 }
52 static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
53 {
54  return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
55 }
56 
57 /*
58 static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
59 {
60  return ev->type == ConfigureNotify && ev->xconfigure.window == *((Window*)win);
61 }
62 static Bool
63 X11_XIfEventTimeout(Display *display, XEvent *event_return, Bool (*predicate)(), XPointer arg, int timeoutMS)
64 {
65  Uint32 start = SDL_GetTicks();
66 
67  while (!X11_XCheckIfEvent(display, event_return, predicate, arg)) {
68  if (SDL_TICKS_PASSED(SDL_GetTicks(), start + timeoutMS)) {
69  return False;
70  }
71  }
72  return True;
73 }
74 */
75 
76 static SDL_bool
77 X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
78 {
80  return (data->fswindow != 0);
81 }
82 
83 static SDL_bool
84 X11_IsWindowMapped(_THIS, SDL_Window * window)
85 {
86  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
87  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
88  XWindowAttributes attr;
89 
90  X11_XGetWindowAttributes(videodata->display, data->xwindow, &attr);
91  if (attr.map_state != IsUnmapped) {
92  return SDL_TRUE;
93  } else {
94  return SDL_FALSE;
95  }
96 }
97 
98 #if 0
99 static SDL_bool
100 X11_IsActionAllowed(SDL_Window *window, Atom action)
101 {
102  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
103  Atom _NET_WM_ALLOWED_ACTIONS = data->videodata->_NET_WM_ALLOWED_ACTIONS;
104  Atom type;
105  Display *display = data->videodata->display;
106  int form;
107  unsigned long remain;
108  unsigned long len, i;
109  Atom *list;
110  SDL_bool ret = SDL_FALSE;
111 
112  if (X11_XGetWindowProperty(display, data->xwindow, _NET_WM_ALLOWED_ACTIONS, 0, 1024, False, XA_ATOM, &type, &form, &len, &remain, (unsigned char **)&list) == Success)
113  {
114  for (i=0; i<len; ++i)
115  {
116  if (list[i] == action) {
117  ret = SDL_TRUE;
118  break;
119  }
120  }
121  X11_XFree(list);
122  }
123  return ret;
124 }
125 #endif /* 0 */
126 
127 void
128 X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags)
129 {
130  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
131  Display *display = videodata->display;
132  /* !!! FIXME: just dereference videodata below instead of copying to locals. */
133  Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
134  /* Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN; */
135  Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
136  Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
137  Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
138  Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
139  Atom _NET_WM_STATE_ABOVE = videodata->_NET_WM_STATE_ABOVE;
140  Atom _NET_WM_STATE_SKIP_TASKBAR = videodata->_NET_WM_STATE_SKIP_TASKBAR;
141  Atom _NET_WM_STATE_SKIP_PAGER = videodata->_NET_WM_STATE_SKIP_PAGER;
142  Atom atoms[16];
143  int count = 0;
144 
145  /* The window manager sets this property, we shouldn't set it.
146  If we did, this would indicate to the window manager that we don't
147  actually want to be mapped during X11_XMapRaised(), which would be bad.
148  *
149  if (flags & SDL_WINDOW_HIDDEN) {
150  atoms[count++] = _NET_WM_STATE_HIDDEN;
151  }
152  */
153 
154  if (flags & SDL_WINDOW_ALWAYS_ON_TOP) {
155  atoms[count++] = _NET_WM_STATE_ABOVE;
156  }
157  if (flags & SDL_WINDOW_SKIP_TASKBAR) {
158  atoms[count++] = _NET_WM_STATE_SKIP_TASKBAR;
159  atoms[count++] = _NET_WM_STATE_SKIP_PAGER;
160  }
161  if (flags & SDL_WINDOW_INPUT_FOCUS) {
162  atoms[count++] = _NET_WM_STATE_FOCUSED;
163  }
164  if (flags & SDL_WINDOW_MAXIMIZED) {
165  atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
166  atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
167  }
168  if (flags & SDL_WINDOW_FULLSCREEN) {
169  atoms[count++] = _NET_WM_STATE_FULLSCREEN;
170  }
171 
172  SDL_assert(count <= SDL_arraysize(atoms));
173 
174  if (count > 0) {
175  X11_XChangeProperty(display, xwindow, _NET_WM_STATE, XA_ATOM, 32,
176  PropModeReplace, (unsigned char *)atoms, count);
177  } else {
178  X11_XDeleteProperty(display, xwindow, _NET_WM_STATE);
179  }
180 }
181 
182 Uint32
183 X11_GetNetWMState(_THIS, Window xwindow)
184 {
185  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
186  Display *display = videodata->display;
187  Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
188  Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN;
189  Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
190  Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
191  Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
192  Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
193  Atom actualType;
194  int actualFormat;
195  unsigned long i, numItems, bytesAfter;
196  unsigned char *propertyValue = NULL;
197  long maxLength = 1024;
198  Uint32 flags = 0;
199 
200  if (X11_XGetWindowProperty(display, xwindow, _NET_WM_STATE,
201  0l, maxLength, False, XA_ATOM, &actualType,
202  &actualFormat, &numItems, &bytesAfter,
203  &propertyValue) == Success) {
204  Atom *atoms = (Atom *) propertyValue;
205  int maximized = 0;
206  int fullscreen = 0;
207 
208  for (i = 0; i < numItems; ++i) {
209  if (atoms[i] == _NET_WM_STATE_HIDDEN) {
210  flags |= SDL_WINDOW_HIDDEN;
211  } else if (atoms[i] == _NET_WM_STATE_FOCUSED) {
212  flags |= SDL_WINDOW_INPUT_FOCUS;
213  } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
214  maximized |= 1;
215  } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
216  maximized |= 2;
217  } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
218  fullscreen = 1;
219  }
220  }
221  if (maximized == 3) {
222  flags |= SDL_WINDOW_MAXIMIZED;
223  }
224 
225  if (fullscreen == 1) {
226  flags |= SDL_WINDOW_FULLSCREEN;
227  }
228 
229  /* If the window is unmapped, numItems will be zero and _NET_WM_STATE_HIDDEN
230  * will not be set. Do an additional check to see if the window is unmapped
231  * and mark it as SDL_WINDOW_HIDDEN if it is.
232  */
233  {
234  XWindowAttributes attr;
235  SDL_memset(&attr,0,sizeof(attr));
236  X11_XGetWindowAttributes(videodata->display, xwindow, &attr);
237  if (attr.map_state == IsUnmapped) {
238  flags |= SDL_WINDOW_HIDDEN;
239  }
240  }
241  X11_XFree(propertyValue);
242  }
243 
244  /* FIXME, check the size hints for resizable */
245  /* flags |= SDL_WINDOW_RESIZABLE; */
246 
247  return flags;
248 }
249 
250 static int
251 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
252 {
253  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
254  SDL_WindowData *data;
255  int numwindows = videodata->numwindows;
256  int windowlistlength = videodata->windowlistlength;
257  SDL_WindowData **windowlist = videodata->windowlist;
258 
259  /* Allocate the window data */
260  data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
261  if (!data) {
262  return SDL_OutOfMemory();
263  }
264  data->window = window;
265  data->xwindow = w;
266 #ifdef X_HAVE_UTF8_STRING
267  if (SDL_X11_HAVE_UTF8 && videodata->im) {
268  data->ic =
269  X11_XCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
270  XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
271  NULL);
272  }
273 #endif
274  data->created = created;
275  data->videodata = videodata;
276 
277  /* Associate the data with the window */
278 
279  if (numwindows < windowlistlength) {
280  windowlist[numwindows] = data;
281  videodata->numwindows++;
282  } else {
283  windowlist =
284  (SDL_WindowData **) SDL_realloc(windowlist,
285  (numwindows +
286  1) * sizeof(*windowlist));
287  if (!windowlist) {
288  SDL_free(data);
289  return SDL_OutOfMemory();
290  }
291  windowlist[numwindows] = data;
292  videodata->numwindows++;
293  videodata->windowlistlength++;
294  videodata->windowlist = windowlist;
295  }
296 
297  /* Fill in the SDL window with the window data */
298  {
299  XWindowAttributes attrib;
300 
301  X11_XGetWindowAttributes(data->videodata->display, w, &attrib);
302  window->x = attrib.x;
303  window->y = attrib.y;
304  window->w = attrib.width;
305  window->h = attrib.height;
306  if (attrib.map_state != IsUnmapped) {
307  window->flags |= SDL_WINDOW_SHOWN;
308  } else {
309  window->flags &= ~SDL_WINDOW_SHOWN;
310  }
311  data->visual = attrib.visual;
312  data->colormap = attrib.colormap;
313  }
314 
315  window->flags |= X11_GetNetWMState(_this, w);
316 
317  {
318  Window FocalWindow;
319  int RevertTo=0;
320  X11_XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo);
321  if (FocalWindow==w)
322  {
323  window->flags |= SDL_WINDOW_INPUT_FOCUS;
324  }
325 
326  if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
328  }
329 
330  if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
331  /* Tell x11 to clip mouse */
332  }
333  }
334 
335  /* All done! */
336  window->driverdata = data;
337  return 0;
338 }
339 
340 static void
341 SetWindowBordered(Display *display, int screen, Window window, SDL_bool border)
342 {
343  /*
344  * this code used to check for KWM_WIN_DECORATION, but KDE hasn't
345  * supported it for years and years. It now respects _MOTIF_WM_HINTS.
346  * Gnome is similar: just use the Motif atom.
347  */
348 
349  Atom WM_HINTS = X11_XInternAtom(display, "_MOTIF_WM_HINTS", True);
350  if (WM_HINTS != None) {
351  /* Hints used by Motif compliant window managers */
352  struct
353  {
354  unsigned long flags;
355  unsigned long functions;
356  unsigned long decorations;
357  long input_mode;
358  unsigned long status;
359  } MWMHints = {
360  (1L << 1), 0, border ? 1 : 0, 0, 0
361  };
362 
363  X11_XChangeProperty(display, window, WM_HINTS, WM_HINTS, 32,
364  PropModeReplace, (unsigned char *) &MWMHints,
365  sizeof(MWMHints) / sizeof(long));
366  } else { /* set the transient hints instead, if necessary */
367  X11_XSetTransientForHint(display, window, RootWindow(display, screen));
368  }
369 }
370 
371 int
373 {
375  SDL_DisplayData *displaydata =
377  SDL_WindowData *windowdata;
378  Display *display = data->display;
379  int screen = displaydata->screen;
380  Visual *visual;
381  int depth;
382  XSetWindowAttributes xattr;
383  Window w;
384  XSizeHints *sizehints;
385  XWMHints *wmhints;
386  XClassHint *classhints;
387  Atom _NET_WM_BYPASS_COMPOSITOR;
388  Atom _NET_WM_WINDOW_TYPE;
389  Atom wintype;
390  const char *wintype_name = NULL;
391  long compositor = 1;
392  Atom _NET_WM_PID;
393  Atom XdndAware, xdnd_version = 5;
394  long fevent = 0;
395 
396 #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_EGL
397  if ((window->flags & SDL_WINDOW_OPENGL) &&
398  !SDL_getenv("SDL_VIDEO_X11_VISUALID")) {
399  XVisualInfo *vinfo = NULL;
400 
401 #if SDL_VIDEO_OPENGL_EGL
404  && ( !_this->gl_data || X11_GL_UseEGL(_this) )
405 #endif
406  ) {
407  vinfo = X11_GLES_GetVisual(_this, display, screen);
408  } else
409 #endif
410  {
411 #if SDL_VIDEO_OPENGL_GLX
412  vinfo = X11_GL_GetVisual(_this, display, screen);
413 #endif
414  }
415 
416  if (!vinfo) {
417  return -1;
418  }
419  visual = vinfo->visual;
420  depth = vinfo->depth;
421  X11_XFree(vinfo);
422  } else
423 #endif
424  {
425  visual = displaydata->visual;
426  depth = displaydata->depth;
427  }
428 
429  xattr.override_redirect = ((window->flags & SDL_WINDOW_TOOLTIP) || (window->flags & SDL_WINDOW_POPUP_MENU)) ? True : False;
430  xattr.background_pixmap = None;
431  xattr.border_pixel = 0;
432 
433  if (visual->class == DirectColor) {
434  XColor *colorcells;
435  int i;
436  int ncolors;
437  int rmax, gmax, bmax;
438  int rmask, gmask, bmask;
439  int rshift, gshift, bshift;
440 
441  xattr.colormap =
442  X11_XCreateColormap(display, RootWindow(display, screen),
443  visual, AllocAll);
444 
445  /* If we can't create a colormap, then we must die */
446  if (!xattr.colormap) {
447  return SDL_SetError("Could not create writable colormap");
448  }
449 
450  /* OK, we got a colormap, now fill it in as best as we can */
451  colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
452  if (!colorcells) {
453  return SDL_OutOfMemory();
454  }
455  ncolors = visual->map_entries;
456  rmax = 0xffff;
457  gmax = 0xffff;
458  bmax = 0xffff;
459 
460  rshift = 0;
461  rmask = visual->red_mask;
462  while (0 == (rmask & 1)) {
463  rshift++;
464  rmask >>= 1;
465  }
466 
467  gshift = 0;
468  gmask = visual->green_mask;
469  while (0 == (gmask & 1)) {
470  gshift++;
471  gmask >>= 1;
472  }
473 
474  bshift = 0;
475  bmask = visual->blue_mask;
476  while (0 == (bmask & 1)) {
477  bshift++;
478  bmask >>= 1;
479  }
480 
481  /* build the color table pixel values */
482  for (i = 0; i < ncolors; i++) {
483  Uint32 red = (rmax * i) / (ncolors - 1);
484  Uint32 green = (gmax * i) / (ncolors - 1);
485  Uint32 blue = (bmax * i) / (ncolors - 1);
486 
487  Uint32 rbits = (rmask * i) / (ncolors - 1);
488  Uint32 gbits = (gmask * i) / (ncolors - 1);
489  Uint32 bbits = (bmask * i) / (ncolors - 1);
490 
491  Uint32 pix =
492  (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
493 
494  colorcells[i].pixel = pix;
495 
496  colorcells[i].red = red;
497  colorcells[i].green = green;
498  colorcells[i].blue = blue;
499 
500  colorcells[i].flags = DoRed | DoGreen | DoBlue;
501  }
502 
503  X11_XStoreColors(display, xattr.colormap, colorcells, ncolors);
504 
505  SDL_free(colorcells);
506  } else {
507  xattr.colormap =
508  X11_XCreateColormap(display, RootWindow(display, screen),
509  visual, AllocNone);
510  }
511 
512  w = X11_XCreateWindow(display, RootWindow(display, screen),
513  window->x, window->y, window->w, window->h,
514  0, depth, InputOutput, visual,
515  (CWOverrideRedirect | CWBackPixmap | CWBorderPixel |
516  CWColormap), &xattr);
517  if (!w) {
518  return SDL_SetError("Couldn't create window");
519  }
520 
521  SetWindowBordered(display, screen, w,
522  (window->flags & SDL_WINDOW_BORDERLESS) == 0);
523 
524  sizehints = X11_XAllocSizeHints();
525  /* Setup the normal size hints */
526  sizehints->flags = 0;
527  if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
528  sizehints->min_width = sizehints->max_width = window->w;
529  sizehints->min_height = sizehints->max_height = window->h;
530  sizehints->flags |= (PMaxSize | PMinSize);
531  }
532  sizehints->x = window->x;
533  sizehints->y = window->y;
534  sizehints->flags |= USPosition;
535 
536  /* Setup the input hints so we get keyboard input */
537  wmhints = X11_XAllocWMHints();
538  wmhints->input = True;
539  wmhints->window_group = data->window_group;
540  wmhints->flags = InputHint | WindowGroupHint;
541 
542  /* Setup the class hints so we can get an icon (AfterStep) */
543  classhints = X11_XAllocClassHint();
544  classhints->res_name = data->classname;
545  classhints->res_class = data->classname;
546 
547  /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
548  X11_XSetWMProperties(display, w, NULL, NULL, NULL, 0, sizehints, wmhints, classhints);
549 
550  X11_XFree(sizehints);
551  X11_XFree(wmhints);
552  X11_XFree(classhints);
553  /* Set the PID related to the window for the given hostname, if possible */
554  if (data->pid > 0) {
555  long pid = (long) data->pid;
556  _NET_WM_PID = X11_XInternAtom(display, "_NET_WM_PID", False);
557  X11_XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
558  (unsigned char *) &pid, 1);
559  }
560 
561  /* Set the window manager state */
562  X11_SetNetWMState(_this, w, window->flags);
563 
564  compositor = 2; /* don't disable compositing except for "normal" windows */
565 
566  if (window->flags & SDL_WINDOW_UTILITY) {
567  wintype_name = "_NET_WM_WINDOW_TYPE_UTILITY";
568  } else if (window->flags & SDL_WINDOW_TOOLTIP) {
569  wintype_name = "_NET_WM_WINDOW_TYPE_TOOLTIP";
570  } else if (window->flags & SDL_WINDOW_POPUP_MENU) {
571  wintype_name = "_NET_WM_WINDOW_TYPE_POPUP_MENU";
572  } else {
573  wintype_name = "_NET_WM_WINDOW_TYPE_NORMAL";
574  compositor = 1; /* disable compositing for "normal" windows */
575  }
576 
577  /* Let the window manager know what type of window we are. */
578  _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
579  wintype = X11_XInternAtom(display, wintype_name, False);
580  X11_XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
581  PropModeReplace, (unsigned char *)&wintype, 1);
582 
583  _NET_WM_BYPASS_COMPOSITOR = X11_XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False);
584  X11_XChangeProperty(display, w, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
585  PropModeReplace,
586  (unsigned char *)&compositor, 1);
587 
588  {
589  Atom protocols[3];
590  int proto_count = 0;
591 
592  protocols[proto_count++] = data->WM_DELETE_WINDOW; /* Allow window to be deleted by the WM */
593  protocols[proto_count++] = data->WM_TAKE_FOCUS; /* Since we will want to set input focus explicitly */
594 
595  /* Default to using ping if there is no hint */
597  protocols[proto_count++] = data->_NET_WM_PING; /* Respond so WM knows we're alive */
598  }
599 
600  SDL_assert(proto_count <= sizeof(protocols) / sizeof(protocols[0]));
601 
602  X11_XSetWMProtocols(display, w, protocols, proto_count);
603  }
604 
605  if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
606  X11_XDestroyWindow(display, w);
607  return -1;
608  }
609  windowdata = (SDL_WindowData *) window->driverdata;
610 
612  if ((window->flags & SDL_WINDOW_OPENGL) &&
614 #if SDL_VIDEO_OPENGL_GLX
615  && ( !_this->gl_data || X11_GL_UseEGL(_this) )
616 #endif
617  ) {
618 #if SDL_VIDEO_OPENGL_EGL
619  if (!_this->egl_data) {
620  X11_XDestroyWindow(display, w);
621  return -1;
622  }
623 
624  /* Create the GLES window surface */
625  windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) w);
626 
627  if (windowdata->egl_surface == EGL_NO_SURFACE) {
628  X11_XDestroyWindow(display, w);
629  return SDL_SetError("Could not create GLES window surface");
630  }
631 #else
632  return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
633 #endif /* SDL_VIDEO_OPENGL_EGL */
634  }
635 #endif
636 
637 
638 #ifdef X_HAVE_UTF8_STRING
639  if (SDL_X11_HAVE_UTF8 && windowdata->ic) {
640  X11_XGetICValues(windowdata->ic, XNFilterEvents, &fevent, NULL);
641  }
642 #endif
643 
644  X11_Xinput2SelectTouch(_this, window);
645 
646  X11_XSelectInput(display, w,
647  (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
648  ExposureMask | ButtonPressMask | ButtonReleaseMask |
649  PointerMotionMask | KeyPressMask | KeyReleaseMask |
650  PropertyChangeMask | StructureNotifyMask |
651  KeymapStateMask | fevent));
652 
653  XdndAware = X11_XInternAtom(display, "XdndAware", False);
654  X11_XChangeProperty(display, w, XdndAware, XA_ATOM, 32,
655  PropModeReplace,
656  (unsigned char*)&xdnd_version, 1);
657 
658  X11_XFlush(display);
659 
660  return 0;
661 }
662 
663 int
664 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
665 {
666  Window w = (Window) data;
667 
668  window->title = X11_GetWindowTitle(_this, w);
669 
670  if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
671  return -1;
672  }
673  return 0;
674 }
675 
676 char *
677 X11_GetWindowTitle(_THIS, Window xwindow)
678 {
680  Display *display = data->display;
681  int status, real_format;
682  Atom real_type;
683  unsigned long items_read, items_left;
684  unsigned char *propdata;
685  char *title = NULL;
686 
687  status = X11_XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
688  0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
689  &items_read, &items_left, &propdata);
690  if (status == Success && propdata) {
691  title = SDL_strdup(SDL_static_cast(char*, propdata));
692  X11_XFree(propdata);
693  } else {
694  status = X11_XGetWindowProperty(display, xwindow, XA_WM_NAME,
695  0L, 8192L, False, XA_STRING, &real_type, &real_format,
696  &items_read, &items_left, &propdata);
697  if (status == Success && propdata) {
698  title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
699  X11_XFree(propdata);
700  } else {
701  title = SDL_strdup("");
702  }
703  }
704  return title;
705 }
706 
707 void
709 {
710  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
711  Display *display = data->videodata->display;
712  XTextProperty titleprop;
713  Status status;
714  const char *title = window->title ? window->title : "";
715  char *title_locale = NULL;
716 
717 #ifdef X_HAVE_UTF8_STRING
718  Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
719 #endif
720 
721  title_locale = SDL_iconv_utf8_locale(title);
722  if (!title_locale) {
723  SDL_OutOfMemory();
724  return;
725  }
726 
727  status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
728  SDL_free(title_locale);
729  if (status) {
730  X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
731  X11_XFree(titleprop.value);
732  }
733 #ifdef X_HAVE_UTF8_STRING
734  if (SDL_X11_HAVE_UTF8) {
735  status = X11_Xutf8TextListToTextProperty(display, (char **) &title, 1,
736  XUTF8StringStyle, &titleprop);
737  if (status == Success) {
738  X11_XSetTextProperty(display, data->xwindow, &titleprop,
739  _NET_WM_NAME);
740  X11_XFree(titleprop.value);
741  }
742  }
743 #endif
744 
745  X11_XFlush(display);
746 }
747 
748 void
750 {
751  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
752  Display *display = data->videodata->display;
753  Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
754 
755  if (icon) {
756  int propsize;
757  long *propdata;
758 
759  /* Set the _NET_WM_ICON property */
761  propsize = 2 + (icon->w * icon->h);
762  propdata = SDL_malloc(propsize * sizeof(long));
763  if (propdata) {
764  int x, y;
765  Uint32 *src;
766  long *dst;
767 
768  propdata[0] = icon->w;
769  propdata[1] = icon->h;
770  dst = &propdata[2];
771  for (y = 0; y < icon->h; ++y) {
772  src = (Uint32*)((Uint8*)icon->pixels + y * icon->pitch);
773  for (x = 0; x < icon->w; ++x) {
774  *dst++ = *src++;
775  }
776  }
777  X11_XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
778  32, PropModeReplace, (unsigned char *) propdata,
779  propsize);
780  }
781  SDL_free(propdata);
782  } else {
783  X11_XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
784  }
785  X11_XFlush(display);
786 }
787 
788 void
790 {
791  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
792  Display *display = data->videodata->display;
793 
794  X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
795  X11_XFlush(display);
796 }
797 
798 void
800 {
801  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
802  Display *display = data->videodata->display;
803 
804  if (window->flags & SDL_WINDOW_RESIZABLE) {
805  XSizeHints *sizehints = X11_XAllocSizeHints();
806  long userhints;
807 
808  X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
809 
810  sizehints->min_width = window->min_w;
811  sizehints->min_height = window->min_h;
812  sizehints->flags |= PMinSize;
813 
814  X11_XSetWMNormalHints(display, data->xwindow, sizehints);
815 
816  X11_XFree(sizehints);
817 
818  /* See comment in X11_SetWindowSize. */
819  X11_XResizeWindow(display, data->xwindow, window->w, window->h);
820  X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
821  X11_XRaiseWindow(display, data->xwindow);
822  }
823 
824  X11_XFlush(display);
825 }
826 
827 void
829 {
830  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
831  Display *display = data->videodata->display;
832 
833  if (window->flags & SDL_WINDOW_RESIZABLE) {
834  XSizeHints *sizehints = X11_XAllocSizeHints();
835  long userhints;
836 
837  X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
838 
839  sizehints->max_width = window->max_w;
840  sizehints->max_height = window->max_h;
841  sizehints->flags |= PMaxSize;
842 
843  X11_XSetWMNormalHints(display, data->xwindow, sizehints);
844 
845  X11_XFree(sizehints);
846 
847  /* See comment in X11_SetWindowSize. */
848  X11_XResizeWindow(display, data->xwindow, window->w, window->h);
849  X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
850  X11_XRaiseWindow(display, data->xwindow);
851  }
852 
853  X11_XFlush(display);
854 }
855 
856 void
858 {
859  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
860  Display *display = data->videodata->display;
861 
862  if (SDL_IsShapedWindow(window)) {
863  X11_ResizeWindowShape(window);
864  }
865  if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
866  /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the X11_XResizeWindow, thus
867  we must set the size hints to adjust the window size. */
868  XSizeHints *sizehints = X11_XAllocSizeHints();
869  long userhints;
870 
871  X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
872 
873  sizehints->min_width = sizehints->max_width = window->w;
874  sizehints->min_height = sizehints->max_height = window->h;
875  sizehints->flags |= PMinSize | PMaxSize;
876 
877  X11_XSetWMNormalHints(display, data->xwindow, sizehints);
878 
879  X11_XFree(sizehints);
880 
881  /* From Pierre-Loup:
882  WMs each have their little quirks with that. When you change the
883  size hints, they get a ConfigureNotify event with the
884  WM_NORMAL_SIZE_HINTS Atom. They all save the hints then, but they
885  don't all resize the window right away to enforce the new hints.
886 
887  Some of them resize only after:
888  - A user-initiated move or resize
889  - A code-initiated move or resize
890  - Hiding & showing window (Unmap & map)
891 
892  The following move & resize seems to help a lot of WMs that didn't
893  properly update after the hints were changed. We don't do a
894  hide/show, because there are supposedly subtle problems with doing so
895  and transitioning from windowed to fullscreen in Unity.
896  */
897  X11_XResizeWindow(display, data->xwindow, window->w, window->h);
898  X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
899  X11_XRaiseWindow(display, data->xwindow);
900  } else {
901  X11_XResizeWindow(display, data->xwindow, window->w, window->h);
902  }
903 
904  X11_XFlush(display);
905 }
906 
907 int
908 X11_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right)
909 {
910  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
911 
912  *left = data->border_left;
913  *right = data->border_right;
914  *top = data->border_top;
915  *bottom = data->border_bottom;
916 
917  return 0;
918 }
919 
920 int
921 X11_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
922 {
923  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
924  Display *display = data->videodata->display;
925  Atom _NET_WM_WINDOW_OPACITY = data->videodata->_NET_WM_WINDOW_OPACITY;
926 
927  if (opacity == 1.0f) {
928  X11_XDeleteProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY);
929  } else {
930  const Uint32 FullyOpaque = 0xFFFFFFFF;
931  const long alpha = (long) ((double)opacity * (double)FullyOpaque);
932  X11_XChangeProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
933  PropModeReplace, (unsigned char *)&alpha, 1);
934  }
935 
936  return 0;
937 }
938 
939 int
940 X11_SetWindowModalFor(_THIS, SDL_Window * modal_window, SDL_Window * parent_window) {
941  SDL_WindowData *data = (SDL_WindowData *) modal_window->driverdata;
942  SDL_WindowData *parent_data = (SDL_WindowData *) parent_window->driverdata;
943  Display *display = data->videodata->display;
944 
945  X11_XSetTransientForHint(display, data->xwindow, parent_data->xwindow);
946  return 0;
947 }
948 
949 int
951 {
952  if (X11_IsWindowMapped(_this, window)) {
953  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
954  Display *display = data->videodata->display;
955  X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime);
956  X11_XFlush(display);
957  return 0;
958  }
959  return -1;
960 }
961 
962 void
963 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
964 {
965  const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
966  const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
967  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
968  SDL_DisplayData *displaydata =
970  Display *display = data->videodata->display;
971  XEvent event;
972 
973  SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
974  X11_XFlush(display);
975 
976  if (visible) {
977  XWindowAttributes attr;
978  do {
979  X11_XSync(display, False);
980  X11_XGetWindowAttributes(display, data->xwindow, &attr);
981  } while (attr.map_state != IsViewable);
982 
983  if (focused) {
984  X11_XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
985  }
986  }
987 
988  /* make sure these don't make it to the real event queue if they fired here. */
989  X11_XSync(display, False);
990  X11_XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
991  X11_XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
992 }
993 
994 void
995 X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
996 {
997  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
998  Display *display = data->videodata->display;
999 
1000  XSizeHints *sizehints = X11_XAllocSizeHints();
1001  long userhints;
1002 
1003  X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
1004 
1005  if (resizable) {
1006  /* FIXME: Is there a better way to get max window size from X? -flibit */
1007  const int maxsize = 0x7FFFFFFF;
1008  sizehints->min_width = window->min_w;
1009  sizehints->min_height = window->min_h;
1010  sizehints->max_width = (window->max_w == 0) ? maxsize : window->max_w;
1011  sizehints->max_height = (window->max_h == 0) ? maxsize : window->max_h;
1012  } else {
1013  sizehints->min_width = window->w;
1014  sizehints->min_height = window->h;
1015  sizehints->max_width = window->w;
1016  sizehints->max_height = window->h;
1017  }
1018  sizehints->flags |= PMinSize | PMaxSize;
1019 
1020  X11_XSetWMNormalHints(display, data->xwindow, sizehints);
1021 
1022  X11_XFree(sizehints);
1023 
1024  /* See comment in X11_SetWindowSize. */
1025  X11_XResizeWindow(display, data->xwindow, window->w, window->h);
1026  X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
1027  X11_XRaiseWindow(display, data->xwindow);
1028 
1029  X11_XFlush(display);
1030 }
1031 
1032 void
1033 X11_ShowWindow(_THIS, SDL_Window * window)
1034 {
1035  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1036  Display *display = data->videodata->display;
1037  XEvent event;
1038 
1039  if (!X11_IsWindowMapped(_this, window)) {
1040  X11_XMapRaised(display, data->xwindow);
1041  /* Blocking wait for "MapNotify" event.
1042  * We use X11_XIfEvent because pXWindowEvent takes a mask rather than a type,
1043  * and XCheckTypedWindowEvent doesn't block */
1044  if(!(window->flags & SDL_WINDOW_FOREIGN))
1045  X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
1046  X11_XFlush(display);
1047  }
1048 
1049  if (!data->videodata->net_wm) {
1050  /* no WM means no FocusIn event, which confuses us. Force it. */
1051  X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime);
1052  X11_XFlush(display);
1053  }
1054 }
1055 
1056 void
1057 X11_HideWindow(_THIS, SDL_Window * window)
1058 {
1059  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1061  Display *display = data->videodata->display;
1062  XEvent event;
1063 
1064  if (X11_IsWindowMapped(_this, window)) {
1065  X11_XWithdrawWindow(display, data->xwindow, displaydata->screen);
1066  /* Blocking wait for "UnmapNotify" event */
1067  if(!(window->flags & SDL_WINDOW_FOREIGN))
1068  X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
1069  X11_XFlush(display);
1070  }
1071 }
1072 
1073 static void
1074 SetWindowActive(_THIS, SDL_Window * window)
1075 {
1076  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1077  SDL_DisplayData *displaydata =
1079  Display *display = data->videodata->display;
1080  Atom _NET_ACTIVE_WINDOW = data->videodata->_NET_ACTIVE_WINDOW;
1081 
1082  if (X11_IsWindowMapped(_this, window)) {
1083  XEvent e;
1084 
1085  /*printf("SDL Window %p: sending _NET_ACTIVE_WINDOW with timestamp %lu\n", window, data->user_time);*/
1086 
1087  SDL_zero(e);
1088  e.xany.type = ClientMessage;
1089  e.xclient.message_type = _NET_ACTIVE_WINDOW;
1090  e.xclient.format = 32;
1091  e.xclient.window = data->xwindow;
1092  e.xclient.data.l[0] = 1; /* source indication. 1 = application */
1093  e.xclient.data.l[1] = data->user_time;
1094  e.xclient.data.l[2] = 0;
1095 
1096  X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
1097  SubstructureNotifyMask | SubstructureRedirectMask, &e);
1098 
1099  X11_XFlush(display);
1100  }
1101 }
1102 
1103 void
1104 X11_RaiseWindow(_THIS, SDL_Window * window)
1105 {
1106  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1107  Display *display = data->videodata->display;
1108 
1109  X11_XRaiseWindow(display, data->xwindow);
1110  SetWindowActive(_this, window);
1111  X11_XFlush(display);
1112 }
1113 
1114 static void
1115 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
1116 {
1117  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1118  SDL_DisplayData *displaydata =
1120  Display *display = data->videodata->display;
1121  Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
1122  Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
1123  Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
1124 
1125  if (maximized) {
1126  window->flags |= SDL_WINDOW_MAXIMIZED;
1127  } else {
1128  window->flags &= ~SDL_WINDOW_MAXIMIZED;
1129  }
1130 
1131  if (X11_IsWindowMapped(_this, window)) {
1132  XEvent e;
1133 
1134  SDL_zero(e);
1135  e.xany.type = ClientMessage;
1136  e.xclient.message_type = _NET_WM_STATE;
1137  e.xclient.format = 32;
1138  e.xclient.window = data->xwindow;
1139  e.xclient.data.l[0] =
1140  maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1141  e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
1142  e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
1143  e.xclient.data.l[3] = 0l;
1144 
1145  X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
1146  SubstructureNotifyMask | SubstructureRedirectMask, &e);
1147  } else {
1148  X11_SetNetWMState(_this, data->xwindow, window->flags);
1149  }
1150  X11_XFlush(display);
1151 }
1152 
1153 void
1155 {
1156  SetWindowMaximized(_this, window, SDL_TRUE);
1157 }
1158 
1159 void
1161 {
1162  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1163  SDL_DisplayData *displaydata =
1165  Display *display = data->videodata->display;
1166 
1167  X11_XIconifyWindow(display, data->xwindow, displaydata->screen);
1168  X11_XFlush(display);
1169 }
1170 
1171 void
1173 {
1174  SetWindowMaximized(_this, window, SDL_FALSE);
1175  X11_ShowWindow(_this, window);
1176  SetWindowActive(_this, window);
1177 }
1178 
1179 /* This asks the Window Manager to handle fullscreen for us. This is the modern way. */
1180 static void
1181 X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
1182 {
1183  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1184  SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
1185  Display *display = data->videodata->display;
1186  Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
1187  Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
1188 
1189  if (X11_IsWindowMapped(_this, window)) {
1190  XEvent e;
1191 
1192  if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
1193  /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
1194  can be resized to the fullscreen resolution (or reset so we're not resizable again) */
1195  XSizeHints *sizehints = X11_XAllocSizeHints();
1196  long flags = 0;
1197  X11_XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
1198  /* set the resize flags on */
1199  if (fullscreen) {
1200  /* we are going fullscreen so turn the flags off */
1201  sizehints->flags &= ~(PMinSize | PMaxSize);
1202  } else {
1203  /* Reset the min/max width height to make the window non-resizable again */
1204  sizehints->flags |= PMinSize | PMaxSize;
1205  sizehints->min_width = sizehints->max_width = window->windowed.w;
1206  sizehints->min_height = sizehints->max_height = window->windowed.h;
1207  }
1208  X11_XSetWMNormalHints(display, data->xwindow, sizehints);
1209  X11_XFree(sizehints);
1210  }
1211 
1212  SDL_zero(e);
1213  e.xany.type = ClientMessage;
1214  e.xclient.message_type = _NET_WM_STATE;
1215  e.xclient.format = 32;
1216  e.xclient.window = data->xwindow;
1217  e.xclient.data.l[0] =
1218  fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1219  e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
1220  e.xclient.data.l[3] = 0l;
1221 
1222  X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
1223  SubstructureNotifyMask | SubstructureRedirectMask, &e);
1224 
1225  /* Fullscreen windows sometimes end up being marked maximized by
1226  window managers. Force it back to how we expect it to be. */
1227  if (!fullscreen && ((window->flags & SDL_WINDOW_MAXIMIZED) == 0)) {
1228  SDL_zero(e);
1229  e.xany.type = ClientMessage;
1230  e.xclient.message_type = _NET_WM_STATE;
1231  e.xclient.format = 32;
1232  e.xclient.window = data->xwindow;
1233  e.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
1234  e.xclient.data.l[1] = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
1235  e.xclient.data.l[2] = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
1236  e.xclient.data.l[3] = 0l;
1237  X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
1238  SubstructureNotifyMask | SubstructureRedirectMask, &e);
1239  }
1240  } else {
1241  Uint32 flags;
1242 
1243  flags = window->flags;
1244  if (fullscreen) {
1245  flags |= SDL_WINDOW_FULLSCREEN;
1246  } else {
1247  flags &= ~SDL_WINDOW_FULLSCREEN;
1248  }
1249  X11_SetNetWMState(_this, data->xwindow, flags);
1250  }
1251 
1252  if (data->visual->class == DirectColor) {
1253  if ( fullscreen ) {
1254  X11_XInstallColormap(display, data->colormap);
1255  } else {
1256  X11_XUninstallColormap(display, data->colormap);
1257  }
1258  }
1259 
1260  X11_XFlush(display);
1261 }
1262 
1263 /* This handles fullscreen itself, outside the Window Manager. */
1264 static void
1265 X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
1266 {
1267  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1268  SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
1269  Visual *visual = data->visual;
1270  Display *display = data->videodata->display;
1271  const int screen = displaydata->screen;
1272  Window root = RootWindow(display, screen);
1273  const int def_vis = (visual == DefaultVisual(display, screen));
1274  unsigned long xattrmask = 0;
1275  XSetWindowAttributes xattr;
1276  XEvent ev;
1277  SDL_Rect rect;
1278 
1279  if ( data->fswindow ) {
1280  return; /* already fullscreen, I hope. */
1281  }
1282 
1283  X11_GetDisplayBounds(_this, _display, &rect);
1284 
1285  SDL_zero(xattr);
1286  xattr.override_redirect = True;
1287  xattrmask |= CWOverrideRedirect;
1288  xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
1289  xattrmask |= CWBackPixel;
1290  xattr.border_pixel = 0;
1291  xattrmask |= CWBorderPixel;
1292  xattr.colormap = data->colormap;
1293  xattrmask |= CWColormap;
1294 
1295  data->fswindow = X11_XCreateWindow(display, root,
1296  rect.x, rect.y, rect.w, rect.h, 0,
1297  displaydata->depth, InputOutput,
1298  visual, xattrmask, &xattr);
1299 
1300  X11_XSelectInput(display, data->fswindow, StructureNotifyMask);
1301  X11_XSetWindowBackground(display, data->fswindow, 0);
1302  X11_XInstallColormap(display, data->colormap);
1303  X11_XClearWindow(display, data->fswindow);
1304  X11_XMapRaised(display, data->fswindow);
1305 
1306  /* Make sure the fswindow is in view by warping mouse to the corner */
1307  X11_XUngrabPointer(display, CurrentTime);
1308  X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
1309 
1310  /* Wait to be mapped, filter Unmap event out if it arrives. */
1311  X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
1312  X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
1313 
1314 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
1315  if ( displaydata->use_vidmode ) {
1316  X11_XF86VidModeLockModeSwitch(display, screen, True);
1317  }
1318 #endif
1319 
1320  SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
1321 
1322  /* Center actual window within our cover-the-screen window. */
1323  X11_XReparentWindow(display, data->xwindow, data->fswindow,
1324  (rect.w - window->w) / 2, (rect.h - window->h) / 2);
1325 
1326  /* Move the mouse to the upper left to make sure it's on-screen */
1327  X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
1328 
1329  /* Center mouse in the fullscreen window. */
1330  rect.x += (rect.w / 2);
1331  rect.y += (rect.h / 2);
1332  X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
1333 
1334  /* Wait to be mapped, filter Unmap event out if it arrives. */
1335  X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
1336  X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
1337 
1338  SDL_UpdateWindowGrab(window);
1339 }
1340 
1341 static void
1342 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
1343 {
1344  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1345  SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
1346  Display *display = data->videodata->display;
1347  const int screen = displaydata->screen;
1348  Window root = RootWindow(display, screen);
1349  Window fswindow = data->fswindow;
1350  XEvent ev;
1351 
1352  if (!data->fswindow) {
1353  return; /* already not fullscreen, I hope. */
1354  }
1355 
1356  data->fswindow = None;
1357 
1358 #if SDL_VIDEO_DRIVER_X11_VIDMODE
1359  if ( displaydata->use_vidmode ) {
1360  X11_XF86VidModeLockModeSwitch(display, screen, False);
1361  }
1362 #endif
1363 
1364  SDL_UpdateWindowGrab(window);
1365 
1366  X11_XReparentWindow(display, data->xwindow, root, window->x, window->y);
1367 
1368  /* flush these events so they don't confuse normal event handling */
1369  X11_XSync(display, False);
1370  X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
1371  X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
1372 
1373  SetWindowBordered(display, screen, data->xwindow,
1374  (window->flags & SDL_WINDOW_BORDERLESS) == 0);
1375 
1376  X11_XWithdrawWindow(display, fswindow, screen);
1377 
1378  /* Wait to be unmapped. */
1379  X11_XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&fswindow);
1380  X11_XDestroyWindow(display, fswindow);
1381 }
1382 
1383 
1384 void
1385 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
1386 {
1387  /* !!! FIXME: SDL_Hint? */
1388  SDL_bool legacy = SDL_FALSE;
1389  const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
1390  if (env) {
1391  legacy = SDL_atoi(env);
1392  } else {
1393  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
1394  SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
1395  if ( displaydata->use_vidmode ) {
1396  legacy = SDL_TRUE; /* the new stuff only works with XRandR. */
1397  } else if ( !videodata->net_wm ) {
1398  legacy = SDL_TRUE; /* The window manager doesn't support it */
1399  } else {
1400  /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
1401  /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
1402  legacy = SDL_FALSE; /* try the new way. */
1403  }
1404  }
1405 
1406  if (legacy) {
1407  if (fullscreen) {
1408  X11_BeginWindowFullscreenLegacy(_this, window, _display);
1409  } else {
1410  X11_EndWindowFullscreenLegacy(_this, window, _display);
1411  }
1412  } else {
1413  X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
1414  }
1415 }
1416 
1417 
1418 int
1419 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
1420 {
1421  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1422  Display *display = data->videodata->display;
1423  Visual *visual = data->visual;
1424  Colormap colormap = data->colormap;
1425  XColor *colorcells;
1426  int ncolors;
1427  int rmask, gmask, bmask;
1428  int rshift, gshift, bshift;
1429  int i;
1430 
1431  if (visual->class != DirectColor) {
1432  return SDL_SetError("Window doesn't have DirectColor visual");
1433  }
1434 
1435  ncolors = visual->map_entries;
1436  colorcells = SDL_malloc(ncolors * sizeof(XColor));
1437  if (!colorcells) {
1438  return SDL_OutOfMemory();
1439  }
1440 
1441  rshift = 0;
1442  rmask = visual->red_mask;
1443  while (0 == (rmask & 1)) {
1444  rshift++;
1445  rmask >>= 1;
1446  }
1447 
1448  gshift = 0;
1449  gmask = visual->green_mask;
1450  while (0 == (gmask & 1)) {
1451  gshift++;
1452  gmask >>= 1;
1453  }
1454 
1455  bshift = 0;
1456  bmask = visual->blue_mask;
1457  while (0 == (bmask & 1)) {
1458  bshift++;
1459  bmask >>= 1;
1460  }
1461 
1462  /* build the color table pixel values */
1463  for (i = 0; i < ncolors; i++) {
1464  Uint32 rbits = (rmask * i) / (ncolors - 1);
1465  Uint32 gbits = (gmask * i) / (ncolors - 1);
1466  Uint32 bbits = (bmask * i) / (ncolors - 1);
1467  Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
1468 
1469  colorcells[i].pixel = pix;
1470 
1471  colorcells[i].red = ramp[(0 * 256) + i];
1472  colorcells[i].green = ramp[(1 * 256) + i];
1473  colorcells[i].blue = ramp[(2 * 256) + i];
1474 
1475  colorcells[i].flags = DoRed | DoGreen | DoBlue;
1476  }
1477 
1478  X11_XStoreColors(display, colormap, colorcells, ncolors);
1479  X11_XFlush(display);
1480  SDL_free(colorcells);
1481 
1482  return 0;
1483 }
1484 
1485 void
1486 X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
1487 {
1488  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1489  Display *display = data->videodata->display;
1490  SDL_bool oldstyle_fullscreen;
1491  SDL_bool grab_keyboard;
1492 
1493  /* ICCCM2.0-compliant window managers can handle fullscreen windows
1494  If we're using XVidMode to change resolution we need to confine
1495  the cursor so we don't pan around the virtual desktop.
1496  */
1497  oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
1498 
1499  if (oldstyle_fullscreen || grabbed) {
1500  /* Try to grab the mouse */
1501  if (!data->videodata->broken_pointer_grab) {
1502  const unsigned int mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask;
1503  int attempts;
1504  int result;
1505 
1506  /* Try for up to 5000ms (5s) to grab. If it still fails, stop trying. */
1507  for (attempts = 0; attempts < 100; attempts++) {
1508  result = X11_XGrabPointer(display, data->xwindow, True, mask, GrabModeAsync,
1509  GrabModeAsync, data->xwindow, None, CurrentTime);
1510  if (result == GrabSuccess) {
1511  break;
1512  }
1513  SDL_Delay(50);
1514  }
1515 
1516  if (result != GrabSuccess) {
1517  SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "The X server refused to let us grab the mouse. You might experience input bugs.");
1518  data->videodata->broken_pointer_grab = SDL_TRUE; /* don't try again. */
1519  }
1520  }
1521 
1522  /* Raise the window if we grab the mouse */
1523  X11_XRaiseWindow(display, data->xwindow);
1524 
1525  /* Now grab the keyboard */
1527  grab_keyboard = SDL_TRUE;
1528  } else {
1529  /* We need to do this with the old style override_redirect
1530  fullscreen window otherwise we won't get keyboard focus.
1531  */
1532  grab_keyboard = oldstyle_fullscreen;
1533  }
1534  if (grab_keyboard) {
1535  X11_XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
1536  GrabModeAsync, CurrentTime);
1537  }
1538  } else {
1539  X11_XUngrabPointer(display, CurrentTime);
1540  X11_XUngrabKeyboard(display, CurrentTime);
1541  }
1542  X11_XSync(display, False);
1543 }
1544 
1545 void
1547 {
1548  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1549 
1550  if (data) {
1551  SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
1552  Display *display = videodata->display;
1553  int numwindows = videodata->numwindows;
1554  SDL_WindowData **windowlist = videodata->windowlist;
1555  int i;
1556 
1557  if (windowlist) {
1558  for (i = 0; i < numwindows; ++i) {
1559  if (windowlist[i] && (windowlist[i]->window == window)) {
1560  windowlist[i] = windowlist[numwindows - 1];
1561  windowlist[numwindows - 1] = NULL;
1562  videodata->numwindows--;
1563  break;
1564  }
1565  }
1566  }
1567 #ifdef X_HAVE_UTF8_STRING
1568  if (data->ic) {
1569  X11_XDestroyIC(data->ic);
1570  }
1571 #endif
1572  if (data->created) {
1573  X11_XDestroyWindow(display, data->xwindow);
1574  X11_XFlush(display);
1575  }
1576  SDL_free(data);
1577  }
1578  window->driverdata = NULL;
1579 }
1580 
1581 SDL_bool
1583 {
1584  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1585  Display *display = data->videodata->display;
1586 
1587  if (info->version.major == SDL_MAJOR_VERSION &&
1588  info->version.minor == SDL_MINOR_VERSION) {
1589  info->subsystem = SDL_SYSWM_X11;
1590  info->info.x11.display = display;
1591  info->info.x11.window = data->xwindow;
1592  return SDL_TRUE;
1593  } else {
1594  SDL_SetError("Application not compiled with SDL %d.%d",
1596  return SDL_FALSE;
1597  }
1598 }
1599 
1600 int
1602 {
1603  return 0; /* just succeed, the real work is done elsewhere. */
1604 }
1605 
1606 #endif /* SDL_VIDEO_DRIVER_X11 */
1607 
1608 /* vi: set ts=4 sw=4 expandtab: */
void SDL_UpdateWindowGrab(SDL_Window *window)
Definition: SDL_video.c:2427
#define SDL_MINOR_VERSION
Definition: SDL_version.h:61
int X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
Atom _NET_WM_STATE_FULLSCREEN
Definition: SDL_x11video.h:100
int X11_ResizeWindowShape(SDL_Window *window)
Atom _NET_WM_ALLOWED_ACTIONS
Definition: SDL_x11video.h:104
void X11_SetWindowTitle(_THIS, SDL_Window *window)
#define SDL_IsShapedWindow
Visual * visual
Definition: SDL_x11window.h:48
GLuint64EXT * result
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
Uint32 X11_GetNetWMState(_THIS, Window xwindow)
SDL_bool broken_pointer_grab
Definition: SDL_x11video.h:129
#define SDL_VIDEO_OPENGL_ES
GLdouble GLdouble right
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 Uint32 * e
GLenum GLenum dst
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
#define EGL_NO_SURFACE
Definition: egl.h:100
unsigned long user_time
Definition: SDL_x11window.h:68
Atom _NET_WM_STATE_MAXIMIZED_VERT
Definition: SDL_x11video.h:98
Colormap colormap
Definition: SDL_x11window.h:49
#define SDL_MAJOR_VERSION
Definition: SDL_version.h:60
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display dpy)
Definition: SDL_x11sym.h:44
SDL_Rect rect
Definition: testrelative.c:27
struct wl_display * display
int windowlistlength
Definition: SDL_x11video.h:84
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
SDL_version version
Definition: SDL_syswm.h:196
Uint8 major
Definition: SDL_version.h:53
SDL_WindowData ** windowlist
Definition: SDL_x11video.h:83
GLbyte green
GLint GLint bottom
GLfloat f
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:197
void X11_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
void X11_MinimizeWindow(_THIS, SDL_Window *window)
SDL_Window * window
Atom _NET_WM_WINDOW_OPACITY
Definition: SDL_x11video.h:110
void X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags)
uint32_t Uint32
Definition: SDL_stdinc.h:181
#define SDL_realloc
GLenum src
GLdouble GLdouble GLdouble GLdouble top
SDL_Rect windowed
Definition: SDL_sysvideo.h:87
GLenum GLsizei len
#define SDL_VIDEO_OPENGL_ES2
Definition: SDL_config.h:349
GLfloat GLfloat GLfloat alpha
int X11_SetWindowOpacity(_THIS, SDL_Window *window, float opacity)
void X11_MaximizeWindow(_THIS, SDL_Window *window)
struct SDL_GLDriverData * gl_data
Definition: SDL_sysvideo.h:378
#define SDL_GetHintBoolean
#define SDL_HINT_GRAB_KEYBOARD
A variable controlling whether grabbing input grabs the keyboard.
Definition: SDL_hints.h:250
const GLubyte GLuint red
Definition: SDL_glfuncs.h:79
int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay *sdl_display, SDL_Rect *rect)
Atom _NET_WM_STATE
Definition: SDL_x11video.h:95
GLsizei maxLength
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
EGLNativeWindowType NativeWindowType
Definition: eglplatform.h:112
#define SDL_iconv_utf8_locale(S)
Definition: SDL_stdinc.h:545
Atom _NET_WM_STATE_SKIP_TASKBAR
Definition: SDL_x11video.h:102
Atom _NET_WM_STATE_HIDDEN
Definition: SDL_x11video.h:96
#define SDL_HINT_VIDEO_X11_NET_WM_PING
A variable controlling whether the X11 _NET_WM_PING protocol should be supported. ...
Definition: SDL_hints.h:211
Atom _NET_ACTIVE_WINDOW
Definition: SDL_x11video.h:112
Atom WM_DELETE_WINDOW
Definition: SDL_x11video.h:93
int X11_CreateWindow(_THIS, SDL_Window *window)
Atom _NET_WM_STATE_SKIP_PAGER
Definition: SDL_x11video.h:103
void * pixels
Definition: SDL_surface.h:75
int X11_SetWindowGammaRamp(_THIS, SDL_Window *window, const Uint16 *ramp)
#define _THIS
struct SDL_VideoData * videodata
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
struct _cl_event * event
int X11_CreateWindowFrom(_THIS, SDL_Window *window, const void *data)
GLenum GLint GLuint mask
#define SDL_static_cast(type, expression)
Definition: SDL_stdinc.h:116
int X11_SetWindowInputFocus(_THIS, SDL_Window *window)
void X11_RestoreWindow(_THIS, SDL_Window *window)
GLubyte GLubyte GLubyte GLubyte w
int X11_GetWindowBordersSize(_THIS, SDL_Window *window, int *top, int *left, int *bottom, int *right)
Uint8 minor
Definition: SDL_version.h:54
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
char * title
Definition: SDL_sysvideo.h:77
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
int x
Definition: SDL_rect.h:66
void X11_ShowWindow(_THIS, SDL_Window *window)
void X11_DestroyWindow(_THIS, SDL_Window *window)
#define SDL_VIDEO_OPENGL_GLX
Definition: SDL_config.h:353
int w
Definition: SDL_rect.h:67
struct SDL_SysWMinfo::@18::@19 x11
#define SDL_atoi
#define SDL_Delay
GLenum GLenum GLsizei const GLuint GLboolean enabled
#define SDL_getenv
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
#define SDL_assert(condition)
Definition: SDL_assert.h:169
void X11_SetWindowMinimumSize(_THIS, SDL_Window *window)
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
int X11_SetWindowModalFor(_THIS, SDL_Window *modal_window, SDL_Window *parent_window)
SDL_PixelFormat * format
Definition: SDL_surface.h:72
GLint GLint GLsizei GLsizei GLsizei depth
Definition: SDL_opengl.h:1572
Atom _NET_WM_STATE_MAXIMIZED_HORZ
Definition: SDL_x11video.h:99
#define SDL_SetError
GLbitfield flags
#define SDL_calloc
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1073
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
int h
Definition: SDL_rect.h:67
#define SDL_strdup
The type used to identify a window.
Definition: SDL_sysvideo.h:73
GLbyte GLbyte blue
Atom _NET_WM_STATE_FOCUSED
Definition: SDL_x11video.h:97
void X11_RaiseWindow(_THIS, SDL_Window *window)
#define SDL_iconv_string
SDL_bool net_wm
Definition: SDL_x11video.h:89
void X11_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon)
char * X11_GetWindowTitle(_THIS, Window xwindow)
GLint GLint GLsizei GLsizei GLsizei GLint border
Definition: SDL_opengl.h:1572
uint16_t Uint16
Definition: SDL_stdinc.h:169
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
union SDL_SysWMinfo::@18 info
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define SDL_malloc
struct SDL_VideoDevice::@34 gl_config
void * driverdata
Definition: SDL_sysvideo.h:111
void X11_SetWindowSize(_THIS, SDL_Window *window)
#define SDL_LogWarn
Atom _NET_WM_STATE_ABOVE
Definition: SDL_x11video.h:101
Uint32 flags
Definition: SDL_sysvideo.h:83
void X11_SetWindowBordered(_THIS, SDL_Window *window, SDL_bool bordered)
void X11_HideWindow(_THIS, SDL_Window *window)
SDL_Renderer * screen
void X11_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable)
void X11_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
int y
Definition: SDL_rect.h:66
Atom WM_TAKE_FOCUS
Definition: SDL_x11video.h:94
#define SDL_memset
EGLSurface egl_surface
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
SDL_bool X11_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
void X11_SetWindowMaximumSize(_THIS, SDL_Window *window)
GLint left
void X11_Xinput2SelectTouch(_THIS, SDL_Window *window)
void X11_SetWindowPosition(_THIS, SDL_Window *window)