src/video/x11/SDL_x11framebuffer.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 02 Mar 2013 20:44:16 -0800
changeset 6950 1ddb72193079
parent 6885 700f1b25f77f
child 7014 3e0d048e1c14
permissions -rw-r--r--
Added a mouse ID to the mouse events, which set to the special value SDL_TOUCH_MOUSEID for mouse events simulated by touch input.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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     int x, y, w ,h;
   158 #ifndef NO_SHARED_MEMORY
   159     if (data->use_mitshm) {
   160         for (i = 0; i < numrects; ++i) {
   161             x = rects[i].x;
   162             y = rects[i].y;
   163             w = rects[i].w;
   164             h = rects[i].h;
   165 
   166             if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
   167                 /* Clipped? */
   168                 continue;
   169             }
   170             if (x < 0)
   171             {
   172                 x += w;
   173                 w += rects[i].x;
   174             }
   175             if (y < 0)
   176             {
   177                 y += h;
   178                 h += rects[i].y;
   179             }
   180             if (x + w > window->w)
   181                 w = window->w - x;
   182             if (y + h > window->h)
   183                 h = window->h - y;
   184 
   185             XShmPutImage(display, data->xwindow, data->gc, data->ximage,
   186                 x, y, x, y, w, h, False);
   187         }
   188     }
   189     else
   190 #endif /* !NO_SHARED_MEMORY */
   191     {
   192         for (i = 0; i < numrects; ++i) {
   193             x = rects[i].x;
   194             y = rects[i].y;
   195             w = rects[i].w;
   196             h = rects[i].h;
   197 
   198             if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
   199                 /* Clipped? */
   200                 continue;
   201             }
   202             if (x < 0)
   203             {
   204                 x += w;
   205                 w += rects[i].x;
   206             }
   207             if (y < 0)
   208             {
   209                 y += h;
   210                 h += rects[i].y;
   211             }
   212             if (x + w > window->w)
   213                 w = window->w - x;
   214             if (y + h > window->h)
   215                 h = window->h - y;
   216 
   217             XPutImage(display, data->xwindow, data->gc, data->ximage,
   218                 x, y, x, y, w, h);
   219         }
   220     }
   221 
   222     XSync(display, False);
   223 
   224     return 0;
   225 }
   226 
   227 void
   228 X11_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
   229 {
   230     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   231     Display *display;
   232 
   233     if (!data) {
   234         /* The window wasn't fully initialized */
   235         return;
   236     }
   237 
   238     display = data->videodata->display;
   239 
   240     if (data->ximage) {
   241         XDestroyImage(data->ximage);
   242 
   243 #ifndef NO_SHARED_MEMORY
   244         if (data->use_mitshm) {
   245             XShmDetach(display, &data->shminfo);
   246             XSync(display, False);
   247             shmdt(data->shminfo.shmaddr);
   248             data->use_mitshm = SDL_FALSE;
   249         }
   250 #endif /* !NO_SHARED_MEMORY */
   251 
   252         data->ximage = NULL;
   253     }
   254     if (data->gc) {
   255         XFreeGC(display, data->gc);
   256         data->gc = NULL;
   257     }
   258 }
   259 
   260 #endif /* SDL_VIDEO_DRIVER_X11 */
   261 
   262 /* vi: set ts=4 sw=4 expandtab: */