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