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