• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 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;
shm_errhandler(Display * d,XErrorEvent * e)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 
have_mitshm(void)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
X11_CreateWindowFramebuffer(_THIS,SDL_Window * window,Uint32 * format,void ** pixels,int * pitch)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, True);
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
X11_UpdateWindowFramebuffer(_THIS,SDL_Window * window,const SDL_Rect * rects,int numrects)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
X11_DestroyWindowFramebuffer(_THIS,SDL_Window * window)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: */
258