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