src/video/x11/SDL_x11framebuffer.c
author Sam Lantinga
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

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