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
isMapNotify(Display * dpy,XEvent * ev,XPointer win)49 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
50 {
51 return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
52 }
isUnmapNotify(Display * dpy,XEvent * ev,XPointer win)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
X11_IsWindowLegacyFullscreen(_THIS,SDL_Window * window)78 X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
79 {
80 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
81 return (data->fswindow != 0);
82 }
83
84 static SDL_bool
X11_IsWindowMapped(_THIS,SDL_Window * window)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
X11_SetNetWMState(_THIS,Window xwindow,Uint32 flags)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
X11_GetNetWMState(_THIS,Window xwindow)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
SetupWindowData(_THIS,SDL_Window * window,Window w,BOOL created)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) {
315 SDL_SetKeyboardFocus(data->window);
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
SetWindowBordered(Display * display,int screen,Window window,SDL_bool border)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
X11_CreateWindow(_THIS,SDL_Window * window)360 X11_CreateWindow(_THIS, SDL_Window * window)
361 {
362 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
363 SDL_DisplayData *displaydata =
364 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
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
390 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
391 #if SDL_VIDEO_OPENGL_GLX
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 */
584 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_PING, SDL_TRUE)) {
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
599 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
600 if ((window->flags & SDL_WINDOW_OPENGL) &&
601 _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
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
X11_CreateWindowFrom(_THIS,SDL_Window * window,const void * data)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 *
X11_GetWindowTitle(_THIS,Window xwindow)665 X11_GetWindowTitle(_THIS, Window xwindow)
666 {
667 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
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
X11_SetWindowTitle(_THIS,SDL_Window * window)696 X11_SetWindowTitle(_THIS, SDL_Window * window)
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
X11_SetWindowIcon(_THIS,SDL_Window * window,SDL_Surface * icon)737 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
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 */
748 SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
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
X11_SetWindowPosition(_THIS,SDL_Window * window)777 X11_SetWindowPosition(_THIS, SDL_Window * window)
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
X11_SetWindowMinimumSize(_THIS,SDL_Window * window)787 X11_SetWindowMinimumSize(_THIS, SDL_Window * window)
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
X11_SetWindowMaximumSize(_THIS,SDL_Window * window)816 X11_SetWindowMaximumSize(_THIS, SDL_Window * window)
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
X11_SetWindowSize(_THIS,SDL_Window * window)845 X11_SetWindowSize(_THIS, SDL_Window * window)
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
X11_GetWindowBordersSize(_THIS,SDL_Window * window,int * top,int * left,int * bottom,int * right)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
X11_SetWindowOpacity(_THIS,SDL_Window * window,float opacity)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
X11_SetWindowModalFor(_THIS,SDL_Window * modal_window,SDL_Window * parent_window)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
X11_SetWindowInputFocus(_THIS,SDL_Window * window)938 X11_SetWindowInputFocus(_THIS, SDL_Window * window)
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
X11_SetWindowBordered(_THIS,SDL_Window * window,SDL_bool bordered)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 =
957 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
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
X11_SetWindowResizable(_THIS,SDL_Window * window,SDL_bool resizable)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
X11_ShowWindow(_THIS,SDL_Window * window)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
X11_HideWindow(_THIS,SDL_Window * window)1044 X11_HideWindow(_THIS, SDL_Window * window)
1045 {
1046 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1047 SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(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
SetWindowActive(_THIS,SDL_Window * window)1060 SetWindowActive(_THIS, SDL_Window * window)
1061 {
1062 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1063 SDL_DisplayData *displaydata =
1064 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
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
X11_RaiseWindow(_THIS,SDL_Window * window)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
SetWindowMaximized(_THIS,SDL_Window * window,SDL_bool maximized)1101 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
1102 {
1103 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1104 SDL_DisplayData *displaydata =
1105 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
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
X11_MaximizeWindow(_THIS,SDL_Window * window)1140 X11_MaximizeWindow(_THIS, SDL_Window * window)
1141 {
1142 SetWindowMaximized(_this, window, SDL_TRUE);
1143 }
1144
1145 void
X11_MinimizeWindow(_THIS,SDL_Window * window)1146 X11_MinimizeWindow(_THIS, SDL_Window * window)
1147 {
1148 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1149 SDL_DisplayData *displaydata =
1150 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
1151 Display *display = data->videodata->display;
1152
1153 X11_XIconifyWindow(display, data->xwindow, displaydata->screen);
1154 X11_XFlush(display);
1155 }
1156
1157 void
X11_RestoreWindow(_THIS,SDL_Window * window)1158 X11_RestoreWindow(_THIS, SDL_Window * window)
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
X11_SetWindowFullscreenViaWM(_THIS,SDL_Window * window,SDL_VideoDisplay * _display,SDL_bool fullscreen)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
X11_BeginWindowFullscreenLegacy(_THIS,SDL_Window * window,SDL_VideoDisplay * _display)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
X11_EndWindowFullscreenLegacy(_THIS,SDL_Window * window,SDL_VideoDisplay * _display)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
X11_SetWindowFullscreen(_THIS,SDL_Window * window,SDL_VideoDisplay * _display,SDL_bool fullscreen)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
X11_SetWindowGammaRamp(_THIS,SDL_Window * window,const Uint16 * ramp)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
X11_SetWindowGrab(_THIS,SDL_Window * window,SDL_bool grabbed)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 */
1501 if (SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) {
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
X11_DestroyWindow(_THIS,SDL_Window * window)1521 X11_DestroyWindow(_THIS, SDL_Window * window)
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
X11_GetWindowWMInfo(_THIS,SDL_Window * window,SDL_SysWMinfo * info)1557 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
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",
1570 SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
1571 return SDL_FALSE;
1572 }
1573 }
1574
1575 int
X11_SetWindowHitTest(SDL_Window * window,SDL_bool enabled)1576 X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
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: */
1584