src/video/x11/SDL_x11framebuffer.c
author Ethan Lee <flibitijibibo@flibitijibibo.com>
Wed, 17 Jul 2019 23:20:57 -0400
changeset 12950 05dddfb66b85
parent 12503 806492103856
permissions -rw-r--r--
Copypaste SDL_NSLog to UIKit backend, document it as such
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 "SDL_x11video.h"
    26 #include "SDL_x11framebuffer.h"
    27 
    28 
    29 #ifndef NO_SHARED_MEMORY
    30 
    31 /* Shared memory error handler routine */
    32 static int shm_error;
    33 static int (*X_handler)(Display *, XErrorEvent *) = NULL;
    34 static int shm_errhandler(Display *d, XErrorEvent *e)
    35 {
    36         if ( e->error_code == BadAccess ) {
    37             shm_error = True;
    38             return(0);
    39         } else
    40         return(X_handler(d,e));
    41 }
    42 
    43 static SDL_bool have_mitshm(void)
    44 {
    45     /* Only use shared memory on local X servers */
    46     if ( (SDL_strncmp(X11_XDisplayName(NULL), ":", 1) == 0) ||
    47          (SDL_strncmp(X11_XDisplayName(NULL), "unix:", 5) == 0) ) {
    48         return SDL_X11_HAVE_SHM;
    49     }
    50     return SDL_FALSE;
    51 }
    52 
    53 #endif /* !NO_SHARED_MEMORY */
    54 
    55 int
    56 X11_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format,
    57                             void ** pixels, int *pitch)
    58 {
    59     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    60     Display *display = data->videodata->display;
    61     XGCValues gcv;
    62     XVisualInfo vinfo;
    63 
    64     /* Free the old framebuffer surface */
    65     X11_DestroyWindowFramebuffer(_this, window);
    66 
    67     /* Create the graphics context for drawing */
    68     gcv.graphics_exposures = False;
    69     data->gc = X11_XCreateGC(display, data->xwindow, GCGraphicsExposures, &gcv);
    70     if (!data->gc) {
    71         return SDL_SetError("Couldn't create graphics context");
    72     }
    73 
    74     /* Find out the pixel format and depth */
    75     if (X11_GetVisualInfoFromVisual(display, data->visual, &vinfo) < 0) {
    76         return SDL_SetError("Couldn't get window visual information");
    77     }
    78 
    79     *format = X11_GetPixelFormatFromVisualInfo(display, &vinfo);
    80     if (*format == SDL_PIXELFORMAT_UNKNOWN) {
    81         return SDL_SetError("Unknown window pixel format");
    82     }
    83 
    84     /* Calculate pitch */
    85     *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
    86 
    87     /* Create the actual image */
    88 #ifndef NO_SHARED_MEMORY
    89     if (have_mitshm()) {
    90         XShmSegmentInfo *shminfo = &data->shminfo;
    91 
    92         shminfo->shmid = shmget(IPC_PRIVATE, window->h*(*pitch), IPC_CREAT | 0777);
    93         if ( shminfo->shmid >= 0 ) {
    94             shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0);
    95             shminfo->readOnly = False;
    96             if ( shminfo->shmaddr != (char *)-1 ) {
    97                 shm_error = False;
    98                 X_handler = X11_XSetErrorHandler(shm_errhandler);
    99                 X11_XShmAttach(display, shminfo);
   100                 X11_XSync(display, False);
   101                 X11_XSetErrorHandler(X_handler);
   102                 if ( shm_error )
   103                     shmdt(shminfo->shmaddr);
   104             } else {
   105                 shm_error = True;
   106             }
   107             shmctl(shminfo->shmid, IPC_RMID, NULL);
   108         } else {
   109             shm_error = True;
   110         }
   111         if (!shm_error) {
   112             data->ximage = X11_XShmCreateImage(display, data->visual,
   113                              vinfo.depth, ZPixmap,
   114                              shminfo->shmaddr, shminfo,
   115                              window->w, window->h);
   116             if (!data->ximage) {
   117                 X11_XShmDetach(display, shminfo);
   118                 X11_XSync(display, False);
   119                 shmdt(shminfo->shmaddr);
   120             } else {
   121                 /* Done! */
   122                 data->use_mitshm = SDL_TRUE;
   123                 *pixels = shminfo->shmaddr;
   124                 return 0;
   125             }
   126         }
   127     }
   128 #endif /* not NO_SHARED_MEMORY */
   129 
   130     *pixels = SDL_malloc(window->h*(*pitch));
   131     if (*pixels == NULL) {
   132         return SDL_OutOfMemory();
   133     }
   134 
   135     data->ximage = X11_XCreateImage(display, data->visual,
   136                       vinfo.depth, ZPixmap, 0, (char *)(*pixels),
   137                       window->w, window->h, 32, 0);
   138     if (!data->ximage) {
   139         SDL_free(*pixels);
   140         return SDL_SetError("Couldn't create XImage");
   141     }
   142     return 0;
   143 }
   144 
   145 int
   146 X11_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects,
   147                             int numrects)
   148 {
   149     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   150     Display *display = data->videodata->display;
   151     int i;
   152     int x, y, w ,h;
   153 #ifndef NO_SHARED_MEMORY
   154     if (data->use_mitshm) {
   155         for (i = 0; i < numrects; ++i) {
   156             x = rects[i].x;
   157             y = rects[i].y;
   158             w = rects[i].w;
   159             h = rects[i].h;
   160 
   161             if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
   162                 /* Clipped? */
   163                 continue;
   164             }
   165             if (x < 0)
   166             {
   167                 x += w;
   168                 w += rects[i].x;
   169             }
   170             if (y < 0)
   171             {
   172                 y += h;
   173                 h += rects[i].y;
   174             }
   175             if (x + w > window->w)
   176                 w = window->w - x;
   177             if (y + h > window->h)
   178                 h = window->h - y;
   179 
   180             X11_XShmPutImage(display, data->xwindow, data->gc, data->ximage,
   181                 x, y, x, y, w, h, False);
   182         }
   183     }
   184     else
   185 #endif /* !NO_SHARED_MEMORY */
   186     {
   187         for (i = 0; i < numrects; ++i) {
   188             x = rects[i].x;
   189             y = rects[i].y;
   190             w = rects[i].w;
   191             h = rects[i].h;
   192 
   193             if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
   194                 /* Clipped? */
   195                 continue;
   196             }
   197             if (x < 0)
   198             {
   199                 x += w;
   200                 w += rects[i].x;
   201             }
   202             if (y < 0)
   203             {
   204                 y += h;
   205                 h += rects[i].y;
   206             }
   207             if (x + w > window->w)
   208                 w = window->w - x;
   209             if (y + h > window->h)
   210                 h = window->h - y;
   211 
   212             X11_XPutImage(display, data->xwindow, data->gc, data->ximage,
   213                 x, y, x, y, w, h);
   214         }
   215     }
   216 
   217     X11_XSync(display, False);
   218 
   219     return 0;
   220 }
   221 
   222 void
   223 X11_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
   224 {
   225     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   226     Display *display;
   227 
   228     if (!data) {
   229         /* The window wasn't fully initialized */
   230         return;
   231     }
   232 
   233     display = data->videodata->display;
   234 
   235     if (data->ximage) {
   236         XDestroyImage(data->ximage);
   237 
   238 #ifndef NO_SHARED_MEMORY
   239         if (data->use_mitshm) {
   240             X11_XShmDetach(display, &data->shminfo);
   241             X11_XSync(display, False);
   242             shmdt(data->shminfo.shmaddr);
   243             data->use_mitshm = SDL_FALSE;
   244         }
   245 #endif /* !NO_SHARED_MEMORY */
   246 
   247         data->ximage = NULL;
   248     }
   249     if (data->gc) {
   250         X11_XFreeGC(display, data->gc);
   251         data->gc = NULL;
   252     }
   253 }
   254 
   255 #endif /* SDL_VIDEO_DRIVER_X11 */
   256 
   257 /* vi: set ts=4 sw=4 expandtab: */