src/video/x11/SDL_x11video.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 09 Apr 2012 23:55:43 -0400
changeset 6305 601b0e251822
parent 6167 c071e1372341
child 6311 4e5e46f43438
permissions -rwxr-xr-x
SDL_ExitProcess() was ignoring exit code parameter.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.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 
    37 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
    38 #include "SDL_x11opengles.h"
    39 #endif
    40 
    41 /* Initialization/Query functions */
    42 static int X11_VideoInit(_THIS);
    43 static void X11_VideoQuit(_THIS);
    44 
    45 /* Find out what class name we should use */
    46 static char *
    47 get_classname()
    48 {
    49     char *spot;
    50 #if defined(__LINUX__) || defined(__FREEBSD__)
    51     char procfile[1024];
    52     char linkfile[1024];
    53     int linksize;
    54 #endif
    55 
    56     /* First allow environment variable override */
    57     spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
    58     if (spot) {
    59         return SDL_strdup(spot);
    60     }
    61 
    62     /* Next look at the application's executable name */
    63 #if defined(__LINUX__) || defined(__FREEBSD__)
    64 #if defined(__LINUX__)
    65     SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
    66 #elif defined(__FREEBSD__)
    67     SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
    68                  getpid());
    69 #else
    70 #error Where can we find the executable name?
    71 #endif
    72     linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
    73     if (linksize > 0) {
    74         linkfile[linksize] = '\0';
    75         spot = SDL_strrchr(linkfile, '/');
    76         if (spot) {
    77             return SDL_strdup(spot + 1);
    78         } else {
    79             return SDL_strdup(linkfile);
    80         }
    81     }
    82 #endif /* __LINUX__ || __FREEBSD__ */
    83 
    84     /* Finally use the default we've used forever */
    85     return SDL_strdup("SDL_App");
    86 }
    87 
    88 /* X11 driver bootstrap functions */
    89 
    90 static int
    91 X11_Available(void)
    92 {
    93     Display *display = NULL;
    94     if (SDL_X11_LoadSymbols()) {
    95         display = XOpenDisplay(NULL);
    96         if (display != NULL) {
    97             XCloseDisplay(display);
    98         }
    99         SDL_X11_UnloadSymbols();
   100     }
   101     return (display != NULL);
   102 }
   103 
   104 static void
   105 X11_DeleteDevice(SDL_VideoDevice * device)
   106 {
   107     SDL_VideoData *data = (SDL_VideoData *) device->driverdata;
   108     if (data->display) {
   109         XCloseDisplay(data->display);
   110     }
   111     SDL_free(data->windowlist);
   112     SDL_free(device->driverdata);
   113 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   114     SDL_free(device->gles_data);
   115 #endif
   116     SDL_free(device);
   117 
   118     SDL_X11_UnloadSymbols();
   119 }
   120 
   121 static SDL_VideoDevice *
   122 X11_CreateDevice(int devindex)
   123 {
   124     SDL_VideoDevice *device;
   125     SDL_VideoData *data;
   126     const char *display = NULL; /* Use the DISPLAY environment variable */
   127 
   128     if (!SDL_X11_LoadSymbols()) {
   129         return NULL;
   130     }
   131 
   132     /* Initialize all variables that we clean on shutdown */
   133     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
   134     if (!device) {
   135         SDL_OutOfMemory();
   136         return NULL;
   137     }
   138     data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
   139     if (!data) {
   140         SDL_OutOfMemory();
   141         SDL_free(device);
   142         return NULL;
   143     }
   144     device->driverdata = data;
   145 
   146 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   147     device->gles_data = (struct SDL_PrivateGLESData *) SDL_calloc(1, sizeof(SDL_PrivateGLESData));
   148     if (!device->gles_data) {
   149         SDL_OutOfMemory();
   150         return NULL;
   151     }
   152 #endif
   153 
   154     /* FIXME: Do we need this?
   155        if ( (SDL_strncmp(XDisplayName(display), ":", 1) == 0) ||
   156        (SDL_strncmp(XDisplayName(display), "unix:", 5) == 0) ) {
   157        local_X11 = 1;
   158        } else {
   159        local_X11 = 0;
   160        }
   161      */
   162     data->display = XOpenDisplay(display);
   163 #if defined(__osf__) && defined(SDL_VIDEO_DRIVER_X11_DYNAMIC)
   164     /* On Tru64 if linking without -lX11, it fails and you get following message.
   165      * Xlib: connection to ":0.0" refused by server
   166      * Xlib: XDM authorization key matches an existing client!
   167      *
   168      * It succeeds if retrying 1 second later
   169      * or if running xhost +localhost on shell.
   170      */
   171     if (data->display == NULL) {
   172         SDL_Delay(1000);
   173         data->display = XOpenDisplay(display);
   174     }
   175 #endif
   176     if (data->display == NULL) {
   177         SDL_free(device);
   178         SDL_SetError("Couldn't open X11 display");
   179         return NULL;
   180     }
   181 #ifdef X11_DEBUG
   182     XSynchronize(data->display, True);
   183 #endif
   184 
   185     /* Set the function pointers */
   186     device->VideoInit = X11_VideoInit;
   187     device->VideoQuit = X11_VideoQuit;
   188     device->GetDisplayModes = X11_GetDisplayModes;
   189     device->SetDisplayMode = X11_SetDisplayMode;
   190     device->SuspendScreenSaver = X11_SuspendScreenSaver;
   191     device->PumpEvents = X11_PumpEvents;
   192 
   193     device->CreateWindow = X11_CreateWindow;
   194     device->CreateWindowFrom = X11_CreateWindowFrom;
   195     device->SetWindowTitle = X11_SetWindowTitle;
   196     device->SetWindowIcon = X11_SetWindowIcon;
   197     device->SetWindowPosition = X11_SetWindowPosition;
   198     device->SetWindowSize = X11_SetWindowSize;
   199     device->ShowWindow = X11_ShowWindow;
   200     device->HideWindow = X11_HideWindow;
   201     device->RaiseWindow = X11_RaiseWindow;
   202     device->MaximizeWindow = X11_MaximizeWindow;
   203     device->MinimizeWindow = X11_MinimizeWindow;
   204     device->RestoreWindow = X11_RestoreWindow;
   205     device->SetWindowFullscreen = X11_SetWindowFullscreen;
   206     device->SetWindowGammaRamp = X11_SetWindowGammaRamp;
   207     device->SetWindowGrab = X11_SetWindowGrab;
   208     device->DestroyWindow = X11_DestroyWindow;
   209     device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer;
   210     device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer;
   211     device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer;
   212     device->GetWindowWMInfo = X11_GetWindowWMInfo;
   213 
   214     device->shape_driver.CreateShaper = X11_CreateShaper;
   215     device->shape_driver.SetWindowShape = X11_SetWindowShape;
   216     device->shape_driver.ResizeWindowShape = X11_ResizeWindowShape;
   217 
   218 #if SDL_VIDEO_OPENGL_GLX
   219     device->GL_LoadLibrary = X11_GL_LoadLibrary;
   220     device->GL_GetProcAddress = X11_GL_GetProcAddress;
   221     device->GL_UnloadLibrary = X11_GL_UnloadLibrary;
   222     device->GL_CreateContext = X11_GL_CreateContext;
   223     device->GL_MakeCurrent = X11_GL_MakeCurrent;
   224     device->GL_SetSwapInterval = X11_GL_SetSwapInterval;
   225     device->GL_GetSwapInterval = X11_GL_GetSwapInterval;
   226     device->GL_SwapWindow = X11_GL_SwapWindow;
   227     device->GL_DeleteContext = X11_GL_DeleteContext;
   228 #endif
   229 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   230     device->GL_LoadLibrary = X11_GLES_LoadLibrary;
   231     device->GL_GetProcAddress = X11_GLES_GetProcAddress;
   232     device->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
   233     device->GL_CreateContext = X11_GLES_CreateContext;
   234     device->GL_MakeCurrent = X11_GLES_MakeCurrent;
   235     device->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
   236     device->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
   237     device->GL_SwapWindow = X11_GLES_SwapWindow;
   238     device->GL_DeleteContext = X11_GLES_DeleteContext;
   239 #endif
   240 
   241     device->SetClipboardText = X11_SetClipboardText;
   242     device->GetClipboardText = X11_GetClipboardText;
   243     device->HasClipboardText = X11_HasClipboardText;
   244 
   245     device->free = X11_DeleteDevice;
   246 
   247     return device;
   248 }
   249 
   250 VideoBootStrap X11_bootstrap = {
   251     "x11", "SDL X11 video driver",
   252     X11_Available, X11_CreateDevice
   253 };
   254 
   255 static int (*handler) (Display *, XErrorEvent *) = NULL;
   256 static int
   257 X11_CheckWindowManagerErrorHandler(Display * d, XErrorEvent * e)
   258 {
   259     if (e->error_code == BadWindow) {
   260         return (0);
   261     } else {
   262         return (handler(d, e));
   263     }
   264 }
   265 
   266 static void
   267 X11_CheckWindowManager(_THIS)
   268 {
   269     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   270     Display *display = data->display;
   271     Atom _NET_SUPPORTING_WM_CHECK;
   272     int status, real_format;
   273     Atom real_type;
   274     unsigned long items_read, items_left;
   275     unsigned char *propdata;
   276     Window wm_window = 0;
   277 #ifdef DEBUG_WINDOW_MANAGER
   278     char *wm_name;
   279 #endif
   280 
   281     /* Set up a handler to gracefully catch errors */
   282     XSync(display, False);
   283     handler = XSetErrorHandler(X11_CheckWindowManagerErrorHandler);
   284 
   285     _NET_SUPPORTING_WM_CHECK = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
   286     status = XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
   287     if (status == Success && items_read) {
   288         wm_window = ((Window*)propdata)[0];
   289     }
   290     if (propdata) {
   291         XFree(propdata);
   292     }
   293 
   294     if (wm_window) {
   295         status = XGetWindowProperty(display, wm_window, _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
   296         if (status != Success || !items_read || wm_window != ((Window*)propdata)[0]) {
   297             wm_window = None;
   298         }
   299         if (propdata) {
   300             XFree(propdata);
   301         }
   302     }
   303 
   304     /* Reset the error handler, we're done checking */
   305     XSync(display, False);
   306     XSetErrorHandler(handler);
   307 
   308     if (!wm_window) {
   309 #ifdef DEBUG_WINDOW_MANAGER
   310         printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n");
   311 #endif
   312         return;
   313     }
   314     data->net_wm = SDL_TRUE;
   315 
   316 #ifdef DEBUG_WINDOW_MANAGER
   317     wm_name = X11_GetWindowTitle(_this, wm_window);
   318     printf("Window manager: %s\n", wm_name);
   319     SDL_free(wm_name);
   320 #endif
   321 }
   322 
   323 int
   324 X11_VideoInit(_THIS)
   325 {
   326     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   327 
   328     /* Get the window class name, usually the name of the application */
   329     data->classname = get_classname();
   330 
   331     /* Get the process PID to be associated to the window */
   332     data->pid = getpid();
   333 
   334     /* Open a connection to the X input manager */
   335 #ifdef X_HAVE_UTF8_STRING
   336     if (SDL_X11_HAVE_UTF8) {
   337         data->im =
   338             XOpenIM(data->display, NULL, data->classname, data->classname);
   339     }
   340 #endif
   341 
   342     /* Look up some useful Atoms */
   343 #define GET_ATOM(X) data->X = XInternAtom(data->display, #X, False)
   344     GET_ATOM(WM_DELETE_WINDOW);
   345     GET_ATOM(_NET_WM_STATE);
   346     GET_ATOM(_NET_WM_STATE_HIDDEN);
   347     GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
   348     GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
   349     GET_ATOM(_NET_WM_STATE_FULLSCREEN);
   350     GET_ATOM(_NET_WM_NAME);
   351     GET_ATOM(_NET_WM_ICON_NAME);
   352     GET_ATOM(_NET_WM_ICON);
   353     GET_ATOM(UTF8_STRING);
   354 
   355     /* Detect the window manager */
   356     X11_CheckWindowManager(_this);
   357 
   358     if (X11_InitModes(_this) < 0) {
   359         return -1;
   360     }
   361 
   362     if (X11_InitKeyboard(_this) != 0) {
   363         return -1;
   364     }
   365     X11_InitMouse(_this);
   366 
   367     X11_InitTouch(_this);
   368     return 0;
   369 }
   370 
   371 void
   372 X11_VideoQuit(_THIS)
   373 {
   374     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   375 
   376     if (data->classname) {
   377         SDL_free(data->classname);
   378     }
   379 #ifdef X_HAVE_UTF8_STRING
   380     if (data->im) {
   381         XCloseIM(data->im);
   382     }
   383 #endif
   384 
   385     X11_QuitModes(_this);
   386     X11_QuitKeyboard(_this);
   387     X11_QuitMouse(_this);
   388     X11_QuitTouch(_this);
   389 }
   390 
   391 SDL_bool
   392 X11_UseDirectColorVisuals(void)
   393 {
   394     return SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ? SDL_FALSE : SDL_TRUE;
   395 }
   396 
   397 #endif /* SDL_VIDEO_DRIVER_X11 */
   398 
   399 /* vim: set ts=4 sw=4 expandtab: */