Mercurial > sdl-ios-xcode
annotate src/video/x11/SDL_x11video.c @ 1125:a6011e1394d9
Apparently MacOS X will sometimes pass command line arguments to a Cocoa
app as an openFile() message, so we have to make sure we were launched from
the Finder before accepting these as drag'n'drop documents, or they will just
duplicate what's already in argc/argv.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Mon, 22 Aug 2005 14:18:15 +0000 |
parents | 5c7859610bc4 |
children | 045f186426e1 |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
769
b8d311d90021
Updated copyright information for 2004 (Happy New Year!)
Sam Lantinga <slouken@libsdl.org>
parents:
556
diff
changeset
|
3 Copyright (C) 1997-2004 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 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 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
236
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 /* X11 based SDL video driver implementation. | |
29 Note: This implementation does not currently need X11 thread locking, | |
30 since the event thread uses a separate X connection and any | |
31 additional locking necessary is handled internally. However, | |
32 if full locking is neccessary, take a look at XInitThreads(). | |
33 */ | |
34 | |
35 #include <stdlib.h> | |
36 #include <stdio.h> | |
37 #include <unistd.h> | |
38 #include <string.h> | |
39 #include <sys/ioctl.h> | |
40 #ifdef MTRR_SUPPORT | |
41 #include <asm/mtrr.h> | |
42 #include <sys/fcntl.h> | |
43 #endif | |
44 | |
45 #ifdef HAVE_ALLOCA_H | |
46 #include <alloca.h> | |
47 #endif | |
48 | |
49 #ifdef HAVE_ALLOCA | |
50 #define ALLOCA(n) ((void*)alloca(n)) | |
51 #define FREEA(p) | |
52 #else | |
53 #define ALLOCA(n) malloc(n) | |
54 #define FREEA(p) free(p) | |
55 #endif | |
56 | |
57 #include "SDL.h" | |
58 #include "SDL_error.h" | |
59 #include "SDL_timer.h" | |
60 #include "SDL_thread.h" | |
61 #include "SDL_video.h" | |
62 #include "SDL_mouse.h" | |
63 #include "SDL_endian.h" | |
64 #include "SDL_sysvideo.h" | |
65 #include "SDL_pixels_c.h" | |
66 #include "SDL_events_c.h" | |
67 #include "SDL_x11video.h" | |
68 #include "SDL_x11wm_c.h" | |
69 #include "SDL_x11mouse_c.h" | |
70 #include "SDL_x11events_c.h" | |
71 #include "SDL_x11modes_c.h" | |
72 #include "SDL_x11image_c.h" | |
73 #include "SDL_x11yuv_c.h" | |
74 #include "SDL_x11gl_c.h" | |
75 #include "SDL_x11gamma_c.h" | |
76 #include "blank_cursor.h" | |
77 | |
78 /* Initialization/Query functions */ | |
79 static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat); | |
80 static SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); | |
81 static int X11_ToggleFullScreen(_THIS, int on); | |
82 static void X11_UpdateMouse(_THIS); | |
83 static int X11_SetColors(_THIS, int firstcolor, int ncolors, | |
84 SDL_Color *colors); | |
85 static int X11_SetGammaRamp(_THIS, Uint16 *ramp); | |
86 static void X11_VideoQuit(_THIS); | |
87 | |
88 /* X11 driver bootstrap functions */ | |
89 | |
90 static int X11_Available(void) | |
91 { | |
92 Display *display; | |
93 | |
94 display = XOpenDisplay(NULL); | |
95 if ( display != NULL ) { | |
96 XCloseDisplay(display); | |
97 } | |
98 return(display != NULL); | |
99 } | |
100 | |
101 static void X11_DeleteDevice(SDL_VideoDevice *device) | |
102 { | |
103 if ( device ) { | |
104 if ( device->hidden ) { | |
105 free(device->hidden); | |
106 } | |
107 if ( device->gl_data ) { | |
108 free(device->gl_data); | |
109 } | |
110 free(device); | |
111 } | |
112 } | |
113 | |
114 static SDL_VideoDevice *X11_CreateDevice(int devindex) | |
115 { | |
116 SDL_VideoDevice *device; | |
117 | |
118 /* Initialize all variables that we clean on shutdown */ | |
119 device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice)); | |
120 if ( device ) { | |
121 memset(device, 0, (sizeof *device)); | |
122 device->hidden = (struct SDL_PrivateVideoData *) | |
123 malloc((sizeof *device->hidden)); | |
124 device->gl_data = (struct SDL_PrivateGLData *) | |
125 malloc((sizeof *device->gl_data)); | |
126 } | |
127 if ( (device == NULL) || (device->hidden == NULL) || | |
128 (device->gl_data == NULL) ) { | |
129 SDL_OutOfMemory(); | |
130 X11_DeleteDevice(device); | |
131 return(0); | |
132 } | |
133 memset(device->hidden, 0, (sizeof *device->hidden)); | |
134 memset(device->gl_data, 0, (sizeof *device->gl_data)); | |
135 | |
136 /* Set the driver flags */ | |
137 device->handles_any_size = 1; | |
138 | |
139 /* Set the function pointers */ | |
140 device->VideoInit = X11_VideoInit; | |
141 device->ListModes = X11_ListModes; | |
142 device->SetVideoMode = X11_SetVideoMode; | |
143 device->ToggleFullScreen = X11_ToggleFullScreen; | |
144 device->UpdateMouse = X11_UpdateMouse; | |
145 #ifdef XFREE86_XV | |
146 device->CreateYUVOverlay = X11_CreateYUVOverlay; | |
147 #endif | |
148 device->SetColors = X11_SetColors; | |
149 device->UpdateRects = NULL; | |
150 device->VideoQuit = X11_VideoQuit; | |
151 device->AllocHWSurface = X11_AllocHWSurface; | |
152 device->CheckHWBlit = NULL; | |
153 device->FillHWRect = NULL; | |
154 device->SetHWColorKey = NULL; | |
155 device->SetHWAlpha = NULL; | |
156 device->LockHWSurface = X11_LockHWSurface; | |
157 device->UnlockHWSurface = X11_UnlockHWSurface; | |
158 device->FlipHWSurface = X11_FlipHWSurface; | |
159 device->FreeHWSurface = X11_FreeHWSurface; | |
160 device->SetGamma = X11_SetVidModeGamma; | |
161 device->GetGamma = X11_GetVidModeGamma; | |
162 device->SetGammaRamp = X11_SetGammaRamp; | |
163 device->GetGammaRamp = NULL; | |
164 #ifdef HAVE_OPENGL | |
165 device->GL_LoadLibrary = X11_GL_LoadLibrary; | |
166 device->GL_GetProcAddress = X11_GL_GetProcAddress; | |
167 device->GL_GetAttribute = X11_GL_GetAttribute; | |
168 device->GL_MakeCurrent = X11_GL_MakeCurrent; | |
169 device->GL_SwapBuffers = X11_GL_SwapBuffers; | |
170 #endif | |
171 device->SetCaption = X11_SetCaption; | |
172 device->SetIcon = X11_SetIcon; | |
173 device->IconifyWindow = X11_IconifyWindow; | |
174 device->GrabInput = X11_GrabInput; | |
175 device->GetWMInfo = X11_GetWMInfo; | |
176 device->FreeWMCursor = X11_FreeWMCursor; | |
177 device->CreateWMCursor = X11_CreateWMCursor; | |
178 device->ShowWMCursor = X11_ShowWMCursor; | |
179 device->WarpWMCursor = X11_WarpWMCursor; | |
180 device->CheckMouseMode = X11_CheckMouseMode; | |
181 device->InitOSKeymap = X11_InitOSKeymap; | |
182 device->PumpEvents = X11_PumpEvents; | |
183 | |
184 device->free = X11_DeleteDevice; | |
185 | |
186 return device; | |
187 } | |
188 | |
189 VideoBootStrap X11_bootstrap = { | |
190 "x11", "X Window System", | |
191 X11_Available, X11_CreateDevice | |
192 }; | |
193 | |
194 /* Shared memory information */ | |
195 extern int XShmQueryExtension(Display *dpy); /* Not in X11 headers */ | |
196 | |
197 /* Normal X11 error handler routine */ | |
198 static int (*X_handler)(Display *, XErrorEvent *) = NULL; | |
199 static int x_errhandler(Display *d, XErrorEvent *e) | |
200 { | |
201 #ifdef XFREE86_VM | |
202 extern int vm_error; | |
203 #endif | |
204 #ifdef XFREE86_DGAMOUSE | |
205 extern int dga_error; | |
206 #endif | |
207 | |
208 #ifdef XFREE86_VM | |
209 /* VidMode errors are non-fatal. :) */ | |
210 /* Are the errors offset by one from the error base? | |
211 e.g. the error base is 143, the code is 148, and the | |
212 actual error is XF86VidModeExtensionDisabled (4) ? | |
213 */ | |
214 if ( (vm_error >= 0) && | |
215 (((e->error_code == BadRequest)&&(e->request_code == vm_error)) || | |
216 ((e->error_code > vm_error) && | |
217 (e->error_code <= (vm_error+XF86VidModeNumberErrors)))) ) { | |
218 #ifdef XFREE86_DEBUG | |
219 { char errmsg[1024]; | |
220 XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg)); | |
221 printf("VidMode error: %s\n", errmsg); | |
222 } | |
223 #endif | |
224 return(0); | |
225 } | |
226 #endif /* XFREE86_VM */ | |
227 | |
228 #ifdef XFREE86_DGAMOUSE | |
229 /* DGA errors can be non-fatal. :) */ | |
230 if ( (dga_error >= 0) && | |
231 ((e->error_code > dga_error) && | |
232 (e->error_code <= (dga_error+XF86DGANumberErrors))) ) { | |
233 #ifdef XFREE86_DEBUG | |
234 { char errmsg[1024]; | |
235 XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg)); | |
236 printf("DGA error: %s\n", errmsg); | |
237 } | |
238 #endif | |
239 return(0); | |
240 } | |
241 #endif /* XFREE86_DGAMOUSE */ | |
242 | |
243 return(X_handler(d,e)); | |
244 } | |
245 | |
246 /* X11 I/O error handler routine */ | |
247 static int (*XIO_handler)(Display *) = NULL; | |
248 static int xio_errhandler(Display *d) | |
249 { | |
250 /* Ack! Lost X11 connection! */ | |
251 | |
252 /* We will crash if we try to clean up our display */ | |
253 if ( current_video->hidden->Ximage ) { | |
254 SDL_VideoSurface->pixels = NULL; | |
255 } | |
256 current_video->hidden->X11_Display = NULL; | |
257 | |
258 /* Continue with the standard X11 error handler */ | |
259 return(XIO_handler(d)); | |
260 } | |
261 | |
262 /* Create auxiliary (toplevel) windows with the current visual */ | |
263 static void create_aux_windows(_THIS) | |
264 { | |
265 XSetWindowAttributes xattr; | |
266 XWMHints *hints; | |
267 XTextProperty titleprop, iconprop; | |
268 int def_vis = (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen)); | |
269 | |
270 /* Don't create any extra windows if we are being managed */ | |
271 if ( SDL_windowid ) { | |
272 FSwindow = 0; | |
273 WMwindow = strtol(SDL_windowid, NULL, 0); | |
274 return; | |
275 } | |
276 | |
277 if(FSwindow) | |
278 XDestroyWindow(SDL_Display, FSwindow); | |
279 | |
280 xattr.override_redirect = True; | |
281 xattr.background_pixel = def_vis ? BlackPixel(SDL_Display, SDL_Screen) : 0; | |
282 xattr.border_pixel = 0; | |
283 xattr.colormap = SDL_XColorMap; | |
284 | |
499
f480ecd70499
Added an aborted try at making fullscreen work on Xinerama screen != 0
Sam Lantinga <slouken@libsdl.org>
parents:
497
diff
changeset
|
285 FSwindow = XCreateWindow(SDL_Display, SDL_Root, |
f480ecd70499
Added an aborted try at making fullscreen work on Xinerama screen != 0
Sam Lantinga <slouken@libsdl.org>
parents:
497
diff
changeset
|
286 xinerama_x, xinerama_y, 32, 32, 0, |
0 | 287 this->hidden->depth, InputOutput, SDL_Visual, |
288 CWOverrideRedirect | CWBackPixel | CWBorderPixel | |
289 | CWColormap, | |
290 &xattr); | |
291 | |
292 XSelectInput(SDL_Display, FSwindow, StructureNotifyMask); | |
293 | |
294 /* Tell KDE to keep the fullscreen window on top */ | |
295 { | |
296 XEvent ev; | |
297 long mask; | |
298 | |
299 memset(&ev, 0, sizeof(ev)); | |
300 ev.xclient.type = ClientMessage; | |
301 ev.xclient.window = SDL_Root; | |
302 ev.xclient.message_type = XInternAtom(SDL_Display, | |
303 "KWM_KEEP_ON_TOP", False); | |
304 ev.xclient.format = 32; | |
305 ev.xclient.data.l[0] = FSwindow; | |
306 ev.xclient.data.l[1] = CurrentTime; | |
307 mask = SubstructureRedirectMask; | |
308 XSendEvent(SDL_Display, SDL_Root, False, mask, &ev); | |
309 } | |
310 | |
311 hints = NULL; | |
312 titleprop.value = iconprop.value = NULL; | |
313 if(WMwindow) { | |
314 /* All window attributes must survive the recreation */ | |
315 hints = XGetWMHints(SDL_Display, WMwindow); | |
316 XGetWMName(SDL_Display, WMwindow, &titleprop); | |
317 XGetWMIconName(SDL_Display, WMwindow, &iconprop); | |
318 XDestroyWindow(SDL_Display, WMwindow); | |
319 } | |
320 | |
321 /* Create the window for windowed management */ | |
322 /* (reusing the xattr structure above) */ | |
323 WMwindow = XCreateWindow(SDL_Display, SDL_Root, 0, 0, 32, 32, 0, | |
324 this->hidden->depth, InputOutput, SDL_Visual, | |
325 CWBackPixel | CWBorderPixel | CWColormap, | |
326 &xattr); | |
327 | |
328 /* Set the input hints so we get keyboard input */ | |
329 if(!hints) { | |
330 hints = XAllocWMHints(); | |
331 hints->input = True; | |
332 hints->flags = InputHint; | |
333 } | |
334 XSetWMHints(SDL_Display, WMwindow, hints); | |
335 XFree(hints); | |
336 if(titleprop.value) { | |
337 XSetWMName(SDL_Display, WMwindow, &titleprop); | |
338 XFree(titleprop.value); | |
339 } | |
340 if(iconprop.value) { | |
341 XSetWMIconName(SDL_Display, WMwindow, &iconprop); | |
342 XFree(iconprop.value); | |
343 } | |
344 | |
345 XSelectInput(SDL_Display, WMwindow, | |
346 FocusChangeMask | KeyPressMask | KeyReleaseMask | |
347 | PropertyChangeMask | StructureNotifyMask | KeymapStateMask); | |
348 | |
349 /* Set the class hints so we can get an icon (AfterStep) */ | |
350 { | |
351 XClassHint *classhints; | |
352 classhints = XAllocClassHint(); | |
353 if(classhints != NULL) { | |
449
8a687496061f
Added an environment variable SDL_VIDEO_X11_WMCLASS
Sam Lantinga <slouken@libsdl.org>
parents:
444
diff
changeset
|
354 char *classname = getenv("SDL_VIDEO_X11_WMCLASS"); |
8a687496061f
Added an environment variable SDL_VIDEO_X11_WMCLASS
Sam Lantinga <slouken@libsdl.org>
parents:
444
diff
changeset
|
355 if ( ! classname ) { |
8a687496061f
Added an environment variable SDL_VIDEO_X11_WMCLASS
Sam Lantinga <slouken@libsdl.org>
parents:
444
diff
changeset
|
356 classname = "SDL_App"; |
8a687496061f
Added an environment variable SDL_VIDEO_X11_WMCLASS
Sam Lantinga <slouken@libsdl.org>
parents:
444
diff
changeset
|
357 } |
8a687496061f
Added an environment variable SDL_VIDEO_X11_WMCLASS
Sam Lantinga <slouken@libsdl.org>
parents:
444
diff
changeset
|
358 classhints->res_name = classname; |
8a687496061f
Added an environment variable SDL_VIDEO_X11_WMCLASS
Sam Lantinga <slouken@libsdl.org>
parents:
444
diff
changeset
|
359 classhints->res_class = classname; |
0 | 360 XSetClassHint(SDL_Display, WMwindow, classhints); |
361 XFree(classhints); | |
362 } | |
363 } | |
364 | |
365 /* Allow the window to be deleted by the window manager */ | |
366 WM_DELETE_WINDOW = XInternAtom(SDL_Display, "WM_DELETE_WINDOW", False); | |
367 XSetWMProtocols(SDL_Display, WMwindow, &WM_DELETE_WINDOW, 1); | |
368 } | |
369 | |
370 static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat) | |
371 { | |
372 char *display; | |
373 int i; | |
374 | |
375 /* Open the X11 display */ | |
376 display = NULL; /* Get it from DISPLAY environment variable */ | |
377 | |
378 if ( (strncmp(XDisplayName(display), ":", 1) == 0) || | |
379 (strncmp(XDisplayName(display), "unix:", 5) == 0) ) { | |
380 local_X11 = 1; | |
381 } else { | |
382 local_X11 = 0; | |
383 } | |
384 SDL_Display = XOpenDisplay(display); | |
385 if ( SDL_Display == NULL ) { | |
386 SDL_SetError("Couldn't open X11 display"); | |
387 return(-1); | |
388 } | |
389 #ifdef X11_DEBUG | |
390 XSynchronize(SDL_Display, True); | |
391 #endif | |
392 | |
393 /* Create an alternate X display for graphics updates -- allows us | |
394 to do graphics updates in a separate thread from event handling. | |
395 Thread-safe X11 doesn't seem to exist. | |
396 */ | |
397 GFX_Display = XOpenDisplay(display); | |
398 if ( GFX_Display == NULL ) { | |
399 SDL_SetError("Couldn't open X11 display"); | |
400 return(-1); | |
401 } | |
402 | |
403 /* Set the normal X error handler */ | |
404 X_handler = XSetErrorHandler(x_errhandler); | |
405 | |
406 /* Set the error handler if we lose the X display */ | |
407 XIO_handler = XSetIOErrorHandler(xio_errhandler); | |
408 | |
409 /* use default screen (from $DISPLAY) */ | |
410 SDL_Screen = DefaultScreen(SDL_Display); | |
411 | |
412 #ifndef NO_SHARED_MEMORY | |
413 /* Check for MIT shared memory extension */ | |
556
08588ee79a67
Fixed compile error if there is no X11 shared memory support.
Sam Lantinga <slouken@libsdl.org>
parents:
499
diff
changeset
|
414 use_mitshm = 0; |
0 | 415 if ( local_X11 ) { |
416 use_mitshm = XShmQueryExtension(SDL_Display); | |
417 } | |
418 #endif /* NO_SHARED_MEMORY */ | |
419 | |
420 /* Get the available video modes */ | |
421 if(X11_GetVideoModes(this) < 0) | |
422 return -1; | |
423 | |
424 /* Determine the default screen depth: | |
425 Use the default visual (or at least one with the same depth) */ | |
426 SDL_DisplayColormap = DefaultColormap(SDL_Display, SDL_Screen); | |
427 for(i = 0; i < this->hidden->nvisuals; i++) | |
428 if(this->hidden->visuals[i].depth == DefaultDepth(SDL_Display, | |
429 SDL_Screen)) | |
430 break; | |
431 if(i == this->hidden->nvisuals) { | |
432 /* default visual was useless, take the deepest one instead */ | |
433 i = 0; | |
434 } | |
435 SDL_Visual = this->hidden->visuals[i].visual; | |
436 if ( SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen) ) { | |
437 SDL_XColorMap = SDL_DisplayColormap; | |
438 } else { | |
439 SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, | |
440 SDL_Visual, AllocNone); | |
441 } | |
442 this->hidden->depth = this->hidden->visuals[i].depth; | |
443 vformat->BitsPerPixel = this->hidden->visuals[i].bpp; | |
444 if ( vformat->BitsPerPixel > 8 ) { | |
445 vformat->Rmask = SDL_Visual->red_mask; | |
446 vformat->Gmask = SDL_Visual->green_mask; | |
447 vformat->Bmask = SDL_Visual->blue_mask; | |
448 } | |
449 X11_SaveVidModeGamma(this); | |
450 | |
451 /* See if we have been passed a window to use */ | |
452 SDL_windowid = getenv("SDL_WINDOWID"); | |
453 | |
454 /* Create the fullscreen and managed windows */ | |
455 create_aux_windows(this); | |
456 | |
457 /* Create the blank cursor */ | |
458 SDL_BlankCursor = this->CreateWMCursor(this, blank_cdata, blank_cmask, | |
459 BLANK_CWIDTH, BLANK_CHEIGHT, | |
460 BLANK_CHOTX, BLANK_CHOTY); | |
461 | |
462 /* Fill in some window manager capabilities */ | |
463 this->info.wm_available = 1; | |
464 | |
465 /* We're done! */ | |
466 XFlush(SDL_Display); | |
467 return(0); | |
468 } | |
469 | |
470 static void X11_DestroyWindow(_THIS, SDL_Surface *screen) | |
471 { | |
472 /* Clean up OpenGL */ | |
473 if ( screen ) { | |
474 screen->flags &= ~(SDL_OPENGL|SDL_OPENGLBLIT); | |
475 } | |
476 X11_GL_Shutdown(this); | |
477 | |
478 if ( ! SDL_windowid ) { | |
479 /* Hide the managed window */ | |
480 if ( WMwindow ) { | |
481 XUnmapWindow(SDL_Display, WMwindow); | |
482 } | |
483 if ( screen && (screen->flags & SDL_FULLSCREEN) ) { | |
484 screen->flags &= ~SDL_FULLSCREEN; | |
485 X11_LeaveFullScreen(this); | |
486 } | |
487 | |
488 /* Destroy the output window */ | |
489 if ( SDL_Window ) { | |
490 XDestroyWindow(SDL_Display, SDL_Window); | |
491 } | |
492 | |
493 /* Free the colormap entries */ | |
494 if ( SDL_XPixels ) { | |
495 int numcolors; | |
496 unsigned long pixel; | |
497 numcolors = SDL_Visual->map_entries; | |
498 for ( pixel=0; pixel<numcolors; ++pixel ) { | |
499 while ( SDL_XPixels[pixel] > 0 ) { | |
500 XFreeColors(GFX_Display, | |
501 SDL_DisplayColormap,&pixel,1,0); | |
502 --SDL_XPixels[pixel]; | |
503 } | |
504 } | |
505 free(SDL_XPixels); | |
506 SDL_XPixels = NULL; | |
507 } | |
508 | |
509 /* Free the graphics context */ | |
510 if ( SDL_GC ) { | |
511 XFreeGC(SDL_Display, SDL_GC); | |
512 SDL_GC = 0; | |
513 } | |
514 } | |
515 } | |
516 | |
497
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
517 static SDL_bool X11_WindowPosition(_THIS, int *x, int *y, int w, int h) |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
518 { |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
519 const char *window = getenv("SDL_VIDEO_WINDOW_POS"); |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
520 const char *center = getenv("SDL_VIDEO_CENTERED"); |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
521 if ( window ) { |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
522 if ( sscanf(window, "%d,%d", x, y) == 2 ) { |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
523 return SDL_TRUE; |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
524 } |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
525 if ( strcmp(window, "center") == 0 ) { |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
526 center = window; |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
527 } |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
528 } |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
529 if ( center ) { |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
530 *x = (DisplayWidth(SDL_Display, SDL_Screen) - w)/2; |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
531 *y = (DisplayHeight(SDL_Display, SDL_Screen) - h)/2; |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
532 return SDL_TRUE; |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
533 } |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
534 return SDL_FALSE; |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
535 } |
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
536 |
0 | 537 static void X11_SetSizeHints(_THIS, int w, int h, Uint32 flags) |
538 { | |
539 XSizeHints *hints; | |
540 | |
541 hints = XAllocSizeHints(); | |
542 if ( hints ) { | |
543 if ( flags & SDL_RESIZABLE ) { | |
544 hints->min_width = 32; | |
545 hints->min_height = 32; | |
546 hints->max_height = 4096; | |
547 hints->max_width = 4096; | |
548 } else { | |
549 hints->min_width = hints->max_width = w; | |
550 hints->min_height = hints->max_height = h; | |
551 } | |
552 hints->flags = PMaxSize | PMinSize; | |
553 if ( flags & SDL_FULLSCREEN ) { | |
554 hints->x = 0; | |
555 hints->y = 0; | |
556 hints->flags |= USPosition; | |
557 } else | |
558 /* Center it, if desired */ | |
497
bb2d68294e81
Cleaned up the SDL_VIDEO_WINDOW_POS variable support
Sam Lantinga <slouken@libsdl.org>
parents:
485
diff
changeset
|
559 if ( X11_WindowPosition(this, &hints->x, &hints->y, w, h) ) { |
0 | 560 hints->flags |= USPosition; |
561 XMoveWindow(SDL_Display, WMwindow, hints->x, hints->y); | |
562 | |
563 /* Flush the resize event so we don't catch it later */ | |
564 XSync(SDL_Display, True); | |
565 } | |
566 XSetWMNormalHints(SDL_Display, WMwindow, hints); | |
567 XFree(hints); | |
568 } | |
569 | |
570 /* Respect the window caption style */ | |
571 if ( flags & SDL_NOFRAME ) { | |
572 SDL_bool set; | |
573 Atom WM_HINTS; | |
574 | |
575 /* We haven't modified the window manager hints yet */ | |
576 set = SDL_FALSE; | |
577 | |
578 /* First try to set MWM hints */ | |
579 WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True); | |
580 if ( WM_HINTS != None ) { | |
581 /* Hints used by Motif compliant window managers */ | |
582 struct { | |
583 unsigned long flags; | |
584 unsigned long functions; | |
585 unsigned long decorations; | |
586 long input_mode; | |
587 unsigned long status; | |
588 } MWMHints = { (1L << 1), 0, 0, 0, 0 }; | |
589 | |
590 XChangeProperty(SDL_Display, WMwindow, | |
591 WM_HINTS, WM_HINTS, 32, | |
592 PropModeReplace, | |
593 (unsigned char *)&MWMHints, | |
594 sizeof(MWMHints)/sizeof(long)); | |
595 set = SDL_TRUE; | |
596 } | |
597 /* Now try to set KWM hints */ | |
598 WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True); | |
599 if ( WM_HINTS != None ) { | |
600 long KWMHints = 0; | |
601 | |
602 XChangeProperty(SDL_Display, WMwindow, | |
603 WM_HINTS, WM_HINTS, 32, | |
604 PropModeReplace, | |
605 (unsigned char *)&KWMHints, | |
606 sizeof(KWMHints)/sizeof(long)); | |
607 set = SDL_TRUE; | |
608 } | |
609 /* Now try to set GNOME hints */ | |
610 WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True); | |
611 if ( WM_HINTS != None ) { | |
612 long GNOMEHints = 0; | |
613 | |
614 XChangeProperty(SDL_Display, WMwindow, | |
615 WM_HINTS, WM_HINTS, 32, | |
616 PropModeReplace, | |
617 (unsigned char *)&GNOMEHints, | |
618 sizeof(GNOMEHints)/sizeof(long)); | |
619 set = SDL_TRUE; | |
620 } | |
621 /* Finally set the transient hints if necessary */ | |
622 if ( ! set ) { | |
623 XSetTransientForHint(SDL_Display, WMwindow, SDL_Root); | |
624 } | |
625 } else { | |
626 SDL_bool set; | |
627 Atom WM_HINTS; | |
628 | |
629 /* We haven't modified the window manager hints yet */ | |
630 set = SDL_FALSE; | |
631 | |
632 /* First try to unset MWM hints */ | |
633 WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True); | |
634 if ( WM_HINTS != None ) { | |
635 XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); | |
636 set = SDL_TRUE; | |
637 } | |
638 /* Now try to unset KWM hints */ | |
639 WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True); | |
640 if ( WM_HINTS != None ) { | |
641 XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); | |
642 set = SDL_TRUE; | |
643 } | |
644 /* Now try to unset GNOME hints */ | |
645 WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True); | |
646 if ( WM_HINTS != None ) { | |
647 XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); | |
648 set = SDL_TRUE; | |
649 } | |
650 /* Finally unset the transient hints if necessary */ | |
651 if ( ! set ) { | |
652 /* NOTE: Does this work? */ | |
653 XSetTransientForHint(SDL_Display, WMwindow, None); | |
654 } | |
655 } | |
656 } | |
657 | |
658 static int X11_CreateWindow(_THIS, SDL_Surface *screen, | |
659 int w, int h, int bpp, Uint32 flags) | |
660 { | |
661 int i, depth; | |
662 Visual *vis; | |
663 int vis_change; | |
664 | |
665 /* If a window is already present, destroy it and start fresh */ | |
666 if ( SDL_Window ) { | |
667 X11_DestroyWindow(this, screen); | |
860
2bac79e27868
Create a 2D window and then manually focus a different window on your desktop,
Ryan C. Gordon <icculus@icculus.org>
parents:
769
diff
changeset
|
668 switch_waiting = 0; /* Prevent jump back to now-meaningless state. */ |
0 | 669 } |
670 | |
671 /* See if we have been given a window id */ | |
672 if ( SDL_windowid ) { | |
673 SDL_Window = strtol(SDL_windowid, NULL, 0); | |
674 } else { | |
675 SDL_Window = 0; | |
676 } | |
677 | |
678 /* find out which visual we are going to use */ | |
679 if ( flags & SDL_OPENGL ) { | |
680 XVisualInfo *vi; | |
681 | |
682 vi = X11_GL_GetVisual(this); | |
683 if( !vi ) { | |
684 return -1; | |
685 } | |
686 vis = vi->visual; | |
687 depth = vi->depth; | |
688 } else if ( SDL_windowid ) { | |
689 XWindowAttributes a; | |
690 | |
691 XGetWindowAttributes(SDL_Display, SDL_Window, &a); | |
692 vis = a.visual; | |
693 depth = a.depth; | |
694 } else { | |
695 for ( i = 0; i < this->hidden->nvisuals; i++ ) { | |
696 if ( this->hidden->visuals[i].bpp == bpp ) | |
697 break; | |
698 } | |
699 if ( i == this->hidden->nvisuals ) { | |
700 SDL_SetError("No matching visual for requested depth"); | |
701 return -1; /* should never happen */ | |
702 } | |
703 vis = this->hidden->visuals[i].visual; | |
704 depth = this->hidden->visuals[i].depth; | |
705 } | |
706 #ifdef X11_DEBUG | |
707 printf("Choosing %s visual at %d bpp - %d colormap entries\n", vis->class == PseudoColor ? "PseudoColor" : (vis->class == TrueColor ? "TrueColor" : (vis->class == DirectColor ? "DirectColor" : "Unknown")), depth, vis->map_entries); | |
708 #endif | |
709 vis_change = (vis != SDL_Visual); | |
710 SDL_Visual = vis; | |
711 this->hidden->depth = depth; | |
712 | |
713 /* Allocate the new pixel format for this video mode */ | |
714 if ( ! SDL_ReallocFormat(screen, bpp, | |
715 vis->red_mask, vis->green_mask, vis->blue_mask, 0) ) | |
716 return -1; | |
717 | |
718 /* Create the appropriate colormap */ | |
719 if ( SDL_XColorMap != SDL_DisplayColormap ) { | |
720 XFreeColormap(SDL_Display, SDL_XColorMap); | |
721 } | |
722 if ( SDL_Visual->class == PseudoColor ) { | |
723 int ncolors; | |
724 | |
725 /* Allocate the pixel flags */ | |
726 ncolors = SDL_Visual->map_entries; | |
727 SDL_XPixels = malloc(ncolors * sizeof(int)); | |
728 if(SDL_XPixels == NULL) { | |
729 SDL_OutOfMemory(); | |
730 return -1; | |
731 } | |
732 memset(SDL_XPixels, 0, ncolors * sizeof(*SDL_XPixels)); | |
733 | |
734 /* always allocate a private colormap on non-default visuals */ | |
735 if ( SDL_Visual != DefaultVisual(SDL_Display, SDL_Screen) ) { | |
736 flags |= SDL_HWPALETTE; | |
737 } | |
738 if ( flags & SDL_HWPALETTE ) { | |
739 screen->flags |= SDL_HWPALETTE; | |
740 SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, | |
741 SDL_Visual, AllocAll); | |
742 } else { | |
743 SDL_XColorMap = SDL_DisplayColormap; | |
744 } | |
745 } else if ( SDL_Visual->class == DirectColor ) { | |
746 | |
747 /* Create a colormap which we can manipulate for gamma */ | |
748 SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, | |
749 SDL_Visual, AllocAll); | |
750 XSync(SDL_Display, False); | |
751 | |
752 /* Initialize the colormap to the identity mapping */ | |
753 SDL_GetGammaRamp(0, 0, 0); | |
754 this->screen = screen; | |
755 X11_SetGammaRamp(this, this->gamma); | |
756 this->screen = NULL; | |
757 } else { | |
758 /* Create a read-only colormap for our window */ | |
759 SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, | |
760 SDL_Visual, AllocNone); | |
761 } | |
762 | |
763 /* Recreate the auxiliary windows, if needed (required for GL) */ | |
764 if ( vis_change ) | |
765 create_aux_windows(this); | |
766 | |
767 if(screen->flags & SDL_HWPALETTE) { | |
768 /* Since the full-screen window might have got a nonzero background | |
769 colour (0 is white on some displays), we should reset the | |
770 background to 0 here since that is what the user expects | |
771 with a private colormap */ | |
772 XSetWindowBackground(SDL_Display, FSwindow, 0); | |
773 XClearWindow(SDL_Display, FSwindow); | |
774 } | |
775 | |
776 /* resize the (possibly new) window manager window */ | |
777 if( !SDL_windowid ) { | |
778 X11_SetSizeHints(this, w, h, flags); | |
779 current_w = w; | |
780 current_h = h; | |
781 XResizeWindow(SDL_Display, WMwindow, w, h); | |
782 } | |
783 | |
784 /* Create (or use) the X11 display window */ | |
785 if ( !SDL_windowid ) { | |
786 if ( flags & SDL_OPENGL ) { | |
787 if ( X11_GL_CreateWindow(this, w, h) < 0 ) { | |
788 return(-1); | |
789 } | |
790 } else { | |
791 XSetWindowAttributes swa; | |
792 | |
793 swa.background_pixel = 0; | |
794 swa.border_pixel = 0; | |
795 swa.colormap = SDL_XColorMap; | |
796 SDL_Window = XCreateWindow(SDL_Display, WMwindow, | |
797 0, 0, w, h, 0, depth, | |
798 InputOutput, SDL_Visual, | |
799 CWBackPixel | CWBorderPixel | |
800 | CWColormap, &swa); | |
801 } | |
802 /* Only manage our input if we own the window */ | |
803 XSelectInput(SDL_Display, SDL_Window, | |
804 ( EnterWindowMask | LeaveWindowMask | |
805 | ButtonPressMask | ButtonReleaseMask | |
806 | PointerMotionMask | ExposureMask )); | |
807 } | |
808 | |
809 /* Create the graphics context here, once we have a window */ | |
810 if ( flags & SDL_OPENGL ) { | |
811 if ( X11_GL_CreateContext(this) < 0 ) { | |
812 return(-1); | |
813 } else { | |
814 screen->flags |= SDL_OPENGL; | |
815 } | |
816 } else { | |
817 XGCValues gcv; | |
818 | |
819 gcv.graphics_exposures = False; | |
820 SDL_GC = XCreateGC(SDL_Display, SDL_Window, | |
821 GCGraphicsExposures, &gcv); | |
822 if ( ! SDL_GC ) { | |
823 SDL_SetError("Couldn't create graphics context"); | |
824 return(-1); | |
825 } | |
826 } | |
827 | |
828 /* Set our colormaps when not setting a GL mode */ | |
829 if ( ! (flags & SDL_OPENGL) ) { | |
830 XSetWindowColormap(SDL_Display, SDL_Window, SDL_XColorMap); | |
831 if( !SDL_windowid ) { | |
832 XSetWindowColormap(SDL_Display, FSwindow, SDL_XColorMap); | |
833 XSetWindowColormap(SDL_Display, WMwindow, SDL_XColorMap); | |
834 } | |
835 } | |
836 | |
837 #if 0 /* This is an experiment - are the graphics faster now? - nope. */ | |
838 if ( getenv("SDL_VIDEO_X11_BACKINGSTORE") ) | |
839 #endif | |
840 /* Cache the window in the server, when possible */ | |
841 { | |
842 Screen *xscreen; | |
843 XSetWindowAttributes a; | |
844 | |
845 xscreen = ScreenOfDisplay(SDL_Display, SDL_Screen); | |
846 a.backing_store = DoesBackingStore(xscreen); | |
847 if ( a.backing_store != NotUseful ) { | |
848 XChangeWindowAttributes(SDL_Display, SDL_Window, | |
849 CWBackingStore, &a); | |
850 } | |
851 } | |
852 | |
853 /* Update the internal keyboard state */ | |
854 X11_SetKeyboardState(SDL_Display, NULL); | |
855 | |
444
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
856 /* When the window is first mapped, ignore non-modifier keys */ |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
857 { |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
858 Uint8 *keys = SDL_GetKeyState(NULL); |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
859 for ( i = 0; i < SDLK_LAST; ++i ) { |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
860 switch (i) { |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
861 case SDLK_NUMLOCK: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
862 case SDLK_CAPSLOCK: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
863 case SDLK_LCTRL: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
864 case SDLK_RCTRL: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
865 case SDLK_LSHIFT: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
866 case SDLK_RSHIFT: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
867 case SDLK_LALT: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
868 case SDLK_RALT: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
869 case SDLK_LMETA: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
870 case SDLK_RMETA: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
871 case SDLK_MODE: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
872 break; |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
873 default: |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
874 keys[i] = SDL_RELEASED; |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
875 break; |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
876 } |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
877 } |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
878 } |
406b12a17b15
Only modifier key state is noted when X11 window opens
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
879 |
0 | 880 /* Map them both and go fullscreen, if requested */ |
881 if ( ! SDL_windowid ) { | |
882 XMapWindow(SDL_Display, SDL_Window); | |
883 XMapWindow(SDL_Display, WMwindow); | |
160 | 884 X11_WaitMapped(this, WMwindow); |
0 | 885 if ( flags & SDL_FULLSCREEN ) { |
886 screen->flags |= SDL_FULLSCREEN; | |
887 X11_EnterFullScreen(this); | |
888 } else { | |
889 screen->flags &= ~SDL_FULLSCREEN; | |
890 } | |
891 } | |
892 return(0); | |
893 } | |
894 | |
895 static int X11_ResizeWindow(_THIS, | |
896 SDL_Surface *screen, int w, int h, Uint32 flags) | |
897 { | |
898 if ( ! SDL_windowid ) { | |
899 /* Resize the window manager window */ | |
900 X11_SetSizeHints(this, w, h, flags); | |
901 current_w = w; | |
902 current_h = h; | |
903 XResizeWindow(SDL_Display, WMwindow, w, h); | |
904 | |
905 /* Resize the fullscreen and display windows */ | |
906 if ( flags & SDL_FULLSCREEN ) { | |
907 if ( screen->flags & SDL_FULLSCREEN ) { | |
908 X11_ResizeFullScreen(this); | |
909 } else { | |
910 screen->flags |= SDL_FULLSCREEN; | |
911 X11_EnterFullScreen(this); | |
912 } | |
913 } else { | |
914 if ( screen->flags & SDL_FULLSCREEN ) { | |
915 screen->flags &= ~SDL_FULLSCREEN; | |
916 X11_LeaveFullScreen(this); | |
917 } | |
918 } | |
919 XResizeWindow(SDL_Display, SDL_Window, w, h); | |
920 } | |
921 return(0); | |
922 } | |
923 | |
924 SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, | |
925 int width, int height, int bpp, Uint32 flags) | |
926 { | |
927 Uint32 saved_flags; | |
928 | |
929 /* Lock the event thread, in multi-threading environments */ | |
930 SDL_Lock_EventThread(); | |
931 | |
932 /* Check the combination of flags we were passed */ | |
933 if ( flags & SDL_FULLSCREEN ) { | |
934 /* Clear fullscreen flag if not supported */ | |
935 if ( SDL_windowid ) { | |
936 flags &= ~SDL_FULLSCREEN; | |
937 } | |
938 } | |
939 | |
940 /* Flush any delayed updates */ | |
941 XSync(GFX_Display, False); | |
942 | |
943 /* Set up the X11 window */ | |
944 saved_flags = current->flags; | |
867
5c7859610bc4
Force recreation of X11 window if going to or from a SDL_NOFRAME vidmode.
Ryan C. Gordon <icculus@icculus.org>
parents:
860
diff
changeset
|
945 if ( (SDL_Window) && ((saved_flags&SDL_OPENGL) == (flags&SDL_OPENGL)) |
5c7859610bc4
Force recreation of X11 window if going to or from a SDL_NOFRAME vidmode.
Ryan C. Gordon <icculus@icculus.org>
parents:
860
diff
changeset
|
946 && (bpp == current->format->BitsPerPixel) |
5c7859610bc4
Force recreation of X11 window if going to or from a SDL_NOFRAME vidmode.
Ryan C. Gordon <icculus@icculus.org>
parents:
860
diff
changeset
|
947 && ((saved_flags&SDL_NOFRAME) == (flags&SDL_NOFRAME)) ) { |
0 | 948 if (X11_ResizeWindow(this, current, width, height, flags) < 0) { |
949 current = NULL; | |
950 goto done; | |
951 } | |
952 } else { | |
953 if (X11_CreateWindow(this,current,width,height,bpp,flags) < 0) { | |
954 current = NULL; | |
955 goto done; | |
956 } | |
957 } | |
958 | |
959 /* Set up the new mode framebuffer */ | |
960 if ( ((current->w != width) || (current->h != height)) || | |
961 ((saved_flags&SDL_OPENGL) != (flags&SDL_OPENGL)) ) { | |
962 current->w = width; | |
963 current->h = height; | |
964 current->pitch = SDL_CalculatePitch(current); | |
965 X11_ResizeImage(this, current, flags); | |
966 } | |
967 current->flags |= (flags&(SDL_RESIZABLE|SDL_NOFRAME)); | |
968 | |
969 done: | |
970 /* Release the event thread */ | |
971 XSync(SDL_Display, False); | |
972 SDL_Unlock_EventThread(); | |
973 | |
974 /* We're done! */ | |
975 return(current); | |
976 } | |
977 | |
978 static int X11_ToggleFullScreen(_THIS, int on) | |
979 { | |
980 Uint32 event_thread; | |
981 | |
982 /* Don't switch if we don't own the window */ | |
983 if ( SDL_windowid ) { | |
984 return(0); | |
985 } | |
986 | |
987 /* Don't lock if we are the event thread */ | |
988 event_thread = SDL_EventThreadID(); | |
989 if ( event_thread && (SDL_ThreadID() == event_thread) ) { | |
990 event_thread = 0; | |
991 } | |
992 if ( event_thread ) { | |
993 SDL_Lock_EventThread(); | |
994 } | |
995 if ( on ) { | |
996 this->screen->flags |= SDL_FULLSCREEN; | |
997 X11_EnterFullScreen(this); | |
998 } else { | |
999 this->screen->flags &= ~SDL_FULLSCREEN; | |
1000 X11_LeaveFullScreen(this); | |
1001 } | |
1002 X11_RefreshDisplay(this); | |
1003 if ( event_thread ) { | |
1004 SDL_Unlock_EventThread(); | |
1005 } | |
1006 SDL_ResetKeyboard(); | |
1007 return(1); | |
1008 } | |
1009 | |
1010 /* Update the current mouse state and position */ | |
1011 static void X11_UpdateMouse(_THIS) | |
1012 { | |
1013 Window u1; int u2; | |
1014 Window current_win; | |
1015 int x, y; | |
1016 unsigned int mask; | |
1017 | |
1018 /* Lock the event thread, in multi-threading environments */ | |
1019 SDL_Lock_EventThread(); | |
1020 if ( XQueryPointer(SDL_Display, SDL_Window, &u1, ¤t_win, | |
1021 &u2, &u2, &x, &y, &mask) ) { | |
1022 if ( (x >= 0) && (x < SDL_VideoSurface->w) && | |
1023 (y >= 0) && (y < SDL_VideoSurface->h) ) { | |
1024 SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); | |
1025 SDL_PrivateMouseMotion(0, 0, x, y); | |
1026 } else { | |
1027 SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); | |
1028 } | |
1029 } | |
1030 SDL_Unlock_EventThread(); | |
1031 } | |
1032 | |
1033 /* simple colour distance metric. Supposed to be better than a plain | |
1034 Euclidian distance anyway. */ | |
1035 #define COLOUR_FACTOR 3 | |
1036 #define LIGHT_FACTOR 1 | |
1037 #define COLOUR_DIST(r1, g1, b1, r2, g2, b2) \ | |
1038 (COLOUR_FACTOR * (abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2)) \ | |
1039 + LIGHT_FACTOR * abs(r1 + g1 + b1 - (r2 + g2 + b2))) | |
1040 | |
1041 static void allocate_nearest(_THIS, SDL_Color *colors, | |
1042 SDL_Color *want, int nwant) | |
1043 { | |
1044 /* | |
1045 * There is no way to know which ones to choose from, so we retrieve | |
1046 * the entire colormap and try the nearest possible, until we find one | |
1047 * that is shared. | |
1048 */ | |
1049 XColor all[256]; | |
1050 int i; | |
1051 for(i = 0; i < 256; i++) | |
1052 all[i].pixel = i; | |
1053 /* | |
1054 * XQueryColors sets the flags in the XColor struct, so we use | |
1055 * that to keep track of which colours are available | |
1056 */ | |
1057 XQueryColors(GFX_Display, SDL_XColorMap, all, 256); | |
1058 | |
1059 for(i = 0; i < nwant; i++) { | |
1060 XColor *c; | |
1061 int j; | |
1062 int best = 0; | |
1063 int mindist = 0x7fffffff; | |
1064 int ri = want[i].r; | |
1065 int gi = want[i].g; | |
1066 int bi = want[i].b; | |
1067 for(j = 0; j < 256; j++) { | |
1068 int rj, gj, bj, d2; | |
1069 if(!all[j].flags) | |
1070 continue; /* unavailable colour cell */ | |
1071 rj = all[j].red >> 8; | |
1072 gj = all[j].green >> 8; | |
1073 bj = all[j].blue >> 8; | |
1074 d2 = COLOUR_DIST(ri, gi, bi, rj, gj, bj); | |
1075 if(d2 < mindist) { | |
1076 mindist = d2; | |
1077 best = j; | |
1078 } | |
1079 } | |
1080 if(SDL_XPixels[best]) | |
1081 continue; /* already allocated, waste no more time */ | |
1082 c = all + best; | |
1083 if(XAllocColor(GFX_Display, SDL_XColorMap, c)) { | |
1084 /* got it */ | |
236
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1085 colors[c->pixel].r = c->red >> 8; |
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1086 colors[c->pixel].g = c->green >> 8; |
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1087 colors[c->pixel].b = c->blue >> 8; |
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1088 ++SDL_XPixels[c->pixel]; |
0 | 1089 } else { |
1090 /* | |
1091 * The colour couldn't be allocated, probably being | |
1092 * owned as a r/w cell by another client. Flag it as | |
1093 * unavailable and try again. The termination of the | |
1094 * loop is guaranteed since at least black and white | |
1095 * are always there. | |
1096 */ | |
1097 c->flags = 0; | |
1098 i--; | |
1099 } | |
1100 } | |
1101 } | |
1102 | |
1103 int X11_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) | |
1104 { | |
1105 int nrej = 0; | |
1106 | |
1107 /* Check to make sure we have a colormap allocated */ | |
1108 if ( SDL_XPixels == NULL ) { | |
1109 return(0); | |
1110 } | |
1111 if ( (this->screen->flags & SDL_HWPALETTE) == SDL_HWPALETTE ) { | |
1112 /* private writable colormap: just set the colours we need */ | |
1113 XColor *xcmap; | |
1114 int i; | |
1115 xcmap = ALLOCA(ncolors*sizeof(*xcmap)); | |
1116 if(xcmap == NULL) | |
1117 return 0; | |
1118 for ( i=0; i<ncolors; ++i ) { | |
1119 xcmap[i].pixel = i + firstcolor; | |
1120 xcmap[i].red = (colors[i].r<<8)|colors[i].r; | |
1121 xcmap[i].green = (colors[i].g<<8)|colors[i].g; | |
1122 xcmap[i].blue = (colors[i].b<<8)|colors[i].b; | |
1123 xcmap[i].flags = (DoRed|DoGreen|DoBlue); | |
1124 } | |
1125 XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors); | |
1126 XSync(GFX_Display, False); | |
1127 FREEA(xcmap); | |
1128 } else { | |
1129 /* | |
1130 * Shared colormap: We only allocate read-only cells, which | |
1131 * increases the likelyhood of colour sharing with other | |
1132 * clients. The pixel values will almost certainly be | |
1133 * different from the requested ones, so the user has to | |
1134 * walk the colormap and see which index got what colour. | |
1135 * | |
1136 * We can work directly with the logical palette since it | |
1137 * has already been set when we get here. | |
1138 */ | |
1139 SDL_Color *want, *reject; | |
1140 unsigned long *freelist; | |
1141 int i; | |
1142 int nfree = 0; | |
1143 int nc = this->screen->format->palette->ncolors; | |
1144 colors = this->screen->format->palette->colors; | |
1145 freelist = ALLOCA(nc * sizeof(*freelist)); | |
1146 /* make sure multiple allocations of the same cell are freed */ | |
1147 for(i = 0; i < ncolors; i++) { | |
1148 int pixel = firstcolor + i; | |
1149 while(SDL_XPixels[pixel]) { | |
1150 freelist[nfree++] = pixel; | |
1151 --SDL_XPixels[pixel]; | |
1152 } | |
1153 } | |
1154 XFreeColors(GFX_Display, SDL_XColorMap, freelist, nfree, 0); | |
1155 FREEA(freelist); | |
1156 | |
1157 want = ALLOCA(ncolors * sizeof(SDL_Color)); | |
1158 reject = ALLOCA(ncolors * sizeof(SDL_Color)); | |
1159 memcpy(want, colors + firstcolor, ncolors * sizeof(SDL_Color)); | |
1160 /* make sure the user isn't fooled by her own wishes | |
1161 (black is safe, always available in the default colormap) */ | |
1162 memset(colors + firstcolor, 0, ncolors * sizeof(SDL_Color)); | |
1163 | |
1164 /* now try to allocate the colours */ | |
1165 for(i = 0; i < ncolors; i++) { | |
1166 XColor col; | |
1167 col.red = want[i].r << 8; | |
1168 col.green = want[i].g << 8; | |
1169 col.blue = want[i].b << 8; | |
1170 col.flags = DoRed | DoGreen | DoBlue; | |
1171 if(XAllocColor(GFX_Display, SDL_XColorMap, &col)) { | |
1172 /* We got the colour, or at least the nearest | |
1173 the hardware could get. */ | |
1174 colors[col.pixel].r = col.red >> 8; | |
1175 colors[col.pixel].g = col.green >> 8; | |
1176 colors[col.pixel].b = col.blue >> 8; | |
1177 ++SDL_XPixels[col.pixel]; | |
1178 } else { | |
1179 /* | |
1180 * no more free cells, add it to the list | |
1181 * of rejected colours | |
1182 */ | |
1183 reject[nrej++] = want[i]; | |
1184 } | |
1185 } | |
1186 if(nrej) | |
1187 allocate_nearest(this, colors, reject, nrej); | |
1188 FREEA(reject); | |
1189 FREEA(want); | |
1190 } | |
1191 return nrej == 0; | |
1192 } | |
1193 | |
1194 int X11_SetGammaRamp(_THIS, Uint16 *ramp) | |
1195 { | |
1196 int i, ncolors; | |
1197 XColor xcmap[256]; | |
1198 | |
1199 /* See if actually setting the gamma is supported */ | |
1200 if ( SDL_Visual->class != DirectColor ) { | |
1201 SDL_SetError("Gamma correction not supported on this visual"); | |
1202 return(-1); | |
1203 } | |
1204 | |
1205 /* Calculate the appropriate palette for the given gamma ramp */ | |
1206 ncolors = SDL_Visual->map_entries; | |
1207 for ( i=0; i<ncolors; ++i ) { | |
1208 Uint8 c = (256 * i / ncolors); | |
1209 xcmap[i].pixel = SDL_MapRGB(this->screen->format, c, c, c); | |
1210 xcmap[i].red = ramp[0*256+c]; | |
1211 xcmap[i].green = ramp[1*256+c]; | |
1212 xcmap[i].blue = ramp[2*256+c]; | |
1213 xcmap[i].flags = (DoRed|DoGreen|DoBlue); | |
1214 } | |
1215 XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors); | |
1216 XSync(GFX_Display, False); | |
1217 return(0); | |
1218 } | |
1219 | |
1220 /* Note: If we are terminated, this could be called in the middle of | |
1221 another SDL video routine -- notably UpdateRects. | |
1222 */ | |
1223 void X11_VideoQuit(_THIS) | |
1224 { | |
1225 /* Shutdown everything that's still up */ | |
1226 /* The event thread should be done, so we can touch SDL_Display */ | |
1227 if ( SDL_Display != NULL ) { | |
1228 /* Flush any delayed updates */ | |
1229 XSync(GFX_Display, False); | |
1230 | |
1231 /* Start shutting down the windows */ | |
1232 X11_DestroyImage(this, this->screen); | |
1233 X11_DestroyWindow(this, this->screen); | |
1234 X11_FreeVideoModes(this); | |
1235 if ( SDL_XColorMap != SDL_DisplayColormap ) { | |
1236 XFreeColormap(SDL_Display, SDL_XColorMap); | |
1237 } | |
1238 if ( SDL_iconcolors ) { | |
1239 unsigned long pixel; | |
236
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1240 Colormap dcmap = DefaultColormap(SDL_Display, |
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1241 SDL_Screen); |
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1242 for(pixel = 0; pixel < 256; ++pixel) { |
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1243 while(SDL_iconcolors[pixel] > 0) { |
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1244 XFreeColors(GFX_Display, |
3f09f52ac2cc
Fixed X11 icon color allocation (thanks Mattias!)
Sam Lantinga <slouken@libsdl.org>
parents:
160
diff
changeset
|
1245 dcmap, &pixel, 1, 0); |
0 | 1246 --SDL_iconcolors[pixel]; |
1247 } | |
1248 } | |
1249 free(SDL_iconcolors); | |
1250 SDL_iconcolors = NULL; | |
1251 } | |
1252 /* Restore gamma settings if they've changed */ | |
1253 if ( SDL_GetAppState() & SDL_APPACTIVE ) { | |
1254 X11_SwapVidModeGamma(this); | |
1255 } | |
1256 | |
1257 /* Free that blank cursor */ | |
1258 if ( SDL_BlankCursor != NULL ) { | |
1259 this->FreeWMCursor(this, SDL_BlankCursor); | |
1260 SDL_BlankCursor = NULL; | |
1261 } | |
1262 | |
1263 /* Close the X11 graphics connection */ | |
1264 if ( GFX_Display != NULL ) { | |
1265 XCloseDisplay(GFX_Display); | |
1266 GFX_Display = NULL; | |
1267 } | |
1268 | |
1269 /* Close the X11 display connection */ | |
1270 XCloseDisplay(SDL_Display); | |
1271 SDL_Display = NULL; | |
1272 | |
1273 /* Reset the X11 error handlers */ | |
1274 if ( XIO_handler ) { | |
1275 XSetIOErrorHandler(XIO_handler); | |
1276 } | |
1277 if ( X_handler ) { | |
1278 XSetErrorHandler(X_handler); | |
1279 } | |
1280 | |
1281 /* Unload GL library after X11 shuts down */ | |
1282 X11_GL_UnloadLibrary(this); | |
1283 } | |
1284 if ( this->screen && (this->screen->flags & SDL_HWSURFACE) ) { | |
1285 /* Direct screen access, no memory buffer */ | |
1286 this->screen->pixels = NULL; | |
1287 } | |
1288 } | |
1289 |