451ab91e |
1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2012 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 | |
22 | #include <SDL_surface.h> |
23 | |
24 | typedef struct |
25 | { |
26 | Uint8 *src; |
27 | int src_w, src_h; |
28 | int src_pitch; |
29 | int src_skip; |
30 | Uint8 *dst; |
31 | int dst_w, dst_h; |
32 | int dst_pitch; |
33 | int dst_skip; |
34 | SDL_PixelFormat *src_fmt; |
35 | SDL_PixelFormat *dst_fmt; |
36 | Uint8 *table; |
37 | int flags; |
38 | Uint32 colorkey; |
39 | Uint8 r, g, b, a; |
40 | } SDL_BlitInfo; |
41 | |
42 | /* Blit mapping definition */ |
43 | typedef struct SDL_BlitMap |
44 | { |
45 | SDL_Surface *dst; |
46 | int identity; |
47 | SDL_blit blit; |
48 | void *data; |
49 | SDL_BlitInfo info; |
50 | |
51 | /* the version count matches the destination; mismatch indicates |
52 | an invalid mapping */ |
53 | Uint32 dst_palette_version; |
54 | Uint32 src_palette_version; |
55 | } SDL_BlitMap; |
56 | |
57 | typedef struct SDL_VideoInfo |
58 | { |
59 | Uint32 hw_available:1; |
60 | Uint32 wm_available:1; |
61 | Uint32 UnusedBits1:6; |
62 | Uint32 UnusedBits2:1; |
63 | Uint32 blit_hw:1; |
64 | Uint32 blit_hw_CC:1; |
65 | Uint32 blit_hw_A:1; |
66 | Uint32 blit_sw:1; |
67 | Uint32 blit_sw_CC:1; |
68 | Uint32 blit_sw_A:1; |
69 | Uint32 blit_fill:1; |
70 | Uint32 UnusedBits3:16; |
71 | Uint32 video_mem; |
72 | |
73 | SDL_PixelFormat *vfmt; |
74 | |
75 | int current_w; |
76 | int current_h; |
77 | } SDL_VideoInfo; |
78 | |
79 | #define SDL_ANYFORMAT 0x00100000 |
80 | #define SDL_HWPALETTE 0x00200000 |
81 | #define SDL_FULLSCREEN 0x00800000 |
82 | #define SDL_RESIZABLE 0x01000000 |
83 | #define SDL_NOFRAME 0x02000000 |
84 | #define SDL_OPENGL 0x04000000 |
85 | #define SDL_HWSURFACE 0x08000001 /**< \note Not used */ |
86 | |
87 | #define SDL_BUTTON_WHEELUP 4 |
88 | #define SDL_BUTTON_WHEELDOWN 5 |
89 | |
90 | int initialized_video = 0; |
91 | |
92 | static SDL_Window *SDL_VideoWindow = NULL; |
93 | static SDL_Surface *SDL_WindowSurface = NULL; |
94 | static SDL_Surface *SDL_VideoSurface = NULL; |
95 | static SDL_Surface *SDL_ShadowSurface = NULL; |
96 | static SDL_Surface *SDL_PublicSurface = NULL; |
97 | static SDL_Rect SDL_VideoViewport; |
98 | static char *wm_title = NULL; |
99 | static Uint32 SDL_VideoFlags = 0; |
100 | static SDL_GLContext *SDL_VideoContext = NULL; |
101 | static SDL_Surface *SDL_VideoIcon; |
102 | |
103 | static void |
104 | SDL_WM_SetCaption(const char *title, const char *icon) |
105 | { |
106 | if (wm_title) { |
107 | SDL_free(wm_title); |
108 | } |
109 | if (title) { |
110 | wm_title = SDL_strdup(title); |
111 | } else { |
112 | wm_title = NULL; |
113 | } |
114 | SDL_SetWindowTitle(SDL_VideoWindow, wm_title); |
115 | } |
116 | |
117 | static int |
118 | GetVideoDisplay() |
119 | { |
120 | const char *variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_DISPLAY"); |
121 | if ( !variable ) { |
122 | variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_HEAD"); |
123 | } |
124 | if ( variable ) { |
125 | return SDL_atoi(variable); |
126 | } else { |
127 | return 0; |
128 | } |
129 | } |
130 | |
131 | static const SDL_VideoInfo * |
132 | SDL_GetVideoInfo(void) |
133 | { |
134 | static SDL_VideoInfo info; |
135 | SDL_DisplayMode mode; |
136 | |
137 | /* Memory leak, compatibility code, who cares? */ |
138 | if (!info.vfmt && SDL_GetDesktopDisplayMode(GetVideoDisplay(), &mode) == 0) { |
139 | info.vfmt = SDL_AllocFormat(mode.format); |
140 | info.current_w = mode.w; |
141 | info.current_h = mode.h; |
142 | } |
143 | return &info; |
144 | } |
145 | |
146 | static SDL_Rect ** |
147 | SDL_ListModes(const SDL_PixelFormat * format, Uint32 flags) |
148 | { |
149 | int i, nmodes; |
150 | SDL_Rect **modes; |
151 | |
152 | if (!initialized_video) { |
153 | return NULL; |
154 | } |
155 | |
156 | if (!(flags & SDL_FULLSCREEN)) { |
157 | return (SDL_Rect **) (-1); |
158 | } |
159 | |
160 | if (!format) { |
161 | format = SDL_GetVideoInfo()->vfmt; |
162 | } |
163 | |
164 | /* Memory leak, but this is a compatibility function, who cares? */ |
165 | nmodes = 0; |
166 | modes = NULL; |
167 | for (i = 0; i < SDL_GetNumDisplayModes(GetVideoDisplay()); ++i) { |
168 | SDL_DisplayMode mode; |
169 | int bpp; |
170 | |
171 | SDL_GetDisplayMode(GetVideoDisplay(), i, &mode); |
172 | if (!mode.w || !mode.h) { |
173 | return (SDL_Rect **) (-1); |
174 | } |
175 | |
176 | /* Copied from src/video/SDL_pixels.c:SDL_PixelFormatEnumToMasks */ |
177 | if (SDL_BYTESPERPIXEL(mode.format) <= 2) { |
178 | bpp = SDL_BITSPERPIXEL(mode.format); |
179 | } else { |
180 | bpp = SDL_BYTESPERPIXEL(mode.format) * 8; |
181 | } |
182 | |
183 | if (bpp != format->BitsPerPixel) { |
184 | continue; |
185 | } |
186 | if (nmodes > 0 && modes[nmodes - 1]->w == mode.w |
187 | && modes[nmodes - 1]->h == mode.h) { |
188 | continue; |
189 | } |
190 | |
191 | modes = SDL_realloc(modes, (nmodes + 2) * sizeof(*modes)); |
192 | if (!modes) { |
193 | return NULL; |
194 | } |
195 | modes[nmodes] = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect)); |
196 | if (!modes[nmodes]) { |
197 | return NULL; |
198 | } |
199 | modes[nmodes]->x = 0; |
200 | modes[nmodes]->y = 0; |
201 | modes[nmodes]->w = mode.w; |
202 | modes[nmodes]->h = mode.h; |
203 | ++nmodes; |
204 | } |
205 | if (modes) { |
206 | modes[nmodes] = NULL; |
207 | } |
208 | return modes; |
209 | } |
210 | |
211 | static void |
212 | SDL_UpdateRects(SDL_Surface * screen, int numrects, SDL_Rect * rects) |
213 | { |
214 | int i; |
215 | |
216 | if (screen == SDL_ShadowSurface) { |
217 | for (i = 0; i < numrects; ++i) { |
218 | SDL_BlitSurface(SDL_ShadowSurface, &rects[i], SDL_VideoSurface, |
219 | &rects[i]); |
220 | } |
221 | |
222 | /* Fall through to video surface update */ |
223 | screen = SDL_VideoSurface; |
224 | } |
225 | if (screen == SDL_VideoSurface) { |
226 | if (SDL_VideoViewport.x || SDL_VideoViewport.y) { |
227 | SDL_Rect *stackrects = SDL_stack_alloc(SDL_Rect, numrects); |
228 | SDL_Rect *stackrect; |
229 | const SDL_Rect *rect; |
230 | |
231 | /* Offset all the rectangles before updating */ |
232 | for (i = 0; i < numrects; ++i) { |
233 | rect = &rects[i]; |
234 | stackrect = &stackrects[i]; |
235 | stackrect->x = SDL_VideoViewport.x + rect->x; |
236 | stackrect->y = SDL_VideoViewport.y + rect->y; |
237 | stackrect->w = rect->w; |
238 | stackrect->h = rect->h; |
239 | } |
240 | SDL_UpdateWindowSurfaceRects(SDL_VideoWindow, stackrects, numrects); |
241 | SDL_stack_free(stackrects); |
242 | } else { |
243 | SDL_UpdateWindowSurfaceRects(SDL_VideoWindow, rects, numrects); |
244 | } |
245 | } |
246 | } |
247 | |
248 | static void |
249 | SDL_UpdateRect(SDL_Surface * screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h) |
250 | { |
251 | if (screen) { |
252 | SDL_Rect rect; |
253 | |
254 | /* Fill the rectangle */ |
255 | rect.x = (int) x; |
256 | rect.y = (int) y; |
257 | rect.w = (int) (w ? w : screen->w); |
258 | rect.h = (int) (h ? h : screen->h); |
259 | SDL_UpdateRects(screen, 1, &rect); |
260 | } |
261 | } |
262 | |
263 | static int |
264 | SDL_Flip(SDL_Surface * screen) |
265 | { |
266 | SDL_UpdateRect(screen, 0, 0, 0, 0); |
267 | return 0; |
268 | } |
269 | |
270 | /* |
271 | * Calculate the pad-aligned scanline width of a surface |
272 | */ |
273 | static int |
274 | SDL_CalculatePitch(SDL_Surface * surface) |
275 | { |
276 | int pitch; |
277 | |
278 | /* Surface should be 4-byte aligned for speed */ |
279 | pitch = surface->w * surface->format->BytesPerPixel; |
280 | switch (surface->format->BitsPerPixel) { |
281 | case 1: |
282 | pitch = (pitch + 7) / 8; |
283 | break; |
284 | case 4: |
285 | pitch = (pitch + 1) / 2; |
286 | break; |
287 | default: |
288 | break; |
289 | } |
290 | pitch = (pitch + 3) & ~3; /* 4-byte aligning */ |
291 | return (pitch); |
292 | } |
293 | |
294 | static void |
295 | SDL_InvalidateMap(SDL_BlitMap * map) |
296 | { |
297 | if (!map) { |
298 | return; |
299 | } |
300 | if (map->dst) { |
301 | /* Release our reference to the surface - see the note below */ |
302 | if (--map->dst->refcount <= 0) { |
303 | SDL_FreeSurface(map->dst); |
304 | } |
305 | } |
306 | map->dst = NULL; |
307 | map->src_palette_version = 0; |
308 | map->dst_palette_version = 0; |
309 | if (map->info.table) { |
310 | SDL_free(map->info.table); |
311 | map->info.table = NULL; |
312 | } |
313 | } |
314 | |
315 | static void |
316 | SDL_GL_SwapBuffers(void) |
317 | { |
318 | SDL_GL_SwapWindow(SDL_VideoWindow); |
319 | } |
320 | |
321 | static int |
322 | SDL_WM_ToggleFullScreen(SDL_Surface * surface) |
323 | { |
324 | int length; |
325 | void *pixels; |
326 | Uint8 *src, *dst; |
327 | int row; |
328 | int window_w; |
329 | int window_h; |
330 | |
331 | if (!SDL_PublicSurface) { |
332 | SDL_SetError("SDL_SetVideoMode() hasn't been called"); |
333 | return 0; |
334 | } |
335 | |
336 | /* Copy the old bits out */ |
337 | length = SDL_PublicSurface->w * SDL_PublicSurface->format->BytesPerPixel; |
338 | pixels = SDL_malloc(SDL_PublicSurface->h * length); |
339 | if (pixels && SDL_PublicSurface->pixels) { |
340 | src = (Uint8*)SDL_PublicSurface->pixels; |
341 | dst = (Uint8*)pixels; |
342 | for (row = 0; row < SDL_PublicSurface->h; ++row) { |
343 | SDL_memcpy(dst, src, length); |
344 | src += SDL_PublicSurface->pitch; |
345 | dst += length; |
346 | } |
347 | } |
348 | |
349 | /* Do the physical mode switch */ |
350 | if (SDL_GetWindowFlags(SDL_VideoWindow) & SDL_WINDOW_FULLSCREEN) { |
351 | if (SDL_SetWindowFullscreen(SDL_VideoWindow, 0) < 0) { |
352 | return 0; |
353 | } |
354 | SDL_PublicSurface->flags &= ~SDL_FULLSCREEN; |
355 | } else { |
356 | if (SDL_SetWindowFullscreen(SDL_VideoWindow, 1) < 0) { |
357 | return 0; |
358 | } |
359 | SDL_PublicSurface->flags |= SDL_FULLSCREEN; |
360 | } |
361 | |
362 | /* Recreate the screen surface */ |
363 | SDL_WindowSurface = SDL_GetWindowSurface(SDL_VideoWindow); |
364 | if (!SDL_WindowSurface) { |
365 | /* We're totally hosed... */ |
366 | return 0; |
367 | } |
368 | |
369 | /* Center the public surface in the window surface */ |
370 | SDL_GetWindowSize(SDL_VideoWindow, &window_w, &window_h); |
371 | SDL_VideoViewport.x = (window_w - SDL_VideoSurface->w)/2; |
372 | SDL_VideoViewport.y = (window_h - SDL_VideoSurface->h)/2; |
373 | SDL_VideoViewport.w = SDL_VideoSurface->w; |
374 | SDL_VideoViewport.h = SDL_VideoSurface->h; |
375 | |
376 | /* Do some shuffling behind the application's back if format changes */ |
377 | if (SDL_VideoSurface->format->format != SDL_WindowSurface->format->format) { |
378 | if (SDL_ShadowSurface) { |
379 | if (SDL_ShadowSurface->format->format == SDL_WindowSurface->format->format) { |
380 | /* Whee! We don't need a shadow surface anymore! */ |
381 | SDL_VideoSurface->flags &= ~SDL_DONTFREE; |
382 | SDL_FreeSurface(SDL_VideoSurface); |
383 | SDL_free(SDL_ShadowSurface->pixels); |
384 | SDL_VideoSurface = SDL_ShadowSurface; |
385 | SDL_VideoSurface->flags |= SDL_PREALLOC; |
386 | SDL_ShadowSurface = NULL; |
387 | } else { |
388 | /* No problem, just change the video surface format */ |
389 | SDL_FreeFormat(SDL_VideoSurface->format); |
390 | SDL_VideoSurface->format = SDL_WindowSurface->format; |
391 | SDL_VideoSurface->format->refcount++; |
392 | SDL_InvalidateMap(SDL_ShadowSurface->map); |
393 | } |
394 | } else { |
395 | /* We can make the video surface the shadow surface */ |
396 | SDL_ShadowSurface = SDL_VideoSurface; |
397 | SDL_ShadowSurface->pitch = SDL_CalculatePitch(SDL_ShadowSurface); |
398 | SDL_ShadowSurface->pixels = SDL_malloc(SDL_ShadowSurface->h * SDL_ShadowSurface->pitch); |
399 | if (!SDL_ShadowSurface->pixels) { |
400 | /* Uh oh, we're hosed */ |
401 | SDL_ShadowSurface = NULL; |
402 | return 0; |
403 | } |
404 | SDL_ShadowSurface->flags &= ~SDL_PREALLOC; |
405 | |
406 | SDL_VideoSurface = SDL_CreateRGBSurfaceFrom(NULL, 0, 0, 32, 0, 0, 0, 0, 0); |
407 | SDL_VideoSurface->flags = SDL_ShadowSurface->flags; |
408 | SDL_VideoSurface->flags |= SDL_PREALLOC; |
409 | SDL_FreeFormat(SDL_VideoSurface->format); |
410 | SDL_VideoSurface->format = SDL_WindowSurface->format; |
411 | SDL_VideoSurface->format->refcount++; |
412 | SDL_VideoSurface->w = SDL_ShadowSurface->w; |
413 | SDL_VideoSurface->h = SDL_ShadowSurface->h; |
414 | } |
415 | } |
416 | |
417 | /* Update the video surface */ |
418 | SDL_VideoSurface->pitch = SDL_WindowSurface->pitch; |
419 | SDL_VideoSurface->pixels = (void *)((Uint8 *)SDL_WindowSurface->pixels + |
420 | SDL_VideoViewport.y * SDL_VideoSurface->pitch + |
421 | SDL_VideoViewport.x * SDL_VideoSurface->format->BytesPerPixel); |
422 | SDL_SetClipRect(SDL_VideoSurface, NULL); |
423 | |
424 | /* Copy the old bits back */ |
425 | if (pixels) { |
426 | src = (Uint8*)pixels; |
427 | dst = (Uint8*)SDL_PublicSurface->pixels; |
428 | for (row = 0; row < SDL_PublicSurface->h; ++row) { |
429 | SDL_memcpy(dst, src, length); |
430 | src += length; |
431 | dst += SDL_PublicSurface->pitch; |
432 | } |
433 | SDL_Flip(SDL_PublicSurface); |
434 | SDL_free(pixels); |
435 | } |
436 | |
437 | /* We're done! */ |
438 | return 1; |
439 | } |
440 | |
441 | static void |
442 | ClearVideoSurface() |
443 | { |
444 | if (SDL_ShadowSurface) { |
445 | SDL_FillRect(SDL_ShadowSurface, NULL, |
446 | SDL_MapRGB(SDL_ShadowSurface->format, 0, 0, 0)); |
447 | } |
448 | SDL_FillRect(SDL_WindowSurface, NULL, 0); |
449 | SDL_UpdateWindowSurface(SDL_VideoWindow); |
450 | } |
451 | |
452 | static int |
453 | SDL_ResizeVideoMode(int width, int height, int bpp, Uint32 flags) |
454 | { |
455 | int w, h; |
456 | |
457 | /* We can't resize something we don't have... */ |
458 | if (!SDL_VideoSurface) { |
459 | return -1; |
460 | } |
461 | |
462 | /* We probably have to recreate the window in fullscreen mode */ |
463 | if (flags & SDL_FULLSCREEN) { |
464 | return -1; |
465 | } |
466 | |
467 | /* I don't think there's any change we can gracefully make in flags */ |
468 | if (flags != SDL_VideoFlags) { |
469 | return -1; |
470 | } |
471 | if (bpp != SDL_VideoSurface->format->BitsPerPixel) { |
472 | return -1; |
473 | } |
474 | |
475 | /* Resize the window */ |
476 | SDL_GetWindowSize(SDL_VideoWindow, &w, &h); |
477 | if (w != width || h != height) { |
478 | SDL_SetWindowSize(SDL_VideoWindow, width, height); |
479 | } |
480 | |
481 | /* If we're in OpenGL mode, just resize the stub surface and we're done! */ |
482 | if (flags & SDL_OPENGL) { |
483 | SDL_VideoSurface->w = width; |
484 | SDL_VideoSurface->h = height; |
485 | return 0; |
486 | } |
487 | |
488 | SDL_WindowSurface = SDL_GetWindowSurface(SDL_VideoWindow); |
489 | if (!SDL_WindowSurface) { |
490 | return -1; |
491 | } |
492 | if (SDL_VideoSurface->format != SDL_WindowSurface->format) { |
493 | return -1; |
494 | } |
495 | SDL_VideoSurface->w = width; |
496 | SDL_VideoSurface->h = height; |
497 | SDL_VideoSurface->pixels = SDL_WindowSurface->pixels; |
498 | SDL_VideoSurface->pitch = SDL_WindowSurface->pitch; |
499 | SDL_SetClipRect(SDL_VideoSurface, NULL); |
500 | |
501 | if (SDL_ShadowSurface) { |
502 | SDL_ShadowSurface->w = width; |
503 | SDL_ShadowSurface->h = height; |
504 | SDL_ShadowSurface->pitch = SDL_CalculatePitch(SDL_ShadowSurface); |
505 | SDL_ShadowSurface->pixels = |
506 | SDL_realloc(SDL_ShadowSurface->pixels, |
507 | SDL_ShadowSurface->h * SDL_ShadowSurface->pitch); |
508 | SDL_SetClipRect(SDL_ShadowSurface, NULL); |
509 | SDL_InvalidateMap(SDL_ShadowSurface->map); |
510 | } else { |
511 | SDL_PublicSurface = SDL_VideoSurface; |
512 | } |
513 | |
514 | ClearVideoSurface(); |
515 | |
516 | return 0; |
517 | } |
518 | |
519 | static int |
520 | SDL_CompatEventFilter(void *userdata, SDL_Event * event) |
521 | { |
522 | SDL_Event fake; |
523 | |
524 | switch (event->type) { |
525 | case SDL_WINDOWEVENT: |
526 | switch (event->window.event) { |
527 | case SDL_WINDOWEVENT_CLOSE: |
528 | fake.type = SDL_QUIT; |
529 | SDL_PushEvent(&fake); |
530 | break; |
531 | } |
532 | case SDL_KEYDOWN: |
533 | case SDL_KEYUP: |
534 | { |
535 | Uint32 unicode = 0; |
536 | if (event->key.type == SDL_KEYDOWN && event->key.keysym.sym < 256) { |
537 | unicode = event->key.keysym.sym; |
538 | if (unicode >= 'a' && unicode <= 'z') { |
539 | int shifted = !!(event->key.keysym.mod & KMOD_SHIFT); |
540 | int capslock = !!(event->key.keysym.mod & KMOD_CAPS); |
541 | if ((shifted ^ capslock) != 0) { |
542 | unicode = SDL_toupper(unicode); |
543 | } |
544 | } |
545 | } |
546 | if (unicode) { |
547 | event->key.keysym.unicode = unicode; |
548 | } |
549 | break; |
550 | } |
551 | case SDL_TEXTINPUT: |
552 | { |
553 | /* FIXME: Generate an old style key repeat event if needed */ |
554 | //printf("TEXTINPUT: '%s'\n", event->text.text); |
555 | break; |
556 | } |
557 | case SDL_MOUSEMOTION: |
558 | { |
559 | event->motion.x -= SDL_VideoViewport.x; |
560 | event->motion.y -= SDL_VideoViewport.y; |
561 | break; |
562 | } |
563 | case SDL_MOUSEBUTTONDOWN: |
564 | case SDL_MOUSEBUTTONUP: |
565 | { |
566 | event->button.x -= SDL_VideoViewport.x; |
567 | event->button.y -= SDL_VideoViewport.y; |
568 | break; |
569 | } |
570 | case SDL_MOUSEWHEEL: |
571 | { |
572 | Uint8 button; |
573 | int x, y; |
574 | |
575 | if (event->wheel.y == 0) { |
576 | break; |
577 | } |
578 | |
579 | SDL_GetMouseState(&x, &y); |
580 | |
581 | if (event->wheel.y > 0) { |
582 | button = SDL_BUTTON_WHEELUP; |
583 | } else { |
584 | button = SDL_BUTTON_WHEELDOWN; |
585 | } |
586 | |
587 | fake.button.button = button; |
588 | fake.button.x = x; |
589 | fake.button.y = y; |
590 | fake.button.windowID = event->wheel.windowID; |
591 | |
592 | fake.type = SDL_MOUSEBUTTONDOWN; |
593 | fake.button.state = SDL_PRESSED; |
594 | SDL_PushEvent(&fake); |
595 | |
596 | fake.type = SDL_MOUSEBUTTONUP; |
597 | fake.button.state = SDL_RELEASED; |
598 | SDL_PushEvent(&fake); |
599 | break; |
600 | } |
601 | |
602 | } |
603 | return 1; |
604 | } |
605 | |
606 | static void |
607 | GetEnvironmentWindowPosition(int w, int h, int *x, int *y) |
608 | { |
609 | int display = GetVideoDisplay(); |
610 | const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS"); |
611 | const char *center = SDL_getenv("SDL_VIDEO_CENTERED"); |
612 | if (window) { |
613 | if (SDL_sscanf(window, "%d,%d", x, y) == 2) { |
614 | return; |
615 | } |
616 | if (SDL_strcmp(window, "center") == 0) { |
617 | center = window; |
618 | } |
619 | } |
620 | if (center) { |
621 | *x = SDL_WINDOWPOS_CENTERED_DISPLAY(display); |
622 | *y = SDL_WINDOWPOS_CENTERED_DISPLAY(display); |
623 | } |
624 | } |
625 | |
626 | static SDL_Surface * |
627 | SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) |
628 | { |
629 | SDL_DisplayMode desktop_mode; |
630 | int display = GetVideoDisplay(); |
631 | int window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display); |
632 | int window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display); |
633 | int window_w; |
634 | int window_h; |
635 | Uint32 window_flags; |
636 | Uint32 surface_flags; |
637 | |
638 | if (!initialized_video) { |
639 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) { |
640 | return NULL; |
641 | } |
642 | initialized_video = 1; |
643 | } |
644 | |
645 | SDL_GetDesktopDisplayMode(display, &desktop_mode); |
646 | |
647 | if (width == 0) { |
648 | width = desktop_mode.w; |
649 | } |
650 | if (height == 0) { |
651 | height = desktop_mode.h; |
652 | } |
653 | if (bpp == 0) { |
654 | bpp = SDL_BITSPERPIXEL(desktop_mode.format); |
655 | } |
656 | |
657 | /* See if we can simply resize the existing window and surface */ |
658 | if (SDL_ResizeVideoMode(width, height, bpp, flags) == 0) { |
659 | return SDL_PublicSurface; |
660 | } |
661 | |
662 | /* Destroy existing window */ |
663 | SDL_PublicSurface = NULL; |
664 | if (SDL_ShadowSurface) { |
665 | SDL_ShadowSurface->flags &= ~SDL_DONTFREE; |
666 | SDL_FreeSurface(SDL_ShadowSurface); |
667 | SDL_ShadowSurface = NULL; |
668 | } |
669 | if (SDL_VideoSurface) { |
670 | SDL_VideoSurface->flags &= ~SDL_DONTFREE; |
671 | SDL_FreeSurface(SDL_VideoSurface); |
672 | SDL_VideoSurface = NULL; |
673 | } |
674 | if (SDL_VideoContext) { |
675 | /* SDL_GL_MakeCurrent(0, NULL); *//* Doesn't do anything */ |
676 | SDL_GL_DeleteContext(SDL_VideoContext); |
677 | SDL_VideoContext = NULL; |
678 | } |
679 | if (SDL_VideoWindow) { |
680 | SDL_GetWindowPosition(SDL_VideoWindow, &window_x, &window_y); |
681 | SDL_DestroyWindow(SDL_VideoWindow); |
682 | } |
683 | |
684 | /* Set up the event filter */ |
685 | if (!SDL_GetEventFilter(NULL, NULL)) { |
686 | SDL_SetEventFilter(SDL_CompatEventFilter, NULL); |
687 | } |
688 | |
689 | /* Create a new window */ |
690 | window_flags = SDL_WINDOW_SHOWN; |
691 | if (flags & SDL_FULLSCREEN) { |
692 | window_flags |= SDL_WINDOW_FULLSCREEN; |
693 | } |
694 | if (flags & SDL_OPENGL) { |
695 | window_flags |= SDL_WINDOW_OPENGL; |
696 | } |
697 | if (flags & SDL_RESIZABLE) { |
698 | window_flags |= SDL_WINDOW_RESIZABLE; |
699 | } |
700 | if (flags & SDL_NOFRAME) { |
701 | window_flags |= SDL_WINDOW_BORDERLESS; |
702 | } |
703 | GetEnvironmentWindowPosition(width, height, &window_x, &window_y); |
704 | SDL_VideoWindow = |
705 | SDL_CreateWindow(wm_title, window_x, window_y, width, height, |
706 | window_flags); |
707 | if (!SDL_VideoWindow) { |
708 | return NULL; |
709 | } |
710 | SDL_SetWindowIcon(SDL_VideoWindow, SDL_VideoIcon); |
711 | |
712 | window_flags = SDL_GetWindowFlags(SDL_VideoWindow); |
713 | surface_flags = 0; |
714 | if (window_flags & SDL_WINDOW_FULLSCREEN) { |
715 | surface_flags |= SDL_FULLSCREEN; |
716 | } |
717 | if ((window_flags & SDL_WINDOW_OPENGL) && (flags & SDL_OPENGL)) { |
718 | surface_flags |= SDL_OPENGL; |
719 | } |
720 | if (window_flags & SDL_WINDOW_RESIZABLE) { |
721 | surface_flags |= SDL_RESIZABLE; |
722 | } |
723 | if (window_flags & SDL_WINDOW_BORDERLESS) { |
724 | surface_flags |= SDL_NOFRAME; |
725 | } |
726 | |
727 | SDL_VideoFlags = flags; |
728 | |
729 | /* If we're in OpenGL mode, just create a stub surface and we're done! */ |
730 | if (flags & SDL_OPENGL) { |
731 | SDL_VideoContext = SDL_GL_CreateContext(SDL_VideoWindow); |
732 | if (!SDL_VideoContext) { |
733 | return NULL; |
734 | } |
735 | if (SDL_GL_MakeCurrent(SDL_VideoWindow, SDL_VideoContext) < 0) { |
736 | return NULL; |
737 | } |
738 | SDL_VideoSurface = |
739 | SDL_CreateRGBSurfaceFrom(NULL, width, height, bpp, 0, 0, 0, 0, 0); |
740 | if (!SDL_VideoSurface) { |
741 | return NULL; |
742 | } |
743 | SDL_VideoSurface->flags |= surface_flags; |
744 | SDL_PublicSurface = SDL_VideoSurface; |
745 | return SDL_PublicSurface; |
746 | } |
747 | |
748 | /* Create the screen surface */ |
749 | SDL_WindowSurface = SDL_GetWindowSurface(SDL_VideoWindow); |
750 | if (!SDL_WindowSurface) { |
751 | return NULL; |
752 | } |
753 | |
754 | /* Center the public surface in the window surface */ |
755 | SDL_GetWindowSize(SDL_VideoWindow, &window_w, &window_h); |
756 | SDL_VideoViewport.x = (window_w - width)/2; |
757 | SDL_VideoViewport.y = (window_h - height)/2; |
758 | SDL_VideoViewport.w = width; |
759 | SDL_VideoViewport.h = height; |
760 | |
761 | SDL_VideoSurface = SDL_CreateRGBSurfaceFrom(NULL, 0, 0, 32, 0, 0, 0, 0, 0); |
762 | SDL_VideoSurface->flags |= surface_flags; |
763 | SDL_VideoSurface->flags |= SDL_DONTFREE; |
764 | SDL_FreeFormat(SDL_VideoSurface->format); |
765 | SDL_VideoSurface->format = SDL_WindowSurface->format; |
766 | SDL_VideoSurface->format->refcount++; |
767 | SDL_VideoSurface->w = width; |
768 | SDL_VideoSurface->h = height; |
769 | SDL_VideoSurface->pitch = SDL_WindowSurface->pitch; |
770 | SDL_VideoSurface->pixels = (void *)((Uint8 *)SDL_WindowSurface->pixels + |
771 | SDL_VideoViewport.y * SDL_VideoSurface->pitch + |
772 | SDL_VideoViewport.x * SDL_VideoSurface->format->BytesPerPixel); |
773 | SDL_SetClipRect(SDL_VideoSurface, NULL); |
774 | |
775 | /* Create a shadow surface if necessary */ |
776 | if ((bpp != SDL_VideoSurface->format->BitsPerPixel) |
777 | && !(flags & SDL_ANYFORMAT)) { |
778 | SDL_ShadowSurface = |
779 | SDL_CreateRGBSurface(0, width, height, bpp, 0, 0, 0, 0); |
780 | if (!SDL_ShadowSurface) { |
781 | return NULL; |
782 | } |
783 | SDL_ShadowSurface->flags |= surface_flags; |
784 | SDL_ShadowSurface->flags |= SDL_DONTFREE; |
785 | |
786 | /* 8-bit SDL_ShadowSurface surfaces report that they have exclusive palette */ |
787 | if (SDL_ShadowSurface->format->palette) { |
788 | SDL_ShadowSurface->flags |= SDL_HWPALETTE; |
789 | //TODO SDL_DitherColors(SDL_ShadowSurface->format->palette->colors, |
790 | // SDL_ShadowSurface->format->BitsPerPixel); |
791 | } |
792 | SDL_FillRect(SDL_ShadowSurface, NULL, |
793 | SDL_MapRGB(SDL_ShadowSurface->format, 0, 0, 0)); |
794 | } |
795 | SDL_PublicSurface = |
796 | (SDL_ShadowSurface ? SDL_ShadowSurface : SDL_VideoSurface); |
797 | |
798 | ClearVideoSurface(); |
799 | |
800 | /* We're finally done! */ |
801 | return SDL_PublicSurface; |
802 | } |