Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / src / api / vidext_sdl2_compat.h
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 }