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.
slouken@5182
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 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
*/
slouken@5182
    21
#include "SDL_config.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 */
slouken@5182
    46
    if ( (SDL_strncmp(XDisplayName(NULL), ":", 1) == 0) ||
slouken@5182
    47
         (SDL_strncmp(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;
slouken@5182
    69
    data->gc = XCreateGC(display, data->xwindow, GCGraphicsExposures, &gcv);
slouken@5182
    70
    if (!data->gc) {
slouken@5182
    71
        SDL_SetError("Couldn't create graphics context");
slouken@5182
    72
        return -1;
slouken@5182
    73
    }
slouken@5182
    74
slouken@5182
    75
    /* Find out the pixel format and depth */
slouken@5182
    76
    if (X11_GetVisualInfoFromVisual(display, data->visual, &vinfo) < 0) {
slouken@5182
    77
        SDL_SetError("Couldn't get window visual information");
slouken@5182
    78
        return -1;
slouken@5182
    79
    }
slouken@5182
    80
slouken@5182
    81
    *format = X11_GetPixelFormatFromVisualInfo(display, &vinfo);
slouken@5182
    82
    if (*format == SDL_PIXELFORMAT_UNKNOWN) {
slouken@5182
    83
        SDL_SetError("Unknown window pixel format");
slouken@5182
    84
        return -1;
slouken@5182
    85
    }
slouken@5182
    86
slouken@5182
    87
    /* Calculate pitch */
slouken@5182
    88
    *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
slouken@5182
    89
slouken@5182
    90
    /* Create the actual image */
slouken@5182
    91
#ifndef NO_SHARED_MEMORY
slouken@5182
    92
    if (have_mitshm()) {
slouken@5182
    93
        XShmSegmentInfo *shminfo = &data->shminfo;
slouken@5182
    94
slouken@5182
    95
        shminfo->shmid = shmget(IPC_PRIVATE, window->h*(*pitch), IPC_CREAT | 0777);
slouken@5182
    96
        if ( shminfo->shmid >= 0 ) {
slouken@5182
    97
            shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0);
slouken@5182
    98
            shminfo->readOnly = False;
slouken@5182
    99
            if ( shminfo->shmaddr != (char *)-1 ) {
slouken@5182
   100
                shm_error = False;
slouken@5182
   101
                X_handler = XSetErrorHandler(shm_errhandler);
slouken@5182
   102
                XShmAttach(display, shminfo);
slouken@5182
   103
                XSync(display, True);
slouken@5182
   104
                XSetErrorHandler(X_handler);
slouken@5182
   105
                if ( shm_error )
slouken@5182
   106
                    shmdt(shminfo->shmaddr);
slouken@5182
   107
            } else {
slouken@5182
   108
                shm_error = True;
slouken@5182
   109
            }
slouken@5182
   110
            shmctl(shminfo->shmid, IPC_RMID, NULL);
slouken@5182
   111
        } else {
slouken@5182
   112
            shm_error = True;
slouken@5182
   113
        }
slouken@5182
   114
        if (!shm_error) {
slouken@5182
   115
            data->ximage = XShmCreateImage(display, data->visual,
slouken@5182
   116
                             vinfo.depth, ZPixmap,
slouken@5182
   117
                             shminfo->shmaddr, shminfo, 
slouken@5182
   118
                             window->w, window->h);
slouken@5182
   119
            if (!data->ximage) {
slouken@5182
   120
                XShmDetach(display, shminfo);
slouken@5182
   121
                XSync(display, False);
slouken@5182
   122
                shmdt(shminfo->shmaddr);
slouken@5182
   123
            } else {
slouken@5182
   124
                /* Done! */
slouken@5182
   125
                data->use_mitshm = SDL_TRUE;
slouken@5182
   126
                *pixels = shminfo->shmaddr;
slouken@5182
   127
                return 0;
slouken@5182
   128
            }
slouken@5182
   129
        }
slouken@5182
   130
    }
slouken@5182
   131
#endif /* not NO_SHARED_MEMORY */
slouken@5182
   132
slouken@5182
   133
    *pixels = SDL_malloc(window->h*(*pitch));
slouken@5182
   134
    if (*pixels == NULL) {
slouken@5182
   135
        SDL_OutOfMemory();
slouken@5182
   136
        return -1;
slouken@5182
   137
    }
slouken@5182
   138
slouken@5182
   139
    data->ximage = XCreateImage(display, data->visual,
slouken@5182
   140
                      vinfo.depth, ZPixmap, 0, (char *)(*pixels), 
slouken@5182
   141
                      window->w, window->h, 32, 0);
slouken@5182
   142
    if (!data->ximage) {
slouken@5182
   143
        SDL_free(*pixels);
slouken@5182
   144
        SDL_SetError("Couldn't create XImage");
slouken@5182
   145
        return -1;
slouken@5182
   146
    }
slouken@5182
   147
    return 0;
slouken@5182
   148
}
slouken@5182
   149
slouken@5182
   150
int
slouken@5297
   151
X11_UpdateWindowFramebuffer(_THIS, SDL_Window * window, SDL_Rect * rects,
slouken@5297
   152
                            int numrects)
slouken@5182
   153
{
slouken@5182
   154
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@5182
   155
    Display *display = data->videodata->display;
slouken@5182
   156
    int i;
slouken@6351
   157
    int x, y, w ,h;
slouken@5182
   158
#ifndef NO_SHARED_MEMORY
slouken@5182
   159
    if (data->use_mitshm) {
slouken@5182
   160
        for (i = 0; i < numrects; ++i) {
slouken@6351
   161
            x = rects[i].x;
slouken@6351
   162
            y = rects[i].y;
slouken@6351
   163
            w = rects[i].w;
slouken@6351
   164
            h = rects[i].h;
slouken@5182
   165
slouken@6351
   166
            if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
slouken@6351
   167
                /* Clipped? */
slouken@5182
   168
                continue;
slouken@5182
   169
            }
slouken@6351
   170
            if (x < 0)
slouken@6351
   171
            {
slouken@6351
   172
                x += w;
slouken@6351
   173
                w += rects[i].x;
slouken@6351
   174
            }
slouken@6351
   175
            if (y < 0)
slouken@6351
   176
            {
slouken@6351
   177
                y += h;
slouken@6351
   178
                h += rects[i].y;
slouken@6351
   179
            }
slouken@6351
   180
            if (x + w > window->w)
slouken@6351
   181
                w = window->w - x;
slouken@6351
   182
            if (y + h > window->h)
slouken@6351
   183
                h = window->h - y;
slouken@6351
   184
slouken@5182
   185
            XShmPutImage(display, data->xwindow, data->gc, data->ximage,
slouken@6351
   186
                x, y, x, y, w, h, False);
slouken@5182
   187
        }
slouken@5182
   188
    }
slouken@5182
   189
    else
slouken@5182
   190
#endif /* !NO_SHARED_MEMORY */
slouken@5182
   191
    {
slouken@5182
   192
        for (i = 0; i < numrects; ++i) {
slouken@6351
   193
            x = rects[i].x;
slouken@6351
   194
            y = rects[i].y;
slouken@6351
   195
            w = rects[i].w;
slouken@6351
   196
            h = rects[i].h;
slouken@5182
   197
slouken@6351
   198
            if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
slouken@6351
   199
                /* Clipped? */
slouken@5182
   200
                continue;
slouken@5182
   201
            }
slouken@6351
   202
            if (x < 0)
slouken@6351
   203
            {
slouken@6351
   204
                x += w;
slouken@6351
   205
                w += rects[i].x;
slouken@6351
   206
            }
slouken@6351
   207
            if (y < 0)
slouken@6351
   208
            {
slouken@6351
   209
                y += h;
slouken@6351
   210
                h += rects[i].y;
slouken@6351
   211
            }
slouken@6351
   212
            if (x + w > window->w)
slouken@6351
   213
                w = window->w - x;
slouken@6351
   214
            if (y + h > window->h)
slouken@6351
   215
                h = window->h - y;
slouken@6351
   216
slouken@5182
   217
            XPutImage(display, data->xwindow, data->gc, data->ximage,
slouken@6351
   218
                x, y, x, y, w, h);
slouken@5182
   219
        }
slouken@5182
   220
    }
icculus@5981
   221
slouken@5182
   222
    XSync(display, False);
icculus@5981
   223
icculus@5981
   224
    return 0;
slouken@5182
   225
}
slouken@5182
   226
slouken@5182
   227
void
slouken@5182
   228
X11_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
slouken@5182
   229
{
slouken@5182
   230
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@6180
   231
    Display *display;
slouken@6180
   232
slouken@6180
   233
    if (!data) {
slouken@6180
   234
        /* The window wasn't fully initialized */
slouken@6180
   235
        return;
slouken@6180
   236
    }
slouken@6180
   237
slouken@6180
   238
    display = data->videodata->display;
slouken@5182
   239
slouken@5182
   240
    if (data->ximage) {
slouken@5182
   241
        XDestroyImage(data->ximage);
slouken@5182
   242
slouken@5182
   243
#ifndef NO_SHARED_MEMORY
slouken@5182
   244
        if (data->use_mitshm) {
slouken@5182
   245
            XShmDetach(display, &data->shminfo);
slouken@5182
   246
            XSync(display, False);
slouken@5182
   247
            shmdt(data->shminfo.shmaddr);
slouken@5182
   248
            data->use_mitshm = SDL_FALSE;
slouken@5182
   249
        }
slouken@5182
   250
#endif /* !NO_SHARED_MEMORY */
slouken@5182
   251
slouken@5182
   252
        data->ximage = NULL;
slouken@5182
   253
    }
slouken@5182
   254
    if (data->gc) {
slouken@5182
   255
        XFreeGC(display, data->gc);
slouken@5182
   256
        data->gc = NULL;
slouken@5182
   257
    }
slouken@5182
   258
}
slouken@5182
   259
slouken@5481
   260
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@5481
   261
slouken@5182
   262
/* vi: set ts=4 sw=4 expandtab: */