SDL_x11video.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:36k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
  4.     This library is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU Library General Public
  6.     License as published by the Free Software Foundation; either
  7.     version 2 of the License, or (at your option) any later version.
  8.     This library is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.     Library General Public License for more details.
  12.     You should have received a copy of the GNU Library General Public
  13.     License along with this library; if not, write to the Free
  14.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15.     Sam Lantinga
  16.     slouken@libsdl.org
  17. */
  18. #ifdef SAVE_RCSID
  19. static char rcsid =
  20.  "@(#) $Id: SDL_x11video.c,v 1.4 2002/04/22 21:38:06 wmay Exp $";
  21. #endif
  22. /* X11 based SDL video driver implementation.
  23.    Note:  This implementation does not currently need X11 thread locking,
  24.           since the event thread uses a separate X connection and any
  25.           additional locking necessary is handled internally.  However,
  26.           if full locking is neccessary, take a look at XInitThreads().
  27. */
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <unistd.h>
  31. #include <string.h>
  32. #include <sys/ioctl.h>
  33. #ifdef MTRR_SUPPORT
  34. #include <asm/mtrr.h>
  35. #include <sys/fcntl.h>
  36. #endif
  37. #ifdef HAVE_ALLOCA_H
  38. #include <alloca.h>
  39. #endif
  40. #ifdef HAVE_ALLOCA
  41. #define ALLOCA(n) ((void*)alloca(n))
  42. #define FREEA(p)
  43. #else
  44. #define ALLOCA(n) malloc(n)
  45. #define FREEA(p) free(p)
  46. #endif
  47. #include "SDL.h"
  48. #include "SDL_error.h"
  49. #include "SDL_timer.h"
  50. #include "SDL_thread.h"
  51. #include "SDL_video.h"
  52. #include "SDL_mouse.h"
  53. #include "SDL_endian.h"
  54. #include "SDL_sysvideo.h"
  55. #include "SDL_pixels_c.h"
  56. #include "SDL_events_c.h"
  57. #include "SDL_x11video.h"
  58. #include "SDL_x11wm_c.h"
  59. #include "SDL_x11mouse_c.h"
  60. #include "SDL_x11events_c.h"
  61. #include "SDL_x11modes_c.h"
  62. #include "SDL_x11image_c.h"
  63. #include "SDL_x11yuv_c.h"
  64. #include "SDL_x11gl_c.h"
  65. #include "SDL_x11gamma_c.h"
  66. #include "blank_cursor.h"
  67. /* Initialization/Query functions */
  68. static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat);
  69. static SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
  70. static int X11_ToggleFullScreen(_THIS, int on);
  71. static void X11_UpdateMouse(_THIS);
  72. static int X11_SetColors(_THIS, int firstcolor, int ncolors,
  73.  SDL_Color *colors);
  74. static int X11_SetGammaRamp(_THIS, Uint16 *ramp);
  75. static void X11_VideoQuit(_THIS);
  76. /* X11 driver bootstrap functions */
  77. static int X11_Available(void)
  78. {
  79. Display *display;
  80. display = XOpenDisplay(NULL);
  81. if ( display != NULL ) {
  82. XCloseDisplay(display);
  83. }
  84. return(display != NULL);
  85. }
  86. static void X11_DeleteDevice(SDL_VideoDevice *device)
  87. {
  88. if ( device ) {
  89. if ( device->hidden ) {
  90. free(device->hidden);
  91. }
  92. if ( device->gl_data ) {
  93. free(device->gl_data);
  94. }
  95. free(device);
  96. }
  97. }
  98. static SDL_VideoDevice *X11_CreateDevice(int devindex)
  99. {
  100. SDL_VideoDevice *device;
  101. /* Initialize all variables that we clean on shutdown */
  102. device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
  103. if ( device ) {
  104. memset(device, 0, (sizeof *device));
  105. device->hidden = (struct SDL_PrivateVideoData *)
  106. malloc((sizeof *device->hidden));
  107. device->gl_data = (struct SDL_PrivateGLData *)
  108. malloc((sizeof *device->gl_data));
  109. }
  110. if ( (device == NULL) || (device->hidden == NULL) ||
  111.                          (device->gl_data == NULL) ) {
  112. SDL_OutOfMemory();
  113. X11_DeleteDevice(device);
  114. return(0);
  115. }
  116. memset(device->hidden, 0, (sizeof *device->hidden));
  117. memset(device->gl_data, 0, (sizeof *device->gl_data));
  118. /* Set the driver flags */
  119. device->handles_any_size = 1;
  120. /* Set the function pointers */
  121. device->VideoInit = X11_VideoInit;
  122. device->ListModes = X11_ListModes;
  123. device->SetVideoMode = X11_SetVideoMode;
  124. device->ToggleFullScreen = X11_ToggleFullScreen;
  125. device->UpdateMouse = X11_UpdateMouse;
  126. #ifdef XFREE86_XV
  127. device->CreateYUVOverlay = X11_CreateYUVOverlay;
  128. #endif
  129. device->SetColors = X11_SetColors;
  130. device->UpdateRects = NULL;
  131. device->VideoQuit = X11_VideoQuit;
  132. device->AllocHWSurface = X11_AllocHWSurface;
  133. device->CheckHWBlit = NULL;
  134. device->FillHWRect = NULL;
  135. device->SetHWColorKey = NULL;
  136. device->SetHWAlpha = NULL;
  137. device->LockHWSurface = X11_LockHWSurface;
  138. device->UnlockHWSurface = X11_UnlockHWSurface;
  139. device->FlipHWSurface = X11_FlipHWSurface;
  140. device->FreeHWSurface = X11_FreeHWSurface;
  141. device->SetGamma = X11_SetVidModeGamma;
  142. device->GetGamma = X11_GetVidModeGamma;
  143. device->SetGammaRamp = X11_SetGammaRamp;
  144. device->GetGammaRamp = NULL;
  145. #ifdef HAVE_OPENGL
  146. device->GL_LoadLibrary = X11_GL_LoadLibrary;
  147. device->GL_GetProcAddress = X11_GL_GetProcAddress;
  148. device->GL_GetAttribute = X11_GL_GetAttribute;
  149. device->GL_MakeCurrent = X11_GL_MakeCurrent;
  150. device->GL_SwapBuffers = X11_GL_SwapBuffers;
  151. #endif
  152. device->SetCaption = X11_SetCaption;
  153. device->SetIcon = X11_SetIcon;
  154. device->IconifyWindow = X11_IconifyWindow;
  155. device->GrabInput = X11_GrabInput;
  156. device->GetWMInfo = X11_GetWMInfo;
  157. device->FreeWMCursor = X11_FreeWMCursor;
  158. device->CreateWMCursor = X11_CreateWMCursor;
  159. device->ShowWMCursor = X11_ShowWMCursor;
  160. device->WarpWMCursor = X11_WarpWMCursor;
  161. device->CheckMouseMode = X11_CheckMouseMode;
  162. device->InitOSKeymap = X11_InitOSKeymap;
  163. device->PumpEvents = X11_PumpEvents;
  164. device->free = X11_DeleteDevice;
  165. return device;
  166. }
  167. VideoBootStrap X11_bootstrap = {
  168. "x11", "X Window System",
  169. X11_Available, X11_CreateDevice
  170. };
  171. /* Shared memory information */
  172. extern int XShmQueryExtension(Display *dpy); /* Not in X11 headers */
  173. /* Normal X11 error handler routine */
  174. static int (*X_handler)(Display *, XErrorEvent *) = NULL;
  175. static int x_errhandler(Display *d, XErrorEvent *e)
  176. {
  177. #ifdef XFREE86_VM
  178. extern int vm_error;
  179. #endif
  180. #ifdef XFREE86_DGAMOUSE
  181. extern int dga_error;
  182. #endif
  183. #ifdef XFREE86_VM
  184. /* VidMode errors are non-fatal. :) */
  185. /* Are the errors offset by one from the error base?
  186.    e.g. the error base is 143, the code is 148, and the
  187.         actual error is XF86VidModeExtensionDisabled (4) ?
  188.  */
  189.         if ( (vm_error >= 0) &&
  190.      (((e->error_code == BadRequest)&&(e->request_code == vm_error)) ||
  191.       ((e->error_code > vm_error) &&
  192.        (e->error_code <= (vm_error+XF86VidModeNumberErrors)))) ) {
  193. #ifdef XFREE86_DEBUG
  194. { char errmsg[1024];
  195.   XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg));
  196. printf("VidMode error: %sn", errmsg);
  197. }
  198. #endif
  199.          return(0);
  200.         }
  201. #endif /* XFREE86_VM */
  202. #ifdef XFREE86_DGAMOUSE
  203. /* DGA errors can be non-fatal. :) */
  204.         if ( (dga_error >= 0) &&
  205.      ((e->error_code > dga_error) &&
  206.       (e->error_code <= (dga_error+XF86DGANumberErrors))) ) {
  207. #ifdef XFREE86_DEBUG
  208. { char errmsg[1024];
  209.   XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg));
  210. printf("DGA error: %sn", errmsg);
  211. }
  212. #endif
  213.          return(0);
  214.         }
  215. #endif /* XFREE86_DGAMOUSE */
  216. return(X_handler(d,e));
  217. }
  218. /* X11 I/O error handler routine */
  219. static int (*XIO_handler)(Display *) = NULL;
  220. static int xio_errhandler(Display *d)
  221. {
  222. /* Ack!  Lost X11 connection! */
  223. /* We will crash if we try to clean up our display */
  224. if ( current_video->hidden->Ximage ) {
  225. SDL_VideoSurface->pixels = NULL;
  226. }
  227. current_video->hidden->X11_Display = NULL;
  228. /* Continue with the standard X11 error handler */
  229. return(XIO_handler(d));
  230. }
  231. /* Create auxiliary (toplevel) windows with the current visual */
  232. static void create_aux_windows(_THIS)
  233. {
  234.     XSetWindowAttributes xattr;
  235.     XWMHints *hints;
  236.     XTextProperty titleprop, iconprop;
  237.     int def_vis = (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen));
  238.     /* Don't create any extra windows if we are being managed */
  239.     if ( SDL_windowid ) {
  240. FSwindow = 0;
  241. WMwindow = strtol(SDL_windowid, NULL, 0);
  242.         return;
  243.     }
  244.     if(FSwindow)
  245. XDestroyWindow(SDL_Display, FSwindow);
  246.     xattr.override_redirect = True;
  247.     xattr.background_pixel = def_vis ? BlackPixel(SDL_Display, SDL_Screen) : 0;
  248.     xattr.border_pixel = 0;
  249.     xattr.colormap = SDL_XColorMap;
  250.     FSwindow = XCreateWindow(SDL_Display, SDL_Root, 0, 0, 32, 32, 0,
  251.      this->hidden->depth, InputOutput, SDL_Visual,
  252.      CWOverrideRedirect | CWBackPixel | CWBorderPixel
  253.      | CWColormap,
  254.      &xattr);
  255.     XSelectInput(SDL_Display, FSwindow, StructureNotifyMask);
  256.     /* Tell KDE to keep the fullscreen window on top */
  257.     {
  258. XEvent ev;
  259. long mask;
  260. memset(&ev, 0, sizeof(ev));
  261. ev.xclient.type = ClientMessage;
  262. ev.xclient.window = SDL_Root;
  263. ev.xclient.message_type = XInternAtom(SDL_Display,
  264.       "KWM_KEEP_ON_TOP", False);
  265. ev.xclient.format = 32;
  266. ev.xclient.data.l[0] = FSwindow;
  267. ev.xclient.data.l[1] = CurrentTime;
  268. mask = SubstructureRedirectMask;
  269. XSendEvent(SDL_Display, SDL_Root, False, mask, &ev);
  270.     }
  271.     hints = NULL;
  272.     titleprop.value = iconprop.value = NULL;
  273.     if(WMwindow) {
  274. /* All window attributes must survive the recreation */
  275. hints = XGetWMHints(SDL_Display, WMwindow);
  276. XGetWMName(SDL_Display, WMwindow, &titleprop);
  277. XGetWMIconName(SDL_Display, WMwindow, &iconprop);
  278. XDestroyWindow(SDL_Display, WMwindow);
  279.     }
  280.     /* Create the window for windowed management */
  281.     /* (reusing the xattr structure above) */
  282.     WMwindow = XCreateWindow(SDL_Display, SDL_Root, 0, 0, 32, 32, 0,
  283.      this->hidden->depth, InputOutput, SDL_Visual,
  284.      CWBackPixel | CWBorderPixel | CWColormap,
  285.      &xattr);
  286.     /* Set the input hints so we get keyboard input */
  287.     if(!hints) {
  288. hints = XAllocWMHints();
  289. hints->input = True;
  290. hints->flags = InputHint;
  291.     }
  292.     XSetWMHints(SDL_Display, WMwindow, hints);
  293.     XFree(hints);
  294.     if(titleprop.value) {
  295. XSetWMName(SDL_Display, WMwindow, &titleprop);
  296. XFree(titleprop.value);
  297.     }
  298.     if(iconprop.value) {
  299. XSetWMIconName(SDL_Display, WMwindow, &iconprop);
  300. XFree(iconprop.value);
  301.     }
  302.     XSelectInput(SDL_Display, WMwindow,
  303.  FocusChangeMask | KeyPressMask | KeyReleaseMask
  304.  | PropertyChangeMask | StructureNotifyMask | KeymapStateMask);
  305.     /* Set the class hints so we can get an icon (AfterStep) */
  306.     {
  307. XClassHint *classhints;
  308. classhints = XAllocClassHint();
  309. if(classhints != NULL) {
  310.     classhints->res_name = "SDL_App";
  311.     classhints->res_class = "SDL_App";
  312.     XSetClassHint(SDL_Display, WMwindow, classhints);
  313.     XFree(classhints);
  314. }
  315.     }
  316.     /* Allow the window to be deleted by the window manager */
  317.     WM_DELETE_WINDOW = XInternAtom(SDL_Display, "WM_DELETE_WINDOW", False);
  318.     XSetWMProtocols(SDL_Display, WMwindow, &WM_DELETE_WINDOW, 1);
  319. }
  320. static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat)
  321. {
  322. char *display;
  323. int i;
  324. /* Open the X11 display */
  325. display = NULL; /* Get it from DISPLAY environment variable */
  326. if ( (strncmp(XDisplayName(display), ":", 1) == 0) ||
  327.      (strncmp(XDisplayName(display), "unix:", 5) == 0) ) {
  328. local_X11 = 1;
  329. } else {
  330. local_X11 = 0;
  331. }
  332. SDL_Display = XOpenDisplay(display);
  333. if ( SDL_Display == NULL ) {
  334. SDL_SetError("Couldn't open X11 display");
  335. return(-1);
  336. }
  337. #ifdef X11_DEBUG
  338. XSynchronize(SDL_Display, True);
  339. #endif
  340. /* Create an alternate X display for graphics updates -- allows us
  341.    to do graphics updates in a separate thread from event handling.
  342.    Thread-safe X11 doesn't seem to exist.
  343.  */
  344. GFX_Display = XOpenDisplay(display);
  345. if ( GFX_Display == NULL ) {
  346. SDL_SetError("Couldn't open X11 display");
  347. return(-1);
  348. }
  349. /* Set the normal X error handler */
  350. X_handler = XSetErrorHandler(x_errhandler);
  351. /* Set the error handler if we lose the X display */
  352. XIO_handler = XSetIOErrorHandler(xio_errhandler);
  353. /* use default screen (from $DISPLAY) */
  354. SDL_Screen = DefaultScreen(SDL_Display);
  355. use_mitshm = 0;
  356. #ifndef NO_SHARED_MEMORY
  357. /* Check for MIT shared memory extension */
  358. if ( local_X11 ) {
  359. use_mitshm = XShmQueryExtension(SDL_Display);
  360. }
  361. #endif /* NO_SHARED_MEMORY */
  362. /* Get the available video modes */
  363. if(X11_GetVideoModes(this) < 0)
  364.     return -1;
  365. /* Determine the default screen depth:
  366.    Use the default visual (or at least one with the same depth) */
  367. SDL_DisplayColormap = DefaultColormap(SDL_Display, SDL_Screen);
  368. for(i = 0; i < this->hidden->nvisuals; i++)
  369.     if(this->hidden->visuals[i].depth == DefaultDepth(SDL_Display,
  370.       SDL_Screen))
  371. break;
  372. if(i == this->hidden->nvisuals) {
  373.     /* default visual was useless, take the deepest one instead */
  374.     i = 0;
  375. }
  376. SDL_Visual = this->hidden->visuals[i].visual;
  377. if ( SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen) ) {
  378.     SDL_XColorMap = SDL_DisplayColormap;
  379. } else {
  380.     SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
  381.     SDL_Visual, AllocNone);
  382. }
  383. this->hidden->depth = this->hidden->visuals[i].depth;
  384. vformat->BitsPerPixel = this->hidden->visuals[i].bpp;
  385. if ( vformat->BitsPerPixel > 8 ) {
  386. vformat->Rmask = SDL_Visual->red_mask;
  387.    vformat->Gmask = SDL_Visual->green_mask;
  388.    vformat->Bmask = SDL_Visual->blue_mask;
  389. }
  390. X11_SaveVidModeGamma(this);
  391. /* See if we have been passed a window to use */
  392. SDL_windowid = getenv("SDL_WINDOWID");
  393. /* Create the fullscreen and managed windows */
  394. create_aux_windows(this);
  395. /* Create the blank cursor */
  396. SDL_BlankCursor = this->CreateWMCursor(this, blank_cdata, blank_cmask,
  397. BLANK_CWIDTH, BLANK_CHEIGHT,
  398. BLANK_CHOTX, BLANK_CHOTY);
  399. /* Fill in some window manager capabilities */
  400. this->info.wm_available = 1;
  401. /* We're done! */
  402. XFlush(SDL_Display);
  403. return(0);
  404. }
  405. static void X11_DestroyWindow(_THIS, SDL_Surface *screen)
  406. {
  407. /* Clean up OpenGL */
  408. if ( screen ) {
  409. screen->flags &= ~(SDL_OPENGL|SDL_OPENGLBLIT);
  410. }
  411. X11_GL_Shutdown(this);
  412. if ( ! SDL_windowid ) {
  413. /* Hide the managed window */
  414. if ( WMwindow ) {
  415. XUnmapWindow(SDL_Display, WMwindow);
  416. }
  417. if ( screen && (screen->flags & SDL_FULLSCREEN) ) {
  418. screen->flags &= ~SDL_FULLSCREEN;
  419. X11_LeaveFullScreen(this);
  420. }
  421. /* Destroy the output window */
  422. if ( SDL_Window ) {
  423. XDestroyWindow(SDL_Display, SDL_Window);
  424. }
  425. /* Free the colormap entries */
  426. if ( SDL_XPixels ) {
  427. int numcolors;
  428. unsigned long pixel;
  429. numcolors = SDL_Visual->map_entries;
  430. for ( pixel=0; pixel<numcolors; ++pixel ) {
  431. while ( SDL_XPixels[pixel] > 0 ) {
  432. XFreeColors(GFX_Display,
  433. SDL_DisplayColormap,&pixel,1,0);
  434. --SDL_XPixels[pixel];
  435. }
  436. }
  437. free(SDL_XPixels);
  438. SDL_XPixels = NULL;
  439. /* Free the graphics context */
  440. if ( SDL_GC ) {
  441. XFreeGC(SDL_Display, SDL_GC);
  442. SDL_GC = 0;
  443. }
  444. }
  445. }
  446. static void X11_SetSizeHints(_THIS, int w, int h, Uint32 flags)
  447. {
  448. XSizeHints *hints;
  449. hints = XAllocSizeHints();
  450. if ( hints ) {
  451. if ( flags & SDL_RESIZABLE ) {
  452. hints->min_width = 32;
  453. hints->min_height = 32;
  454. hints->max_height = 4096;
  455. hints->max_width = 4096;
  456. } else {
  457. hints->min_width = hints->max_width = w;
  458. hints->min_height = hints->max_height = h;
  459. }
  460. hints->flags = PMaxSize | PMinSize;
  461. if ( flags & SDL_FULLSCREEN ) {
  462. hints->x = 0;
  463. hints->y = 0;
  464. hints->flags |= USPosition;
  465. } else
  466. /* Center it, if desired */
  467. if ( getenv("SDL_VIDEO_CENTERED") ) {
  468. int display_w, display_h;
  469. display_w = DisplayWidth(SDL_Display, SDL_Screen);
  470. display_h = DisplayHeight(SDL_Display, SDL_Screen);
  471. hints->x = (display_w - w)/2;
  472. hints->y = (display_h - h)/2;
  473. hints->flags |= USPosition;
  474. XMoveWindow(SDL_Display, WMwindow, hints->x, hints->y);
  475. /* Flush the resize event so we don't catch it later */
  476. XSync(SDL_Display, True);
  477. }
  478. XSetWMNormalHints(SDL_Display, WMwindow, hints);
  479. XFree(hints);
  480. }
  481. /* Respect the window caption style */
  482. if ( flags & SDL_NOFRAME ) {
  483. SDL_bool set;
  484. Atom WM_HINTS;
  485. /* We haven't modified the window manager hints yet */
  486. set = SDL_FALSE;
  487. /* First try to set MWM hints */
  488. WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True);
  489. if ( WM_HINTS != None ) {
  490. /* Hints used by Motif compliant window managers */
  491. struct {
  492. unsigned long flags;
  493. unsigned long functions;
  494. unsigned long decorations;
  495. long input_mode;
  496. unsigned long status;
  497. } MWMHints = { (1L << 1), 0, 0, 0, 0 };
  498. XChangeProperty(SDL_Display, WMwindow,
  499.                 WM_HINTS, WM_HINTS, 32,
  500.                 PropModeReplace,
  501. (unsigned char *)&MWMHints,
  502. sizeof(MWMHints)/sizeof(long));
  503. set = SDL_TRUE;
  504. }
  505. /* Now try to set KWM hints */
  506. WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True);
  507. if ( WM_HINTS != None ) {
  508. long KWMHints = 0;
  509. XChangeProperty(SDL_Display, WMwindow,
  510.                 WM_HINTS, WM_HINTS, 32,
  511.                 PropModeReplace,
  512. (unsigned char *)&KWMHints,
  513. sizeof(KWMHints)/sizeof(long));
  514. set = SDL_TRUE;
  515. }
  516. /* Now try to set GNOME hints */
  517. WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True);
  518. if ( WM_HINTS != None ) {
  519. long GNOMEHints = 0;
  520. XChangeProperty(SDL_Display, WMwindow,
  521.                 WM_HINTS, WM_HINTS, 32,
  522.                 PropModeReplace,
  523. (unsigned char *)&GNOMEHints,
  524. sizeof(GNOMEHints)/sizeof(long));
  525. set = SDL_TRUE;
  526. }
  527. /* Finally set the transient hints if necessary */
  528. if ( ! set ) {
  529. XSetTransientForHint(SDL_Display, WMwindow, SDL_Root);
  530. }
  531. } else {
  532. SDL_bool set;
  533. Atom WM_HINTS;
  534. /* We haven't modified the window manager hints yet */
  535. set = SDL_FALSE;
  536. /* First try to unset MWM hints */
  537. WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True);
  538. if ( WM_HINTS != None ) {
  539. XDeleteProperty(SDL_Display, WMwindow, WM_HINTS);
  540. set = SDL_TRUE;
  541. }
  542. /* Now try to unset KWM hints */
  543. WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True);
  544. if ( WM_HINTS != None ) {
  545. XDeleteProperty(SDL_Display, WMwindow, WM_HINTS);
  546. set = SDL_TRUE;
  547. }
  548. /* Now try to unset GNOME hints */
  549. WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True);
  550. if ( WM_HINTS != None ) {
  551. XDeleteProperty(SDL_Display, WMwindow, WM_HINTS);
  552. set = SDL_TRUE;
  553. }
  554. /* Finally unset the transient hints if necessary */
  555. if ( ! set ) {
  556. /* NOTE: Does this work? */
  557. XSetTransientForHint(SDL_Display, WMwindow, None);
  558. }
  559. }
  560. }
  561. static int X11_CreateWindow(_THIS, SDL_Surface *screen,
  562.     int w, int h, int bpp, Uint32 flags)
  563. {
  564. int i, depth;
  565. Visual *vis;
  566. int vis_change;
  567. /* If a window is already present, destroy it and start fresh */
  568. if ( SDL_Window ) {
  569. X11_DestroyWindow(this, screen);
  570. }
  571. /* See if we have been given a window id */
  572. if ( SDL_windowid ) {
  573. SDL_Window = strtol(SDL_windowid, NULL, 0);
  574. } else {
  575. SDL_Window = 0;
  576. }
  577. /* find out which visual we are going to use */
  578. if ( flags & SDL_OPENGL ) {
  579. XVisualInfo *vi;
  580. vi = X11_GL_GetVisual(this);
  581. if( !vi ) {
  582. return -1;
  583. }
  584. vis = vi->visual;
  585. depth = vi->depth;
  586. } else if ( SDL_windowid ) {
  587. XWindowAttributes a;
  588. XGetWindowAttributes(SDL_Display, SDL_Window, &a);
  589. vis = a.visual;
  590. depth = a.depth;
  591. } else {
  592. for ( i = 0; i < this->hidden->nvisuals; i++ ) {
  593. if ( this->hidden->visuals[i].bpp == bpp )
  594. break;
  595. }
  596. if ( i == this->hidden->nvisuals ) {
  597. SDL_SetError("No matching visual for requested depth");
  598. return -1; /* should never happen */
  599. }
  600. vis = this->hidden->visuals[i].visual;
  601. depth = this->hidden->visuals[i].depth;
  602. }
  603. #ifdef X11_DEBUG
  604.         printf("Choosing %s visual at %d bpp - %d colormap entriesn", vis->class == PseudoColor ? "PseudoColor" : (vis->class == TrueColor ? "TrueColor" : (vis->class == DirectColor ? "DirectColor" : "Unknown")), depth, vis->map_entries);
  605. #endif
  606. vis_change = (vis != SDL_Visual);
  607. SDL_Visual = vis;
  608. this->hidden->depth = depth;
  609. /* Allocate the new pixel format for this video mode */
  610. if ( ! SDL_ReallocFormat(screen, bpp,
  611. vis->red_mask, vis->green_mask, vis->blue_mask, 0) )
  612. return -1;
  613. /* Create the appropriate colormap */
  614. if ( SDL_XColorMap != SDL_DisplayColormap ) {
  615. XFreeColormap(SDL_Display, SDL_XColorMap);
  616. }
  617. if ( SDL_Visual->class == PseudoColor ) {
  618.     int ncolors;
  619.     /* Allocate the pixel flags */
  620.     ncolors = SDL_Visual->map_entries;
  621.     SDL_XPixels = malloc(ncolors * sizeof(int));
  622.     if(SDL_XPixels == NULL) {
  623. SDL_OutOfMemory();
  624. return -1;
  625.     }
  626.     memset(SDL_XPixels, 0, ncolors * sizeof(*SDL_XPixels));
  627.     /* always allocate a private colormap on non-default visuals */
  628.     if ( SDL_Visual != DefaultVisual(SDL_Display, SDL_Screen) ) {
  629. flags |= SDL_HWPALETTE;
  630.     }
  631.     if ( flags & SDL_HWPALETTE ) {
  632. screen->flags |= SDL_HWPALETTE;
  633. SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
  634.                                 SDL_Visual, AllocAll);
  635.     } else {
  636. SDL_XColorMap = SDL_DisplayColormap;
  637.     }
  638. } else if ( SDL_Visual->class == DirectColor ) {
  639.     /* Create a colormap which we can manipulate for gamma */
  640.     SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
  641.                             SDL_Visual, AllocAll);
  642.             XSync(SDL_Display, False);
  643.     /* Initialize the colormap to the identity mapping */
  644.     SDL_GetGammaRamp(0, 0, 0);
  645.     this->screen = screen;
  646.     X11_SetGammaRamp(this, this->gamma);
  647.     this->screen = NULL;
  648. } else {
  649.     /* Create a read-only colormap for our window */
  650.     SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
  651.                                     SDL_Visual, AllocNone);
  652. }
  653. /* Recreate the auxiliary windows, if needed (required for GL) */
  654. if ( vis_change )
  655.     create_aux_windows(this);
  656. if(screen->flags & SDL_HWPALETTE) {
  657.     /* Since the full-screen window might have got a nonzero background
  658.        colour (0 is white on some displays), we should reset the
  659.        background to 0 here since that is what the user expects
  660.        with a private colormap */
  661.     XSetWindowBackground(SDL_Display, FSwindow, 0);
  662.     XClearWindow(SDL_Display, FSwindow);
  663. }
  664. /* resize the (possibly new) window manager window */
  665. if( !SDL_windowid ) {
  666.         X11_SetSizeHints(this, w, h, flags);
  667. current_w = w;
  668. current_h = h;
  669. XResizeWindow(SDL_Display, WMwindow, w, h);
  670. }
  671. /* Create (or use) the X11 display window */
  672. if ( !SDL_windowid ) {
  673. if ( flags & SDL_OPENGL ) {
  674. if ( X11_GL_CreateWindow(this, w, h) < 0 ) {
  675. return(-1);
  676. }
  677. } else {
  678. XSetWindowAttributes swa;
  679. swa.background_pixel = 0;
  680. swa.border_pixel = 0;
  681. swa.colormap = SDL_XColorMap;
  682. SDL_Window = XCreateWindow(SDL_Display, WMwindow,
  683.                             0, 0, w, h, 0, depth,
  684.                             InputOutput, SDL_Visual,
  685.                             CWBackPixel | CWBorderPixel
  686.                             | CWColormap, &swa);
  687. }
  688. /* Only manage our input if we own the window */
  689. XSelectInput(SDL_Display, SDL_Window,
  690. ( EnterWindowMask | LeaveWindowMask
  691. | ButtonPressMask | ButtonReleaseMask
  692. | PointerMotionMask | ExposureMask ));
  693. }
  694. /* Create the graphics context here, once we have a window */
  695. if ( flags & SDL_OPENGL ) {
  696. if ( X11_GL_CreateContext(this) < 0 ) {
  697. return(-1);
  698. } else {
  699. screen->flags |= SDL_OPENGL;
  700. }
  701. } else {
  702. XGCValues gcv;
  703. gcv.graphics_exposures = False;
  704. SDL_GC = XCreateGC(SDL_Display, SDL_Window,
  705.                    GCGraphicsExposures, &gcv);
  706. if ( ! SDL_GC ) {
  707. SDL_SetError("Couldn't create graphics context");
  708. return(-1);
  709. }
  710. }
  711. /* Set our colormaps when not setting a GL mode */
  712. if ( ! (flags & SDL_OPENGL) ) {
  713. XSetWindowColormap(SDL_Display, SDL_Window, SDL_XColorMap);
  714. if( !SDL_windowid ) {
  715.     XSetWindowColormap(SDL_Display, FSwindow, SDL_XColorMap);
  716.     XSetWindowColormap(SDL_Display, WMwindow, SDL_XColorMap);
  717. }
  718. }
  719. #if 0 /* This is an experiment - are the graphics faster now? - nope. */
  720. if ( getenv("SDL_VIDEO_X11_BACKINGSTORE") )
  721. #endif
  722. /* Cache the window in the server, when possible */
  723. {
  724. Screen *xscreen;
  725. XSetWindowAttributes a;
  726. xscreen = ScreenOfDisplay(SDL_Display, SDL_Screen);
  727. a.backing_store = DoesBackingStore(xscreen);
  728. if ( a.backing_store != NotUseful ) {
  729. XChangeWindowAttributes(SDL_Display, SDL_Window,
  730.                         CWBackingStore, &a);
  731. }
  732. }
  733. /* Update the internal keyboard state */
  734. X11_SetKeyboardState(SDL_Display, NULL);
  735. /* Map them both and go fullscreen, if requested */
  736. if ( ! SDL_windowid ) {
  737. XMapWindow(SDL_Display, SDL_Window);
  738. XMapWindow(SDL_Display, WMwindow);
  739. X11_WaitMapped(this, WMwindow);
  740. if ( flags & SDL_FULLSCREEN ) {
  741. screen->flags |= SDL_FULLSCREEN;
  742. X11_EnterFullScreen(this);
  743. } else {
  744. screen->flags &= ~SDL_FULLSCREEN;
  745. }
  746. }
  747. return(0);
  748. }
  749. static int X11_ResizeWindow(_THIS,
  750. SDL_Surface *screen, int w, int h, Uint32 flags)
  751. {
  752. if ( ! SDL_windowid ) {
  753. /* Resize the window manager window */
  754. X11_SetSizeHints(this, w, h, flags);
  755. current_w = w;
  756. current_h = h;
  757. XResizeWindow(SDL_Display, WMwindow, w, h);
  758. /* Resize the fullscreen and display windows */
  759. if ( flags & SDL_FULLSCREEN ) {
  760. if ( screen->flags & SDL_FULLSCREEN ) {
  761. X11_ResizeFullScreen(this);
  762. } else {
  763. screen->flags |= SDL_FULLSCREEN;
  764. X11_EnterFullScreen(this);
  765. }
  766. } else {
  767. if ( screen->flags & SDL_FULLSCREEN ) {
  768. screen->flags &= ~SDL_FULLSCREEN;
  769. X11_LeaveFullScreen(this);
  770. }
  771. }
  772. XResizeWindow(SDL_Display, SDL_Window, w, h);
  773. }
  774. return(0);
  775. }
  776. SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current,
  777. int width, int height, int bpp, Uint32 flags)
  778. {
  779. Uint32 saved_flags;
  780. /* Lock the event thread, in multi-threading environments */
  781. SDL_Lock_EventThread();
  782. /* Check the combination of flags we were passed */
  783. if ( flags & SDL_FULLSCREEN ) {
  784. /* Clear fullscreen flag if not supported */
  785. if ( SDL_windowid ) {
  786. flags &= ~SDL_FULLSCREEN;
  787. }
  788. }
  789. /* Flush any delayed updates */
  790. XSync(GFX_Display, False);
  791. /* Set up the X11 window */
  792. saved_flags = current->flags;
  793. if (SDL_Window && (saved_flags&SDL_OPENGL) == (flags&SDL_OPENGL)
  794.     && bpp == current->format->BitsPerPixel) {
  795. if (X11_ResizeWindow(this, current, width, height, flags) < 0) {
  796. current = NULL;
  797. goto done;
  798. }
  799. } else {
  800. if (X11_CreateWindow(this,current,width,height,bpp,flags) < 0) {
  801. current = NULL;
  802. goto done;
  803. }
  804. }
  805. /* Set up the new mode framebuffer */
  806. if ( ((current->w != width) || (current->h != height)) ||
  807.              ((saved_flags&SDL_OPENGL) != (flags&SDL_OPENGL)) ) {
  808. current->w = width;
  809. current->h = height;
  810. current->pitch = SDL_CalculatePitch(current);
  811. X11_ResizeImage(this, current, flags);
  812. }
  813. current->flags |= (flags&(SDL_RESIZABLE|SDL_NOFRAME));
  814.   done:
  815. /* Release the event thread */
  816. XSync(SDL_Display, False);
  817. SDL_Unlock_EventThread();
  818. /* We're done! */
  819. return(current);
  820. }
  821. static int X11_ToggleFullScreen(_THIS, int on)
  822. {
  823. Uint32 event_thread;
  824. /* Don't switch if we don't own the window */
  825. if ( SDL_windowid ) {
  826. return(0);
  827. }
  828. /* Don't lock if we are the event thread */
  829. event_thread = SDL_EventThreadID();
  830. if ( event_thread && (SDL_ThreadID() == event_thread) ) {
  831. event_thread = 0;
  832. }
  833. if ( event_thread ) {
  834. SDL_Lock_EventThread();
  835. }
  836. if ( on ) {
  837. this->screen->flags |= SDL_FULLSCREEN;
  838. X11_EnterFullScreen(this);
  839. } else {
  840. this->screen->flags &= ~SDL_FULLSCREEN;
  841. X11_LeaveFullScreen(this);
  842. }
  843. X11_RefreshDisplay(this);
  844. if ( event_thread ) {
  845. SDL_Unlock_EventThread();
  846. }
  847. SDL_ResetKeyboard();
  848. return(1);
  849. }
  850. /* Update the current mouse state and position */
  851. static void X11_UpdateMouse(_THIS)
  852. {
  853. Window u1; int u2;
  854. Window current_win;
  855. int x, y;
  856. unsigned int mask;
  857. /* Lock the event thread, in multi-threading environments */
  858. SDL_Lock_EventThread();
  859. if ( XQueryPointer(SDL_Display, SDL_Window, &u1, &current_win,
  860.                    &u2, &u2, &x, &y, &mask) ) {
  861. if ( (x >= 0) && (x < SDL_VideoSurface->w) &&
  862.      (y >= 0) && (y < SDL_VideoSurface->h) ) {
  863. SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
  864. SDL_PrivateMouseMotion(0, 0, x, y);
  865. } else {
  866. SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
  867. }
  868. }
  869. SDL_Unlock_EventThread();
  870. }
  871. /* simple colour distance metric. Supposed to be better than a plain
  872.    Euclidian distance anyway. */
  873. #define COLOUR_FACTOR 3
  874. #define LIGHT_FACTOR 1
  875. #define COLOUR_DIST(r1, g1, b1, r2, g2, b2)
  876. (COLOUR_FACTOR * (abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2))
  877.  + LIGHT_FACTOR * abs(r1 + g1 + b1 - (r2 + g2 + b2)))
  878. static void allocate_nearest(_THIS, SDL_Color *colors,
  879.      SDL_Color *want, int nwant)
  880. {
  881. /*
  882.  * There is no way to know which ones to choose from, so we retrieve
  883.  * the entire colormap and try the nearest possible, until we find one
  884.  * that is shared.
  885.  */
  886. XColor all[256];
  887. int i;
  888. for(i = 0; i < 256; i++)
  889. all[i].pixel = i;
  890. /* 
  891.  * XQueryColors sets the flags in the XColor struct, so we use
  892.  * that to keep track of which colours are available
  893.  */
  894. XQueryColors(GFX_Display, SDL_XColorMap, all, 256);
  895. for(i = 0; i < nwant; i++) {
  896. XColor *c;
  897. int j;
  898. int best = 0;
  899. int mindist = 0x7fffffff;
  900. int ri = want[i].r;
  901. int gi = want[i].g;
  902. int bi = want[i].b;
  903. for(j = 0; j < 256; j++) {
  904. int rj, gj, bj, d2;
  905. if(!all[j].flags)
  906. continue; /* unavailable colour cell */
  907. rj = all[j].red >> 8;
  908. gj = all[j].green >> 8;
  909. bj = all[j].blue >> 8;
  910. d2 = COLOUR_DIST(ri, gi, bi, rj, gj, bj);
  911. if(d2 < mindist) {
  912. mindist = d2;
  913. best = j;
  914. }
  915. }
  916. if(SDL_XPixels[best])
  917. continue; /* already allocated, waste no more time */
  918. c = all + best;
  919. if(XAllocColor(GFX_Display, SDL_XColorMap, c)) {
  920. /* got it */
  921. colors[c->pixel].r = c->red >> 8;
  922. colors[c->pixel].g = c->green >> 8;
  923. colors[c->pixel].b = c->blue >> 8;
  924. ++SDL_XPixels[c->pixel];
  925. } else {
  926. /* 
  927.  * The colour couldn't be allocated, probably being
  928.  * owned as a r/w cell by another client. Flag it as
  929.  * unavailable and try again. The termination of the
  930.  * loop is guaranteed since at least black and white
  931.  * are always there.
  932.  */
  933. c->flags = 0;
  934. i--;
  935. }
  936. }
  937. }
  938. int X11_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
  939. {
  940. int nrej = 0;
  941. /* Check to make sure we have a colormap allocated */
  942. if ( SDL_XPixels == NULL ) {
  943. return(0);
  944. }
  945. if ( (this->screen->flags & SDL_HWPALETTE) == SDL_HWPALETTE ) {
  946.         /* private writable colormap: just set the colours we need */
  947.         XColor  *xcmap;
  948. int i;
  949.         xcmap = ALLOCA(ncolors*sizeof(*xcmap));
  950. if(xcmap == NULL)
  951.         return 0;
  952. for ( i=0; i<ncolors; ++i ) {
  953. xcmap[i].pixel = i + firstcolor;
  954. xcmap[i].red   = (colors[i].r<<8)|colors[i].r;
  955. xcmap[i].green = (colors[i].g<<8)|colors[i].g;
  956. xcmap[i].blue  = (colors[i].b<<8)|colors[i].b;
  957. xcmap[i].flags = (DoRed|DoGreen|DoBlue);
  958. }
  959. XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
  960. XSync(GFX_Display, False);
  961. FREEA(xcmap);
  962. } else {
  963.         /*
  964.  * Shared colormap: We only allocate read-only cells, which
  965.  * increases the likelyhood of colour sharing with other
  966.  * clients. The pixel values will almost certainly be
  967.  * different from the requested ones, so the user has to
  968.  * walk the colormap and see which index got what colour.
  969.  *
  970.  * We can work directly with the logical palette since it
  971.  * has already been set when we get here.
  972.  */
  973. SDL_Color *want, *reject;
  974.         unsigned long *freelist;
  975. int i;
  976. int nfree = 0;
  977. int nc = this->screen->format->palette->ncolors;
  978.         colors = this->screen->format->palette->colors;
  979. freelist = ALLOCA(nc * sizeof(*freelist));
  980. /* make sure multiple allocations of the same cell are freed */
  981.         for(i = 0; i < ncolors; i++) {
  982.         int pixel = firstcolor + i;
  983.         while(SDL_XPixels[pixel]) {
  984.         freelist[nfree++] = pixel;
  985. --SDL_XPixels[pixel];
  986. }
  987. }
  988. XFreeColors(GFX_Display, SDL_XColorMap, freelist, nfree, 0);
  989. FREEA(freelist);
  990. want = ALLOCA(ncolors * sizeof(SDL_Color));
  991. reject = ALLOCA(ncolors * sizeof(SDL_Color));
  992. memcpy(want, colors + firstcolor, ncolors * sizeof(SDL_Color));
  993. /* make sure the user isn't fooled by her own wishes
  994.    (black is safe, always available in the default colormap) */
  995. memset(colors + firstcolor, 0, ncolors * sizeof(SDL_Color));
  996. /* now try to allocate the colours */
  997. for(i = 0; i < ncolors; i++) {
  998.         XColor col;
  999. col.red = want[i].r << 8;
  1000. col.green = want[i].g << 8;
  1001. col.blue = want[i].b << 8;
  1002. col.flags = DoRed | DoGreen | DoBlue;
  1003. if(XAllocColor(GFX_Display, SDL_XColorMap, &col)) {
  1004.         /* We got the colour, or at least the nearest
  1005.    the hardware could get. */
  1006.         colors[col.pixel].r = col.red >> 8;
  1007. colors[col.pixel].g = col.green >> 8;
  1008. colors[col.pixel].b = col.blue >> 8;
  1009. ++SDL_XPixels[col.pixel];
  1010. } else {
  1011. /*
  1012.  * no more free cells, add it to the list
  1013.  * of rejected colours
  1014.  */
  1015. reject[nrej++] = want[i];
  1016. }
  1017. }
  1018. if(nrej)
  1019. allocate_nearest(this, colors, reject, nrej);
  1020. FREEA(reject);
  1021. FREEA(want);
  1022. }
  1023. return nrej == 0;
  1024. }
  1025. int X11_SetGammaRamp(_THIS, Uint16 *ramp)
  1026. {
  1027. int i, ncolors;
  1028. XColor xcmap[256];
  1029. /* See if actually setting the gamma is supported */
  1030. if ( SDL_Visual->class != DirectColor ) {
  1031.     SDL_SetError("Gamma correction not supported on this visual");
  1032.     return(-1);
  1033. }
  1034. /* Calculate the appropriate palette for the given gamma ramp */
  1035. ncolors = SDL_Visual->map_entries;
  1036. for ( i=0; i<ncolors; ++i ) {
  1037. Uint8 c = (256 * i / ncolors);
  1038. xcmap[i].pixel = SDL_MapRGB(this->screen->format, c, c, c);
  1039. xcmap[i].red   = ramp[0*256+c];
  1040. xcmap[i].green = ramp[1*256+c];
  1041. xcmap[i].blue  = ramp[2*256+c];
  1042. xcmap[i].flags = (DoRed|DoGreen|DoBlue);
  1043. }
  1044. XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
  1045. XSync(GFX_Display, False);
  1046. return(0);
  1047. }
  1048. /* Note:  If we are terminated, this could be called in the middle of
  1049.    another SDL video routine -- notably UpdateRects.
  1050. */
  1051. void X11_VideoQuit(_THIS)
  1052. {
  1053. /* Shutdown everything that's still up */
  1054. /* The event thread should be done, so we can touch SDL_Display */
  1055. if ( SDL_Display != NULL ) {
  1056. /* Flush any delayed updates */
  1057. XSync(GFX_Display, False);
  1058. /* Start shutting down the windows */
  1059. X11_DestroyImage(this, this->screen);
  1060. X11_DestroyWindow(this, this->screen);
  1061. X11_FreeVideoModes(this);
  1062. if ( SDL_XColorMap != SDL_DisplayColormap ) {
  1063. XFreeColormap(SDL_Display, SDL_XColorMap);
  1064. }
  1065. if ( SDL_iconcolors ) {
  1066. unsigned long pixel;
  1067. Colormap dcmap = DefaultColormap(SDL_Display,
  1068.  SDL_Screen);
  1069. for(pixel = 0; pixel < 256; ++pixel) {
  1070. while(SDL_iconcolors[pixel] > 0) {
  1071. XFreeColors(GFX_Display,
  1072.     dcmap, &pixel, 1, 0);
  1073. --SDL_iconcolors[pixel];
  1074. }
  1075. }
  1076. free(SDL_iconcolors);
  1077. SDL_iconcolors = NULL;
  1078. /* Restore gamma settings if they've changed */
  1079. if ( SDL_GetAppState() & SDL_APPACTIVE ) {
  1080. X11_SwapVidModeGamma(this);
  1081. }
  1082. /* Free that blank cursor */
  1083. if ( SDL_BlankCursor != NULL ) {
  1084. this->FreeWMCursor(this, SDL_BlankCursor);
  1085. SDL_BlankCursor = NULL;
  1086. }
  1087. /* Close the X11 graphics connection */
  1088. if ( GFX_Display != NULL ) {
  1089. XCloseDisplay(GFX_Display);
  1090. GFX_Display = NULL;
  1091. }
  1092. /* Close the X11 display connection */
  1093. XCloseDisplay(SDL_Display);
  1094. SDL_Display = NULL;
  1095. /* Reset the X11 error handlers */
  1096. if ( XIO_handler ) {
  1097. XSetIOErrorHandler(XIO_handler);
  1098. }
  1099. if ( X_handler ) {
  1100. XSetErrorHandler(X_handler);
  1101. }
  1102. /* Unload GL library after X11 shuts down */
  1103. X11_GL_UnloadLibrary(this);
  1104. }
  1105. if ( this->screen && (this->screen->flags & SDL_HWSURFACE) ) {
  1106. /* Direct screen access, no memory buffer */
  1107. this->screen->pixels = NULL;
  1108. }
  1109. }