Atlas - SDL_x11window.c
Home / ext / SDL2 / src / video / x11 Lines: 2 | Size: 55074 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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; 87 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 88 XWindowAttributes attr; 89 90 X11_XGetWindowAttributes(videodata->display, data->xwindow, &attr); 91 if (attr.map_state != IsUnmapped) { 92 return SDL_TRUE; 93 } else { 94 return SDL_FALSE; 95 } 96} 97 98#if 0 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{ 130 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 131 Display *display = videodata->display; 132 /* !!! FIXME: just dereference videodata below instead of copying to locals. */ 133 Atom _NET_WM_STATE = videodata->_NET_WM_STATE; 134 /* Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN; */ 135 Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED; 136 Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT; 137 Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ; 138 Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN; 139 Atom _NET_WM_STATE_ABOVE = videodata->_NET_WM_STATE_ABOVE; 140 Atom _NET_WM_STATE_SKIP_TASKBAR = videodata->_NET_WM_STATE_SKIP_TASKBAR; 141 Atom _NET_WM_STATE_SKIP_PAGER = videodata->_NET_WM_STATE_SKIP_PAGER; 142 Atom atoms[16]; 143 int count = 0; 144 145 /* The window manager sets this property, we shouldn't set it. 146 If we did, this would indicate to the window manager that we don't 147 actually want to be mapped during X11_XMapRaised(), which would be bad. 148 * 149 if (flags & SDL_WINDOW_HIDDEN) { 150 atoms[count++] = _NET_WM_STATE_HIDDEN; 151 } 152 */ 153 154 if (flags & SDL_WINDOW_ALWAYS_ON_TOP) { 155 atoms[count++] = _NET_WM_STATE_ABOVE; 156 } 157 if (flags & SDL_WINDOW_SKIP_TASKBAR) { 158 atoms[count++] = _NET_WM_STATE_SKIP_TASKBAR; 159 atoms[count++] = _NET_WM_STATE_SKIP_PAGER; 160 } 161 if (flags & SDL_WINDOW_INPUT_FOCUS) { 162 atoms[count++] = _NET_WM_STATE_FOCUSED; 163 } 164 if (flags & SDL_WINDOW_MAXIMIZED) { 165 atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT; 166 atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ; 167 } 168 if (flags & SDL_WINDOW_FULLSCREEN) { 169 atoms[count++] = _NET_WM_STATE_FULLSCREEN; 170 } 171 172 SDL_assert(count <= SDL_arraysize(atoms)); 173 174 if (count > 0) { 175 X11_XChangeProperty(display, xwindow, _NET_WM_STATE, XA_ATOM, 32, 176 PropModeReplace, (unsigned char *)atoms, count); 177 } else { 178 X11_XDeleteProperty(display, xwindow, _NET_WM_STATE); 179 } 180} 181 182Uint32 183X11_GetNetWMState(_THIS, Window xwindow) 184{ 185 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 186 Display *display = videodata->display; 187 Atom _NET_WM_STATE = videodata->_NET_WM_STATE; 188 Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN; 189 Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED; 190 Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT; 191 Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ; 192 Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN; 193 Atom actualType; 194 int actualFormat; 195 unsigned long i, numItems, bytesAfter; 196 unsigned char *propertyValue = NULL; 197 long maxLength = 1024; 198 Uint32 flags = 0; 199 200 if (X11_XGetWindowProperty(display, xwindow, _NET_WM_STATE, 201 0l, maxLength, False, XA_ATOM, &actualType, 202 &actualFormat, &numItems, &bytesAfter, 203 &propertyValue) == Success) { 204 Atom *atoms = (Atom *) propertyValue; 205 int maximized = 0; 206 int fullscreen = 0; 207 208 for (i = 0; i < numItems; ++i) { 209 if (atoms[i] == _NET_WM_STATE_HIDDEN) { 210 flags |= SDL_WINDOW_HIDDEN; 211 } else if (atoms[i] == _NET_WM_STATE_FOCUSED) { 212 flags |= SDL_WINDOW_INPUT_FOCUS; 213 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) { 214 maximized |= 1; 215 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) { 216 maximized |= 2; 217 } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) { 218 fullscreen = 1; 219 } 220 } 221 if (maximized == 3) { 222 flags |= SDL_WINDOW_MAXIMIZED; 223 } 224 225 if (fullscreen == 1) { 226 flags |= SDL_WINDOW_FULLSCREEN; 227 } 228 229 /* If the window is unmapped, numItems will be zero and _NET_WM_STATE_HIDDEN 230 * will not be set. Do an additional check to see if the window is unmapped 231 * and mark it as SDL_WINDOW_HIDDEN if it is. 232 */ 233 { 234 XWindowAttributes attr; 235 SDL_memset(&attr,0,sizeof(attr)); 236 X11_XGetWindowAttributes(videodata->display, xwindow, &attr); 237 if (attr.map_state == IsUnmapped) { 238 flags |= SDL_WINDOW_HIDDEN; 239 } 240 } 241 X11_XFree(propertyValue); 242 } 243 244 /* FIXME, check the size hints for resizable */ 245 /* flags |= SDL_WINDOW_RESIZABLE; */ 246 247 return flags; 248} 249 250static int 251SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created) 252{ 253 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; 254 SDL_WindowData *data; 255 int numwindows = videodata->numwindows; 256 int windowlistlength = videodata->windowlistlength; 257 SDL_WindowData **windowlist = videodata->windowlist; 258 259 /* Allocate the window data */ 260 data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data)); 261 if (!data) { 262 return SDL_OutOfMemory(); 263 } 264 data->window = window; 265 data->xwindow = w; 266#ifdef X_HAVE_UTF8_STRING 267 if (SDL_X11_HAVE_UTF8 && videodata->im) { 268 data->ic = 269 X11_XCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w, 270 XNInputStyle, XIMPreeditNothing | XIMStatusNothing, 271 NULL); 272 } 273#endif 274 data->created = created; 275 data->videodata = videodata; 276 277 /* Associate the data with the window */ 278 279 if (numwindows < windowlistlength) { 280 windowlist[numwindows] = data; 281 videodata->numwindows++; 282 } else { 283 windowlist = 284 (SDL_WindowData **) SDL_realloc(windowlist, 285 (numwindows + 286 1) * sizeof(*windowlist)); 287 if (!windowlist) { 288 SDL_free(data); 289 return SDL_OutOfMemory(); 290 } 291 windowlist[numwindows] = data; 292 videodata->numwindows++; 293 videodata->windowlistlength++; 294 videodata->windowlist = windowlist; 295 } 296 297 /* Fill in the SDL window with the window data */ 298 { 299 XWindowAttributes attrib; 300 301 X11_XGetWindowAttributes(data->videodata->display, w, &attrib); 302 window->x = attrib.x; 303 window->y = attrib.y; 304 window->w = attrib.width; 305 window->h = attrib.height; 306 if (attrib.map_state != IsUnmapped) { 307 window->flags |= SDL_WINDOW_SHOWN; 308 } else { 309 window->flags &= ~SDL_WINDOW_SHOWN; 310 } 311 data->visual = attrib.visual; 312 data->colormap = attrib.colormap; 313 } 314 315 window->flags |= X11_GetNetWMState(_this, w); 316 317 { 318 Window FocalWindow; 319 int RevertTo=0; 320 X11_XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo); 321 if (FocalWindow==w) 322 { 323 window->flags |= SDL_WINDOW_INPUT_FOCUS; 324 } 325 326 if (window->flags & SDL_WINDOW_INPUT_FOCUS) { 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 372X11_CreateWindow(_THIS, SDL_Window * window) 373{ 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; 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 401 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES 402#if SDL_VIDEO_OPENGL_GLX 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 */ 561 X11_SetNetWMState(_this, w, window->flags); 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); 581 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, SDL_TRUE)) { 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 */ 596 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_PING, SDL_TRUE)) { 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 611#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 612 if ((window->flags & SDL_WINDOW_OPENGL) && 613 _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES 614#if SDL_VIDEO_OPENGL_GLX 615 && ( !_this->gl_data || X11_GL_UseEGL(_this) ) 616#endif 617 ) { 618#if SDL_VIDEO_OPENGL_EGL 619 if (!_this->egl_data) { 620 X11_XDestroyWindow(display, w); 621 return -1; 622 } 623 624 /* Create the GLES window surface */ 625 windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) w); 626 627 if (windowdata->egl_surface == EGL_NO_SURFACE) { 628 X11_XDestroyWindow(display, w); 629 return SDL_SetError("Could not create GLES window surface"); 630 } 631#else 632 return SDL_SetError("Could not create GLES window surface (EGL support not configured)"); 633#endif /* SDL_VIDEO_OPENGL_EGL */ 634 } 635#endif 636 637 638#ifdef X_HAVE_UTF8_STRING 639 if (SDL_X11_HAVE_UTF8 && windowdata->ic) { 640 X11_XGetICValues(windowdata->ic, XNFilterEvents, &fevent, NULL); 641 } 642#endif 643 644 X11_Xinput2SelectTouch(_this, window); 645 646 X11_XSelectInput(display, w, 647 (FocusChangeMask | EnterWindowMask | LeaveWindowMask | 648 ExposureMask | ButtonPressMask | ButtonReleaseMask | 649 PointerMotionMask | KeyPressMask | KeyReleaseMask | 650 PropertyChangeMask | StructureNotifyMask | 651 KeymapStateMask | fevent)); 652 653 X11_XFlush(display); 654 655 return 0; 656} 657 658int 659X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) 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{ 674 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 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 703X11_SetWindowTitle(_THIS, SDL_Window * window) 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) { 718 SDL_OutOfMemory(); 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 744X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) 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 */ 755 SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888); 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 784X11_SetWindowPosition(_THIS, SDL_Window * window) 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 794X11_SetWindowMinimumSize(_THIS, SDL_Window * window) 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 823X11_SetWindowMaximumSize(_THIS, SDL_Window * window) 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 852X11_SetWindowSize(_THIS, SDL_Window * window) 853{ 854 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 855 Display *display = data->videodata->display; 856 857 if (SDL_IsShapedWindow(window)) { 858 X11_ResizeWindowShape(window); 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 903X11_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right) 904{ 905 SDL_WindowData *data = (SDL_WindowData *)window->driverdata; 906 907 *left = data->border_left; 908 *right = data->border_right; 909 *top = data->border_top; 910 *bottom = data->border_bottom; 911 912 return 0; 913} 914 915int 916X11_SetWindowOpacity(_THIS, SDL_Window * window, float opacity) 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 945X11_SetWindowInputFocus(_THIS, SDL_Window * window) 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 958X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) 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 = 964 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; 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 990X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) 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 1028X11_ShowWindow(_THIS, SDL_Window * window) 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 1052X11_HideWindow(_THIS, SDL_Window * window) 1053{ 1054 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 1055 SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(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 = 1073 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; 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 1099X11_RaiseWindow(_THIS, SDL_Window * window) 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 = 1114 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; 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 { 1143 X11_SetNetWMState(_this, data->xwindow, window->flags); 1144 } 1145 X11_XFlush(display); 1146} 1147 1148void 1149X11_MaximizeWindow(_THIS, SDL_Window * window) 1150{ 1151 SetWindowMaximized(_this, window, SDL_TRUE); 1152} 1153 1154void 1155X11_MinimizeWindow(_THIS, SDL_Window * window) 1156{ 1157 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 1158 SDL_DisplayData *displaydata = 1159 (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; 1160 Display *display = data->videodata->display; 1161 1162 X11_XIconifyWindow(display, data->xwindow, displaydata->screen); 1163 X11_XFlush(display); 1164} 1165 1166void 1167X11_RestoreWindow(_THIS, SDL_Window * window) 1168{ 1169 SetWindowMaximized(_this, window, SDL_FALSE); 1170 X11_ShowWindow(_this, window); 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) { 1240 flags |= SDL_WINDOW_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 1333 SDL_UpdateWindowGrab(window); 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 1359 SDL_UpdateWindowGrab(window); 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 1380X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen) 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 1414X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp) 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 1481X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) 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 */ 1521 if (SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) { 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 1541X11_DestroyWindow(_THIS, SDL_Window * window) 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 1576SDL_bool 1577X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) 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", 1590 SDL_MAJOR_VERSION, SDL_MINOR_VERSION); 1591 return SDL_FALSE; 1592 } 1593} 1594 1595int 1596X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled) 1597{ 1598 return 0; /* just succeed, the real work is done elsewhere. */ 1599} 1600 1601void 1602X11_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept) 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: */ 1620[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.