1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 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: */ |
254 | |