2 Simple DirectMedia Layer
3 Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_DRIVER_X11
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"
32 #include "SDL_x11video.h"
33 #include "SDL_x11mouse.h"
34 #include "SDL_x11shape.h"
35 #include "SDL_x11xinput2.h"
37 #if SDL_VIDEO_OPENGL_EGL
38 #include "SDL_x11opengles.h"
41 #include "SDL_timer.h"
42 #include "SDL_syswm.h"
45 #define _NET_WM_STATE_REMOVE 0l
46 #define _NET_WM_STATE_ADD 1l
48 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
50 return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
52 static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
54 return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
58 static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
60 return ev->type == ConfigureNotify && ev->xconfigure.window == *((Window*)win);
63 X11_XIfEventTimeout(Display *display, XEvent *event_return, Bool (*predicate)(), XPointer arg, int timeoutMS)
65 Uint32 start = SDL_GetTicks();
67 while (!X11_XCheckIfEvent(display, event_return, predicate, arg)) {
68 if (SDL_TICKS_PASSED(SDL_GetTicks(), start + timeoutMS)) {
77 X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
79 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
80 return (data->fswindow != 0);
84 X11_IsWindowMapped(_THIS, SDL_Window * window)
86 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
87 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
88 XWindowAttributes attr;
90 X11_XGetWindowAttributes(videodata->display, data->xwindow, &attr);
91 if (attr.map_state != IsUnmapped) {
100 X11_IsActionAllowed(SDL_Window *window, Atom action)
102 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
103 Atom _NET_WM_ALLOWED_ACTIONS = data->videodata->_NET_WM_ALLOWED_ACTIONS;
105 Display *display = data->videodata->display;
107 unsigned long remain;
108 unsigned long len, i;
110 SDL_bool ret = SDL_FALSE;
112 if (X11_XGetWindowProperty(display, data->xwindow, _NET_WM_ALLOWED_ACTIONS, 0, 1024, False, XA_ATOM, &type, &form, &len, &remain, (unsigned char **)&list) == Success)
114 for (i=0; i<len; ++i)
116 if (list[i] == action) {
128 X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags)
130 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
131 Display *display = videodata->display;
132 /* !!! FIXME: just dereference videodata below instead of copying to locals. */
133 Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
134 /* Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN; */
135 Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
136 Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
137 Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
138 Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
139 Atom _NET_WM_STATE_ABOVE = videodata->_NET_WM_STATE_ABOVE;
140 Atom _NET_WM_STATE_SKIP_TASKBAR = videodata->_NET_WM_STATE_SKIP_TASKBAR;
141 Atom _NET_WM_STATE_SKIP_PAGER = videodata->_NET_WM_STATE_SKIP_PAGER;
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.
149 if (flags & SDL_WINDOW_HIDDEN) {
150 atoms[count++] = _NET_WM_STATE_HIDDEN;
154 if (flags & SDL_WINDOW_ALWAYS_ON_TOP) {
155 atoms[count++] = _NET_WM_STATE_ABOVE;
157 if (flags & SDL_WINDOW_SKIP_TASKBAR) {
158 atoms[count++] = _NET_WM_STATE_SKIP_TASKBAR;
159 atoms[count++] = _NET_WM_STATE_SKIP_PAGER;
161 if (flags & SDL_WINDOW_INPUT_FOCUS) {
162 atoms[count++] = _NET_WM_STATE_FOCUSED;
164 if (flags & SDL_WINDOW_MAXIMIZED) {
165 atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
166 atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
168 if (flags & SDL_WINDOW_FULLSCREEN) {
169 atoms[count++] = _NET_WM_STATE_FULLSCREEN;
172 SDL_assert(count <= SDL_arraysize(atoms));
175 X11_XChangeProperty(display, xwindow, _NET_WM_STATE, XA_ATOM, 32,
176 PropModeReplace, (unsigned char *)atoms, count);
178 X11_XDeleteProperty(display, xwindow, _NET_WM_STATE);
183 X11_GetNetWMState(_THIS, Window xwindow)
185 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
186 Display *display = videodata->display;
187 Atom _NET_WM_STATE = videodata->_NET_WM_STATE;
188 Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN;
189 Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED;
190 Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT;
191 Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
192 Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN;
195 unsigned long i, numItems, bytesAfter;
196 unsigned char *propertyValue = NULL;
197 long maxLength = 1024;
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;
208 for (i = 0; i < numItems; ++i) {
209 if (atoms[i] == _NET_WM_STATE_HIDDEN) {
210 flags |= SDL_WINDOW_HIDDEN;
211 } else if (atoms[i] == _NET_WM_STATE_FOCUSED) {
212 flags |= SDL_WINDOW_INPUT_FOCUS;
213 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
215 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
217 } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
221 if (maximized == 3) {
222 flags |= SDL_WINDOW_MAXIMIZED;
225 if (fullscreen == 1) {
226 flags |= SDL_WINDOW_FULLSCREEN;
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.
234 XWindowAttributes attr;
235 SDL_memset(&attr,0,sizeof(attr));
236 X11_XGetWindowAttributes(videodata->display, xwindow, &attr);
237 if (attr.map_state == IsUnmapped) {
238 flags |= SDL_WINDOW_HIDDEN;
241 X11_XFree(propertyValue);
244 /* FIXME, check the size hints for resizable */
245 /* flags |= SDL_WINDOW_RESIZABLE; */
251 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
253 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
254 SDL_WindowData *data;
255 int numwindows = videodata->numwindows;
256 int windowlistlength = videodata->windowlistlength;
257 SDL_WindowData **windowlist = videodata->windowlist;
259 /* Allocate the window data */
260 data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
262 return SDL_OutOfMemory();
264 data->window = window;
266 #ifdef X_HAVE_UTF8_STRING
267 if (SDL_X11_HAVE_UTF8 && videodata->im) {
269 X11_XCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
270 XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
274 data->created = created;
275 data->videodata = videodata;
277 /* Associate the data with the window */
279 if (numwindows < windowlistlength) {
280 windowlist[numwindows] = data;
281 videodata->numwindows++;
284 (SDL_WindowData **) SDL_realloc(windowlist,
286 1) * sizeof(*windowlist));
289 return SDL_OutOfMemory();
291 windowlist[numwindows] = data;
292 videodata->numwindows++;
293 videodata->windowlistlength++;
294 videodata->windowlist = windowlist;
297 /* Fill in the SDL window with the window data */
299 XWindowAttributes attrib;
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;
309 window->flags &= ~SDL_WINDOW_SHOWN;
311 data->visual = attrib.visual;
312 data->colormap = attrib.colormap;
315 window->flags |= X11_GetNetWMState(_this, w);
320 X11_XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo);
323 window->flags |= SDL_WINDOW_INPUT_FOCUS;
326 if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
327 SDL_SetKeyboardFocus(data->window);
330 if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
331 /* Tell x11 to clip mouse */
336 window->driverdata = data;
341 SetWindowBordered(Display *display, int screen, Window window, SDL_bool border)
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.
349 Atom WM_HINTS = X11_XInternAtom(display, "_MOTIF_WM_HINTS", True);
350 if (WM_HINTS != None) {
351 /* Hints used by Motif compliant window managers */
355 unsigned long functions;
356 unsigned long decorations;
358 unsigned long status;
360 (1L << 1), 0, border ? 1 : 0, 0, 0
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));
372 X11_CreateWindow(_THIS, SDL_Window * window)
374 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
375 SDL_DisplayData *displaydata =
376 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
377 SDL_WindowData *windowdata;
378 Display *display = data->display;
379 int screen = displaydata->screen;
382 XSetWindowAttributes xattr;
384 XSizeHints *sizehints;
386 XClassHint *classhints;
387 Atom _NET_WM_BYPASS_COMPOSITOR;
388 Atom _NET_WM_WINDOW_TYPE;
390 const char *wintype_name = NULL;
393 Atom XdndAware, xdnd_version = 5;
396 #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_EGL
397 if ((window->flags & SDL_WINDOW_OPENGL) &&
398 !SDL_getenv("SDL_VIDEO_X11_VISUALID")) {
399 XVisualInfo *vinfo = NULL;
401 #if SDL_VIDEO_OPENGL_EGL
402 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
403 #if SDL_VIDEO_OPENGL_GLX
404 && ( !_this->gl_data || X11_GL_UseEGL(_this) )
407 vinfo = X11_GLES_GetVisual(_this, display, screen);
411 #if SDL_VIDEO_OPENGL_GLX
412 vinfo = X11_GL_GetVisual(_this, display, screen);
419 visual = vinfo->visual;
420 depth = vinfo->depth;
425 visual = displaydata->visual;
426 depth = displaydata->depth;
431 xattr.override_redirect = ((window->flags & SDL_WINDOW_TOOLTIP) || (window->flags & SDL_WINDOW_POPUP_MENU)) ? True : False;
432 xattr.background_pixmap = None;
433 xattr.border_pixel = 0;
435 if (visual->class == DirectColor) {
439 int rmax, gmax, bmax;
440 int rmask, gmask, bmask;
441 int rshift, gshift, bshift;
444 X11_XCreateColormap(display, RootWindow(display, screen),
447 /* If we can't create a colormap, then we must die */
448 if (!xattr.colormap) {
449 return SDL_SetError("Could not create writable colormap");
452 /* OK, we got a colormap, now fill it in as best as we can */
453 colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
455 return SDL_OutOfMemory();
457 ncolors = visual->map_entries;
463 rmask = visual->red_mask;
464 while (0 == (rmask & 1)) {
470 gmask = visual->green_mask;
471 while (0 == (gmask & 1)) {
477 bmask = visual->blue_mask;
478 while (0 == (bmask & 1)) {
483 /* build the color table pixel values */
484 for (i = 0; i < ncolors; i++) {
485 Uint32 red = (rmax * i) / (ncolors - 1);
486 Uint32 green = (gmax * i) / (ncolors - 1);
487 Uint32 blue = (bmax * i) / (ncolors - 1);
489 Uint32 rbits = (rmask * i) / (ncolors - 1);
490 Uint32 gbits = (gmask * i) / (ncolors - 1);
491 Uint32 bbits = (bmask * i) / (ncolors - 1);
494 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
496 colorcells[i].pixel = pix;
498 colorcells[i].red = red;
499 colorcells[i].green = green;
500 colorcells[i].blue = blue;
502 colorcells[i].flags = DoRed | DoGreen | DoBlue;
505 X11_XStoreColors(display, xattr.colormap, colorcells, ncolors);
507 SDL_free(colorcells);
510 X11_XCreateColormap(display, RootWindow(display, screen),
514 w = X11_XCreateWindow(display, RootWindow(display, screen),
515 window->x, window->y, window->w, window->h,
516 0, depth, InputOutput, visual,
517 (CWOverrideRedirect | CWBackPixmap | CWBorderPixel |
518 CWColormap), &xattr);
520 return SDL_SetError("Couldn't create window");
523 SetWindowBordered(display, screen, w,
524 (window->flags & SDL_WINDOW_BORDERLESS) == 0);
526 sizehints = X11_XAllocSizeHints();
527 /* Setup the normal size hints */
528 sizehints->flags = 0;
529 if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
530 sizehints->min_width = sizehints->max_width = window->w;
531 sizehints->min_height = sizehints->max_height = window->h;
532 sizehints->flags |= (PMaxSize | PMinSize);
534 sizehints->x = window->x;
535 sizehints->y = window->y;
536 sizehints->flags |= USPosition;
538 /* Setup the input hints so we get keyboard input */
539 wmhints = X11_XAllocWMHints();
540 wmhints->input = True;
541 wmhints->window_group = data->window_group;
542 wmhints->flags = InputHint | WindowGroupHint;
544 /* Setup the class hints so we can get an icon (AfterStep) */
545 classhints = X11_XAllocClassHint();
546 classhints->res_name = data->classname;
547 classhints->res_class = data->classname;
549 /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
550 X11_XSetWMProperties(display, w, NULL, NULL, NULL, 0, sizehints, wmhints, classhints);
552 X11_XFree(sizehints);
554 X11_XFree(classhints);
555 /* Set the PID related to the window for the given hostname, if possible */
557 long pid = (long) data->pid;
558 _NET_WM_PID = X11_XInternAtom(display, "_NET_WM_PID", False);
559 X11_XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
560 (unsigned char *) &pid, 1);
563 /* Set the window manager state */
564 X11_SetNetWMState(_this, w, window->flags);
566 compositor = 2; /* don't disable compositing except for "normal" windows */
568 if (window->flags & SDL_WINDOW_UTILITY) {
569 wintype_name = "_NET_WM_WINDOW_TYPE_UTILITY";
570 } else if (window->flags & SDL_WINDOW_TOOLTIP) {
571 wintype_name = "_NET_WM_WINDOW_TYPE_TOOLTIP";
572 } else if (window->flags & SDL_WINDOW_POPUP_MENU) {
573 wintype_name = "_NET_WM_WINDOW_TYPE_POPUP_MENU";
575 wintype_name = "_NET_WM_WINDOW_TYPE_NORMAL";
576 compositor = 1; /* disable compositing for "normal" windows */
579 /* Let the window manager know what type of window we are. */
580 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
581 wintype = X11_XInternAtom(display, wintype_name, False);
582 X11_XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
583 PropModeReplace, (unsigned char *)&wintype, 1);
584 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, SDL_TRUE)) {
585 _NET_WM_BYPASS_COMPOSITOR = X11_XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False);
586 X11_XChangeProperty(display, w, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
588 (unsigned char *)&compositor, 1);
595 protocols[proto_count++] = data->WM_DELETE_WINDOW; /* Allow window to be deleted by the WM */
596 protocols[proto_count++] = data->WM_TAKE_FOCUS; /* Since we will want to set input focus explicitly */
598 /* Default to using ping if there is no hint */
599 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_PING, SDL_TRUE)) {
600 protocols[proto_count++] = data->_NET_WM_PING; /* Respond so WM knows we're alive */
603 SDL_assert(proto_count <= sizeof(protocols) / sizeof(protocols[0]));
605 X11_XSetWMProtocols(display, w, protocols, proto_count);
608 if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
609 X11_XDestroyWindow(display, w);
612 windowdata = (SDL_WindowData *) window->driverdata;
614 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
615 if ((window->flags & SDL_WINDOW_OPENGL) &&
616 _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
617 #if SDL_VIDEO_OPENGL_GLX
618 && ( !_this->gl_data || X11_GL_UseEGL(_this) )
621 #if SDL_VIDEO_OPENGL_EGL
622 if (!_this->egl_data) {
623 X11_XDestroyWindow(display, w);
627 /* Create the GLES window surface */
628 windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) w);
630 if (windowdata->egl_surface == EGL_NO_SURFACE) {
631 X11_XDestroyWindow(display, w);
632 return SDL_SetError("Could not create GLES window surface");
635 return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
636 #endif /* SDL_VIDEO_OPENGL_EGL */
641 #ifdef X_HAVE_UTF8_STRING
642 if (SDL_X11_HAVE_UTF8 && windowdata->ic) {
643 X11_XGetICValues(windowdata->ic, XNFilterEvents, &fevent, NULL);
647 X11_Xinput2SelectTouch(_this, window);
649 X11_XSelectInput(display, w,
650 (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
651 ExposureMask | ButtonPressMask | ButtonReleaseMask |
652 PointerMotionMask | KeyPressMask | KeyReleaseMask |
653 PropertyChangeMask | StructureNotifyMask |
654 KeymapStateMask | fevent));
656 XdndAware = X11_XInternAtom(display, "XdndAware", False);
657 X11_XChangeProperty(display, w, XdndAware, XA_ATOM, 32,
659 (unsigned char*)&xdnd_version, 1);
667 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
669 Window w = (Window) data;
671 window->title = X11_GetWindowTitle(_this, w);
673 if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
680 X11_GetWindowTitle(_THIS, Window xwindow)
682 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
683 Display *display = data->display;
684 int status, real_format;
686 unsigned long items_read, items_left;
687 unsigned char *propdata;
690 status = X11_XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
691 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
692 &items_read, &items_left, &propdata);
693 if (status == Success && propdata) {
694 title = SDL_strdup(SDL_static_cast(char*, propdata));
697 status = X11_XGetWindowProperty(display, xwindow, XA_WM_NAME,
698 0L, 8192L, False, XA_STRING, &real_type, &real_format,
699 &items_read, &items_left, &propdata);
700 if (status == Success && propdata) {
701 title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
704 title = SDL_strdup("");
711 X11_SetWindowTitle(_THIS, SDL_Window * window)
713 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
714 Display *display = data->videodata->display;
715 XTextProperty titleprop;
717 const char *title = window->title ? window->title : "";
718 char *title_locale = NULL;
720 #ifdef X_HAVE_UTF8_STRING
721 Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
724 title_locale = SDL_iconv_utf8_locale(title);
730 status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
731 SDL_free(title_locale);
733 X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
734 X11_XFree(titleprop.value);
736 #ifdef X_HAVE_UTF8_STRING
737 if (SDL_X11_HAVE_UTF8) {
738 status = X11_Xutf8TextListToTextProperty(display, (char **) &title, 1,
739 XUTF8StringStyle, &titleprop);
740 if (status == Success) {
741 X11_XSetTextProperty(display, data->xwindow, &titleprop,
743 X11_XFree(titleprop.value);
752 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
754 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
755 Display *display = data->videodata->display;
756 Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
762 /* Set the _NET_WM_ICON property */
763 SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
764 propsize = 2 + (icon->w * icon->h);
765 propdata = SDL_malloc(propsize * sizeof(long));
771 propdata[0] = icon->w;
772 propdata[1] = icon->h;
774 for (y = 0; y < icon->h; ++y) {
775 src = (Uint32*)((Uint8*)icon->pixels + y * icon->pitch);
776 for (x = 0; x < icon->w; ++x) {
780 X11_XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
781 32, PropModeReplace, (unsigned char *) propdata,
786 X11_XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
792 X11_SetWindowPosition(_THIS, SDL_Window * window)
794 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
795 Display *display = data->videodata->display;
797 X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
802 X11_SetWindowMinimumSize(_THIS, SDL_Window * window)
804 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
805 Display *display = data->videodata->display;
807 if (window->flags & SDL_WINDOW_RESIZABLE) {
808 XSizeHints *sizehints = X11_XAllocSizeHints();
811 X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
813 sizehints->min_width = window->min_w;
814 sizehints->min_height = window->min_h;
815 sizehints->flags |= PMinSize;
817 X11_XSetWMNormalHints(display, data->xwindow, sizehints);
819 X11_XFree(sizehints);
821 /* See comment in X11_SetWindowSize. */
822 X11_XResizeWindow(display, data->xwindow, window->w, window->h);
823 X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
824 X11_XRaiseWindow(display, data->xwindow);
831 X11_SetWindowMaximumSize(_THIS, SDL_Window * window)
833 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
834 Display *display = data->videodata->display;
836 if (window->flags & SDL_WINDOW_RESIZABLE) {
837 XSizeHints *sizehints = X11_XAllocSizeHints();
840 X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
842 sizehints->max_width = window->max_w;
843 sizehints->max_height = window->max_h;
844 sizehints->flags |= PMaxSize;
846 X11_XSetWMNormalHints(display, data->xwindow, sizehints);
848 X11_XFree(sizehints);
850 /* See comment in X11_SetWindowSize. */
851 X11_XResizeWindow(display, data->xwindow, window->w, window->h);
852 X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
853 X11_XRaiseWindow(display, data->xwindow);
860 X11_SetWindowSize(_THIS, SDL_Window * window)
862 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
863 Display *display = data->videodata->display;
865 if (SDL_IsShapedWindow(window)) {
866 X11_ResizeWindowShape(window);
868 if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
869 /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the X11_XResizeWindow, thus
870 we must set the size hints to adjust the window size. */
871 XSizeHints *sizehints = X11_XAllocSizeHints();
874 X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
876 sizehints->min_width = sizehints->max_width = window->w;
877 sizehints->min_height = sizehints->max_height = window->h;
878 sizehints->flags |= PMinSize | PMaxSize;
880 X11_XSetWMNormalHints(display, data->xwindow, sizehints);
882 X11_XFree(sizehints);
885 WMs each have their little quirks with that. When you change the
886 size hints, they get a ConfigureNotify event with the
887 WM_NORMAL_SIZE_HINTS Atom. They all save the hints then, but they
888 don't all resize the window right away to enforce the new hints.
890 Some of them resize only after:
891 - A user-initiated move or resize
892 - A code-initiated move or resize
893 - Hiding & showing window (Unmap & map)
895 The following move & resize seems to help a lot of WMs that didn't
896 properly update after the hints were changed. We don't do a
897 hide/show, because there are supposedly subtle problems with doing so
898 and transitioning from windowed to fullscreen in Unity.
900 X11_XResizeWindow(display, data->xwindow, window->w, window->h);
901 X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
902 X11_XRaiseWindow(display, data->xwindow);
904 X11_XResizeWindow(display, data->xwindow, window->w, window->h);
911 X11_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right)
913 SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
915 *left = data->border_left;
916 *right = data->border_right;
917 *top = data->border_top;
918 *bottom = data->border_bottom;
924 X11_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
926 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
927 Display *display = data->videodata->display;
928 Atom _NET_WM_WINDOW_OPACITY = data->videodata->_NET_WM_WINDOW_OPACITY;
930 if (opacity == 1.0f) {
931 X11_XDeleteProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY);
933 const Uint32 FullyOpaque = 0xFFFFFFFF;
934 const long alpha = (long) ((double)opacity * (double)FullyOpaque);
935 X11_XChangeProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
936 PropModeReplace, (unsigned char *)&alpha, 1);
943 X11_SetWindowModalFor(_THIS, SDL_Window * modal_window, SDL_Window * parent_window) {
944 SDL_WindowData *data = (SDL_WindowData *) modal_window->driverdata;
945 SDL_WindowData *parent_data = (SDL_WindowData *) parent_window->driverdata;
946 Display *display = data->videodata->display;
948 X11_XSetTransientForHint(display, data->xwindow, parent_data->xwindow);
953 X11_SetWindowInputFocus(_THIS, SDL_Window * window)
955 if (X11_IsWindowMapped(_this, window)) {
956 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
957 Display *display = data->videodata->display;
958 X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime);
966 X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
968 const SDL_bool focused = ((window->flags & SDL_WINDOW_INPUT_FOCUS) != 0);
969 const SDL_bool visible = ((window->flags & SDL_WINDOW_HIDDEN) == 0);
970 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
971 SDL_DisplayData *displaydata =
972 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
973 Display *display = data->videodata->display;
976 SetWindowBordered(display, displaydata->screen, data->xwindow, bordered);
980 XWindowAttributes attr;
982 X11_XSync(display, False);
983 X11_XGetWindowAttributes(display, data->xwindow, &attr);
984 } while (attr.map_state != IsViewable);
987 X11_XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
991 /* make sure these don't make it to the real event queue if they fired here. */
992 X11_XSync(display, False);
993 X11_XCheckIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
994 X11_XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
998 X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
1000 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1001 Display *display = data->videodata->display;
1003 XSizeHints *sizehints = X11_XAllocSizeHints();
1006 X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
1009 /* FIXME: Is there a better way to get max window size from X? -flibit */
1010 const int maxsize = 0x7FFFFFFF;
1011 sizehints->min_width = window->min_w;
1012 sizehints->min_height = window->min_h;
1013 sizehints->max_width = (window->max_w == 0) ? maxsize : window->max_w;
1014 sizehints->max_height = (window->max_h == 0) ? maxsize : window->max_h;
1016 sizehints->min_width = window->w;
1017 sizehints->min_height = window->h;
1018 sizehints->max_width = window->w;
1019 sizehints->max_height = window->h;
1021 sizehints->flags |= PMinSize | PMaxSize;
1023 X11_XSetWMNormalHints(display, data->xwindow, sizehints);
1025 X11_XFree(sizehints);
1027 /* See comment in X11_SetWindowSize. */
1028 X11_XResizeWindow(display, data->xwindow, window->w, window->h);
1029 X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top);
1030 X11_XRaiseWindow(display, data->xwindow);
1032 X11_XFlush(display);
1036 X11_ShowWindow(_THIS, SDL_Window * window)
1038 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1039 Display *display = data->videodata->display;
1042 if (!X11_IsWindowMapped(_this, window)) {
1043 X11_XMapRaised(display, data->xwindow);
1044 /* Blocking wait for "MapNotify" event.
1045 * We use X11_XIfEvent because pXWindowEvent takes a mask rather than a type,
1046 * and XCheckTypedWindowEvent doesn't block */
1047 if(!(window->flags & SDL_WINDOW_FOREIGN))
1048 X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
1049 X11_XFlush(display);
1052 if (!data->videodata->net_wm) {
1053 /* no WM means no FocusIn event, which confuses us. Force it. */
1054 X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime);
1055 X11_XFlush(display);
1060 X11_HideWindow(_THIS, SDL_Window * window)
1062 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1063 SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
1064 Display *display = data->videodata->display;
1067 if (X11_IsWindowMapped(_this, window)) {
1068 X11_XWithdrawWindow(display, data->xwindow, displaydata->screen);
1069 /* Blocking wait for "UnmapNotify" event */
1070 if(!(window->flags & SDL_WINDOW_FOREIGN))
1071 X11_XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);
1072 X11_XFlush(display);
1077 SetWindowActive(_THIS, SDL_Window * window)
1079 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1080 SDL_DisplayData *displaydata =
1081 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
1082 Display *display = data->videodata->display;
1083 Atom _NET_ACTIVE_WINDOW = data->videodata->_NET_ACTIVE_WINDOW;
1085 if (X11_IsWindowMapped(_this, window)) {
1088 /*printf("SDL Window %p: sending _NET_ACTIVE_WINDOW with timestamp %lu\n", window, data->user_time);*/
1091 e.xany.type = ClientMessage;
1092 e.xclient.message_type = _NET_ACTIVE_WINDOW;
1093 e.xclient.format = 32;
1094 e.xclient.window = data->xwindow;
1095 e.xclient.data.l[0] = 1; /* source indication. 1 = application */
1096 e.xclient.data.l[1] = data->user_time;
1097 e.xclient.data.l[2] = 0;
1099 X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
1100 SubstructureNotifyMask | SubstructureRedirectMask, &e);
1102 X11_XFlush(display);
1107 X11_RaiseWindow(_THIS, SDL_Window * window)
1109 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1110 Display *display = data->videodata->display;
1112 X11_XRaiseWindow(display, data->xwindow);
1113 SetWindowActive(_this, window);
1114 X11_XFlush(display);
1118 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
1120 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1121 SDL_DisplayData *displaydata =
1122 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
1123 Display *display = data->videodata->display;
1124 Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
1125 Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
1126 Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
1129 window->flags |= SDL_WINDOW_MAXIMIZED;
1131 window->flags &= ~SDL_WINDOW_MAXIMIZED;
1134 if (X11_IsWindowMapped(_this, window)) {
1138 e.xany.type = ClientMessage;
1139 e.xclient.message_type = _NET_WM_STATE;
1140 e.xclient.format = 32;
1141 e.xclient.window = data->xwindow;
1142 e.xclient.data.l[0] =
1143 maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1144 e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
1145 e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
1146 e.xclient.data.l[3] = 0l;
1148 X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
1149 SubstructureNotifyMask | SubstructureRedirectMask, &e);
1151 X11_SetNetWMState(_this, data->xwindow, window->flags);
1153 X11_XFlush(display);
1157 X11_MaximizeWindow(_THIS, SDL_Window * window)
1159 SetWindowMaximized(_this, window, SDL_TRUE);
1163 X11_MinimizeWindow(_THIS, SDL_Window * window)
1165 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1166 SDL_DisplayData *displaydata =
1167 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
1168 Display *display = data->videodata->display;
1170 X11_XIconifyWindow(display, data->xwindow, displaydata->screen);
1171 X11_XFlush(display);
1175 X11_RestoreWindow(_THIS, SDL_Window * window)
1177 SetWindowMaximized(_this, window, SDL_FALSE);
1178 X11_ShowWindow(_this, window);
1179 SetWindowActive(_this, window);
1182 /* This asks the Window Manager to handle fullscreen for us. This is the modern way. */
1184 X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
1186 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1187 SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
1188 Display *display = data->videodata->display;
1189 Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
1190 Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
1192 if (X11_IsWindowMapped(_this, window)) {
1195 if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
1196 /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
1197 can be resized to the fullscreen resolution (or reset so we're not resizable again) */
1198 XSizeHints *sizehints = X11_XAllocSizeHints();
1200 X11_XGetWMNormalHints(display, data->xwindow, sizehints, &flags);
1201 /* set the resize flags on */
1203 /* we are going fullscreen so turn the flags off */
1204 sizehints->flags &= ~(PMinSize | PMaxSize);
1206 /* Reset the min/max width height to make the window non-resizable again */
1207 sizehints->flags |= PMinSize | PMaxSize;
1208 sizehints->min_width = sizehints->max_width = window->windowed.w;
1209 sizehints->min_height = sizehints->max_height = window->windowed.h;
1211 X11_XSetWMNormalHints(display, data->xwindow, sizehints);
1212 X11_XFree(sizehints);
1216 e.xany.type = ClientMessage;
1217 e.xclient.message_type = _NET_WM_STATE;
1218 e.xclient.format = 32;
1219 e.xclient.window = data->xwindow;
1220 e.xclient.data.l[0] =
1221 fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1222 e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
1223 e.xclient.data.l[3] = 0l;
1225 X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
1226 SubstructureNotifyMask | SubstructureRedirectMask, &e);
1228 /* Fullscreen windows sometimes end up being marked maximized by
1229 window managers. Force it back to how we expect it to be. */
1230 if (!fullscreen && ((window->flags & SDL_WINDOW_MAXIMIZED) == 0)) {
1232 e.xany.type = ClientMessage;
1233 e.xclient.message_type = _NET_WM_STATE;
1234 e.xclient.format = 32;
1235 e.xclient.window = data->xwindow;
1236 e.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
1237 e.xclient.data.l[1] = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
1238 e.xclient.data.l[2] = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
1239 e.xclient.data.l[3] = 0l;
1240 X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
1241 SubstructureNotifyMask | SubstructureRedirectMask, &e);
1246 flags = window->flags;
1248 flags |= SDL_WINDOW_FULLSCREEN;
1250 flags &= ~SDL_WINDOW_FULLSCREEN;
1252 X11_SetNetWMState(_this, data->xwindow, flags);
1255 if (data->visual->class == DirectColor) {
1257 X11_XInstallColormap(display, data->colormap);
1259 X11_XUninstallColormap(display, data->colormap);
1263 X11_XFlush(display);
1266 /* This handles fullscreen itself, outside the Window Manager. */
1268 X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
1270 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1271 SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
1272 Visual *visual = data->visual;
1273 Display *display = data->videodata->display;
1274 const int screen = displaydata->screen;
1275 Window root = RootWindow(display, screen);
1276 const int def_vis = (visual == DefaultVisual(display, screen));
1277 unsigned long xattrmask = 0;
1278 XSetWindowAttributes xattr;
1282 if ( data->fswindow ) {
1283 return; /* already fullscreen, I hope. */
1286 X11_GetDisplayBounds(_this, _display, &rect);
1289 xattr.override_redirect = True;
1290 xattrmask |= CWOverrideRedirect;
1291 xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
1292 xattrmask |= CWBackPixel;
1293 xattr.border_pixel = 0;
1294 xattrmask |= CWBorderPixel;
1295 xattr.colormap = data->colormap;
1296 xattrmask |= CWColormap;
1298 data->fswindow = X11_XCreateWindow(display, root,
1299 rect.x, rect.y, rect.w, rect.h, 0,
1300 displaydata->depth, InputOutput,
1301 visual, xattrmask, &xattr);
1303 X11_XSelectInput(display, data->fswindow, StructureNotifyMask);
1304 X11_XSetWindowBackground(display, data->fswindow, 0);
1305 X11_XInstallColormap(display, data->colormap);
1306 X11_XClearWindow(display, data->fswindow);
1307 X11_XMapRaised(display, data->fswindow);
1309 /* Make sure the fswindow is in view by warping mouse to the corner */
1310 X11_XUngrabPointer(display, CurrentTime);
1311 X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
1313 /* Wait to be mapped, filter Unmap event out if it arrives. */
1314 X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
1315 X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
1317 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
1318 if ( displaydata->use_vidmode ) {
1319 X11_XF86VidModeLockModeSwitch(display, screen, True);
1323 SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
1325 /* Center actual window within our cover-the-screen window. */
1326 X11_XReparentWindow(display, data->xwindow, data->fswindow,
1327 (rect.w - window->w) / 2, (rect.h - window->h) / 2);
1329 /* Move the mouse to the upper left to make sure it's on-screen */
1330 X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
1332 /* Center mouse in the fullscreen window. */
1333 rect.x += (rect.w / 2);
1334 rect.y += (rect.h / 2);
1335 X11_XWarpPointer(display, None, root, 0, 0, 0, 0, rect.x, rect.y);
1337 /* Wait to be mapped, filter Unmap event out if it arrives. */
1338 X11_XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
1339 X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
1341 SDL_UpdateWindowGrab(window);
1345 X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
1347 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1348 SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
1349 Display *display = data->videodata->display;
1350 const int screen = displaydata->screen;
1351 Window root = RootWindow(display, screen);
1352 Window fswindow = data->fswindow;
1355 if (!data->fswindow) {
1356 return; /* already not fullscreen, I hope. */
1359 data->fswindow = None;
1361 #if SDL_VIDEO_DRIVER_X11_VIDMODE
1362 if ( displaydata->use_vidmode ) {
1363 X11_XF86VidModeLockModeSwitch(display, screen, False);
1367 SDL_UpdateWindowGrab(window);
1369 X11_XReparentWindow(display, data->xwindow, root, window->x, window->y);
1371 /* flush these events so they don't confuse normal event handling */
1372 X11_XSync(display, False);
1373 X11_XCheckIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
1374 X11_XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
1376 SetWindowBordered(display, screen, data->xwindow,
1377 (window->flags & SDL_WINDOW_BORDERLESS) == 0);
1379 X11_XWithdrawWindow(display, fswindow, screen);
1381 /* Wait to be unmapped. */
1382 X11_XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&fswindow);
1383 X11_XDestroyWindow(display, fswindow);
1388 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
1390 /* !!! FIXME: SDL_Hint? */
1391 SDL_bool legacy = SDL_FALSE;
1392 const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
1394 legacy = SDL_atoi(env);
1396 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
1397 SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
1398 if ( displaydata->use_vidmode ) {
1399 legacy = SDL_TRUE; /* the new stuff only works with XRandR. */
1400 } else if ( !videodata->net_wm ) {
1401 legacy = SDL_TRUE; /* The window manager doesn't support it */
1403 /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
1404 /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
1405 legacy = SDL_FALSE; /* try the new way. */
1411 X11_BeginWindowFullscreenLegacy(_this, window, _display);
1413 X11_EndWindowFullscreenLegacy(_this, window, _display);
1416 X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
1422 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
1424 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1425 Display *display = data->videodata->display;
1426 Visual *visual = data->visual;
1427 Colormap colormap = data->colormap;
1430 int rmask, gmask, bmask;
1431 int rshift, gshift, bshift;
1434 if (visual->class != DirectColor) {
1435 return SDL_SetError("Window doesn't have DirectColor visual");
1438 ncolors = visual->map_entries;
1439 colorcells = SDL_malloc(ncolors * sizeof(XColor));
1441 return SDL_OutOfMemory();
1445 rmask = visual->red_mask;
1446 while (0 == (rmask & 1)) {
1452 gmask = visual->green_mask;
1453 while (0 == (gmask & 1)) {
1459 bmask = visual->blue_mask;
1460 while (0 == (bmask & 1)) {
1465 /* build the color table pixel values */
1466 for (i = 0; i < ncolors; i++) {
1467 Uint32 rbits = (rmask * i) / (ncolors - 1);
1468 Uint32 gbits = (gmask * i) / (ncolors - 1);
1469 Uint32 bbits = (bmask * i) / (ncolors - 1);
1470 Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
1472 colorcells[i].pixel = pix;
1474 colorcells[i].red = ramp[(0 * 256) + i];
1475 colorcells[i].green = ramp[(1 * 256) + i];
1476 colorcells[i].blue = ramp[(2 * 256) + i];
1478 colorcells[i].flags = DoRed | DoGreen | DoBlue;
1481 X11_XStoreColors(display, colormap, colorcells, ncolors);
1482 X11_XFlush(display);
1483 SDL_free(colorcells);
1489 X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
1491 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1492 Display *display = data->videodata->display;
1493 SDL_bool oldstyle_fullscreen;
1494 SDL_bool grab_keyboard;
1496 /* ICCCM2.0-compliant window managers can handle fullscreen windows
1497 If we're using XVidMode to change resolution we need to confine
1498 the cursor so we don't pan around the virtual desktop.
1500 oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
1502 if (oldstyle_fullscreen || grabbed) {
1503 /* Try to grab the mouse */
1504 if (!data->videodata->broken_pointer_grab) {
1505 const unsigned int mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask;
1509 /* Try for up to 5000ms (5s) to grab. If it still fails, stop trying. */
1510 for (attempts = 0; attempts < 100; attempts++) {
1511 result = X11_XGrabPointer(display, data->xwindow, True, mask, GrabModeAsync,
1512 GrabModeAsync, data->xwindow, None, CurrentTime);
1513 if (result == GrabSuccess) {
1519 if (result != GrabSuccess) {
1520 SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "The X server refused to let us grab the mouse. You might experience input bugs.");
1521 data->videodata->broken_pointer_grab = SDL_TRUE; /* don't try again. */
1525 /* Raise the window if we grab the mouse */
1526 X11_XRaiseWindow(display, data->xwindow);
1528 /* Now grab the keyboard */
1529 if (SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) {
1530 grab_keyboard = SDL_TRUE;
1532 /* We need to do this with the old style override_redirect
1533 fullscreen window otherwise we won't get keyboard focus.
1535 grab_keyboard = oldstyle_fullscreen;
1537 if (grab_keyboard) {
1538 X11_XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
1539 GrabModeAsync, CurrentTime);
1542 X11_XUngrabPointer(display, CurrentTime);
1543 X11_XUngrabKeyboard(display, CurrentTime);
1545 X11_XSync(display, False);
1549 X11_DestroyWindow(_THIS, SDL_Window * window)
1551 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1554 SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
1555 Display *display = videodata->display;
1556 int numwindows = videodata->numwindows;
1557 SDL_WindowData **windowlist = videodata->windowlist;
1561 for (i = 0; i < numwindows; ++i) {
1562 if (windowlist[i] && (windowlist[i]->window == window)) {
1563 windowlist[i] = windowlist[numwindows - 1];
1564 windowlist[numwindows - 1] = NULL;
1565 videodata->numwindows--;
1570 #ifdef X_HAVE_UTF8_STRING
1572 X11_XDestroyIC(data->ic);
1575 if (data->created) {
1576 X11_XDestroyWindow(display, data->xwindow);
1577 X11_XFlush(display);
1581 window->driverdata = NULL;
1585 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
1587 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1588 Display *display = data->videodata->display;
1590 if (info->version.major == SDL_MAJOR_VERSION &&
1591 info->version.minor == SDL_MINOR_VERSION) {
1592 info->subsystem = SDL_SYSWM_X11;
1593 info->info.x11.display = display;
1594 info->info.x11.window = data->xwindow;
1597 SDL_SetError("Application not compiled with SDL %d.%d",
1598 SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
1604 X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
1606 return 0; /* just succeed, the real work is done elsewhere. */
1609 #endif /* SDL_VIDEO_DRIVER_X11 */
1611 /* vi: set ts=4 sw=4 expandtab: */