src/video/x11/SDL_x11framebuffer.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 13 Oct 2011 01:08:30 -0400
changeset 5981 75caa8a7d559
parent 5535 96594ac5fd1a
child 6138 4c64952a58fb
permissions -rw-r--r--
Fixed a whole slew of compiler warnings that -Wall exposed.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 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 "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(XDisplayName(NULL), ":", 1) == 0) ||
    47          (SDL_strncmp(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 = XCreateGC(display, data->xwindow, GCGraphicsExposures, &gcv);
    70     if (!data->gc) {
    71         SDL_SetError("Couldn't create graphics context");
    72         return -1;
    73     }
    74 
    75     /* Find out the pixel format and depth */
    76     if (X11_GetVisualInfoFromVisual(display, data->visual, &vinfo) < 0) {
    77         SDL_SetError("Couldn't get window visual information");
    78         return -1;
    79     }
    80 
    81     *format = X11_GetPixelFormatFromVisualInfo(display, &vinfo);
    82     if (*format == SDL_PIXELFORMAT_UNKNOWN) {
    83         SDL_SetError("Unknown window pixel format");
    84         return -1;
    85     }
    86 
    87     /* Calculate pitch */
    88     *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
    89 
    90     /* Create the actual image */
    91 #ifndef NO_SHARED_MEMORY
    92     if (have_mitshm()) {
    93         XShmSegmentInfo *shminfo = &data->shminfo;
    94 
    95         shminfo->shmid = shmget(IPC_PRIVATE, window->h*(*pitch), IPC_CREAT | 0777);
    96         if ( shminfo->shmid >= 0 ) {
    97             shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0);
    98             shminfo->readOnly = False;
    99             if ( shminfo->shmaddr != (char *)-1 ) {
   100                 shm_error = False;
   101                 X_handler = XSetErrorHandler(shm_errhandler);
   102                 XShmAttach(display, shminfo);
   103                 XSync(display, True);
   104                 XSetErrorHandler(X_handler);
   105                 if ( shm_error )
   106                     shmdt(shminfo->shmaddr);
   107             } else {
   108                 shm_error = True;
   109             }
   110             shmctl(shminfo->shmid, IPC_RMID, NULL);
   111         } else {
   112             shm_error = True;
   113         }
   114         if (!shm_error) {
   115             data->ximage = XShmCreateImage(display, data->visual,
   116                              vinfo.depth, ZPixmap,
   117                              shminfo->shmaddr, shminfo, 
   118                              window->w, window->h);
   119             if (!data->ximage) {
   120                 XShmDetach(display, shminfo);
   121                 XSync(display, False);
   122                 shmdt(shminfo->shmaddr);
   123             } else {
   124                 /* Done! */
   125                 data->use_mitshm = SDL_TRUE;
   126                 *pixels = shminfo->shmaddr;
   127                 return 0;
   128             }
   129         }
   130     }
   131 #endif /* not NO_SHARED_MEMORY */
   132 
   133     *pixels = SDL_malloc(window->h*(*pitch));
   134     if (*pixels == NULL) {
   135         SDL_OutOfMemory();
   136         return -1;
   137     }
   138 
   139     data->ximage = XCreateImage(display, data->visual,
   140                       vinfo.depth, ZPixmap, 0, (char *)(*pixels), 
   141                       window->w, window->h, 32, 0);
   142     if (!data->ximage) {
   143         SDL_free(*pixels);
   144         SDL_SetError("Couldn't create XImage");
   145         return -1;
   146     }
   147     return 0;
   148 }
   149 
   150 int
   151 X11_UpdateWindowFramebuffer(_THIS, SDL_Window * window, SDL_Rect * rects,
   152                             int numrects)
   153 {
   154     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   155     Display *display = data->videodata->display;
   156     int i;
   157     SDL_Rect *rect;
   158 
   159 #ifndef NO_SHARED_MEMORY
   160     if (data->use_mitshm) {
   161         for (i = 0; i < numrects; ++i) {
   162             rect = &rects[i];
   163 
   164             if (rect->w == 0 || rect->h == 0) { /* Clipped? */
   165                 continue;
   166             }
   167             XShmPutImage(display, data->xwindow, data->gc, data->ximage,
   168                     rect->x, rect->y,
   169                     rect->x, rect->y, rect->w, rect->h, False);
   170         }
   171     }
   172     else
   173 #endif /* !NO_SHARED_MEMORY */
   174     {
   175         for (i = 0; i < numrects; ++i) {
   176             rect = &rects[i];
   177 
   178             if (rect->w == 0 || rect->h == 0) { /* Clipped? */
   179                 continue;
   180             }
   181             XPutImage(display, data->xwindow, data->gc, data->ximage,
   182                   rect->x, rect->y,
   183                   rect->x, rect->y, rect->w, rect->h);
   184         }
   185     }
   186 
   187     XSync(display, False);
   188 
   189     return 0;
   190 }
   191 
   192 void
   193 X11_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
   194 {
   195     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   196     Display *display = data->videodata->display;
   197 
   198     if (data->ximage) {
   199         XDestroyImage(data->ximage);
   200 
   201 #ifndef NO_SHARED_MEMORY
   202         if (data->use_mitshm) {
   203             XShmDetach(display, &data->shminfo);
   204             XSync(display, False);
   205             shmdt(data->shminfo.shmaddr);
   206             data->use_mitshm = SDL_FALSE;
   207         }
   208 #endif /* !NO_SHARED_MEMORY */
   209 
   210         data->ximage = NULL;
   211     }
   212     if (data->gc) {
   213         XFreeGC(display, data->gc);
   214         data->gc = NULL;
   215     }
   216 }
   217 
   218 #endif /* SDL_VIDEO_DRIVER_X11 */
   219 
   220 /* vi: set ts=4 sw=4 expandtab: */