OSDN Git Service

remove ffmpeg from this project. i will put the ffmpeg to "external/ffmpeg" path
[android-x86/external-stagefright-plugins.git] / SDL-1.3 / android-project / jni / SDL / src / video / SDL_video.c
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 #include "SDL_config.h"
22
23 /* The high-level video driver subsystem */
24
25 #include "SDL.h"
26 #include "SDL_video.h"
27 #include "SDL_sysvideo.h"
28 #include "SDL_blit.h"
29 #include "SDL_pixels_c.h"
30 #include "SDL_rect_c.h"
31 #include "../events/SDL_events_c.h"
32
33 #if SDL_VIDEO_OPENGL
34 #include "SDL_opengl.h"
35 #endif /* SDL_VIDEO_OPENGL */
36
37 #if SDL_VIDEO_OPENGL_ES
38 #include "SDL_opengles.h"
39 #endif /* SDL_VIDEO_OPENGL_ES */
40
41 #if SDL_VIDEO_OPENGL_ES2
42 #include "SDL_opengles2.h"
43 #endif /* SDL_VIDEO_OPENGL_ES2 */
44
45 #include "SDL_syswm.h"
46
47 /* On Windows, windows.h defines CreateWindow */
48 #ifdef CreateWindow
49 #undef CreateWindow
50 #endif
51
52 /* Available video drivers */
53 static VideoBootStrap *bootstrap[] = {
54 #if SDL_VIDEO_DRIVER_COCOA
55     &COCOA_bootstrap,
56 #endif
57 #if SDL_VIDEO_DRIVER_X11
58     &X11_bootstrap,
59 #endif
60 #if SDL_VIDEO_DRIVER_DIRECTFB
61     &DirectFB_bootstrap,
62 #endif
63 #if SDL_VIDEO_DRIVER_WINDOWS
64     &WINDOWS_bootstrap,
65 #endif
66 #if SDL_VIDEO_DRIVER_BWINDOW
67     &BWINDOW_bootstrap,
68 #endif
69 #if SDL_VIDEO_DRIVER_PANDORA
70     &PND_bootstrap,
71 #endif
72 #if SDL_VIDEO_DRIVER_NDS
73     &NDS_bootstrap,
74 #endif
75 #if SDL_VIDEO_DRIVER_UIKIT
76     &UIKIT_bootstrap,
77 #endif
78 #if SDL_VIDEO_DRIVER_ANDROID
79     &Android_bootstrap,
80 #endif
81 #if SDL_VIDEO_DRIVER_DUMMY
82     &DUMMY_bootstrap,
83 #endif
84     NULL
85 };
86
87 static SDL_VideoDevice *_this = NULL;
88
89 #define CHECK_WINDOW_MAGIC(window, retval) \
90     if (!_this) { \
91         SDL_UninitializedVideo(); \
92         return retval; \
93     } \
94     if (!window || window->magic != &_this->window_magic) { \
95         SDL_SetError("Invalid window"); \
96         return retval; \
97     }
98
99 #define CHECK_DISPLAY_INDEX(displayIndex, retval) \
100     if (!_this) { \
101         SDL_UninitializedVideo(); \
102         return retval; \
103     } \
104     if (displayIndex < 0 || displayIndex >= _this->num_displays) { \
105         SDL_SetError("displayIndex must be in the range 0 - %d", \
106                      _this->num_displays - 1); \
107         return retval; \
108     }
109
110 /* Support for framebuffer emulation using an accelerated renderer */
111
112 #define SDL_WINDOWTEXTUREDATA   "_SDL_WindowTextureData"
113
114 typedef struct {
115     SDL_Renderer *renderer;
116     SDL_Texture *texture;
117     void *pixels;
118     int pitch;
119     int bytes_per_pixel;
120 } SDL_WindowTextureData;
121
122 static SDL_bool
123 ShouldUseTextureFramebuffer()
124 {
125     const char *hint;
126
127     /* If there's no native framebuffer support then there's no option */
128     if (!_this->CreateWindowFramebuffer) {
129         return SDL_TRUE;
130     }
131
132     /* If the user has specified a software renderer we can't use a
133        texture framebuffer, or renderer creation will go recursive.
134      */
135     hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
136     if (hint && SDL_strcasecmp(hint, "software") == 0) {
137         return SDL_FALSE;
138     }
139
140     /* See if the user or application wants a specific behavior */
141     hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
142     if (hint) {
143         if (*hint == '0') {
144             return SDL_FALSE;
145         } else {
146             return SDL_TRUE;
147         }
148     }
149
150     /* Each platform has different performance characteristics */
151 #if defined(__WIN32__)
152     /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
153      */
154     return SDL_FALSE;
155
156 #elif defined(__MACOSX__)
157     /* Mac OS X uses OpenGL as the native fast path */
158     return SDL_TRUE;
159
160 #elif defined(__LINUX__)
161     /* Properly configured OpenGL drivers are faster than MIT-SHM */
162 #if SDL_VIDEO_OPENGL
163     /* Ugh, find a way to cache this value! */
164     {
165         SDL_Window *window;
166         SDL_GLContext context;
167         SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
168
169         window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
170         if (window) {
171             context = SDL_GL_CreateContext(window);
172             if (context) {
173                 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
174                 const char *vendor = NULL;
175
176                 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
177                 if (glGetStringFunc) {
178                     vendor = (const char *) glGetStringFunc(GL_VENDOR);
179                 }
180                 /* Add more vendors here at will... */
181                 if (vendor &&
182                     (SDL_strstr(vendor, "ATI Technologies") ||
183                      SDL_strstr(vendor, "NVIDIA"))) {
184                     hasAcceleratedOpenGL = SDL_TRUE;
185                 }
186                 SDL_GL_DeleteContext(context);
187             }
188             SDL_DestroyWindow(window);
189         }
190         return hasAcceleratedOpenGL;
191     }
192 #elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
193     /* Let's be optimistic about this! */
194     return SDL_TRUE;
195 #else
196     return SDL_FALSE;
197 #endif
198
199 #else
200     /* Play it safe, assume that if there is a framebuffer driver that it's
201        optimized for the current platform.
202     */
203     return SDL_FALSE;
204 #endif
205 }
206
207 static int
208 SDL_CreateWindowTexture(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
209 {
210     SDL_WindowTextureData *data;
211     SDL_RendererInfo info;
212     Uint32 i;
213
214     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
215     if (!data) {
216         SDL_Renderer *renderer = NULL;
217         SDL_RendererInfo info;
218         int i;
219         const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
220
221         /* Check to see if there's a specific driver requested */
222         if (hint && *hint != '0' && *hint != '1' &&
223             SDL_strcasecmp(hint, "software") != 0) {
224             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
225                 SDL_GetRenderDriverInfo(i, &info);
226                 if (SDL_strcasecmp(info.name, hint) == 0) {
227                     renderer = SDL_CreateRenderer(window, i, 0);
228                     break;
229                 }
230             }
231         }
232
233         if (!renderer) {
234             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
235                 SDL_GetRenderDriverInfo(i, &info);
236                 if (SDL_strcmp(info.name, "software") != 0) {
237                     renderer = SDL_CreateRenderer(window, i, 0);
238                     if (renderer) {
239                         break;
240                     }
241                 }
242             }
243         }
244         if (!renderer) {
245             SDL_SetError("No hardware accelerated renderers available");
246             return -1;
247         }
248
249         /* Create the data after we successfully create the renderer (bug #1116) */
250         data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data));
251         if (!data) {
252             SDL_DestroyRenderer(renderer);
253             SDL_OutOfMemory();
254             return -1;
255         }
256         SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data);
257
258         data->renderer = renderer;
259     }
260
261     /* Free any old texture and pixel data */
262     if (data->texture) {
263         SDL_DestroyTexture(data->texture);
264         data->texture = NULL;
265     }
266     if (data->pixels) {
267         SDL_free(data->pixels);
268         data->pixels = NULL;
269     }
270
271     if (SDL_GetRendererInfo(data->renderer, &info) < 0) {
272         return -1;
273     }
274
275     /* Find the first format without an alpha channel */
276     *format = info.texture_formats[0];
277     for (i = 0; i < info.num_texture_formats; ++i) {
278         if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) &&
279             !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) {
280             *format = info.texture_formats[i];
281             break;
282         }
283     }
284
285     data->texture = SDL_CreateTexture(data->renderer, *format,
286                                       SDL_TEXTUREACCESS_STREAMING,
287                                       window->w, window->h);
288     if (!data->texture) {
289         return -1;
290     }
291
292     /* Create framebuffer data */
293     data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format);
294     data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3);
295     data->pixels = SDL_malloc(window->h * data->pitch);
296     if (!data->pixels) {
297         SDL_OutOfMemory();
298         return -1;
299     }
300
301     *pixels = data->pixels;
302     *pitch = data->pitch;
303
304     /* Make sure we're not double-scaling the viewport */
305     SDL_RenderSetViewport(data->renderer, NULL);
306
307     return 0;
308 }
309
310 static int
311 SDL_UpdateWindowTexture(_THIS, SDL_Window * window, SDL_Rect * rects, int numrects)
312 {
313     SDL_WindowTextureData *data;
314     SDL_Rect rect;
315     void *src;
316
317     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
318     if (!data || !data->texture) {
319         SDL_SetError("No window texture data");
320         return -1;
321     }
322
323     /* Update a single rect that contains subrects for best DMA performance */
324     if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) {
325         src = (void *)((Uint8 *)data->pixels +
326                         rect.y * data->pitch +
327                         rect.x * data->bytes_per_pixel);
328         if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) {
329             return -1;
330         }
331
332         if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) {
333             return -1;
334         }
335
336         SDL_RenderPresent(data->renderer);
337     }
338     return 0;
339 }
340
341 static void
342 SDL_DestroyWindowTexture(_THIS, SDL_Window * window)
343 {
344     SDL_WindowTextureData *data;
345
346     data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL);
347     if (!data) {
348         return;
349     }
350     if (data->texture) {
351         SDL_DestroyTexture(data->texture);
352     }
353     if (data->renderer) {
354         SDL_DestroyRenderer(data->renderer);
355     }
356     if (data->pixels) {
357         SDL_free(data->pixels);
358     }
359     SDL_free(data);
360 }
361
362
363 static int
364 cmpmodes(const void *A, const void *B)
365 {
366     SDL_DisplayMode a = *(const SDL_DisplayMode *) A;
367     SDL_DisplayMode b = *(const SDL_DisplayMode *) B;
368
369     if (a.w != b.w) {
370         return b.w - a.w;
371     }
372     if (a.h != b.h) {
373         return b.h - a.h;
374     }
375     if (SDL_BITSPERPIXEL(a.format) != SDL_BITSPERPIXEL(b.format)) {
376         return SDL_BITSPERPIXEL(b.format) - SDL_BITSPERPIXEL(a.format);
377     }
378     if (SDL_PIXELLAYOUT(a.format) != SDL_PIXELLAYOUT(b.format)) {
379         return SDL_PIXELLAYOUT(b.format) - SDL_PIXELLAYOUT(a.format);
380     }
381     if (a.refresh_rate != b.refresh_rate) {
382         return b.refresh_rate - a.refresh_rate;
383     }
384     return 0;
385 }
386
387 static void
388 SDL_UninitializedVideo()
389 {
390     SDL_SetError("Video subsystem has not been initialized");
391 }
392
393 int
394 SDL_GetNumVideoDrivers(void)
395 {
396     return SDL_arraysize(bootstrap) - 1;
397 }
398
399 const char *
400 SDL_GetVideoDriver(int index)
401 {
402     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
403         return bootstrap[index]->name;
404     }
405     return NULL;
406 }
407
408 /*
409  * Initialize the video and event subsystems -- determine native pixel format
410  */
411 int
412 SDL_VideoInit(const char *driver_name)
413 {
414     SDL_VideoDevice *video;
415     int index;
416     int i;
417
418     /* Check to make sure we don't overwrite '_this' */
419     if (_this != NULL) {
420         SDL_VideoQuit();
421     }
422
423     /* Start the event loop */
424     if (SDL_StartEventLoop() < 0 ||
425         SDL_KeyboardInit() < 0 ||
426         SDL_MouseInit() < 0 ||
427         SDL_TouchInit() < 0 ||
428         SDL_QuitInit() < 0) {
429         return -1;
430     }
431
432     /* Select the proper video driver */
433     index = 0;
434     video = NULL;
435     if (driver_name == NULL) {
436         driver_name = SDL_getenv("SDL_VIDEODRIVER");
437     }
438     if (driver_name != NULL) {
439         for (i = 0; bootstrap[i]; ++i) {
440             if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
441                 video = bootstrap[i]->create(index);
442                 break;
443             }
444         }
445     } else {
446         for (i = 0; bootstrap[i]; ++i) {
447             if (bootstrap[i]->available()) {
448                 video = bootstrap[i]->create(index);
449                 if (video != NULL) {
450                     break;
451                 }
452             }
453         }
454     }
455     if (video == NULL) {
456         if (driver_name) {
457             SDL_SetError("%s not available", driver_name);
458         } else {
459             SDL_SetError("No available video device");
460         }
461         return -1;
462     }
463     _this = video;
464     _this->name = bootstrap[i]->name;
465     _this->next_object_id = 1;
466
467
468     /* Set some very sane GL defaults */
469     _this->gl_config.driver_loaded = 0;
470     _this->gl_config.dll_handle = NULL;
471     _this->gl_config.red_size = 3;
472     _this->gl_config.green_size = 3;
473     _this->gl_config.blue_size = 2;
474     _this->gl_config.alpha_size = 0;
475     _this->gl_config.buffer_size = 0;
476     _this->gl_config.depth_size = 16;
477     _this->gl_config.stencil_size = 0;
478     _this->gl_config.double_buffer = 1;
479     _this->gl_config.accum_red_size = 0;
480     _this->gl_config.accum_green_size = 0;
481     _this->gl_config.accum_blue_size = 0;
482     _this->gl_config.accum_alpha_size = 0;
483     _this->gl_config.stereo = 0;
484     _this->gl_config.multisamplebuffers = 0;
485     _this->gl_config.multisamplesamples = 0;
486     _this->gl_config.retained_backing = 1;
487     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
488 #if SDL_VIDEO_OPENGL
489     _this->gl_config.major_version = 2;
490     _this->gl_config.minor_version = 1;
491 #elif SDL_VIDEO_OPENGL_ES
492     _this->gl_config.major_version = 1;
493     _this->gl_config.minor_version = 1;
494 #elif SDL_VIDEO_OPENGL_ES2
495     _this->gl_config.major_version = 2;
496     _this->gl_config.minor_version = 0;
497 #endif
498
499     /* Initialize the video subsystem */
500     if (_this->VideoInit(_this) < 0) {
501         SDL_VideoQuit();
502         return -1;
503     }
504
505     /* Make sure some displays were added */
506     if (_this->num_displays == 0) {
507         SDL_SetError("The video driver did not add any displays");
508         SDL_VideoQuit();
509         return (-1);
510     }
511
512     /* Add the renderer framebuffer emulation if desired */
513     if (ShouldUseTextureFramebuffer()) {
514         _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
515         _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
516         _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
517     }
518
519     /* We're ready to go! */
520     return 0;
521 }
522
523 const char *
524 SDL_GetCurrentVideoDriver()
525 {
526     if (!_this) {
527         SDL_UninitializedVideo();
528         return NULL;
529     }
530     return _this->name;
531 }
532
533 SDL_VideoDevice *
534 SDL_GetVideoDevice(void)
535 {
536     return _this;
537 }
538
539 int
540 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
541 {
542     SDL_VideoDisplay display;
543
544     SDL_zero(display);
545     if (desktop_mode) {
546         display.desktop_mode = *desktop_mode;
547     }
548     display.current_mode = display.desktop_mode;
549
550     return SDL_AddVideoDisplay(&display);
551 }
552
553 int
554 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
555 {
556     SDL_VideoDisplay *displays;
557     int index = -1;
558
559     displays =
560         SDL_realloc(_this->displays,
561                     (_this->num_displays + 1) * sizeof(*displays));
562     if (displays) {
563         index = _this->num_displays++;
564         displays[index] = *display;
565         displays[index].device = _this;
566         _this->displays = displays;
567     } else {
568         SDL_OutOfMemory();
569     }
570     return index;
571 }
572
573 int
574 SDL_GetNumVideoDisplays(void)
575 {
576     if (!_this) {
577         SDL_UninitializedVideo();
578         return 0;
579     }
580     return _this->num_displays;
581 }
582
583 static int
584 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
585 {
586     int displayIndex;
587
588     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
589         if (display == &_this->displays[displayIndex]) {
590             return displayIndex;
591         }
592     }
593
594     /* Couldn't find the display, just use index 0 */
595     return 0;
596 }
597
598 int
599 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
600 {
601     CHECK_DISPLAY_INDEX(displayIndex, -1);
602
603     if (rect) {
604         SDL_VideoDisplay *display = &_this->displays[displayIndex];
605
606         if (_this->GetDisplayBounds) {
607             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
608                 return 0;
609             }
610         }
611
612         /* Assume that the displays are left to right */
613         if (displayIndex == 0) {
614             rect->x = 0;
615             rect->y = 0;
616         } else {
617             SDL_GetDisplayBounds(displayIndex-1, rect);
618             rect->x += rect->w;
619         }
620         rect->w = display->desktop_mode.w;
621         rect->h = display->desktop_mode.h;
622     }
623     return 0;
624 }
625
626 SDL_bool
627 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
628 {
629     SDL_DisplayMode *modes;
630     int i, nmodes;
631
632     /* Make sure we don't already have the mode in the list */
633     modes = display->display_modes;
634     nmodes = display->num_display_modes;
635     for (i = nmodes; i--;) {
636         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
637             return SDL_FALSE;
638         }
639     }
640
641     /* Go ahead and add the new mode */
642     if (nmodes == display->max_display_modes) {
643         modes =
644             SDL_realloc(modes,
645                         (display->max_display_modes + 32) * sizeof(*modes));
646         if (!modes) {
647             return SDL_FALSE;
648         }
649         display->display_modes = modes;
650         display->max_display_modes += 32;
651     }
652     modes[nmodes] = *mode;
653     display->num_display_modes++;
654
655     /* Re-sort video modes */
656     SDL_qsort(display->display_modes, display->num_display_modes,
657               sizeof(SDL_DisplayMode), cmpmodes);
658
659     return SDL_TRUE;
660 }
661
662 static int
663 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
664 {
665     if (!display->num_display_modes && _this->GetDisplayModes) {
666         _this->GetDisplayModes(_this, display);
667         SDL_qsort(display->display_modes, display->num_display_modes,
668                   sizeof(SDL_DisplayMode), cmpmodes);
669     }
670     return display->num_display_modes;
671 }
672
673 int
674 SDL_GetNumDisplayModes(int displayIndex)
675 {
676     CHECK_DISPLAY_INDEX(displayIndex, -1);
677
678     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
679 }
680
681 int
682 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
683 {
684     SDL_VideoDisplay *display;
685
686     CHECK_DISPLAY_INDEX(displayIndex, -1);
687
688     display = &_this->displays[displayIndex];
689     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
690         SDL_SetError("index must be in the range of 0 - %d",
691                      SDL_GetNumDisplayModesForDisplay(display) - 1);
692         return -1;
693     }
694     if (mode) {
695         *mode = display->display_modes[index];
696     }
697     return 0;
698 }
699
700 int
701 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
702 {
703     SDL_VideoDisplay *display;
704
705     CHECK_DISPLAY_INDEX(displayIndex, -1);
706
707     display = &_this->displays[displayIndex];
708     if (mode) {
709         *mode = display->desktop_mode;
710     }
711     return 0;
712 }
713
714 int
715 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
716 {
717     SDL_VideoDisplay *display;
718
719     CHECK_DISPLAY_INDEX(displayIndex, -1);
720
721     display = &_this->displays[displayIndex];
722     if (mode) {
723         *mode = display->current_mode;
724     }
725     return 0;
726 }
727
728 static SDL_DisplayMode *
729 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
730                                     const SDL_DisplayMode * mode,
731                                     SDL_DisplayMode * closest)
732 {
733     Uint32 target_format;
734     int target_refresh_rate;
735     int i;
736     SDL_DisplayMode *current, *match;
737
738     if (!mode || !closest) {
739         SDL_SetError("Missing desired mode or closest mode parameter");
740         return NULL;
741     }
742
743     /* Default to the desktop format */
744     if (mode->format) {
745         target_format = mode->format;
746     } else {
747         target_format = display->desktop_mode.format;
748     }
749
750     /* Default to the desktop refresh rate */
751     if (mode->refresh_rate) {
752         target_refresh_rate = mode->refresh_rate;
753     } else {
754         target_refresh_rate = display->desktop_mode.refresh_rate;
755     }
756
757     match = NULL;
758     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
759         current = &display->display_modes[i];
760
761         if (current->w && (current->w < mode->w)) {
762             /* Out of sorted modes large enough here */
763             break;
764         }
765         if (current->h && (current->h < mode->h)) {
766             if (current->w && (current->w == mode->w)) {
767                 /* Out of sorted modes large enough here */
768                 break;
769             }
770             /* Wider, but not tall enough, due to a different
771                aspect ratio. This mode must be skipped, but closer
772                modes may still follow. */
773             continue;
774         }
775         if (!match || current->w < match->w || current->h < match->h) {
776             match = current;
777             continue;
778         }
779         if (current->format != match->format) {
780             /* Sorted highest depth to lowest */
781             if (current->format == target_format ||
782                 (SDL_BITSPERPIXEL(current->format) >=
783                  SDL_BITSPERPIXEL(target_format)
784                  && SDL_PIXELTYPE(current->format) ==
785                  SDL_PIXELTYPE(target_format))) {
786                 match = current;
787             }
788             continue;
789         }
790         if (current->refresh_rate != match->refresh_rate) {
791             /* Sorted highest refresh to lowest */
792             if (current->refresh_rate >= target_refresh_rate) {
793                 match = current;
794             }
795         }
796     }
797     if (match) {
798         if (match->format) {
799             closest->format = match->format;
800         } else {
801             closest->format = mode->format;
802         }
803         if (match->w && match->h) {
804             closest->w = match->w;
805             closest->h = match->h;
806         } else {
807             closest->w = mode->w;
808             closest->h = mode->h;
809         }
810         if (match->refresh_rate) {
811             closest->refresh_rate = match->refresh_rate;
812         } else {
813             closest->refresh_rate = mode->refresh_rate;
814         }
815         closest->driverdata = match->driverdata;
816
817         /*
818          * Pick some reasonable defaults if the app and driver don't
819          * care
820          */
821         if (!closest->format) {
822             closest->format = SDL_PIXELFORMAT_RGB888;
823         }
824         if (!closest->w) {
825             closest->w = 640;
826         }
827         if (!closest->h) {
828             closest->h = 480;
829         }
830         return closest;
831     }
832     return NULL;
833 }
834
835 SDL_DisplayMode *
836 SDL_GetClosestDisplayMode(int displayIndex,
837                           const SDL_DisplayMode * mode,
838                           SDL_DisplayMode * closest)
839 {
840     SDL_VideoDisplay *display;
841
842     CHECK_DISPLAY_INDEX(displayIndex, NULL);
843
844     display = &_this->displays[displayIndex];
845     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
846 }
847
848 static int
849 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
850 {
851     SDL_DisplayMode display_mode;
852     SDL_DisplayMode current_mode;
853
854     if (mode) {
855         display_mode = *mode;
856
857         /* Default to the current mode */
858         if (!display_mode.format) {
859             display_mode.format = display->current_mode.format;
860         }
861         if (!display_mode.w) {
862             display_mode.w = display->current_mode.w;
863         }
864         if (!display_mode.h) {
865             display_mode.h = display->current_mode.h;
866         }
867         if (!display_mode.refresh_rate) {
868             display_mode.refresh_rate = display->current_mode.refresh_rate;
869         }
870
871         /* Get a good video mode, the closest one possible */
872         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
873             SDL_SetError("No video mode large enough for %dx%d",
874                          display_mode.w, display_mode.h);
875             return -1;
876         }
877     } else {
878         display_mode = display->desktop_mode;
879     }
880
881     /* See if there's anything left to do */
882     current_mode = display->current_mode;
883     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
884         return 0;
885     }
886
887     /* Actually change the display mode */
888     if (!_this->SetDisplayMode) {
889         SDL_SetError("Video driver doesn't support changing display mode");
890         return -1;
891     }
892     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
893         return -1;
894     }
895     display->current_mode = display_mode;
896     return 0;
897 }
898
899 int
900 SDL_GetWindowDisplay(SDL_Window * window)
901 {
902     int displayIndex;
903     int i, dist;
904     int closest = -1;
905     int closest_dist = 0x7FFFFFFF;
906     SDL_Point center;
907     SDL_Point delta;
908     SDL_Rect rect;
909
910     CHECK_WINDOW_MAGIC(window, -1);
911
912     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
913         SDL_WINDOWPOS_ISCENTERED(window->x)) {
914         displayIndex = (window->x & 0xFFFF);
915         if (displayIndex >= _this->num_displays) {
916             displayIndex = 0;
917         }
918         return displayIndex;
919     }
920     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
921         SDL_WINDOWPOS_ISCENTERED(window->y)) {
922         displayIndex = (window->y & 0xFFFF);
923         if (displayIndex >= _this->num_displays) {
924             displayIndex = 0;
925         }
926         return displayIndex;
927     }
928
929     /* Find the display containing the window */
930     center.x = window->x + window->w / 2;
931     center.y = window->y + window->h / 2;
932     for (i = 0; i < _this->num_displays; ++i) {
933         SDL_VideoDisplay *display = &_this->displays[i];
934
935         SDL_GetDisplayBounds(i, &rect);
936         if (display->fullscreen_window == window || SDL_EnclosePoints(&center, 1, &rect, NULL)) {
937             return i;
938         }
939
940         delta.x = center.x - (rect.x + rect.w / 2);
941         delta.y = center.y - (rect.y + rect.h / 2);
942         dist = (delta.x*delta.x + delta.y*delta.y);
943         if (dist < closest_dist) {
944             closest = i;
945             closest_dist = dist;
946         }
947     }
948     if (closest < 0) {
949         SDL_SetError("Couldn't find any displays");
950     }
951     return closest;
952 }
953
954 SDL_VideoDisplay *
955 SDL_GetDisplayForWindow(SDL_Window *window)
956 {
957     int displayIndex = SDL_GetWindowDisplay(window);
958     if (displayIndex >= 0) {
959         return &_this->displays[displayIndex];
960     } else {
961         return NULL;
962     }
963 }
964
965 int
966 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
967 {
968     CHECK_WINDOW_MAGIC(window, -1);
969
970     if (mode) {
971         window->fullscreen_mode = *mode;
972     } else {
973         SDL_zero(window->fullscreen_mode);
974     }
975     return 0;
976 }
977
978 int
979 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
980 {
981     SDL_DisplayMode fullscreen_mode;
982
983     CHECK_WINDOW_MAGIC(window, -1);
984
985     fullscreen_mode = window->fullscreen_mode;
986     if (!fullscreen_mode.w) {
987         fullscreen_mode.w = window->w;
988     }
989     if (!fullscreen_mode.h) {
990         fullscreen_mode.h = window->h;
991     }
992
993     if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
994                                              &fullscreen_mode,
995                                              &fullscreen_mode)) {
996         SDL_SetError("Couldn't find display mode match");
997         return -1;
998     }
999
1000     if (mode) {
1001         *mode = fullscreen_mode;
1002     }
1003     return 0;
1004 }
1005
1006 Uint32
1007 SDL_GetWindowPixelFormat(SDL_Window * window)
1008 {
1009     SDL_VideoDisplay *display;
1010
1011     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
1012
1013     display = SDL_GetDisplayForWindow(window);
1014     return display->current_mode.format;
1015 }
1016
1017 static void
1018 SDL_RestoreMousePosition(SDL_Window *window)
1019 {
1020     int x, y;
1021
1022     if (window == SDL_GetMouseFocus()) {
1023         SDL_GetMouseState(&x, &y);
1024         SDL_WarpMouseInWindow(window, x, y);
1025     }
1026 }
1027
1028 static void
1029 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
1030 {
1031     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1032     SDL_Window *other;
1033
1034     if (fullscreen) {
1035         /* Hide any other fullscreen windows */
1036         if (display->fullscreen_window &&
1037             display->fullscreen_window != window) {
1038             SDL_MinimizeWindow(display->fullscreen_window);
1039         }
1040     }
1041
1042     /* See if anything needs to be done now */
1043     if ((display->fullscreen_window == window) == fullscreen) {
1044         return;
1045     }
1046
1047     /* See if there are any fullscreen windows */
1048     for (other = _this->windows; other; other = other->next) {
1049         SDL_bool setDisplayMode = SDL_FALSE;
1050
1051         if (other == window) {
1052             setDisplayMode = fullscreen;
1053         } else if (FULLSCREEN_VISIBLE(other) &&
1054                    SDL_GetDisplayForWindow(other) == display) {
1055             setDisplayMode = SDL_TRUE;
1056         }
1057
1058         if (setDisplayMode) {
1059             SDL_DisplayMode fullscreen_mode;
1060
1061             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
1062                 SDL_bool resized = SDL_TRUE;
1063
1064                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
1065                     resized = SDL_FALSE;
1066                 }
1067
1068                 SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
1069                 if (_this->SetWindowFullscreen) {
1070                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
1071                 }
1072                 display->fullscreen_window = other;
1073
1074                 /* Generate a mode change event here */
1075                 if (resized) {
1076                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
1077                                         fullscreen_mode.w, fullscreen_mode.h);
1078                 } else {
1079                     SDL_OnWindowResized(other);
1080                 }
1081
1082                 SDL_RestoreMousePosition(other);
1083                 return;
1084             }
1085         }
1086     }
1087
1088     /* Nope, restore the desktop mode */
1089     SDL_SetDisplayModeForDisplay(display, NULL);
1090
1091     if (_this->SetWindowFullscreen) {
1092         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
1093     }
1094     display->fullscreen_window = NULL;
1095
1096     /* Generate a mode change event here */
1097     SDL_OnWindowResized(window);
1098
1099     /* Restore the cursor position */
1100     SDL_RestoreMousePosition(window);
1101 }
1102
1103 #define CREATE_FLAGS \
1104     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE)
1105
1106 static void
1107 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
1108 {
1109     window->windowed.x = window->x;
1110     window->windowed.y = window->y;
1111     window->windowed.w = window->w;
1112     window->windowed.h = window->h;
1113
1114     if (flags & SDL_WINDOW_MAXIMIZED) {
1115         SDL_MaximizeWindow(window);
1116     }
1117     if (flags & SDL_WINDOW_MINIMIZED) {
1118         SDL_MinimizeWindow(window);
1119     }
1120     if (flags & SDL_WINDOW_FULLSCREEN) {
1121         SDL_SetWindowFullscreen(window, SDL_TRUE);
1122     }
1123     if (flags & SDL_WINDOW_INPUT_GRABBED) {
1124         SDL_SetWindowGrab(window, SDL_TRUE);
1125     }
1126     if (!(flags & SDL_WINDOW_HIDDEN)) {
1127         SDL_ShowWindow(window);
1128     }
1129 }
1130
1131 SDL_Window *
1132 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
1133 {
1134     SDL_Window *window;
1135
1136     if (!_this) {
1137         /* Initialize the video system if needed */
1138         if (SDL_VideoInit(NULL) < 0) {
1139             return NULL;
1140         }
1141     }
1142
1143     /* Some platforms have OpenGL enabled by default */
1144 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__
1145     flags |= SDL_WINDOW_OPENGL;
1146 #endif
1147     if (flags & SDL_WINDOW_OPENGL) {
1148         if (!_this->GL_CreateContext) {
1149             SDL_SetError("No OpenGL support in video driver");
1150             return NULL;
1151         }
1152         SDL_GL_LoadLibrary(NULL);
1153     }
1154     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
1155     window->magic = &_this->window_magic;
1156     window->id = _this->next_object_id++;
1157     window->x = x;
1158     window->y = y;
1159     window->w = w;
1160     window->h = h;
1161     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
1162         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
1163         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1164         int displayIndex;
1165         SDL_Rect bounds;
1166
1167         displayIndex = SDL_GetIndexOfDisplay(display);
1168         SDL_GetDisplayBounds(displayIndex, &bounds);
1169         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
1170             window->x = bounds.x + (bounds.w - w) / 2;
1171         }
1172         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
1173             window->y = bounds.y + (bounds.h - h) / 2;
1174         }
1175     }
1176     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
1177     window->brightness = 1.0f;
1178     window->next = _this->windows;
1179     if (_this->windows) {
1180         _this->windows->prev = window;
1181     }
1182     _this->windows = window;
1183
1184     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
1185         SDL_DestroyWindow(window);
1186         return NULL;
1187     }
1188
1189     if (title) {
1190         SDL_SetWindowTitle(window, title);
1191     }
1192     SDL_FinishWindowCreation(window, flags);
1193     
1194     /* If the window was created fullscreen, make sure the mode code matches */
1195     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
1196
1197     return window;
1198 }
1199
1200 SDL_Window *
1201 SDL_CreateWindowFrom(const void *data)
1202 {
1203     SDL_Window *window;
1204
1205     if (!_this) {
1206         SDL_UninitializedVideo();
1207         return NULL;
1208     }
1209     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
1210     window->magic = &_this->window_magic;
1211     window->id = _this->next_object_id++;
1212     window->flags = SDL_WINDOW_FOREIGN;
1213     window->brightness = 1.0f;
1214     window->next = _this->windows;
1215     if (_this->windows) {
1216         _this->windows->prev = window;
1217     }
1218     _this->windows = window;
1219
1220     if (!_this->CreateWindowFrom ||
1221         _this->CreateWindowFrom(_this, window, data) < 0) {
1222         SDL_DestroyWindow(window);
1223         return NULL;
1224     }
1225     return window;
1226 }
1227
1228 int
1229 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
1230 {
1231     char *title = window->title;
1232
1233     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
1234         SDL_SetError("No OpenGL support in video driver");
1235         return -1;
1236     }
1237
1238     if (window->flags & SDL_WINDOW_FOREIGN) {
1239         /* Can't destroy and re-create foreign windows, hrm */
1240         flags |= SDL_WINDOW_FOREIGN;
1241     } else {
1242         flags &= ~SDL_WINDOW_FOREIGN;
1243     }
1244
1245     /* Restore video mode, etc. */
1246     SDL_HideWindow(window);
1247
1248     /* Tear down the old native window */
1249     if (window->surface) {
1250         window->surface->flags &= ~SDL_DONTFREE;
1251         SDL_FreeSurface(window->surface);
1252     }
1253     if (_this->DestroyWindowFramebuffer) {
1254         _this->DestroyWindowFramebuffer(_this, window);
1255     }
1256     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
1257         _this->DestroyWindow(_this, window);
1258     }
1259
1260     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
1261         if (flags & SDL_WINDOW_OPENGL) {
1262             SDL_GL_LoadLibrary(NULL);
1263         } else {
1264             SDL_GL_UnloadLibrary();
1265         }
1266     }
1267
1268     window->title = NULL;
1269     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
1270
1271     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
1272         if (_this->CreateWindow(_this, window) < 0) {
1273             if (flags & SDL_WINDOW_OPENGL) {
1274                 SDL_GL_UnloadLibrary();
1275             }
1276             return -1;
1277         }
1278     }
1279
1280     if (title) {
1281         SDL_SetWindowTitle(window, title);
1282         SDL_free(title);
1283     }
1284     SDL_FinishWindowCreation(window, flags);
1285
1286     return 0;
1287 }
1288
1289 Uint32
1290 SDL_GetWindowID(SDL_Window * window)
1291 {
1292     CHECK_WINDOW_MAGIC(window, 0);
1293
1294     return window->id;
1295 }
1296
1297 SDL_Window *
1298 SDL_GetWindowFromID(Uint32 id)
1299 {
1300     SDL_Window *window;
1301
1302     if (!_this) {
1303         return NULL;
1304     }
1305     for (window = _this->windows; window; window = window->next) {
1306         if (window->id == id) {
1307             return window;
1308         }
1309     }
1310     return NULL;
1311 }
1312
1313 Uint32
1314 SDL_GetWindowFlags(SDL_Window * window)
1315 {
1316     CHECK_WINDOW_MAGIC(window, 0);
1317
1318     return window->flags;
1319 }
1320
1321 void
1322 SDL_SetWindowTitle(SDL_Window * window, const char *title)
1323 {
1324     CHECK_WINDOW_MAGIC(window, );
1325
1326     if (title == window->title) {
1327         return;
1328     }
1329     if (window->title) {
1330         SDL_free(window->title);
1331     }
1332     if (title && *title) {
1333         window->title = SDL_strdup(title);
1334     } else {
1335         window->title = NULL;
1336     }
1337
1338     if (_this->SetWindowTitle) {
1339         _this->SetWindowTitle(_this, window);
1340     }
1341 }
1342
1343 const char *
1344 SDL_GetWindowTitle(SDL_Window * window)
1345 {
1346     CHECK_WINDOW_MAGIC(window, "");
1347
1348     return window->title ? window->title : "";
1349 }
1350
1351 void
1352 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
1353 {
1354     CHECK_WINDOW_MAGIC(window, );
1355
1356     if (!icon) {
1357         return;
1358     }
1359
1360     if (_this->SetWindowIcon) {
1361         _this->SetWindowIcon(_this, window, icon);
1362     }
1363 }
1364
1365 void*
1366 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
1367 {
1368     SDL_WindowUserData *prev, *data;
1369
1370     CHECK_WINDOW_MAGIC(window, NULL);
1371
1372     /* See if the named data already exists */
1373     prev = NULL;
1374     for (data = window->data; data; prev = data, data = data->next) {
1375         if (SDL_strcmp(data->name, name) == 0) {
1376             void *last_value = data->data;
1377
1378             if (userdata) {
1379                 /* Set the new value */
1380                 data->data = userdata;
1381             } else {
1382                 /* Delete this value */
1383                 if (prev) {
1384                     prev->next = data->next;
1385                 } else {
1386                     window->data = data->next;
1387                 }
1388                 SDL_free(data->name);
1389                 SDL_free(data);
1390             }
1391             return last_value;
1392         }
1393     }
1394
1395     /* Add new data to the window */
1396     if (userdata) {
1397         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
1398         data->name = SDL_strdup(name);
1399         data->data = userdata;
1400         data->next = window->data;
1401         window->data = data;
1402     }
1403     return NULL;
1404 }
1405
1406 void *
1407 SDL_GetWindowData(SDL_Window * window, const char *name)
1408 {
1409     SDL_WindowUserData *data;
1410
1411     CHECK_WINDOW_MAGIC(window, NULL);
1412
1413     for (data = window->data; data; data = data->next) {
1414         if (SDL_strcmp(data->name, name) == 0) {
1415             return data->data;
1416         }
1417     }
1418     return NULL;
1419 }
1420
1421 void
1422 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
1423 {
1424     CHECK_WINDOW_MAGIC(window, );
1425
1426     if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
1427         window->x = x;
1428     }
1429     if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
1430         window->y = y;
1431     }
1432     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
1433         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1434         int displayIndex;
1435         SDL_Rect bounds;
1436
1437         displayIndex = SDL_GetIndexOfDisplay(display);
1438         SDL_GetDisplayBounds(displayIndex, &bounds);
1439         if (SDL_WINDOWPOS_ISCENTERED(x)) {
1440             window->x = bounds.x + (bounds.w - window->w) / 2;
1441         }
1442         if (SDL_WINDOWPOS_ISCENTERED(y)) {
1443             window->y = bounds.y + (bounds.h - window->h) / 2;
1444         }
1445     }
1446     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
1447         if (_this->SetWindowPosition) {
1448             _this->SetWindowPosition(_this, window);
1449         }
1450         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
1451     }
1452 }
1453
1454 void
1455 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
1456 {
1457     /* Clear the values */
1458     if (x) {
1459         *x = 0;
1460     }
1461     if (y) {
1462         *y = 0;
1463     }
1464
1465     CHECK_WINDOW_MAGIC(window, );
1466
1467     /* Fullscreen windows are always at their display's origin */
1468     if (window->flags & SDL_WINDOW_FULLSCREEN) {
1469     } else {
1470         if (x) {
1471             *x = window->x;
1472         }
1473         if (y) {
1474             *y = window->y;
1475         }
1476     }
1477 }
1478
1479 void
1480 SDL_SetWindowSize(SDL_Window * window, int w, int h)
1481 {
1482     CHECK_WINDOW_MAGIC(window, );
1483
1484     /* FIXME: Should this change fullscreen modes? */
1485     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
1486         window->w = w;
1487         window->h = h;
1488         if (_this->SetWindowSize) {
1489             _this->SetWindowSize(_this, window);
1490         }
1491         if (window->w == w && window->h == h) {
1492             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
1493             SDL_OnWindowResized(window);
1494         }
1495     }
1496 }
1497
1498 void
1499 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
1500 {
1501     int dummy;
1502
1503     if (!w) {
1504         w = &dummy;
1505     }
1506     if (!h) {
1507         h = &dummy;
1508     }
1509
1510     *w = 0;
1511     *h = 0;
1512
1513     CHECK_WINDOW_MAGIC(window, );
1514
1515     if (_this && window && window->magic == &_this->window_magic) {
1516         if (w) {
1517             *w = window->w;
1518         }
1519         if (h) {
1520             *h = window->h;
1521         }
1522     } else {
1523         if (w) {
1524             *w = 0;
1525         }
1526         if (h) {
1527             *h = 0;
1528         }
1529     }
1530 }
1531
1532 void
1533 SDL_ShowWindow(SDL_Window * window)
1534 {
1535     CHECK_WINDOW_MAGIC(window, );
1536
1537     if (window->flags & SDL_WINDOW_SHOWN) {
1538         return;
1539     }
1540
1541     if (_this->ShowWindow) {
1542         _this->ShowWindow(_this, window);
1543     }
1544     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
1545 }
1546
1547 void
1548 SDL_HideWindow(SDL_Window * window)
1549 {
1550     CHECK_WINDOW_MAGIC(window, );
1551
1552     if (!(window->flags & SDL_WINDOW_SHOWN)) {
1553         return;
1554     }
1555
1556     SDL_UpdateFullscreenMode(window, SDL_FALSE);
1557
1558     if (_this->HideWindow) {
1559         _this->HideWindow(_this, window);
1560     }
1561     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
1562 }
1563
1564 void
1565 SDL_RaiseWindow(SDL_Window * window)
1566 {
1567     CHECK_WINDOW_MAGIC(window, );
1568
1569     if (!(window->flags & SDL_WINDOW_SHOWN)) {
1570         return;
1571     }
1572     if (_this->RaiseWindow) {
1573         _this->RaiseWindow(_this, window);
1574     }
1575 }
1576
1577 void
1578 SDL_MaximizeWindow(SDL_Window * window)
1579 {
1580     CHECK_WINDOW_MAGIC(window, );
1581
1582     if (window->flags & SDL_WINDOW_MAXIMIZED) {
1583         return;
1584     }
1585
1586     if (_this->MaximizeWindow) {
1587         _this->MaximizeWindow(_this, window);
1588     }
1589 }
1590
1591 void
1592 SDL_MinimizeWindow(SDL_Window * window)
1593 {
1594     CHECK_WINDOW_MAGIC(window, );
1595
1596     if (window->flags & SDL_WINDOW_MINIMIZED) {
1597         return;
1598     }
1599
1600     SDL_UpdateFullscreenMode(window, SDL_FALSE);
1601
1602     if (_this->MinimizeWindow) {
1603         _this->MinimizeWindow(_this, window);
1604     }
1605 }
1606
1607 void
1608 SDL_RestoreWindow(SDL_Window * window)
1609 {
1610     CHECK_WINDOW_MAGIC(window, );
1611
1612     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
1613         return;
1614     }
1615
1616     if (_this->RestoreWindow) {
1617         _this->RestoreWindow(_this, window);
1618     }
1619 }
1620
1621 int
1622 SDL_SetWindowFullscreen(SDL_Window * window, SDL_bool fullscreen)
1623 {
1624     CHECK_WINDOW_MAGIC(window, -1);
1625
1626     if (!!fullscreen == !!(window->flags & SDL_WINDOW_FULLSCREEN)) {
1627         return 0;
1628     }
1629     if (fullscreen) {
1630         window->flags |= SDL_WINDOW_FULLSCREEN;
1631     } else {
1632         window->flags &= ~SDL_WINDOW_FULLSCREEN;
1633     }
1634     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
1635
1636     return 0;
1637 }
1638
1639 static SDL_Surface *
1640 SDL_CreateWindowFramebuffer(SDL_Window * window)
1641 {
1642     Uint32 format;
1643     void *pixels;
1644     int pitch;
1645     int bpp;
1646     Uint32 Rmask, Gmask, Bmask, Amask;
1647
1648     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
1649         return NULL;
1650     }
1651
1652     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
1653         return NULL;
1654     }
1655
1656     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
1657         return NULL;
1658     }
1659
1660     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
1661 }
1662
1663 SDL_Surface *
1664 SDL_GetWindowSurface(SDL_Window * window)
1665 {
1666     CHECK_WINDOW_MAGIC(window, NULL);
1667
1668     if (!window->surface_valid) {
1669         if (window->surface) {
1670             window->surface->flags &= ~SDL_DONTFREE;
1671             SDL_FreeSurface(window->surface);
1672         }
1673         window->surface = SDL_CreateWindowFramebuffer(window);
1674         if (window->surface) {
1675             window->surface_valid = SDL_TRUE;
1676             window->surface->flags |= SDL_DONTFREE;
1677         }
1678     }
1679     return window->surface;
1680 }
1681
1682 int
1683 SDL_UpdateWindowSurface(SDL_Window * window)
1684 {
1685     SDL_Rect full_rect;
1686
1687     CHECK_WINDOW_MAGIC(window, -1);
1688
1689     full_rect.x = 0;
1690     full_rect.y = 0;
1691     full_rect.w = window->w;
1692     full_rect.h = window->h;
1693     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
1694 }
1695
1696 int
1697 SDL_UpdateWindowSurfaceRects(SDL_Window * window, SDL_Rect * rects,
1698                              int numrects)
1699 {
1700     CHECK_WINDOW_MAGIC(window, -1);
1701
1702     if (!window->surface_valid) {
1703         SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
1704         return -1;
1705     }
1706
1707     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
1708 }
1709
1710 int
1711 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
1712 {
1713     Uint16 ramp[256];
1714     int status;
1715
1716     CHECK_WINDOW_MAGIC(window, -1);
1717
1718     SDL_CalculateGammaRamp(brightness, ramp);
1719     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
1720     if (status == 0) {
1721         window->brightness = brightness;
1722     }
1723     return status;
1724 }
1725
1726 float
1727 SDL_GetWindowBrightness(SDL_Window * window)
1728 {
1729     CHECK_WINDOW_MAGIC(window, 1.0f);
1730
1731     return window->brightness;
1732 }
1733
1734 int
1735 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
1736                                             const Uint16 * green,
1737                                             const Uint16 * blue)
1738 {
1739     CHECK_WINDOW_MAGIC(window, -1);
1740
1741     if (!_this->SetWindowGammaRamp) {
1742         SDL_Unsupported();
1743         return -1;
1744     }
1745
1746     if (!window->gamma) {
1747         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
1748             return -1;
1749         }
1750     }
1751
1752     if (red) {
1753         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
1754     }
1755     if (green) {
1756         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
1757     }
1758     if (blue) {
1759         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
1760     }
1761     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
1762         return _this->SetWindowGammaRamp(_this, window, window->gamma);
1763     } else {
1764         return 0;
1765     }
1766 }
1767
1768 int
1769 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
1770                                             Uint16 * green,
1771                                             Uint16 * blue)
1772 {
1773     CHECK_WINDOW_MAGIC(window, -1);
1774
1775     if (!window->gamma) {
1776         int i;
1777
1778         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
1779         if (!window->gamma) {
1780             SDL_OutOfMemory();
1781             return -1;
1782         }
1783         window->saved_gamma = window->gamma + 3*256;
1784
1785         if (_this->GetWindowGammaRamp) {
1786             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
1787                 return -1;
1788             }
1789         } else {
1790             /* Create an identity gamma ramp */
1791             for (i = 0; i < 256; ++i) {
1792                 Uint16 value = (Uint16)((i << 8) | i);
1793
1794                 window->gamma[0*256+i] = value;
1795                 window->gamma[1*256+i] = value;
1796                 window->gamma[2*256+i] = value;
1797             }
1798         }
1799         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
1800     }
1801
1802     if (red) {
1803         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
1804     }
1805     if (green) {
1806         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
1807     }
1808     if (blue) {
1809         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
1810     }
1811     return 0;
1812 }
1813
1814 static void
1815 SDL_UpdateWindowGrab(SDL_Window * window)
1816 {
1817     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
1818         _this->SetWindowGrab(_this, window);
1819     }
1820 }
1821
1822 void
1823 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
1824 {
1825     CHECK_WINDOW_MAGIC(window, );
1826
1827     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
1828         return;
1829     }
1830     if (grabbed) {
1831         window->flags |= SDL_WINDOW_INPUT_GRABBED;
1832     } else {
1833         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
1834     }
1835     SDL_UpdateWindowGrab(window);
1836 }
1837
1838 SDL_bool
1839 SDL_GetWindowGrab(SDL_Window * window)
1840 {
1841     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
1842
1843     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
1844 }
1845
1846 void
1847 SDL_OnWindowShown(SDL_Window * window)
1848 {
1849     SDL_OnWindowRestored(window);
1850 }
1851
1852 void
1853 SDL_OnWindowHidden(SDL_Window * window)
1854 {
1855     SDL_UpdateFullscreenMode(window, SDL_FALSE);
1856 }
1857
1858 void
1859 SDL_OnWindowResized(SDL_Window * window)
1860 {
1861     window->surface_valid = SDL_FALSE;
1862     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
1863 }
1864
1865 void
1866 SDL_OnWindowMinimized(SDL_Window * window)
1867 {
1868     SDL_UpdateFullscreenMode(window, SDL_FALSE);
1869 }
1870
1871 void
1872 SDL_OnWindowRestored(SDL_Window * window)
1873 {
1874     SDL_RaiseWindow(window);
1875
1876     if (FULLSCREEN_VISIBLE(window)) {
1877         SDL_UpdateFullscreenMode(window, SDL_TRUE);
1878     }
1879 }
1880
1881 void
1882 SDL_OnWindowFocusGained(SDL_Window * window)
1883 {
1884     if (window->gamma && _this->SetWindowGammaRamp) {
1885         _this->SetWindowGammaRamp(_this, window, window->gamma);
1886     }
1887
1888     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) &&
1889         _this->SetWindowGrab) {
1890         _this->SetWindowGrab(_this, window);
1891     }
1892 }
1893
1894 void
1895 SDL_OnWindowFocusLost(SDL_Window * window)
1896 {
1897     if (window->gamma && _this->SetWindowGammaRamp) {
1898         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
1899     }
1900
1901     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) &&
1902         _this->SetWindowGrab) {
1903         _this->SetWindowGrab(_this, window);
1904     }
1905
1906     /* If we're fullscreen on a single-head system and lose focus, minimize */
1907     if ((window->flags & SDL_WINDOW_FULLSCREEN) && _this->num_displays == 1) {
1908         SDL_MinimizeWindow(window);
1909     }
1910 }
1911
1912 SDL_Window *
1913 SDL_GetFocusWindow(void)
1914 {
1915     SDL_Window *window;
1916
1917     if (!_this) {
1918         return NULL;
1919     }
1920     for (window = _this->windows; window; window = window->next) {
1921         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
1922             return window;
1923         }
1924     }
1925     return NULL;
1926 }
1927
1928 void
1929 SDL_DestroyWindow(SDL_Window * window)
1930 {
1931     SDL_VideoDisplay *display;
1932
1933     CHECK_WINDOW_MAGIC(window, );
1934
1935     /* Restore video mode, etc. */
1936     SDL_HideWindow(window);
1937
1938     /* Make sure this window no longer has focus */
1939     if (SDL_GetKeyboardFocus() == window) {
1940         SDL_SetKeyboardFocus(NULL);
1941     }
1942     if (SDL_GetMouseFocus() == window) {
1943         SDL_SetMouseFocus(NULL);
1944     }
1945
1946     /* make no context current if this is the current context window. */
1947     if (window->flags & SDL_WINDOW_OPENGL) {
1948         if (_this->current_glwin == window) {
1949             SDL_GL_MakeCurrent(NULL, NULL);
1950         }
1951     }
1952
1953     if (window->surface) {
1954         window->surface->flags &= ~SDL_DONTFREE;
1955         SDL_FreeSurface(window->surface);
1956     }
1957     if (_this->DestroyWindowFramebuffer) {
1958         _this->DestroyWindowFramebuffer(_this, window);
1959     }
1960     if (_this->DestroyWindow) {
1961         _this->DestroyWindow(_this, window);
1962     }
1963     if (window->flags & SDL_WINDOW_OPENGL) {
1964         SDL_GL_UnloadLibrary();
1965     }
1966
1967     display = SDL_GetDisplayForWindow(window);
1968     if (display->fullscreen_window == window) {
1969         display->fullscreen_window = NULL;
1970     }
1971
1972     /* Now invalidate magic */
1973     window->magic = NULL;
1974
1975     /* Free memory associated with the window */
1976     if (window->title) {
1977         SDL_free(window->title);
1978     }
1979     if (window->gamma) {
1980         SDL_free(window->gamma);
1981     }
1982     while (window->data) {
1983         SDL_WindowUserData *data = window->data;
1984
1985         window->data = data->next;
1986         SDL_free(data->name);
1987         SDL_free(data);
1988     }
1989
1990     /* Unlink the window from the list */
1991     if (window->next) {
1992         window->next->prev = window->prev;
1993     }
1994     if (window->prev) {
1995         window->prev->next = window->next;
1996     } else {
1997         _this->windows = window->next;
1998     }
1999
2000     SDL_free(window);
2001 }
2002
2003 SDL_bool
2004 SDL_IsScreenSaverEnabled()
2005 {
2006     if (!_this) {
2007         return SDL_TRUE;
2008     }
2009     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
2010 }
2011
2012 void
2013 SDL_EnableScreenSaver()
2014 {
2015     if (!_this) {
2016         return;
2017     }
2018     if (!_this->suspend_screensaver) {
2019         return;
2020     }
2021     _this->suspend_screensaver = SDL_FALSE;
2022     if (_this->SuspendScreenSaver) {
2023         _this->SuspendScreenSaver(_this);
2024     }
2025 }
2026
2027 void
2028 SDL_DisableScreenSaver()
2029 {
2030     if (!_this) {
2031         return;
2032     }
2033     if (_this->suspend_screensaver) {
2034         return;
2035     }
2036     _this->suspend_screensaver = SDL_TRUE;
2037     if (_this->SuspendScreenSaver) {
2038         _this->SuspendScreenSaver(_this);
2039     }
2040 }
2041
2042 void
2043 SDL_VideoQuit(void)
2044 {
2045     int i, j;
2046
2047     if (!_this) {
2048         return;
2049     }
2050
2051     /* Halt event processing before doing anything else */
2052     SDL_QuitQuit();
2053     SDL_MouseQuit();
2054     SDL_KeyboardQuit();
2055     SDL_StopEventLoop();
2056
2057     SDL_EnableScreenSaver();
2058
2059     /* Clean up the system video */
2060     while (_this->windows) {
2061         SDL_DestroyWindow(_this->windows);
2062     }
2063     _this->VideoQuit(_this);
2064
2065     for (i = _this->num_displays; i--;) {
2066         SDL_VideoDisplay *display = &_this->displays[i];
2067         for (j = display->num_display_modes; j--;) {
2068             if (display->display_modes[j].driverdata) {
2069                 SDL_free(display->display_modes[j].driverdata);
2070                 display->display_modes[j].driverdata = NULL;
2071             }
2072         }
2073         if (display->display_modes) {
2074             SDL_free(display->display_modes);
2075             display->display_modes = NULL;
2076         }
2077         if (display->desktop_mode.driverdata) {
2078             SDL_free(display->desktop_mode.driverdata);
2079             display->desktop_mode.driverdata = NULL;
2080         }
2081         if (display->driverdata) {
2082             SDL_free(display->driverdata);
2083             display->driverdata = NULL;
2084         }
2085     }
2086     if (_this->displays) {
2087         SDL_free(_this->displays);
2088         _this->displays = NULL;
2089     }
2090     if (_this->clipboard_text) {
2091         SDL_free(_this->clipboard_text);
2092         _this->clipboard_text = NULL;
2093     }
2094     _this->free(_this);
2095     _this = NULL;
2096 }
2097
2098 int
2099 SDL_GL_LoadLibrary(const char *path)
2100 {
2101     int retval;
2102
2103     if (!_this) {
2104         SDL_UninitializedVideo();
2105         return -1;
2106     }
2107     if (_this->gl_config.driver_loaded) {
2108         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
2109             SDL_SetError("OpenGL library already loaded");
2110             return -1;
2111         }
2112         retval = 0;
2113     } else {
2114         if (!_this->GL_LoadLibrary) {
2115             SDL_SetError("No dynamic GL support in video driver");
2116             return -1;
2117         }
2118         retval = _this->GL_LoadLibrary(_this, path);
2119     }
2120     if (retval == 0) {
2121         ++_this->gl_config.driver_loaded;
2122     }
2123     return (retval);
2124 }
2125
2126 void *
2127 SDL_GL_GetProcAddress(const char *proc)
2128 {
2129     void *func;
2130
2131     if (!_this) {
2132         SDL_UninitializedVideo();
2133         return NULL;
2134     }
2135     func = NULL;
2136     if (_this->GL_GetProcAddress) {
2137         if (_this->gl_config.driver_loaded) {
2138             func = _this->GL_GetProcAddress(_this, proc);
2139         } else {
2140             SDL_SetError("No GL driver has been loaded");
2141         }
2142     } else {
2143         SDL_SetError("No dynamic GL support in video driver");
2144     }
2145     return func;
2146 }
2147
2148 void
2149 SDL_GL_UnloadLibrary(void)
2150 {
2151     if (!_this) {
2152         SDL_UninitializedVideo();
2153         return;
2154     }
2155     if (_this->gl_config.driver_loaded > 0) {
2156         if (--_this->gl_config.driver_loaded > 0) {
2157             return;
2158         }
2159         if (_this->GL_UnloadLibrary) {
2160             _this->GL_UnloadLibrary(_this);
2161         }
2162     }
2163 }
2164
2165 SDL_bool
2166 SDL_GL_ExtensionSupported(const char *extension)
2167 {
2168 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
2169     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
2170     const char *extensions;
2171     const char *start;
2172     const char *where, *terminator;
2173
2174     /* Extension names should not have spaces. */
2175     where = SDL_strchr(extension, ' ');
2176     if (where || *extension == '\0') {
2177         return SDL_FALSE;
2178     }
2179     /* See if there's an environment variable override */
2180     start = SDL_getenv(extension);
2181     if (start && *start == '0') {
2182         return SDL_FALSE;
2183     }
2184     /* Lookup the available extensions */
2185     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
2186     if (glGetStringFunc) {
2187         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
2188     } else {
2189         extensions = NULL;
2190     }
2191     if (!extensions) {
2192         return SDL_FALSE;
2193     }
2194     /*
2195      * It takes a bit of care to be fool-proof about parsing the OpenGL
2196      * extensions string. Don't be fooled by sub-strings, etc.
2197      */
2198
2199     start = extensions;
2200
2201     for (;;) {
2202         where = SDL_strstr(start, extension);
2203         if (!where)
2204             break;
2205
2206         terminator = where + SDL_strlen(extension);
2207         if (where == start || *(where - 1) == ' ')
2208             if (*terminator == ' ' || *terminator == '\0')
2209                 return SDL_TRUE;
2210
2211         start = terminator;
2212     }
2213     return SDL_FALSE;
2214 #else
2215     return SDL_FALSE;
2216 #endif
2217 }
2218
2219 int
2220 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
2221 {
2222 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
2223     int retval;
2224
2225     if (!_this) {
2226         SDL_UninitializedVideo();
2227         return -1;
2228     }
2229     retval = 0;
2230     switch (attr) {
2231     case SDL_GL_RED_SIZE:
2232         _this->gl_config.red_size = value;
2233         break;
2234     case SDL_GL_GREEN_SIZE:
2235         _this->gl_config.green_size = value;
2236         break;
2237     case SDL_GL_BLUE_SIZE:
2238         _this->gl_config.blue_size = value;
2239         break;
2240     case SDL_GL_ALPHA_SIZE:
2241         _this->gl_config.alpha_size = value;
2242         break;
2243     case SDL_GL_DOUBLEBUFFER:
2244         _this->gl_config.double_buffer = value;
2245         break;
2246     case SDL_GL_BUFFER_SIZE:
2247         _this->gl_config.buffer_size = value;
2248         break;
2249     case SDL_GL_DEPTH_SIZE:
2250         _this->gl_config.depth_size = value;
2251         break;
2252     case SDL_GL_STENCIL_SIZE:
2253         _this->gl_config.stencil_size = value;
2254         break;
2255     case SDL_GL_ACCUM_RED_SIZE:
2256         _this->gl_config.accum_red_size = value;
2257         break;
2258     case SDL_GL_ACCUM_GREEN_SIZE:
2259         _this->gl_config.accum_green_size = value;
2260         break;
2261     case SDL_GL_ACCUM_BLUE_SIZE:
2262         _this->gl_config.accum_blue_size = value;
2263         break;
2264     case SDL_GL_ACCUM_ALPHA_SIZE:
2265         _this->gl_config.accum_alpha_size = value;
2266         break;
2267     case SDL_GL_STEREO:
2268         _this->gl_config.stereo = value;
2269         break;
2270     case SDL_GL_MULTISAMPLEBUFFERS:
2271         _this->gl_config.multisamplebuffers = value;
2272         break;
2273     case SDL_GL_MULTISAMPLESAMPLES:
2274         _this->gl_config.multisamplesamples = value;
2275         break;
2276     case SDL_GL_ACCELERATED_VISUAL:
2277         _this->gl_config.accelerated = value;
2278         break;
2279     case SDL_GL_RETAINED_BACKING:
2280         _this->gl_config.retained_backing = value;
2281         break;
2282     case SDL_GL_CONTEXT_MAJOR_VERSION:
2283         _this->gl_config.major_version = value;
2284         break;
2285     case SDL_GL_CONTEXT_MINOR_VERSION:
2286         _this->gl_config.minor_version = value;
2287         break;
2288     default:
2289         SDL_SetError("Unknown OpenGL attribute");
2290         retval = -1;
2291         break;
2292     }
2293     return retval;
2294 #else
2295     SDL_Unsupported();
2296     return -1;
2297 #endif /* SDL_VIDEO_OPENGL */
2298 }
2299
2300 int
2301 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
2302 {
2303 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
2304     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
2305     GLenum(APIENTRY * glGetErrorFunc) (void);
2306     GLenum attrib = 0;
2307     GLenum error = 0;
2308
2309     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
2310     if (!glGetIntegervFunc) {
2311         return -1;
2312     }
2313
2314     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
2315     if (!glGetErrorFunc) {
2316         return -1;
2317     }
2318
2319     /* Clear value in any case */
2320     *value = 0;
2321
2322     switch (attr) {
2323     case SDL_GL_RED_SIZE:
2324         attrib = GL_RED_BITS;
2325         break;
2326     case SDL_GL_BLUE_SIZE:
2327         attrib = GL_BLUE_BITS;
2328         break;
2329     case SDL_GL_GREEN_SIZE:
2330         attrib = GL_GREEN_BITS;
2331         break;
2332     case SDL_GL_ALPHA_SIZE:
2333         attrib = GL_ALPHA_BITS;
2334         break;
2335     case SDL_GL_DOUBLEBUFFER:
2336 #if SDL_VIDEO_OPENGL
2337         attrib = GL_DOUBLEBUFFER;
2338         break;
2339 #else
2340         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
2341         /* parameter which switches double buffer to single buffer. OpenGL ES */
2342         /* SDL driver must set proper value after initialization              */
2343         *value = _this->gl_config.double_buffer;
2344         return 0;
2345 #endif
2346     case SDL_GL_DEPTH_SIZE:
2347         attrib = GL_DEPTH_BITS;
2348         break;
2349     case SDL_GL_STENCIL_SIZE:
2350         attrib = GL_STENCIL_BITS;
2351         break;
2352 #if SDL_VIDEO_OPENGL
2353     case SDL_GL_ACCUM_RED_SIZE:
2354         attrib = GL_ACCUM_RED_BITS;
2355         break;
2356     case SDL_GL_ACCUM_GREEN_SIZE:
2357         attrib = GL_ACCUM_GREEN_BITS;
2358         break;
2359     case SDL_GL_ACCUM_BLUE_SIZE:
2360         attrib = GL_ACCUM_BLUE_BITS;
2361         break;
2362     case SDL_GL_ACCUM_ALPHA_SIZE:
2363         attrib = GL_ACCUM_ALPHA_BITS;
2364         break;
2365     case SDL_GL_STEREO:
2366         attrib = GL_STEREO;
2367         break;
2368 #else
2369     case SDL_GL_ACCUM_RED_SIZE:
2370     case SDL_GL_ACCUM_GREEN_SIZE:
2371     case SDL_GL_ACCUM_BLUE_SIZE:
2372     case SDL_GL_ACCUM_ALPHA_SIZE:
2373     case SDL_GL_STEREO:
2374         /* none of these are supported in OpenGL ES */
2375         *value = 0;
2376         return 0;
2377 #endif
2378     case SDL_GL_MULTISAMPLEBUFFERS:
2379 #if SDL_VIDEO_OPENGL
2380         attrib = GL_SAMPLE_BUFFERS_ARB;
2381 #else
2382         attrib = GL_SAMPLE_BUFFERS;
2383 #endif
2384         break;
2385     case SDL_GL_MULTISAMPLESAMPLES:
2386 #if SDL_VIDEO_OPENGL
2387         attrib = GL_SAMPLES_ARB;
2388 #else
2389         attrib = GL_SAMPLES;
2390 #endif
2391         break;
2392     case SDL_GL_BUFFER_SIZE:
2393         {
2394             GLint bits = 0;
2395             GLint component;
2396
2397             /*
2398              * there doesn't seem to be a single flag in OpenGL
2399              * for this!
2400              */
2401             glGetIntegervFunc(GL_RED_BITS, &component);
2402             bits += component;
2403             glGetIntegervFunc(GL_GREEN_BITS, &component);
2404             bits += component;
2405             glGetIntegervFunc(GL_BLUE_BITS, &component);
2406             bits += component;
2407             glGetIntegervFunc(GL_ALPHA_BITS, &component);
2408             bits += component;
2409
2410             *value = bits;
2411             return 0;
2412         }
2413     case SDL_GL_ACCELERATED_VISUAL:
2414         {
2415             /* FIXME: How do we get this information? */
2416             *value = (_this->gl_config.accelerated != 0);
2417             return 0;
2418         }
2419     case SDL_GL_RETAINED_BACKING:
2420         {
2421             *value = _this->gl_config.retained_backing;
2422             return 0;
2423         }
2424     case SDL_GL_CONTEXT_MAJOR_VERSION:
2425         {
2426             *value = _this->gl_config.major_version;
2427             return 0;
2428         }
2429     case SDL_GL_CONTEXT_MINOR_VERSION:
2430         {
2431             *value = _this->gl_config.minor_version;
2432             return 0;
2433         }
2434     default:
2435         SDL_SetError("Unknown OpenGL attribute");
2436         return -1;
2437     }
2438
2439     glGetIntegervFunc(attrib, (GLint *) value);
2440     error = glGetErrorFunc();
2441     if (error != GL_NO_ERROR) {
2442         switch (error) {
2443         case GL_INVALID_ENUM:
2444             {
2445                 SDL_SetError("OpenGL error: GL_INVALID_ENUM");
2446             }
2447             break;
2448         case GL_INVALID_VALUE:
2449             {
2450                 SDL_SetError("OpenGL error: GL_INVALID_VALUE");
2451             }
2452             break;
2453         default:
2454             {
2455                 SDL_SetError("OpenGL error: %08X", error);
2456             }
2457             break;
2458         }
2459         return -1;
2460     }
2461     return 0;
2462 #else
2463     SDL_Unsupported();
2464     return -1;
2465 #endif /* SDL_VIDEO_OPENGL */
2466 }
2467
2468 SDL_GLContext
2469 SDL_GL_CreateContext(SDL_Window * window)
2470 {
2471     SDL_GLContext ctx = NULL;
2472     CHECK_WINDOW_MAGIC(window, NULL);
2473
2474     if (!(window->flags & SDL_WINDOW_OPENGL)) {
2475         SDL_SetError("The specified window isn't an OpenGL window");
2476         return NULL;
2477     }
2478
2479     ctx = _this->GL_CreateContext(_this, window);
2480
2481     /* Creating a context is assumed to make it current in the SDL driver. */
2482     _this->current_glwin = window;
2483     _this->current_glctx = ctx;
2484
2485     return ctx;
2486 }
2487
2488 int
2489 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
2490 {
2491     int retval;
2492
2493     CHECK_WINDOW_MAGIC(window, -1);
2494
2495     if (!(window->flags & SDL_WINDOW_OPENGL)) {
2496         SDL_SetError("The specified window isn't an OpenGL window");
2497         return -1;
2498     }
2499     if (!ctx) {
2500         window = NULL;
2501     }
2502
2503     if ((window == _this->current_glwin) && (ctx == _this->current_glctx)) {
2504         retval = 0;  /* we're already current. */
2505     } else {
2506         retval = _this->GL_MakeCurrent(_this, window, ctx);
2507         if (retval == 0) {
2508             _this->current_glwin = window;
2509             _this->current_glctx = ctx;
2510         }
2511     }
2512
2513     return retval;
2514 }
2515
2516 int
2517 SDL_GL_SetSwapInterval(int interval)
2518 {
2519     if (!_this) {
2520         SDL_UninitializedVideo();
2521         return -1;
2522     } else if (_this->current_glctx == NULL) {
2523         SDL_SetError("No OpenGL context has been made current");
2524         return -1;
2525     } else if (_this->GL_SetSwapInterval) {
2526         return _this->GL_SetSwapInterval(_this, interval);
2527     } else {
2528         SDL_SetError("Setting the swap interval is not supported");
2529         return -1;
2530     }
2531 }
2532
2533 int
2534 SDL_GL_GetSwapInterval(void)
2535 {
2536     if (!_this) {
2537         SDL_UninitializedVideo();
2538         return -1;
2539     } else if (_this->current_glctx == NULL) {
2540         SDL_SetError("No OpenGL context has been made current");
2541         return -1;
2542     } else if (_this->GL_GetSwapInterval) {
2543         return _this->GL_GetSwapInterval(_this);
2544     } else {
2545         SDL_SetError("Getting the swap interval is not supported");
2546         return -1;
2547     }
2548 }
2549
2550 void
2551 SDL_GL_SwapWindow(SDL_Window * window)
2552 {
2553     CHECK_WINDOW_MAGIC(window, );
2554
2555     if (!(window->flags & SDL_WINDOW_OPENGL)) {
2556         SDL_SetError("The specified window isn't an OpenGL window");
2557         return;
2558     }
2559     _this->GL_SwapWindow(_this, window);
2560 }
2561
2562 void
2563 SDL_GL_DeleteContext(SDL_GLContext context)
2564 {
2565     if (!_this || !_this->gl_data || !context) {
2566         return;
2567     }
2568     _this->GL_MakeCurrent(_this, NULL, NULL);
2569     _this->GL_DeleteContext(_this, context);
2570 }
2571
2572 #if 0                           // FIXME
2573 /*
2574  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
2575  * & 2 for alpha channel.
2576  */
2577 static void
2578 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
2579 {
2580     int x, y;
2581     Uint32 colorkey;
2582 #define SET_MASKBIT(icon, x, y, mask) \
2583         mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
2584
2585     colorkey = icon->format->colorkey;
2586     switch (icon->format->BytesPerPixel) {
2587     case 1:
2588         {
2589             Uint8 *pixels;
2590             for (y = 0; y < icon->h; ++y) {
2591                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
2592                 for (x = 0; x < icon->w; ++x) {
2593                     if (*pixels++ == colorkey) {
2594                         SET_MASKBIT(icon, x, y, mask);
2595                     }
2596                 }
2597             }
2598         }
2599         break;
2600
2601     case 2:
2602         {
2603             Uint16 *pixels;
2604             for (y = 0; y < icon->h; ++y) {
2605                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
2606                 for (x = 0; x < icon->w; ++x) {
2607                     if ((flags & 1) && *pixels == colorkey) {
2608                         SET_MASKBIT(icon, x, y, mask);
2609                     } else if ((flags & 2)
2610                                && (*pixels & icon->format->Amask) == 0) {
2611                         SET_MASKBIT(icon, x, y, mask);
2612                     }
2613                     pixels++;
2614                 }
2615             }
2616         }
2617         break;
2618
2619     case 4:
2620         {
2621             Uint32 *pixels;
2622             for (y = 0; y < icon->h; ++y) {
2623                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
2624                 for (x = 0; x < icon->w; ++x) {
2625                     if ((flags & 1) && *pixels == colorkey) {
2626                         SET_MASKBIT(icon, x, y, mask);
2627                     } else if ((flags & 2)
2628                                && (*pixels & icon->format->Amask) == 0) {
2629                         SET_MASKBIT(icon, x, y, mask);
2630                     }
2631                     pixels++;
2632                 }
2633             }
2634         }
2635         break;
2636     }
2637 }
2638
2639 /*
2640  * Sets the window manager icon for the display window.
2641  */
2642 void
2643 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
2644 {
2645     if (icon && _this->SetIcon) {
2646         /* Generate a mask if necessary, and create the icon! */
2647         if (mask == NULL) {
2648             int mask_len = icon->h * (icon->w + 7) / 8;
2649             int flags = 0;
2650             mask = (Uint8 *) SDL_malloc(mask_len);
2651             if (mask == NULL) {
2652                 return;
2653             }
2654             SDL_memset(mask, ~0, mask_len);
2655             if (icon->flags & SDL_SRCCOLORKEY)
2656                 flags |= 1;
2657             if (icon->flags & SDL_SRCALPHA)
2658                 flags |= 2;
2659             if (flags) {
2660                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
2661             }
2662             _this->SetIcon(_this, icon, mask);
2663             SDL_free(mask);
2664         } else {
2665             _this->SetIcon(_this, icon, mask);
2666         }
2667     }
2668 }
2669 #endif
2670
2671 SDL_bool
2672 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
2673 {
2674     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
2675
2676     if (!info) {
2677         return SDL_FALSE;
2678     }
2679     info->subsystem = SDL_SYSWM_UNKNOWN;
2680
2681     if (!_this->GetWindowWMInfo) {
2682         return SDL_FALSE;
2683     }
2684     return (_this->GetWindowWMInfo(_this, window, info));
2685 }
2686
2687 void
2688 SDL_StartTextInput(void)
2689 {
2690     if (_this && _this->StartTextInput) {
2691         _this->StartTextInput(_this);
2692     }
2693     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
2694     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
2695 }
2696
2697 void
2698 SDL_StopTextInput(void)
2699 {
2700     if (_this && _this->StopTextInput) {
2701         _this->StopTextInput(_this);
2702     }
2703     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
2704     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
2705 }
2706
2707 void
2708 SDL_SetTextInputRect(SDL_Rect *rect)
2709 {
2710     if (_this && _this->SetTextInputRect) {
2711         _this->SetTextInputRect(_this, rect);
2712     }
2713 }
2714
2715 /* vi: set ts=4 sw=4 expandtab: */