cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_x11video.c (14231B)


      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/* Initialization/Query functions */
     43static int X11_VideoInit(_THIS);
     44static void X11_VideoQuit(_THIS);
     45
     46/* Find out what class name we should use */
     47static char *
     48get_classname()
     49{
     50    char *spot;
     51#if defined(__LINUX__) || defined(__FREEBSD__)
     52    char procfile[1024];
     53    char linkfile[1024];
     54    int linksize;
     55#endif
     56
     57    /* First allow environment variable override */
     58    spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
     59    if (spot) {
     60        return SDL_strdup(spot);
     61    }
     62
     63    /* Next look at the application's executable name */
     64#if defined(__LINUX__) || defined(__FREEBSD__)
     65#if defined(__LINUX__)
     66    SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
     67#elif defined(__FREEBSD__)
     68    SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
     69                 getpid());
     70#else
     71#error Where can we find the executable name?
     72#endif
     73    linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
     74    if (linksize > 0) {
     75        linkfile[linksize] = '\0';
     76        spot = SDL_strrchr(linkfile, '/');
     77        if (spot) {
     78            return SDL_strdup(spot + 1);
     79        } else {
     80            return SDL_strdup(linkfile);
     81        }
     82    }
     83#endif /* __LINUX__ || __FREEBSD__ */
     84
     85    /* Finally use the default we've used forever */
     86    return SDL_strdup("SDL_App");
     87}
     88
     89/* X11 driver bootstrap functions */
     90
     91static int
     92X11_Available(void)
     93{
     94    Display *display = NULL;
     95    if (SDL_X11_LoadSymbols()) {
     96        display = X11_XOpenDisplay(NULL);
     97        if (display != NULL) {
     98            X11_XCloseDisplay(display);
     99        }
    100        SDL_X11_UnloadSymbols();
    101    }
    102    return (display != NULL);
    103}
    104
    105static void
    106X11_DeleteDevice(SDL_VideoDevice * device)
    107{
    108    SDL_VideoData *data = (SDL_VideoData *) device->driverdata;
    109    if (data->display) {
    110        X11_XCloseDisplay(data->display);
    111    }
    112    SDL_free(data->windowlist);
    113    SDL_free(device->driverdata);
    114    SDL_free(device);
    115
    116    SDL_X11_UnloadSymbols();
    117}
    118
    119/* An error handler to reset the vidmode and then call the default handler. */
    120static SDL_bool safety_net_triggered = SDL_FALSE;
    121static int (*orig_x11_errhandler) (Display *, XErrorEvent *) = NULL;
    122static int
    123X11_SafetyNetErrHandler(Display * d, XErrorEvent * e)
    124{
    125    SDL_VideoDevice *device = NULL;
    126    /* if we trigger an error in our error handler, don't try again. */
    127    if (!safety_net_triggered) {
    128        safety_net_triggered = SDL_TRUE;
    129        device = SDL_GetVideoDevice();
    130        if (device != NULL) {
    131            int i;
    132            for (i = 0; i < device->num_displays; i++) {
    133                SDL_VideoDisplay *display = &device->displays[i];
    134                if (SDL_memcmp(&display->current_mode, &display->desktop_mode,
    135                               sizeof (SDL_DisplayMode)) != 0) {
    136                    X11_SetDisplayMode(device, display, &display->desktop_mode);
    137                }
    138            }
    139        }
    140    }
    141
    142    if (orig_x11_errhandler != NULL) {
    143        return orig_x11_errhandler(d, e);  /* probably terminate. */
    144    }
    145
    146    return 0;
    147}
    148
    149static SDL_VideoDevice *
    150X11_CreateDevice(int devindex)
    151{
    152    SDL_VideoDevice *device;
    153    SDL_VideoData *data;
    154    const char *display = NULL; /* Use the DISPLAY environment variable */
    155
    156    if (!SDL_X11_LoadSymbols()) {
    157        return NULL;
    158    }
    159
    160    /* Need for threading gl calls. This is also required for the proprietary
    161        nVidia driver to be threaded. */
    162    X11_XInitThreads();
    163
    164    /* Initialize all variables that we clean on shutdown */
    165    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
    166    if (!device) {
    167        SDL_OutOfMemory();
    168        return NULL;
    169    }
    170    data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
    171    if (!data) {
    172        SDL_free(device);
    173        SDL_OutOfMemory();
    174        return NULL;
    175    }
    176    device->driverdata = data;
    177
    178    /* FIXME: Do we need this?
    179       if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) ||
    180       (SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) {
    181       local_X11 = 1;
    182       } else {
    183       local_X11 = 0;
    184       }
    185     */
    186    data->display = X11_XOpenDisplay(display);
    187#if defined(__osf__) && defined(SDL_VIDEO_DRIVER_X11_DYNAMIC)
    188    /* On Tru64 if linking without -lX11, it fails and you get following message.
    189     * Xlib: connection to ":0.0" refused by server
    190     * Xlib: XDM authorization key matches an existing client!
    191     *
    192     * It succeeds if retrying 1 second later
    193     * or if running xhost +localhost on shell.
    194     */
    195    if (data->display == NULL) {
    196        SDL_Delay(1000);
    197        data->display = X11_XOpenDisplay(display);
    198    }
    199#endif
    200    if (data->display == NULL) {
    201        SDL_free(device->driverdata);
    202        SDL_free(device);
    203        SDL_SetError("Couldn't open X11 display");
    204        return NULL;
    205    }
    206#ifdef X11_DEBUG
    207    X11_XSynchronize(data->display, True);
    208#endif
    209
    210    /* Hook up an X11 error handler to recover the desktop resolution. */
    211    safety_net_triggered = SDL_FALSE;
    212    orig_x11_errhandler = X11_XSetErrorHandler(X11_SafetyNetErrHandler);
    213
    214    /* Set the function pointers */
    215    device->VideoInit = X11_VideoInit;
    216    device->VideoQuit = X11_VideoQuit;
    217    device->GetDisplayModes = X11_GetDisplayModes;
    218    device->GetDisplayBounds = X11_GetDisplayBounds;
    219    device->SetDisplayMode = X11_SetDisplayMode;
    220    device->SuspendScreenSaver = X11_SuspendScreenSaver;
    221    device->PumpEvents = X11_PumpEvents;
    222
    223    device->CreateWindow = X11_CreateWindow;
    224    device->CreateWindowFrom = X11_CreateWindowFrom;
    225    device->SetWindowTitle = X11_SetWindowTitle;
    226    device->SetWindowIcon = X11_SetWindowIcon;
    227    device->SetWindowPosition = X11_SetWindowPosition;
    228    device->SetWindowSize = X11_SetWindowSize;
    229    device->SetWindowMinimumSize = X11_SetWindowMinimumSize;
    230    device->SetWindowMaximumSize = X11_SetWindowMaximumSize;
    231    device->ShowWindow = X11_ShowWindow;
    232    device->HideWindow = X11_HideWindow;
    233    device->RaiseWindow = X11_RaiseWindow;
    234    device->MaximizeWindow = X11_MaximizeWindow;
    235    device->MinimizeWindow = X11_MinimizeWindow;
    236    device->RestoreWindow = X11_RestoreWindow;
    237    device->SetWindowBordered = X11_SetWindowBordered;
    238    device->SetWindowFullscreen = X11_SetWindowFullscreen;
    239    device->SetWindowGammaRamp = X11_SetWindowGammaRamp;
    240    device->SetWindowGrab = X11_SetWindowGrab;
    241    device->DestroyWindow = X11_DestroyWindow;
    242    device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer;
    243    device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer;
    244    device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer;
    245    device->GetWindowWMInfo = X11_GetWindowWMInfo;
    246    device->SetWindowHitTest = X11_SetWindowHitTest;
    247
    248    device->shape_driver.CreateShaper = X11_CreateShaper;
    249    device->shape_driver.SetWindowShape = X11_SetWindowShape;
    250    device->shape_driver.ResizeWindowShape = X11_ResizeWindowShape;
    251
    252#if SDL_VIDEO_OPENGL_GLX
    253    device->GL_LoadLibrary = X11_GL_LoadLibrary;
    254    device->GL_GetProcAddress = X11_GL_GetProcAddress;
    255    device->GL_UnloadLibrary = X11_GL_UnloadLibrary;
    256    device->GL_CreateContext = X11_GL_CreateContext;
    257    device->GL_MakeCurrent = X11_GL_MakeCurrent;
    258    device->GL_SetSwapInterval = X11_GL_SetSwapInterval;
    259    device->GL_GetSwapInterval = X11_GL_GetSwapInterval;
    260    device->GL_SwapWindow = X11_GL_SwapWindow;
    261    device->GL_DeleteContext = X11_GL_DeleteContext;
    262#elif SDL_VIDEO_OPENGL_EGL
    263    device->GL_LoadLibrary = X11_GLES_LoadLibrary;
    264    device->GL_GetProcAddress = X11_GLES_GetProcAddress;
    265    device->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
    266    device->GL_CreateContext = X11_GLES_CreateContext;
    267    device->GL_MakeCurrent = X11_GLES_MakeCurrent;
    268    device->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
    269    device->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
    270    device->GL_SwapWindow = X11_GLES_SwapWindow;
    271    device->GL_DeleteContext = X11_GLES_DeleteContext;
    272#endif
    273
    274    device->SetClipboardText = X11_SetClipboardText;
    275    device->GetClipboardText = X11_GetClipboardText;
    276    device->HasClipboardText = X11_HasClipboardText;
    277    device->StartTextInput = X11_StartTextInput;
    278    device->StopTextInput = X11_StopTextInput;
    279    device->SetTextInputRect = X11_SetTextInputRect;
    280    
    281    device->free = X11_DeleteDevice;
    282
    283    return device;
    284}
    285
    286VideoBootStrap X11_bootstrap = {
    287    "x11", "SDL X11 video driver",
    288    X11_Available, X11_CreateDevice
    289};
    290
    291static int (*handler) (Display *, XErrorEvent *) = NULL;
    292static int
    293X11_CheckWindowManagerErrorHandler(Display * d, XErrorEvent * e)
    294{
    295    if (e->error_code == BadWindow) {
    296        return (0);
    297    } else {
    298        return (handler(d, e));
    299    }
    300}
    301
    302static void
    303X11_CheckWindowManager(_THIS)
    304{
    305    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    306    Display *display = data->display;
    307    Atom _NET_SUPPORTING_WM_CHECK;
    308    int status, real_format;
    309    Atom real_type;
    310    unsigned long items_read = 0, items_left = 0;
    311    unsigned char *propdata = NULL;
    312    Window wm_window = 0;
    313#ifdef DEBUG_WINDOW_MANAGER
    314    char *wm_name;
    315#endif
    316
    317    /* Set up a handler to gracefully catch errors */
    318    X11_XSync(display, False);
    319    handler = X11_XSetErrorHandler(X11_CheckWindowManagerErrorHandler);
    320
    321    _NET_SUPPORTING_WM_CHECK = X11_XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
    322    status = X11_XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
    323    if (status == Success) {
    324        if (items_read) {
    325            wm_window = ((Window*)propdata)[0];
    326        }
    327        if (propdata) {
    328            X11_XFree(propdata);
    329            propdata = NULL;
    330        }
    331    }
    332
    333    if (wm_window) {
    334        status = X11_XGetWindowProperty(display, wm_window, _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
    335        if (status != Success || !items_read || wm_window != ((Window*)propdata)[0]) {
    336            wm_window = None;
    337        }
    338        if (status == Success && propdata) {
    339            X11_XFree(propdata);
    340            propdata = NULL;
    341        }
    342    }
    343
    344    /* Reset the error handler, we're done checking */
    345    X11_XSync(display, False);
    346    X11_XSetErrorHandler(handler);
    347
    348    if (!wm_window) {
    349#ifdef DEBUG_WINDOW_MANAGER
    350        printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n");
    351#endif
    352        return;
    353    }
    354    data->net_wm = SDL_TRUE;
    355
    356#ifdef DEBUG_WINDOW_MANAGER
    357    wm_name = X11_GetWindowTitle(_this, wm_window);
    358    printf("Window manager: %s\n", wm_name);
    359    SDL_free(wm_name);
    360#endif
    361}
    362
    363
    364int
    365X11_VideoInit(_THIS)
    366{
    367    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    368
    369    /* Get the window class name, usually the name of the application */
    370    data->classname = get_classname();
    371
    372    /* Get the process PID to be associated to the window */
    373    data->pid = getpid();
    374
    375    /* Open a connection to the X input manager */
    376#ifdef X_HAVE_UTF8_STRING
    377    if (SDL_X11_HAVE_UTF8) {
    378        data->im =
    379            X11_XOpenIM(data->display, NULL, data->classname, data->classname);
    380    }
    381#endif
    382
    383    /* Look up some useful Atoms */
    384#define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False)
    385    GET_ATOM(WM_PROTOCOLS);
    386    GET_ATOM(WM_DELETE_WINDOW);
    387    GET_ATOM(_NET_WM_STATE);
    388    GET_ATOM(_NET_WM_STATE_HIDDEN);
    389    GET_ATOM(_NET_WM_STATE_FOCUSED);
    390    GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
    391    GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
    392    GET_ATOM(_NET_WM_STATE_FULLSCREEN);
    393    GET_ATOM(_NET_WM_ALLOWED_ACTIONS);
    394    GET_ATOM(_NET_WM_ACTION_FULLSCREEN);
    395    GET_ATOM(_NET_WM_NAME);
    396    GET_ATOM(_NET_WM_ICON_NAME);
    397    GET_ATOM(_NET_WM_ICON);
    398    GET_ATOM(_NET_WM_PING);
    399    GET_ATOM(_NET_ACTIVE_WINDOW);
    400    GET_ATOM(UTF8_STRING);
    401    GET_ATOM(PRIMARY);
    402    GET_ATOM(XdndEnter);
    403    GET_ATOM(XdndPosition);
    404    GET_ATOM(XdndStatus);
    405    GET_ATOM(XdndTypeList);
    406    GET_ATOM(XdndActionCopy);
    407    GET_ATOM(XdndDrop);
    408    GET_ATOM(XdndFinished);
    409    GET_ATOM(XdndSelection);
    410
    411    /* Detect the window manager */
    412    X11_CheckWindowManager(_this);
    413
    414    if (X11_InitModes(_this) < 0) {
    415        return -1;
    416    }
    417
    418    X11_InitXinput2(_this);
    419
    420    if (X11_InitKeyboard(_this) != 0) {
    421        return -1;
    422    }
    423    X11_InitMouse(_this);
    424
    425    X11_InitTouch(_this);
    426
    427#if SDL_USE_LIBDBUS
    428    SDL_DBus_Init();
    429#endif
    430
    431    return 0;
    432}
    433
    434void
    435X11_VideoQuit(_THIS)
    436{
    437    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    438
    439    SDL_free(data->classname);
    440#ifdef X_HAVE_UTF8_STRING
    441    if (data->im) {
    442        X11_XCloseIM(data->im);
    443    }
    444#endif
    445
    446    X11_QuitModes(_this);
    447    X11_QuitKeyboard(_this);
    448    X11_QuitMouse(_this);
    449    X11_QuitTouch(_this);
    450
    451#if SDL_USE_LIBDBUS
    452    SDL_DBus_Quit();
    453#endif
    454}
    455
    456SDL_bool
    457X11_UseDirectColorVisuals(void)
    458{
    459    return SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ? SDL_FALSE : SDL_TRUE;
    460}
    461
    462#endif /* SDL_VIDEO_DRIVER_X11 */
    463
    464/* vim: set ts=4 sw=4 expandtab: */