src/video/x11/SDL_x11video.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 27 Sep 2012 23:55:38 -0700
changeset 6481 fab4b15b17e9
parent 6466 ebe165c00fab
child 6484 b904bb684095
permissions -rw-r--r--
Compositing window managers can show and hide windows without ever affecting the mapped state. However they do send NetWM protocol messages to indicate this is happening.
Also refactored the netwm state code so it's consistent between the places that use it.
slouken@1950
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@1950
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1950
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1950
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1950
    20
*/
slouken@1950
    21
#include "SDL_config.h"
slouken@1950
    22
slouken@5481
    23
#if SDL_VIDEO_DRIVER_X11
slouken@5481
    24
slouken@4508
    25
#include <unistd.h> /* For getpid() and readlink() */
slouken@4508
    26
slouken@1950
    27
#include "SDL_video.h"
slouken@1950
    28
#include "SDL_mouse.h"
slouken@1950
    29
#include "../SDL_sysvideo.h"
slouken@1950
    30
#include "../SDL_pixels_c.h"
slouken@1950
    31
slouken@1950
    32
#include "SDL_x11video.h"
slouken@5182
    33
#include "SDL_x11framebuffer.h"
eligottlieb@4782
    34
#include "SDL_x11shape.h"
slouken@4923
    35
#include "SDL_x11touch.h" 
dimitris@6316
    36
#include "SDL_x11xinput2.h"
slouken@2710
    37
slouken@6188
    38
#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
slouken@3218
    39
#include "SDL_x11opengles.h"
slouken@3218
    40
#endif
slouken@1950
    41
slouken@1950
    42
/* Initialization/Query functions */
slouken@1950
    43
static int X11_VideoInit(_THIS);
slouken@1950
    44
static void X11_VideoQuit(_THIS);
slouken@1950
    45
slouken@1951
    46
/* Find out what class name we should use */
slouken@1951
    47
static char *
slouken@1951
    48
get_classname()
slouken@1951
    49
{
slouken@1951
    50
    char *spot;
slouken@1951
    51
#if defined(__LINUX__) || defined(__FREEBSD__)
slouken@1951
    52
    char procfile[1024];
slouken@1951
    53
    char linkfile[1024];
slouken@1951
    54
    int linksize;
slouken@1951
    55
#endif
slouken@1951
    56
slouken@1951
    57
    /* First allow environment variable override */
slouken@1951
    58
    spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
slouken@1951
    59
    if (spot) {
slouken@1951
    60
        return SDL_strdup(spot);
slouken@1951
    61
    }
slouken@1951
    62
slouken@1951
    63
    /* Next look at the application's executable name */
slouken@1951
    64
#if defined(__LINUX__) || defined(__FREEBSD__)
slouken@1951
    65
#if defined(__LINUX__)
slouken@1951
    66
    SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
slouken@1951
    67
#elif defined(__FREEBSD__)
slouken@1951
    68
    SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
slouken@1951
    69
                 getpid());
slouken@1951
    70
#else
slouken@1951
    71
#error Where can we find the executable name?
slouken@1951
    72
#endif
slouken@1951
    73
    linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
slouken@1951
    74
    if (linksize > 0) {
slouken@1951
    75
        linkfile[linksize] = '\0';
slouken@1951
    76
        spot = SDL_strrchr(linkfile, '/');
slouken@1951
    77
        if (spot) {
slouken@1951
    78
            return SDL_strdup(spot + 1);
slouken@1951
    79
        } else {
slouken@1951
    80
            return SDL_strdup(linkfile);
slouken@1951
    81
        }
slouken@1951
    82
    }
slouken@1951
    83
#endif /* __LINUX__ || __FREEBSD__ */
slouken@1951
    84
slouken@1951
    85
    /* Finally use the default we've used forever */
slouken@1951
    86
    return SDL_strdup("SDL_App");
slouken@1951
    87
}
slouken@1951
    88
slouken@1950
    89
/* X11 driver bootstrap functions */
slouken@1950
    90
slouken@1950
    91
static int
slouken@1950
    92
X11_Available(void)
slouken@1950
    93
{
slouken@1950
    94
    Display *display = NULL;
slouken@1950
    95
    if (SDL_X11_LoadSymbols()) {
slouken@1950
    96
        display = XOpenDisplay(NULL);
slouken@1950
    97
        if (display != NULL) {
slouken@1950
    98
            XCloseDisplay(display);
slouken@1950
    99
        }
slouken@1950
   100
        SDL_X11_UnloadSymbols();
slouken@1950
   101
    }
slouken@1950
   102
    return (display != NULL);
slouken@1950
   103
}
slouken@1950
   104
slouken@1950
   105
static void
slouken@1950
   106
X11_DeleteDevice(SDL_VideoDevice * device)
slouken@1950
   107
{
slouken@1950
   108
    SDL_VideoData *data = (SDL_VideoData *) device->driverdata;
slouken@1950
   109
    if (data->display) {
slouken@1950
   110
        XCloseDisplay(data->display);
slouken@1950
   111
    }
bob@2324
   112
    SDL_free(data->windowlist);
slouken@1950
   113
    SDL_free(device->driverdata);
slouken@1950
   114
    SDL_free(device);
slouken@1950
   115
slouken@1950
   116
    SDL_X11_UnloadSymbols();
slouken@1950
   117
}
slouken@1950
   118
slouken@1950
   119
static SDL_VideoDevice *
slouken@1950
   120
X11_CreateDevice(int devindex)
slouken@1950
   121
{
slouken@1950
   122
    SDL_VideoDevice *device;
slouken@1950
   123
    SDL_VideoData *data;
slouken@1950
   124
    const char *display = NULL; /* Use the DISPLAY environment variable */
slouken@1950
   125
slouken@1950
   126
    if (!SDL_X11_LoadSymbols()) {
slouken@1950
   127
        return NULL;
slouken@1950
   128
    }
slouken@1950
   129
slouken@1950
   130
    /* Initialize all variables that we clean on shutdown */
slouken@1950
   131
    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
bob@2323
   132
    if (!device) {
bob@2323
   133
        SDL_OutOfMemory();
bob@2323
   134
        return NULL;
slouken@1950
   135
    }
bob@2323
   136
    data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
bob@2323
   137
    if (!data) {
slouken@1950
   138
        SDL_OutOfMemory();
bob@2323
   139
        SDL_free(device);
slouken@1950
   140
        return NULL;
slouken@1950
   141
    }
slouken@1950
   142
    device->driverdata = data;
slouken@1950
   143
slouken@1950
   144
    /* FIXME: Do we need this?
slouken@1950
   145
       if ( (SDL_strncmp(XDisplayName(display), ":", 1) == 0) ||
slouken@1950
   146
       (SDL_strncmp(XDisplayName(display), "unix:", 5) == 0) ) {
slouken@1950
   147
       local_X11 = 1;
slouken@1950
   148
       } else {
slouken@1950
   149
       local_X11 = 0;
slouken@1950
   150
       }
slouken@1950
   151
     */
slouken@1950
   152
    data->display = XOpenDisplay(display);
slouken@1950
   153
#if defined(__osf__) && defined(SDL_VIDEO_DRIVER_X11_DYNAMIC)
slouken@1950
   154
    /* On Tru64 if linking without -lX11, it fails and you get following message.
slouken@1950
   155
     * Xlib: connection to ":0.0" refused by server
slouken@1950
   156
     * Xlib: XDM authorization key matches an existing client!
slouken@1950
   157
     *
slouken@1950
   158
     * It succeeds if retrying 1 second later
slouken@1950
   159
     * or if running xhost +localhost on shell.
slouken@1950
   160
     */
slouken@1950
   161
    if (data->display == NULL) {
slouken@1950
   162
        SDL_Delay(1000);
slouken@1950
   163
        data->display = XOpenDisplay(display);
slouken@1950
   164
    }
slouken@1950
   165
#endif
slouken@1950
   166
    if (data->display == NULL) {
slouken@6367
   167
        SDL_free(device->driverdata);
slouken@1950
   168
        SDL_free(device);
slouken@1950
   169
        SDL_SetError("Couldn't open X11 display");
slouken@1950
   170
        return NULL;
slouken@1950
   171
    }
slouken@1950
   172
#ifdef X11_DEBUG
slouken@1950
   173
    XSynchronize(data->display, True);
slouken@1950
   174
#endif
slouken@1950
   175
slouken@1950
   176
    /* Set the function pointers */
slouken@1950
   177
    device->VideoInit = X11_VideoInit;
slouken@1950
   178
    device->VideoQuit = X11_VideoQuit;
slouken@1950
   179
    device->GetDisplayModes = X11_GetDisplayModes;
gabomdq@6331
   180
    device->GetDisplayBounds = X11_GetDisplayBounds;
slouken@1950
   181
    device->SetDisplayMode = X11_SetDisplayMode;
slouken@3025
   182
    device->SuspendScreenSaver = X11_SuspendScreenSaver;
slouken@1951
   183
    device->PumpEvents = X11_PumpEvents;
slouken@1950
   184
slouken@1950
   185
    device->CreateWindow = X11_CreateWindow;
slouken@1950
   186
    device->CreateWindowFrom = X11_CreateWindowFrom;
slouken@1950
   187
    device->SetWindowTitle = X11_SetWindowTitle;
slouken@2967
   188
    device->SetWindowIcon = X11_SetWindowIcon;
slouken@1950
   189
    device->SetWindowPosition = X11_SetWindowPosition;
slouken@1950
   190
    device->SetWindowSize = X11_SetWindowSize;
slouken@1950
   191
    device->ShowWindow = X11_ShowWindow;
slouken@1950
   192
    device->HideWindow = X11_HideWindow;
slouken@1950
   193
    device->RaiseWindow = X11_RaiseWindow;
slouken@1950
   194
    device->MaximizeWindow = X11_MaximizeWindow;
slouken@1950
   195
    device->MinimizeWindow = X11_MinimizeWindow;
slouken@1950
   196
    device->RestoreWindow = X11_RestoreWindow;
icculus@6422
   197
    device->SetWindowBordered = X11_SetWindowBordered;
slouken@5302
   198
    device->SetWindowFullscreen = X11_SetWindowFullscreen;
slouken@5466
   199
    device->SetWindowGammaRamp = X11_SetWindowGammaRamp;
slouken@1950
   200
    device->SetWindowGrab = X11_SetWindowGrab;
slouken@1950
   201
    device->DestroyWindow = X11_DestroyWindow;
slouken@5182
   202
    device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer;
slouken@5182
   203
    device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer;
slouken@5182
   204
    device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer;
slouken@1950
   205
    device->GetWindowWMInfo = X11_GetWindowWMInfo;
slouken@5182
   206
eligottlieb@4782
   207
    device->shape_driver.CreateShaper = X11_CreateShaper;
eligottlieb@4782
   208
    device->shape_driver.SetWindowShape = X11_SetWindowShape;
eligottlieb@4782
   209
    device->shape_driver.ResizeWindowShape = X11_ResizeWindowShape;
slouken@5182
   210
slouken@5088
   211
#if SDL_VIDEO_OPENGL_GLX
slouken@6370
   212
    device->GL_LoadLibrary = X11_GL_LoadLibrary;
slouken@6370
   213
    device->GL_GetProcAddress = X11_GL_GetProcAddress;
slouken@6370
   214
    device->GL_UnloadLibrary = X11_GL_UnloadLibrary;
slouken@6370
   215
    device->GL_CreateContext = X11_GL_CreateContext;
slouken@6370
   216
    device->GL_MakeCurrent = X11_GL_MakeCurrent;
slouken@6370
   217
    device->GL_SetSwapInterval = X11_GL_SetSwapInterval;
slouken@6370
   218
    device->GL_GetSwapInterval = X11_GL_GetSwapInterval;
slouken@6370
   219
    device->GL_SwapWindow = X11_GL_SwapWindow;
slouken@6370
   220
    device->GL_DeleteContext = X11_GL_DeleteContext;
slouken@6370
   221
#elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
slouken@6370
   222
    device->GL_LoadLibrary = X11_GLES_LoadLibrary;
slouken@6370
   223
    device->GL_GetProcAddress = X11_GLES_GetProcAddress;
slouken@6370
   224
    device->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
slouken@6370
   225
    device->GL_CreateContext = X11_GLES_CreateContext;
slouken@6370
   226
    device->GL_MakeCurrent = X11_GLES_MakeCurrent;
slouken@6370
   227
    device->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
slouken@6370
   228
    device->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
slouken@6370
   229
    device->GL_SwapWindow = X11_GLES_SwapWindow;
slouken@6370
   230
    device->GL_DeleteContext = X11_GLES_DeleteContext;
slouken@3218
   231
#endif
slouken@1950
   232
slouken@4508
   233
    device->SetClipboardText = X11_SetClipboardText;
slouken@4508
   234
    device->GetClipboardText = X11_GetClipboardText;
slouken@4508
   235
    device->HasClipboardText = X11_HasClipboardText;
slouken@4508
   236
slouken@1950
   237
    device->free = X11_DeleteDevice;
slouken@1950
   238
slouken@1950
   239
    return device;
slouken@1950
   240
}
slouken@1950
   241
slouken@1950
   242
VideoBootStrap X11_bootstrap = {
slouken@1950
   243
    "x11", "SDL X11 video driver",
slouken@1950
   244
    X11_Available, X11_CreateDevice
slouken@1950
   245
};
slouken@1950
   246
slouken@4559
   247
static int (*handler) (Display *, XErrorEvent *) = NULL;
slouken@4559
   248
static int
slouken@4559
   249
X11_CheckWindowManagerErrorHandler(Display * d, XErrorEvent * e)
slouken@4559
   250
{
slouken@4559
   251
    if (e->error_code == BadWindow) {
slouken@4559
   252
        return (0);
slouken@4559
   253
    } else {
slouken@4559
   254
        return (handler(d, e));
slouken@4559
   255
    }
slouken@4559
   256
}
slouken@4508
   257
slouken@4518
   258
static void
slouken@4518
   259
X11_CheckWindowManager(_THIS)
slouken@4518
   260
{
slouken@4518
   261
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@4518
   262
    Display *display = data->display;
slouken@4518
   263
    Atom _NET_SUPPORTING_WM_CHECK;
slouken@4518
   264
    int status, real_format;
slouken@4518
   265
    Atom real_type;
slouken@4518
   266
    unsigned long items_read, items_left;
slouken@4518
   267
    unsigned char *propdata;
slouken@4518
   268
    Window wm_window = 0;
slouken@4518
   269
#ifdef DEBUG_WINDOW_MANAGER
slouken@4518
   270
    char *wm_name;
slouken@4518
   271
#endif
slouken@4518
   272
slouken@4559
   273
    /* Set up a handler to gracefully catch errors */
slouken@4559
   274
    XSync(display, False);
slouken@4559
   275
    handler = XSetErrorHandler(X11_CheckWindowManagerErrorHandler);
slouken@4559
   276
slouken@4518
   277
    _NET_SUPPORTING_WM_CHECK = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
slouken@4518
   278
    status = XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
slouken@4518
   279
    if (status == Success && items_read) {
slouken@4518
   280
        wm_window = ((Window*)propdata)[0];
slouken@4518
   281
    }
slouken@4559
   282
    if (propdata) {
slouken@4559
   283
        XFree(propdata);
slouken@4559
   284
    }
slouken@4559
   285
slouken@4559
   286
    if (wm_window) {
slouken@4559
   287
        status = XGetWindowProperty(display, wm_window, _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
slouken@4559
   288
        if (status != Success || !items_read || wm_window != ((Window*)propdata)[0]) {
slouken@4559
   289
            wm_window = None;
slouken@4559
   290
        }
slouken@4559
   291
        if (propdata) {
slouken@4559
   292
            XFree(propdata);
slouken@4559
   293
        }
slouken@4559
   294
    }
slouken@4559
   295
slouken@4559
   296
    /* Reset the error handler, we're done checking */
slouken@4559
   297
    XSync(display, False);
slouken@4559
   298
    XSetErrorHandler(handler);
slouken@4518
   299
slouken@4518
   300
    if (!wm_window) {
slouken@4518
   301
#ifdef DEBUG_WINDOW_MANAGER
slouken@4518
   302
        printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n");
slouken@4518
   303
#endif
slouken@4518
   304
        return;
slouken@4518
   305
    }
slouken@4518
   306
    data->net_wm = SDL_TRUE;
slouken@4518
   307
slouken@4518
   308
#ifdef DEBUG_WINDOW_MANAGER
slouken@4518
   309
    wm_name = X11_GetWindowTitle(_this, wm_window);
slouken@4518
   310
    printf("Window manager: %s\n", wm_name);
slouken@4518
   311
    SDL_free(wm_name);
slouken@4518
   312
#endif
slouken@4518
   313
}
slouken@1950
   314
slouken@1950
   315
int
slouken@1950
   316
X11_VideoInit(_THIS)
slouken@1950
   317
{
slouken@1951
   318
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@1951
   319
slouken@1951
   320
    /* Get the window class name, usually the name of the application */
slouken@1951
   321
    data->classname = get_classname();
slouken@1951
   322
mail@6167
   323
    /* Get the process PID to be associated to the window */
mail@6167
   324
    data->pid = getpid();
mail@6167
   325
slouken@1951
   326
    /* Open a connection to the X input manager */
slouken@1951
   327
#ifdef X_HAVE_UTF8_STRING
slouken@1951
   328
    if (SDL_X11_HAVE_UTF8) {
slouken@1951
   329
        data->im =
slouken@1951
   330
            XOpenIM(data->display, NULL, data->classname, data->classname);
slouken@1951
   331
    }
slouken@1951
   332
#endif
slouken@1951
   333
slouken@1951
   334
    /* Look up some useful Atoms */
slouken@4518
   335
#define GET_ATOM(X) data->X = XInternAtom(data->display, #X, False)
slouken@4518
   336
    GET_ATOM(WM_DELETE_WINDOW);
slouken@4518
   337
    GET_ATOM(_NET_WM_STATE);
slouken@4518
   338
    GET_ATOM(_NET_WM_STATE_HIDDEN);
slouken@6481
   339
    GET_ATOM(_NET_WM_STATE_FOCUSED);
slouken@4518
   340
    GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
slouken@4518
   341
    GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
slouken@4518
   342
    GET_ATOM(_NET_WM_STATE_FULLSCREEN);
icculus@6466
   343
    GET_ATOM(_NET_WM_ALLOWED_ACTIONS);
slouken@6481
   344
    GET_ATOM(_NET_WM_ACTION_RESIZE);
icculus@6466
   345
    GET_ATOM(_NET_WM_ACTION_FULLSCREEN);
slouken@4518
   346
    GET_ATOM(_NET_WM_NAME);
slouken@4518
   347
    GET_ATOM(_NET_WM_ICON_NAME);
slouken@4518
   348
    GET_ATOM(_NET_WM_ICON);
slouken@4518
   349
    GET_ATOM(UTF8_STRING);
slouken@4518
   350
slouken@4518
   351
    /* Detect the window manager */
slouken@4518
   352
    X11_CheckWindowManager(_this);
slouken@1951
   353
slouken@3521
   354
    if (X11_InitModes(_this) < 0) {
slouken@3521
   355
        return -1;
slouken@3521
   356
    }
slouken@1950
   357
dimitris@6316
   358
    X11_InitXinput2(_this);
slouken@6311
   359
bob@2295
   360
    if (X11_InitKeyboard(_this) != 0) {
bob@2295
   361
        return -1;
bob@2295
   362
    }
slouken@1950
   363
    X11_InitMouse(_this);
slouken@1950
   364
jim@4645
   365
    X11_InitTouch(_this);
slouken@1950
   366
    return 0;
slouken@1950
   367
}
slouken@1950
   368
slouken@1950
   369
void
slouken@1950
   370
X11_VideoQuit(_THIS)
slouken@1950
   371
{
slouken@1951
   372
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@1951
   373
slouken@1951
   374
    if (data->classname) {
slouken@1951
   375
        SDL_free(data->classname);
slouken@1951
   376
    }
slouken@1951
   377
#ifdef X_HAVE_UTF8_STRING
slouken@1951
   378
    if (data->im) {
slouken@1951
   379
        XCloseIM(data->im);
slouken@1951
   380
    }
slouken@1951
   381
#endif
slouken@1951
   382
slouken@1950
   383
    X11_QuitModes(_this);
slouken@1950
   384
    X11_QuitKeyboard(_this);
slouken@1950
   385
    X11_QuitMouse(_this);
jim@4645
   386
    X11_QuitTouch(_this);
slouken@1950
   387
}
slouken@1950
   388
slouken@5466
   389
SDL_bool
slouken@5466
   390
X11_UseDirectColorVisuals(void)
slouken@5466
   391
{
slouken@5466
   392
    return SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ? SDL_FALSE : SDL_TRUE;
slouken@5466
   393
}
slouken@5466
   394
slouken@5481
   395
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@5481
   396
slouken@1950
   397
/* vim: set ts=4 sw=4 expandtab: */