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