diff options
author | Franklin Wei <git@fwei.tk> | 2017-01-21 15:18:31 -0500 |
---|---|---|
committer | Franklin Wei <git@fwei.tk> | 2017-12-23 21:01:26 -0500 |
commit | a855d6202536ff28e5aae4f22a0f31d8f5b325d0 (patch) | |
tree | 8c75f224dd64ed360505afa8843d016b0d75000b /apps/plugins/sdl/src/video/x11/SDL_x11wm.c | |
parent | 01c6dcf6c7b9bb1ad2fa0450f99bacc5f3d3e04b (diff) | |
download | rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.tar.gz rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.zip |
Port of Duke Nukem 3D
This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL
for Rockbox.
Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
Diffstat (limited to 'apps/plugins/sdl/src/video/x11/SDL_x11wm.c')
-rw-r--r-- | apps/plugins/sdl/src/video/x11/SDL_x11wm.c | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11wm.c b/apps/plugins/sdl/src/video/x11/SDL_x11wm.c new file mode 100644 index 0000000000..14c816b942 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11wm.c | |||
@@ -0,0 +1,434 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #include <X11/Xlib.h> | ||
25 | #include <X11/Xutil.h> | ||
26 | |||
27 | #include "SDL_version.h" | ||
28 | #include "SDL_timer.h" | ||
29 | #include "SDL_video.h" | ||
30 | #include "SDL_syswm.h" | ||
31 | #include "../SDL_pixels_c.h" | ||
32 | #include "../../events/SDL_events_c.h" | ||
33 | #include "SDL_x11modes_c.h" | ||
34 | #include "SDL_x11wm_c.h" | ||
35 | |||
36 | static Uint8 reverse_byte(Uint8 x) | ||
37 | { | ||
38 | x = (x & 0xaa) >> 1 | (x & 0x55) << 1; | ||
39 | x = (x & 0xcc) >> 2 | (x & 0x33) << 2; | ||
40 | x = (x & 0xf0) >> 4 | (x & 0x0f) << 4; | ||
41 | return x; | ||
42 | } | ||
43 | |||
44 | void X11_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask) | ||
45 | { | ||
46 | SDL_Surface *sicon; | ||
47 | XWMHints *wmhints; | ||
48 | XImage *icon_image; | ||
49 | Pixmap icon_pixmap; | ||
50 | Pixmap mask_pixmap; | ||
51 | Window icon_window = None; | ||
52 | GC gc; | ||
53 | XGCValues GCvalues; | ||
54 | int i, dbpp; | ||
55 | SDL_Rect bounds; | ||
56 | Uint8 *LSBmask; | ||
57 | Visual *dvis; | ||
58 | char *p; | ||
59 | int masksize; | ||
60 | |||
61 | SDL_Lock_EventThread(); | ||
62 | |||
63 | /* The icon must use the default visual, depth and colormap of the | ||
64 | screen, so it might need a conversion */ | ||
65 | dvis = DefaultVisual(SDL_Display, SDL_Screen); | ||
66 | dbpp = DefaultDepth(SDL_Display, SDL_Screen); | ||
67 | for(i = 0; i < this->hidden->nvisuals; i++) { | ||
68 | if(this->hidden->visuals[i].visual == dvis) { | ||
69 | dbpp = this->hidden->visuals[i].bpp; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | /* The Visual struct is supposed to be opaque but we cheat a little */ | ||
75 | sicon = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h, | ||
76 | dbpp, | ||
77 | dvis->red_mask, dvis->green_mask, | ||
78 | dvis->blue_mask, 0); | ||
79 | if ( sicon == NULL ) | ||
80 | goto done; | ||
81 | |||
82 | if(dbpp == 8) { | ||
83 | /* Default visual is 8bit; we need to allocate colours from | ||
84 | the default colormap */ | ||
85 | SDL_Color want[256], got[256]; | ||
86 | int nwant; | ||
87 | Colormap dcmap; | ||
88 | int missing; | ||
89 | dcmap = DefaultColormap(SDL_Display, SDL_Screen); | ||
90 | if(icon->format->palette) { | ||
91 | /* The icon has a palette as well - we just have to | ||
92 | find those colours */ | ||
93 | nwant = icon->format->palette->ncolors; | ||
94 | SDL_memcpy(want, icon->format->palette->colors, | ||
95 | nwant * sizeof want[0]); | ||
96 | } else { | ||
97 | /* try the standard 6x6x6 cube for lack of better | ||
98 | ideas */ | ||
99 | int r, g, b, i; | ||
100 | for(r = i = 0; r < 256; r += 0x33) | ||
101 | for(g = 0; g < 256; g += 0x33) | ||
102 | for(b = 0; b < 256; b += 0x33, i++) { | ||
103 | want[i].r = r; | ||
104 | want[i].g = g; | ||
105 | want[i].b = b; | ||
106 | } | ||
107 | nwant = 216; | ||
108 | } | ||
109 | if(SDL_iconcolors) { | ||
110 | /* free already allocated colours first */ | ||
111 | unsigned long freelist[512]; | ||
112 | int nfree = 0; | ||
113 | for(i = 0; i < 256; i++) { | ||
114 | while(SDL_iconcolors[i]) { | ||
115 | freelist[nfree++] = i; | ||
116 | SDL_iconcolors[i]--; | ||
117 | } | ||
118 | } | ||
119 | XFreeColors(GFX_Display, dcmap, freelist, nfree, 0); | ||
120 | } | ||
121 | if(!SDL_iconcolors) | ||
122 | SDL_iconcolors = SDL_malloc(256 * sizeof *SDL_iconcolors); | ||
123 | SDL_memset(SDL_iconcolors, 0, 256 * sizeof *SDL_iconcolors); | ||
124 | |||
125 | /* try to allocate the colours */ | ||
126 | SDL_memset(got, 0, sizeof got); | ||
127 | missing = 0; | ||
128 | for(i = 0; i < nwant; i++) { | ||
129 | XColor c; | ||
130 | c.red = want[i].r << 8; | ||
131 | c.green = want[i].g << 8; | ||
132 | c.blue = want[i].b << 8; | ||
133 | c.flags = DoRed | DoGreen | DoBlue; | ||
134 | if(XAllocColor(GFX_Display, dcmap, &c)) { | ||
135 | /* got the colour */ | ||
136 | SDL_iconcolors[c.pixel]++; | ||
137 | got[c.pixel] = want[i]; | ||
138 | } else { | ||
139 | missing = 1; | ||
140 | } | ||
141 | } | ||
142 | if(missing) { | ||
143 | /* Some colours were apparently missing, so we just | ||
144 | allocate all the rest as well */ | ||
145 | XColor cols[256]; | ||
146 | for(i = 0; i < 256; i++) | ||
147 | cols[i].pixel = i; | ||
148 | XQueryColors(GFX_Display, dcmap, cols, 256); | ||
149 | for(i = 0; i < 256; i++) { | ||
150 | got[i].r = cols[i].red >> 8; | ||
151 | got[i].g = cols[i].green >> 8; | ||
152 | got[i].b = cols[i].blue >> 8; | ||
153 | if(!SDL_iconcolors[i]) { | ||
154 | if(XAllocColor(GFX_Display, dcmap, | ||
155 | cols + i)) { | ||
156 | SDL_iconcolors[i] = 1; | ||
157 | } else { | ||
158 | /* index not available */ | ||
159 | got[i].r = 0; | ||
160 | got[i].g = 0; | ||
161 | got[i].b = 0; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | SDL_SetColors(sicon, got, 0, 256); | ||
168 | } | ||
169 | |||
170 | bounds.x = 0; | ||
171 | bounds.y = 0; | ||
172 | bounds.w = icon->w; | ||
173 | bounds.h = icon->h; | ||
174 | if ( SDL_LowerBlit(icon, &bounds, sicon, &bounds) < 0 ) | ||
175 | goto done; | ||
176 | |||
177 | /* We need the mask as given, except in LSBfirst format instead of | ||
178 | MSBfirst. Reverse the bits in each byte. */ | ||
179 | masksize = ((sicon->w + 7) >> 3) * sicon->h; | ||
180 | LSBmask = SDL_malloc(masksize); | ||
181 | if ( LSBmask == NULL ) { | ||
182 | goto done; | ||
183 | } | ||
184 | SDL_memset(LSBmask, 0, masksize); | ||
185 | for(i = 0; i < masksize; i++) | ||
186 | LSBmask[i] = reverse_byte(mask[i]); | ||
187 | mask_pixmap = XCreatePixmapFromBitmapData(SDL_Display, WMwindow, | ||
188 | (char *)LSBmask, | ||
189 | sicon->w, sicon->h, | ||
190 | 1L, 0L, 1); | ||
191 | |||
192 | /* Transfer the image to an X11 pixmap */ | ||
193 | icon_image = XCreateImage(SDL_Display, | ||
194 | DefaultVisual(SDL_Display, SDL_Screen), | ||
195 | DefaultDepth(SDL_Display, SDL_Screen), | ||
196 | ZPixmap, 0, sicon->pixels, | ||
197 | sicon->w, sicon->h, | ||
198 | 32, 0); | ||
199 | icon_image->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN) | ||
200 | ? MSBFirst : LSBFirst; | ||
201 | icon_pixmap = XCreatePixmap(SDL_Display, SDL_Root, sicon->w, sicon->h, | ||
202 | DefaultDepth(SDL_Display, SDL_Screen)); | ||
203 | gc = XCreateGC(SDL_Display, icon_pixmap, 0, &GCvalues); | ||
204 | XPutImage(SDL_Display, icon_pixmap, gc, icon_image, | ||
205 | 0, 0, 0, 0, sicon->w, sicon->h); | ||
206 | XFreeGC(SDL_Display, gc); | ||
207 | XDestroyImage(icon_image); | ||
208 | SDL_free(LSBmask); | ||
209 | sicon->pixels = NULL; | ||
210 | |||
211 | /* Some buggy window managers (some versions of Enlightenment, it | ||
212 | seems) need an icon window *and* icon pixmap to work properly, while | ||
213 | it screws up others. The default is only to use a pixmap. */ | ||
214 | p = SDL_getenv("SDL_VIDEO_X11_ICONWIN"); | ||
215 | if(p && *p) { | ||
216 | icon_window = XCreateSimpleWindow(SDL_Display, SDL_Root, | ||
217 | 0, 0, sicon->w, sicon->h, 0, | ||
218 | CopyFromParent, | ||
219 | CopyFromParent); | ||
220 | XSetWindowBackgroundPixmap(SDL_Display, icon_window, | ||
221 | icon_pixmap); | ||
222 | XClearWindow(SDL_Display, icon_window); | ||
223 | } | ||
224 | |||
225 | /* Set the window icon to the icon pixmap (and icon window) */ | ||
226 | wmhints = XAllocWMHints(); | ||
227 | wmhints->flags = (IconPixmapHint | IconMaskHint | InputHint); | ||
228 | wmhints->icon_pixmap = icon_pixmap; | ||
229 | wmhints->icon_mask = mask_pixmap; | ||
230 | wmhints->input = True; | ||
231 | if(icon_window != None) { | ||
232 | wmhints->flags |= IconWindowHint; | ||
233 | wmhints->icon_window = icon_window; | ||
234 | } | ||
235 | XSetWMHints(SDL_Display, WMwindow, wmhints); | ||
236 | XFree(wmhints); | ||
237 | XSync(SDL_Display, False); | ||
238 | |||
239 | done: | ||
240 | SDL_Unlock_EventThread(); | ||
241 | SDL_FreeSurface(sicon); | ||
242 | } | ||
243 | |||
244 | void X11_SetCaptionNoLock(_THIS, const char *title, const char *icon) | ||
245 | { | ||
246 | XTextProperty titleprop, iconprop; | ||
247 | Status status; | ||
248 | |||
249 | #ifdef X_HAVE_UTF8_STRING | ||
250 | Atom _NET_WM_NAME = 0; | ||
251 | Atom _NET_WM_ICON_NAME = 0; | ||
252 | |||
253 | /* Look up some useful Atoms */ | ||
254 | if (SDL_X11_HAVE_UTF8) { | ||
255 | _NET_WM_NAME = XInternAtom(SDL_Display, "_NET_WM_NAME", False); | ||
256 | _NET_WM_ICON_NAME = XInternAtom(SDL_Display, "_NET_WM_ICON_NAME", False); | ||
257 | } | ||
258 | #endif | ||
259 | |||
260 | if ( title != NULL ) { | ||
261 | char *title_locale = SDL_iconv_utf8_locale(title); | ||
262 | if ( !title_locale ) { | ||
263 | SDL_OutOfMemory(); | ||
264 | return; | ||
265 | } | ||
266 | status = XStringListToTextProperty(&title_locale, 1, &titleprop); | ||
267 | SDL_free(title_locale); | ||
268 | if ( status ) { | ||
269 | XSetTextProperty(SDL_Display, WMwindow, &titleprop, XA_WM_NAME); | ||
270 | XFree(titleprop.value); | ||
271 | } | ||
272 | #ifdef X_HAVE_UTF8_STRING | ||
273 | if (SDL_X11_HAVE_UTF8) { | ||
274 | status = Xutf8TextListToTextProperty(SDL_Display, | ||
275 | (char **)&title, 1, XUTF8StringStyle, &titleprop); | ||
276 | if ( status == Success ) { | ||
277 | XSetTextProperty(SDL_Display, WMwindow, &titleprop, _NET_WM_NAME); | ||
278 | XFree(titleprop.value); | ||
279 | } | ||
280 | } | ||
281 | #endif | ||
282 | } | ||
283 | if ( icon != NULL ) { | ||
284 | char *icon_locale = SDL_iconv_utf8_locale(icon); | ||
285 | if ( !icon_locale ) { | ||
286 | SDL_OutOfMemory(); | ||
287 | return; | ||
288 | } | ||
289 | status = XStringListToTextProperty(&icon_locale, 1, &iconprop); | ||
290 | SDL_free(icon_locale); | ||
291 | if ( status ) { | ||
292 | XSetTextProperty(SDL_Display, WMwindow, &iconprop, XA_WM_ICON_NAME); | ||
293 | XFree(iconprop.value); | ||
294 | } | ||
295 | #ifdef X_HAVE_UTF8_STRING | ||
296 | if (SDL_X11_HAVE_UTF8) { | ||
297 | status = Xutf8TextListToTextProperty(SDL_Display, | ||
298 | (char **)&icon, 1, XUTF8StringStyle, &iconprop); | ||
299 | if ( status == Success ) { | ||
300 | XSetTextProperty(SDL_Display, WMwindow, &iconprop, _NET_WM_ICON_NAME); | ||
301 | XFree(iconprop.value); | ||
302 | } | ||
303 | } | ||
304 | #endif | ||
305 | } | ||
306 | XSync(SDL_Display, False); | ||
307 | } | ||
308 | |||
309 | void X11_SetCaption(_THIS, const char *title, const char *icon) | ||
310 | { | ||
311 | SDL_Lock_EventThread(); | ||
312 | X11_SetCaptionNoLock(this, title, icon); | ||
313 | SDL_Unlock_EventThread(); | ||
314 | } | ||
315 | |||
316 | /* Iconify the window */ | ||
317 | int X11_IconifyWindow(_THIS) | ||
318 | { | ||
319 | int result; | ||
320 | |||
321 | SDL_Lock_EventThread(); | ||
322 | result = XIconifyWindow(SDL_Display, WMwindow, SDL_Screen); | ||
323 | XSync(SDL_Display, False); | ||
324 | SDL_Unlock_EventThread(); | ||
325 | return(result); | ||
326 | } | ||
327 | |||
328 | SDL_GrabMode X11_GrabInputNoLock(_THIS, SDL_GrabMode mode) | ||
329 | { | ||
330 | int result; | ||
331 | |||
332 | if ( this->screen == NULL || SDL_Display == NULL ) { | ||
333 | return(SDL_GRAB_OFF); | ||
334 | } | ||
335 | if ( ! SDL_Window ) { | ||
336 | return(mode); /* Will be set later on mode switch */ | ||
337 | } | ||
338 | if ( mode == SDL_GRAB_OFF ) { | ||
339 | XUngrabPointer(SDL_Display, CurrentTime); | ||
340 | XUngrabKeyboard(SDL_Display, CurrentTime); | ||
341 | } else { | ||
342 | if ( this->screen->flags & SDL_FULLSCREEN ) { | ||
343 | /* Unbind the mouse from the fullscreen window */ | ||
344 | XUngrabPointer(SDL_Display, CurrentTime); | ||
345 | } | ||
346 | /* Try to grab the mouse */ | ||
347 | #if 0 /* We'll wait here until we actually grab, otherwise behavior undefined */ | ||
348 | for ( numtries = 0; numtries < 10; ++numtries ) { | ||
349 | #else | ||
350 | for ( ; ; ) { | ||
351 | #endif | ||
352 | result = XGrabPointer(SDL_Display, SDL_Window, True, 0, | ||
353 | GrabModeAsync, GrabModeAsync, | ||
354 | SDL_Window, None, CurrentTime); | ||
355 | if ( result == GrabSuccess ) { | ||
356 | break; | ||
357 | } | ||
358 | SDL_Delay(100); | ||
359 | } | ||
360 | if ( result != GrabSuccess ) { | ||
361 | /* Uh, oh, what do we do here? */ ; | ||
362 | } | ||
363 | /* Now grab the keyboard */ | ||
364 | XGrabKeyboard(SDL_Display, WMwindow, True, | ||
365 | GrabModeAsync, GrabModeAsync, CurrentTime); | ||
366 | |||
367 | /* Raise the window if we grab the mouse */ | ||
368 | if ( !(this->screen->flags & SDL_FULLSCREEN) ) | ||
369 | XRaiseWindow(SDL_Display, WMwindow); | ||
370 | |||
371 | /* Make sure we register input focus */ | ||
372 | SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS); | ||
373 | /* Since we grabbed the pointer, we have mouse focus, too. */ | ||
374 | SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); | ||
375 | } | ||
376 | XSync(SDL_Display, False); | ||
377 | |||
378 | return(mode); | ||
379 | } | ||
380 | |||
381 | SDL_GrabMode X11_GrabInput(_THIS, SDL_GrabMode mode) | ||
382 | { | ||
383 | SDL_Lock_EventThread(); | ||
384 | mode = X11_GrabInputNoLock(this, mode); | ||
385 | SDL_Unlock_EventThread(); | ||
386 | |||
387 | return(mode); | ||
388 | } | ||
389 | |||
390 | /* If 'info' is the right version, this function fills it and returns 1. | ||
391 | Otherwise, in case of a version mismatch, it returns -1. | ||
392 | */ | ||
393 | static void lock_display(void) | ||
394 | { | ||
395 | SDL_Lock_EventThread(); | ||
396 | } | ||
397 | static void unlock_display(void) | ||
398 | { | ||
399 | /* Make sure any X11 transactions are completed */ | ||
400 | SDL_VideoDevice *this = current_video; | ||
401 | XSync(SDL_Display, False); | ||
402 | SDL_Unlock_EventThread(); | ||
403 | } | ||
404 | |||
405 | #include <stdio.h> | ||
406 | int X11_GetWMInfo(_THIS, SDL_SysWMinfo *info) | ||
407 | { | ||
408 | if ( info->version.major <= SDL_MAJOR_VERSION ) { | ||
409 | info->subsystem = SDL_SYSWM_X11; | ||
410 | info->info.x11.display = SDL_Display; | ||
411 | info->info.x11.window = SDL_Window; | ||
412 | if ( SDL_VERSIONNUM(info->version.major, | ||
413 | info->version.minor, | ||
414 | info->version.patch) >= 1002 ) { | ||
415 | info->info.x11.fswindow = FSwindow; | ||
416 | info->info.x11.wmwindow = WMwindow; | ||
417 | } | ||
418 | |||
419 | |||
420 | if ( SDL_VERSIONNUM(info->version.major, | ||
421 | info->version.minor, | ||
422 | info->version.patch) >= 1212 ) { | ||
423 | info->info.x11.gfxdisplay = GFX_Display; | ||
424 | } | ||
425 | |||
426 | info->info.x11.lock_func = lock_display; | ||
427 | info->info.x11.unlock_func = unlock_display; | ||
428 | return(1); | ||
429 | } else { | ||
430 | SDL_SetError("Application not compiled with SDL %d.%d\n", | ||
431 | SDL_MAJOR_VERSION, SDL_MINOR_VERSION); | ||
432 | return(-1); | ||
433 | } | ||
434 | } | ||