src/video/x11/SDL_x11video.c
author Sam Lantinga
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8287 fee216d949e3
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     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 <unistd.h> /* For getpid() and readlink() */
    26 
    27 #include "SDL_video.h"
    28 #include "SDL_mouse.h"
    29 #include "../SDL_sysvideo.h"
    30 #include "../SDL_pixels_c.h"
    31 
    32 #include "SDL_x11video.h"
    33 #include "SDL_x11framebuffer.h"
    34 #include "SDL_x11shape.h"
    35 #include "SDL_x11touch.h"
    36 #include "SDL_x11xinput2.h"
    37 
    38 #if SDL_VIDEO_OPENGL_EGL
    39 #include "SDL_x11opengles.h"
    40 #endif
    41 
    42 /* !!! FIXME: move dbus stuff to somewhere under src/core/linux ... */
    43 #if SDL_USE_LIBDBUS
    44 /* we never link directly to libdbus. */
    45 #include "SDL_loadso.h"
    46 static const char *dbus_library = "libdbus-1.so.3";
    47 static void *dbus_handle = NULL;
    48 
    49 /* !!! FIXME: this is kinda ugly. */
    50 static SDL_bool
    51 load_dbus_sym(const char *fn, void **addr)
    52 {
    53     *addr = SDL_LoadFunction(dbus_handle, fn);
    54     if (*addr == NULL) {
    55         /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
    56         return SDL_FALSE;
    57     }
    58 
    59     return SDL_TRUE;
    60 }
    61 
    62 /* libdbus entry points... */
    63 static DBusConnection *(*DBUS_dbus_bus_get_private)(DBusBusType, DBusError *) = NULL;
    64 static void (*DBUS_dbus_connection_set_exit_on_disconnect)(DBusConnection *, dbus_bool_t) = NULL;
    65 static dbus_bool_t (*DBUS_dbus_connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *) = NULL;
    66 static void (*DBUS_dbus_connection_close)(DBusConnection *) = NULL;
    67 static void (*DBUS_dbus_connection_unref)(DBusConnection *) = NULL;
    68 static void (*DBUS_dbus_connection_flush)(DBusConnection *) = NULL;
    69 static DBusMessage *(*DBUS_dbus_message_new_method_call)(const char *, const char *, const char *, const char *) = NULL;
    70 static void (*DBUS_dbus_message_unref)(DBusMessage *) = NULL;
    71 static void (*DBUS_dbus_error_init)(DBusError *) = NULL;
    72 static dbus_bool_t (*DBUS_dbus_error_is_set)(const DBusError *) = NULL;
    73 static void (*DBUS_dbus_error_free)(DBusError *) = NULL;
    74 
    75 static int
    76 load_dbus_syms(void)
    77 {
    78     /* cast funcs to char* first, to please GCC's strict aliasing rules. */
    79     #define SDL_DBUS_SYM(x) \
    80         if (!load_dbus_sym(#x, (void **) (char *) &DBUS_##x)) return -1
    81 
    82     SDL_DBUS_SYM(dbus_bus_get_private);
    83     SDL_DBUS_SYM(dbus_connection_set_exit_on_disconnect);
    84     SDL_DBUS_SYM(dbus_connection_send);
    85     SDL_DBUS_SYM(dbus_connection_close);
    86     SDL_DBUS_SYM(dbus_connection_unref);
    87     SDL_DBUS_SYM(dbus_connection_flush);
    88     SDL_DBUS_SYM(dbus_message_new_method_call);
    89     SDL_DBUS_SYM(dbus_message_unref);
    90     SDL_DBUS_SYM(dbus_error_init);
    91     SDL_DBUS_SYM(dbus_error_is_set);
    92     SDL_DBUS_SYM(dbus_error_free);
    93 
    94     #undef SDL_DBUS_SYM
    95 
    96     return 0;
    97 }
    98 
    99 static void
   100 UnloadDBUSLibrary(void)
   101 {
   102     if (dbus_handle != NULL) {
   103         SDL_UnloadObject(dbus_handle);
   104         dbus_handle = NULL;
   105     }
   106 }
   107 
   108 static int
   109 LoadDBUSLibrary(void)
   110 {
   111     int retval = 0;
   112     if (dbus_handle == NULL) {
   113         dbus_handle = SDL_LoadObject(dbus_library);
   114         if (dbus_handle == NULL) {
   115             retval = -1;
   116             /* Don't call SDL_SetError(): SDL_LoadObject already did. */
   117         } else {
   118             retval = load_dbus_syms();
   119             if (retval < 0) {
   120                 UnloadDBUSLibrary();
   121             }
   122         }
   123     }
   124 
   125     return retval;
   126 }
   127 
   128 static void
   129 X11_InitDBus(_THIS)
   130 {
   131     if (LoadDBUSLibrary() != -1) {
   132         SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   133         DBusError err;
   134         DBUS_dbus_error_init(&err);
   135         data->dbus = DBUS_dbus_bus_get_private(DBUS_BUS_SESSION, &err);
   136         if (DBUS_dbus_error_is_set(&err)) {
   137             DBUS_dbus_error_free(&err);
   138             if (data->dbus) {
   139                 DBUS_dbus_connection_unref(data->dbus);
   140                 data->dbus = NULL;
   141             }
   142             return;  /* oh well */
   143         }
   144         DBUS_dbus_connection_set_exit_on_disconnect(data->dbus, 0);
   145     }
   146 }
   147 
   148 static void
   149 X11_QuitDBus(_THIS)
   150 {
   151     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   152     if (data->dbus) {
   153         DBUS_dbus_connection_close(data->dbus);
   154         DBUS_dbus_connection_unref(data->dbus);
   155         data->dbus = NULL;
   156     }
   157 }
   158 
   159 void
   160 SDL_dbus_screensaver_tickle(_THIS)
   161 {
   162     const SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   163     DBusConnection *conn = data->dbus;
   164     if (conn != NULL) {
   165         DBusMessage *msg = DBUS_dbus_message_new_method_call("org.gnome.ScreenSaver",
   166                                                              "/org/gnome/ScreenSaver",
   167                                                              "org.gnome.ScreenSaver",
   168                                                              "SimulateUserActivity");
   169         if (msg != NULL) {
   170             if (DBUS_dbus_connection_send(conn, msg, NULL)) {
   171                 DBUS_dbus_connection_flush(conn);
   172             }
   173             DBUS_dbus_message_unref(msg);
   174         }
   175     }
   176 }
   177 #endif
   178 
   179 /* Initialization/Query functions */
   180 static int X11_VideoInit(_THIS);
   181 static void X11_VideoQuit(_THIS);
   182 
   183 /* Find out what class name we should use */
   184 static char *
   185 get_classname()
   186 {
   187     char *spot;
   188 #if defined(__LINUX__) || defined(__FREEBSD__)
   189     char procfile[1024];
   190     char linkfile[1024];
   191     int linksize;
   192 #endif
   193 
   194     /* First allow environment variable override */
   195     spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
   196     if (spot) {
   197         return SDL_strdup(spot);
   198     }
   199 
   200     /* Next look at the application's executable name */
   201 #if defined(__LINUX__) || defined(__FREEBSD__)
   202 #if defined(__LINUX__)
   203     SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
   204 #elif defined(__FREEBSD__)
   205     SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
   206                  getpid());
   207 #else
   208 #error Where can we find the executable name?
   209 #endif
   210     linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
   211     if (linksize > 0) {
   212         linkfile[linksize] = '\0';
   213         spot = SDL_strrchr(linkfile, '/');
   214         if (spot) {
   215             return SDL_strdup(spot + 1);
   216         } else {
   217             return SDL_strdup(linkfile);
   218         }
   219     }
   220 #endif /* __LINUX__ || __FREEBSD__ */
   221 
   222     /* Finally use the default we've used forever */
   223     return SDL_strdup("SDL_App");
   224 }
   225 
   226 /* X11 driver bootstrap functions */
   227 
   228 static int
   229 X11_Available(void)
   230 {
   231     Display *display = NULL;
   232     if (SDL_X11_LoadSymbols()) {
   233         display = X11_XOpenDisplay(NULL);
   234         if (display != NULL) {
   235             X11_XCloseDisplay(display);
   236         }
   237         SDL_X11_UnloadSymbols();
   238     }
   239     return (display != NULL);
   240 }
   241 
   242 static void
   243 X11_DeleteDevice(SDL_VideoDevice * device)
   244 {
   245     SDL_VideoData *data = (SDL_VideoData *) device->driverdata;
   246     if (data->display) {
   247         X11_XCloseDisplay(data->display);
   248     }
   249     SDL_free(data->windowlist);
   250     SDL_free(device->driverdata);
   251     SDL_free(device);
   252 
   253     SDL_X11_UnloadSymbols();
   254 }
   255 
   256 /* An error handler to reset the vidmode and then call the default handler. */
   257 static SDL_bool safety_net_triggered = SDL_FALSE;
   258 static int (*orig_x11_errhandler) (Display *, XErrorEvent *) = NULL;
   259 static int
   260 X11_SafetyNetErrHandler(Display * d, XErrorEvent * e)
   261 {
   262     SDL_VideoDevice *device = NULL;
   263     /* if we trigger an error in our error handler, don't try again. */
   264     if (!safety_net_triggered) {
   265         safety_net_triggered = SDL_TRUE;
   266         device = SDL_GetVideoDevice();
   267         if (device != NULL) {
   268             int i;
   269             for (i = 0; i < device->num_displays; i++) {
   270                 SDL_VideoDisplay *display = &device->displays[i];
   271                 if (SDL_memcmp(&display->current_mode, &display->desktop_mode,
   272                                sizeof (SDL_DisplayMode)) != 0) {
   273                     X11_SetDisplayMode(device, display, &display->desktop_mode);
   274                 }
   275             }
   276         }
   277     }
   278 
   279     if (orig_x11_errhandler != NULL) {
   280         return orig_x11_errhandler(d, e);  /* probably terminate. */
   281     }
   282 
   283     return 0;
   284 }
   285 
   286 static SDL_VideoDevice *
   287 X11_CreateDevice(int devindex)
   288 {
   289     SDL_VideoDevice *device;
   290     SDL_VideoData *data;
   291     const char *display = NULL; /* Use the DISPLAY environment variable */
   292 
   293     if (!SDL_X11_LoadSymbols()) {
   294         return NULL;
   295     }
   296 
   297     /* Need for threading gl calls. This is also required for the proprietary
   298         nVidia driver to be threaded. */
   299     X11_XInitThreads();
   300 
   301     /* Initialize all variables that we clean on shutdown */
   302     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
   303     if (!device) {
   304         SDL_OutOfMemory();
   305         return NULL;
   306     }
   307     data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
   308     if (!data) {
   309         SDL_free(device);
   310         SDL_OutOfMemory();
   311         return NULL;
   312     }
   313     device->driverdata = data;
   314 
   315     /* FIXME: Do we need this?
   316        if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) ||
   317        (SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) {
   318        local_X11 = 1;
   319        } else {
   320        local_X11 = 0;
   321        }
   322      */
   323     data->display = X11_XOpenDisplay(display);
   324 #if defined(__osf__) && defined(SDL_VIDEO_DRIVER_X11_DYNAMIC)
   325     /* On Tru64 if linking without -lX11, it fails and you get following message.
   326      * Xlib: connection to ":0.0" refused by server
   327      * Xlib: XDM authorization key matches an existing client!
   328      *
   329      * It succeeds if retrying 1 second later
   330      * or if running xhost +localhost on shell.
   331      */
   332     if (data->display == NULL) {
   333         SDL_Delay(1000);
   334         data->display = X11_XOpenDisplay(display);
   335     }
   336 #endif
   337     if (data->display == NULL) {
   338         SDL_free(device->driverdata);
   339         SDL_free(device);
   340         SDL_SetError("Couldn't open X11 display");
   341         return NULL;
   342     }
   343 #ifdef X11_DEBUG
   344     X11_XSynchronize(data->display, True);
   345 #endif
   346 
   347     /* Hook up an X11 error handler to recover the desktop resolution. */
   348     safety_net_triggered = SDL_FALSE;
   349     orig_x11_errhandler = X11_XSetErrorHandler(X11_SafetyNetErrHandler);
   350 
   351     /* Set the function pointers */
   352     device->VideoInit = X11_VideoInit;
   353     device->VideoQuit = X11_VideoQuit;
   354     device->GetDisplayModes = X11_GetDisplayModes;
   355     device->GetDisplayBounds = X11_GetDisplayBounds;
   356     device->SetDisplayMode = X11_SetDisplayMode;
   357     device->SuspendScreenSaver = X11_SuspendScreenSaver;
   358     device->PumpEvents = X11_PumpEvents;
   359 
   360     device->CreateWindow = X11_CreateWindow;
   361     device->CreateWindowFrom = X11_CreateWindowFrom;
   362     device->SetWindowTitle = X11_SetWindowTitle;
   363     device->SetWindowIcon = X11_SetWindowIcon;
   364     device->SetWindowPosition = X11_SetWindowPosition;
   365     device->SetWindowSize = X11_SetWindowSize;
   366     device->SetWindowMinimumSize = X11_SetWindowMinimumSize;
   367     device->SetWindowMaximumSize = X11_SetWindowMaximumSize;
   368     device->ShowWindow = X11_ShowWindow;
   369     device->HideWindow = X11_HideWindow;
   370     device->RaiseWindow = X11_RaiseWindow;
   371     device->MaximizeWindow = X11_MaximizeWindow;
   372     device->MinimizeWindow = X11_MinimizeWindow;
   373     device->RestoreWindow = X11_RestoreWindow;
   374     device->SetWindowBordered = X11_SetWindowBordered;
   375     device->SetWindowFullscreen = X11_SetWindowFullscreen;
   376     device->SetWindowGammaRamp = X11_SetWindowGammaRamp;
   377     device->SetWindowGrab = X11_SetWindowGrab;
   378     device->DestroyWindow = X11_DestroyWindow;
   379     device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer;
   380     device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer;
   381     device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer;
   382     device->GetWindowWMInfo = X11_GetWindowWMInfo;
   383 
   384     device->shape_driver.CreateShaper = X11_CreateShaper;
   385     device->shape_driver.SetWindowShape = X11_SetWindowShape;
   386     device->shape_driver.ResizeWindowShape = X11_ResizeWindowShape;
   387 
   388 #if SDL_VIDEO_OPENGL_GLX
   389     device->GL_LoadLibrary = X11_GL_LoadLibrary;
   390     device->GL_GetProcAddress = X11_GL_GetProcAddress;
   391     device->GL_UnloadLibrary = X11_GL_UnloadLibrary;
   392     device->GL_CreateContext = X11_GL_CreateContext;
   393     device->GL_MakeCurrent = X11_GL_MakeCurrent;
   394     device->GL_SetSwapInterval = X11_GL_SetSwapInterval;
   395     device->GL_GetSwapInterval = X11_GL_GetSwapInterval;
   396     device->GL_SwapWindow = X11_GL_SwapWindow;
   397     device->GL_DeleteContext = X11_GL_DeleteContext;
   398 #elif SDL_VIDEO_OPENGL_EGL
   399     device->GL_LoadLibrary = X11_GLES_LoadLibrary;
   400     device->GL_GetProcAddress = X11_GLES_GetProcAddress;
   401     device->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
   402     device->GL_CreateContext = X11_GLES_CreateContext;
   403     device->GL_MakeCurrent = X11_GLES_MakeCurrent;
   404     device->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
   405     device->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
   406     device->GL_SwapWindow = X11_GLES_SwapWindow;
   407     device->GL_DeleteContext = X11_GLES_DeleteContext;
   408 #endif
   409 
   410     device->SetClipboardText = X11_SetClipboardText;
   411     device->GetClipboardText = X11_GetClipboardText;
   412     device->HasClipboardText = X11_HasClipboardText;
   413 
   414     device->free = X11_DeleteDevice;
   415 
   416     return device;
   417 }
   418 
   419 VideoBootStrap X11_bootstrap = {
   420     "x11", "SDL X11 video driver",
   421     X11_Available, X11_CreateDevice
   422 };
   423 
   424 static int (*handler) (Display *, XErrorEvent *) = NULL;
   425 static int
   426 X11_CheckWindowManagerErrorHandler(Display * d, XErrorEvent * e)
   427 {
   428     if (e->error_code == BadWindow) {
   429         return (0);
   430     } else {
   431         return (handler(d, e));
   432     }
   433 }
   434 
   435 static void
   436 X11_CheckWindowManager(_THIS)
   437 {
   438     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   439     Display *display = data->display;
   440     Atom _NET_SUPPORTING_WM_CHECK;
   441     int status, real_format;
   442     Atom real_type;
   443     unsigned long items_read = 0, items_left = 0;
   444     unsigned char *propdata = NULL;
   445     Window wm_window = 0;
   446 #ifdef DEBUG_WINDOW_MANAGER
   447     char *wm_name;
   448 #endif
   449 
   450     /* Set up a handler to gracefully catch errors */
   451     X11_XSync(display, False);
   452     handler = X11_XSetErrorHandler(X11_CheckWindowManagerErrorHandler);
   453 
   454     _NET_SUPPORTING_WM_CHECK = X11_XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
   455     status = X11_XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
   456     if (status == Success) {
   457         if (items_read) {
   458             wm_window = ((Window*)propdata)[0];
   459         }
   460         if (propdata) {
   461             X11_XFree(propdata);
   462             propdata = NULL;
   463         }
   464     }
   465 
   466     if (wm_window) {
   467         status = X11_XGetWindowProperty(display, wm_window, _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
   468         if (status != Success || !items_read || wm_window != ((Window*)propdata)[0]) {
   469             wm_window = None;
   470         }
   471         if (status == Success && propdata) {
   472             X11_XFree(propdata);
   473             propdata = NULL;
   474         }
   475     }
   476 
   477     /* Reset the error handler, we're done checking */
   478     X11_XSync(display, False);
   479     X11_XSetErrorHandler(handler);
   480 
   481     if (!wm_window) {
   482 #ifdef DEBUG_WINDOW_MANAGER
   483         printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n");
   484 #endif
   485         return;
   486     }
   487     data->net_wm = SDL_TRUE;
   488 
   489 #ifdef DEBUG_WINDOW_MANAGER
   490     wm_name = X11_GetWindowTitle(_this, wm_window);
   491     printf("Window manager: %s\n", wm_name);
   492     SDL_free(wm_name);
   493 #endif
   494 }
   495 
   496 
   497 int
   498 X11_VideoInit(_THIS)
   499 {
   500     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   501 
   502     /* Get the window class name, usually the name of the application */
   503     data->classname = get_classname();
   504 
   505     /* Get the process PID to be associated to the window */
   506     data->pid = getpid();
   507 
   508     /* Open a connection to the X input manager */
   509 #ifdef X_HAVE_UTF8_STRING
   510     if (SDL_X11_HAVE_UTF8) {
   511         data->im =
   512             X11_XOpenIM(data->display, NULL, data->classname, data->classname);
   513     }
   514 #endif
   515 
   516     /* Look up some useful Atoms */
   517 #define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False)
   518     GET_ATOM(WM_PROTOCOLS);
   519     GET_ATOM(WM_DELETE_WINDOW);
   520     GET_ATOM(_NET_WM_STATE);
   521     GET_ATOM(_NET_WM_STATE_HIDDEN);
   522     GET_ATOM(_NET_WM_STATE_FOCUSED);
   523     GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
   524     GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
   525     GET_ATOM(_NET_WM_STATE_FULLSCREEN);
   526     GET_ATOM(_NET_WM_ALLOWED_ACTIONS);
   527     GET_ATOM(_NET_WM_ACTION_FULLSCREEN);
   528     GET_ATOM(_NET_WM_NAME);
   529     GET_ATOM(_NET_WM_ICON_NAME);
   530     GET_ATOM(_NET_WM_ICON);
   531     GET_ATOM(_NET_WM_PING);
   532     GET_ATOM(_NET_ACTIVE_WINDOW);
   533     GET_ATOM(UTF8_STRING);
   534     GET_ATOM(PRIMARY);
   535     GET_ATOM(XdndEnter);
   536     GET_ATOM(XdndPosition);
   537     GET_ATOM(XdndStatus);
   538     GET_ATOM(XdndTypeList);
   539     GET_ATOM(XdndActionCopy);
   540     GET_ATOM(XdndDrop);
   541     GET_ATOM(XdndFinished);
   542     GET_ATOM(XdndSelection);
   543 
   544     /* Detect the window manager */
   545     X11_CheckWindowManager(_this);
   546 
   547     if (X11_InitModes(_this) < 0) {
   548         return -1;
   549     }
   550 
   551     X11_InitXinput2(_this);
   552 
   553     if (X11_InitKeyboard(_this) != 0) {
   554         return -1;
   555     }
   556     X11_InitMouse(_this);
   557 
   558     X11_InitTouch(_this);
   559 
   560 #if SDL_USE_LIBDBUS
   561     X11_InitDBus(_this);
   562 #endif
   563 
   564     return 0;
   565 }
   566 
   567 void
   568 X11_VideoQuit(_THIS)
   569 {
   570     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   571 
   572     SDL_free(data->classname);
   573 #ifdef X_HAVE_UTF8_STRING
   574     if (data->im) {
   575         X11_XCloseIM(data->im);
   576     }
   577 #endif
   578 
   579     X11_QuitModes(_this);
   580     X11_QuitKeyboard(_this);
   581     X11_QuitMouse(_this);
   582     X11_QuitTouch(_this);
   583 
   584 #if SDL_USE_LIBDBUS
   585     X11_QuitDBus(_this);
   586 #endif
   587 }
   588 
   589 SDL_bool
   590 X11_UseDirectColorVisuals(void)
   591 {
   592     return SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ? SDL_FALSE : SDL_TRUE;
   593 }
   594 
   595 #endif /* SDL_VIDEO_DRIVER_X11 */
   596 
   597 /* vim: set ts=4 sw=4 expandtab: */