src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 21 Feb 2011 16:45:23 -0800
changeset 5375 16877f74123c
parent 5373 02007fd16991
child 5380 2de85077eb0b
permissions -rw-r--r--
Implemented Cocoa_SetWindowIcon(), added SDL_ConvertSurfaceFormat()
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* The high-level video driver subsystem */
    25 
    26 #include "SDL.h"
    27 #include "SDL_video.h"
    28 #include "SDL_sysvideo.h"
    29 #include "SDL_blit.h"
    30 #include "SDL_pixels_c.h"
    31 #include "SDL_rect_c.h"
    32 #include "../events/SDL_events_c.h"
    33 
    34 #if SDL_VIDEO_OPENGL
    35 #include "SDL_opengl.h"
    36 #endif /* SDL_VIDEO_OPENGL */
    37 
    38 #if SDL_VIDEO_OPENGL_ES
    39 #include "SDL_opengles.h"
    40 #endif /* SDL_VIDEO_OPENGL_ES */
    41 
    42 #if SDL_VIDEO_OPENGL_ES2
    43 #include "SDL_opengles2.h"
    44 #endif /* SDL_VIDEO_OPENGL_ES2 */
    45 
    46 #include "SDL_syswm.h"
    47 
    48 /* On Windows, windows.h defines CreateWindow */
    49 #ifdef CreateWindow
    50 #undef CreateWindow
    51 #endif
    52 
    53 /* Available video drivers */
    54 static VideoBootStrap *bootstrap[] = {
    55 #if SDL_VIDEO_DRIVER_COCOA
    56     &COCOA_bootstrap,
    57 #endif
    58 #if SDL_VIDEO_DRIVER_X11
    59     &X11_bootstrap,
    60 #endif
    61 #if SDL_VIDEO_DRIVER_DIRECTFB
    62     &DirectFB_bootstrap,
    63 #endif
    64 #if SDL_VIDEO_DRIVER_WINDOWS
    65     &WINDOWS_bootstrap,
    66 #endif
    67 #if SDL_VIDEO_DRIVER_BWINDOW
    68     &BWINDOW_bootstrap,
    69 #endif
    70 #if SDL_VIDEO_DRIVER_PANDORA
    71     &PND_bootstrap,
    72 #endif
    73 #if SDL_VIDEO_DRIVER_NDS
    74     &NDS_bootstrap,
    75 #endif
    76 #if SDL_VIDEO_DRIVER_UIKIT
    77     &UIKIT_bootstrap,
    78 #endif
    79 #if SDL_VIDEO_DRIVER_ANDROID
    80     &Android_bootstrap,
    81 #endif
    82 #if SDL_VIDEO_DRIVER_DUMMY
    83     &DUMMY_bootstrap,
    84 #endif
    85     NULL
    86 };
    87 
    88 static SDL_VideoDevice *_this = NULL;
    89 
    90 #define CHECK_WINDOW_MAGIC(window, retval) \
    91     if (!_this) { \
    92         SDL_UninitializedVideo(); \
    93         return retval; \
    94     } \
    95     if (!window || window->magic != &_this->window_magic) { \
    96         SDL_SetError("Invalid window"); \
    97         return retval; \
    98     }
    99 
   100 #define CHECK_DISPLAY_INDEX(displayIndex, retval) \
   101     if (!_this) { \
   102         SDL_UninitializedVideo(); \
   103         return retval; \
   104     } \
   105     if (displayIndex < 0 || displayIndex >= _this->num_displays) { \
   106         SDL_SetError("displayIndex must be in the range 0 - %d", \
   107                      _this->num_displays - 1); \
   108         return retval; \
   109     }
   110 
   111 /* Various local functions */
   112 static void SDL_UpdateWindowGrab(SDL_Window * window);
   113 
   114 /* Support for framebuffer emulation using an accelerated renderer */
   115 
   116 #define SDL_WINDOWTEXTUREDATA   "_SDL_WindowTextureData"
   117 
   118 typedef struct {
   119     SDL_Renderer *renderer;
   120     SDL_Texture *texture;
   121     void *pixels;
   122     int pitch;
   123     int bytes_per_pixel;
   124 } SDL_WindowTextureData;
   125 
   126 static SDL_bool
   127 ShouldUseTextureFramebuffer()
   128 {
   129     const char *hint;
   130 
   131     /* If there's no native framebuffer support then there's no option */
   132     if (!_this->CreateWindowFramebuffer) {
   133         return SDL_TRUE;
   134     }
   135 
   136     /* If the user has specified a software renderer we can't use a
   137        texture framebuffer, or renderer creation will go recursive.
   138      */
   139     hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
   140     if (hint && SDL_strcasecmp(hint, "software") == 0) {
   141         return SDL_FALSE;
   142     }
   143 
   144     /* See if the user or application wants a specific behavior */
   145     hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   146     if (hint) {
   147         if (*hint == '0') {
   148             return SDL_FALSE;
   149         } else {
   150             return SDL_TRUE;
   151         }
   152     }
   153 
   154     /* Each platform has different performance characteristics */
   155 #if defined(__WIN32__)
   156     /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
   157      */
   158     return SDL_FALSE;
   159 
   160 #elif defined(__MACOSX__)
   161     /* Mac OS X uses OpenGL as the native fast path */
   162     return SDL_TRUE;
   163 
   164 #elif defined(__LINUX__)
   165     /* Properly configured OpenGL drivers are faster than MIT-SHM */
   166 #if SDL_VIDEO_OPENGL
   167     /* Ugh, find a way to cache this value! */
   168     {
   169         SDL_Window *window;
   170         SDL_GLContext context;
   171         SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
   172 
   173         window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL);
   174         if (window) {
   175             context = SDL_GL_CreateContext(window);
   176             if (context) {
   177                 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
   178                 const char *vendor = NULL;
   179 
   180                 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
   181                 if (glGetStringFunc) {
   182                     vendor = (const char *) glGetStringFunc(GL_VENDOR);
   183                 }
   184                 /* Add more vendors here at will... */
   185                 if (vendor &&
   186                     (SDL_strstr(vendor, "ATI Technologies") ||
   187                      SDL_strstr(vendor, "NVIDIA"))) {
   188                     hasAcceleratedOpenGL = SDL_TRUE;
   189                 }
   190                 SDL_GL_DeleteContext(context);
   191             }
   192             SDL_DestroyWindow(window);
   193         }
   194         return hasAcceleratedOpenGL;
   195     }
   196 #else
   197     return SDL_FALSE;
   198 #endif
   199 
   200 #else
   201     /* Play it safe, assume that if there is a framebuffer driver that it's
   202        optimized for the current platform.
   203     */
   204     return SDL_FALSE;
   205 #endif
   206 }
   207 
   208 static int
   209 SDL_CreateWindowTexture(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
   210 {
   211     SDL_WindowTextureData *data;
   212     SDL_RendererInfo info;
   213     Uint32 i;
   214 
   215     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
   216     if (!data) {
   217         SDL_Renderer *renderer = NULL;
   218         SDL_RendererInfo info;
   219         int i;
   220         const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   221 
   222         /* Check to see if there's a specific driver requested */
   223         if (hint && *hint != '0' && *hint != '1' &&
   224             SDL_strcasecmp(hint, "software") != 0) {
   225             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   226                 SDL_GetRenderDriverInfo(i, &info);
   227                 if (SDL_strcasecmp(info.name, hint) == 0) {
   228                     renderer = SDL_CreateRenderer(window, i, 0);
   229                     break;
   230                 }
   231             }
   232         }
   233 
   234         if (!renderer) {
   235             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   236                 SDL_GetRenderDriverInfo(i, &info);
   237                 if (SDL_strcmp(info.name, "software") != 0) {
   238                     renderer = SDL_CreateRenderer(window, i, 0);
   239                     if (renderer) {
   240                         break;
   241                     }
   242                 }
   243             }
   244         }
   245         if (!renderer) {
   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 int
   584 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
   585 {
   586     CHECK_DISPLAY_INDEX(displayIndex, -1);
   587 
   588     if (rect) {
   589         SDL_VideoDisplay *display = &_this->displays[displayIndex];
   590 
   591         if (_this->GetDisplayBounds) {
   592             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
   593                 return 0;
   594             }
   595         }
   596 
   597         /* Assume that the displays are left to right */
   598         if (displayIndex == 0) {
   599             rect->x = 0;
   600             rect->y = 0;
   601         } else {
   602             SDL_GetDisplayBounds(displayIndex-1, rect);
   603             rect->x += rect->w;
   604         }
   605         rect->w = display->desktop_mode.w;
   606         rect->h = display->desktop_mode.h;
   607     }
   608     return 0;
   609 }
   610 
   611 SDL_bool
   612 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
   613 {
   614     SDL_DisplayMode *modes;
   615     int i, nmodes;
   616 
   617     /* Make sure we don't already have the mode in the list */
   618     modes = display->display_modes;
   619     nmodes = display->num_display_modes;
   620     for (i = nmodes; i--;) {
   621         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
   622             return SDL_FALSE;
   623         }
   624     }
   625 
   626     /* Go ahead and add the new mode */
   627     if (nmodes == display->max_display_modes) {
   628         modes =
   629             SDL_realloc(modes,
   630                         (display->max_display_modes + 32) * sizeof(*modes));
   631         if (!modes) {
   632             return SDL_FALSE;
   633         }
   634         display->display_modes = modes;
   635         display->max_display_modes += 32;
   636     }
   637     modes[nmodes] = *mode;
   638     display->num_display_modes++;
   639 
   640     /* Re-sort video modes */
   641     SDL_qsort(display->display_modes, display->num_display_modes,
   642               sizeof(SDL_DisplayMode), cmpmodes);
   643 
   644     return SDL_TRUE;
   645 }
   646 
   647 SDL_VideoDisplay *
   648 SDL_GetFirstDisplay(void)
   649 {
   650     return &_this->displays[0];
   651 }
   652 
   653 static int
   654 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
   655 {
   656     if (!display->num_display_modes && _this->GetDisplayModes) {
   657         _this->GetDisplayModes(_this, display);
   658         SDL_qsort(display->display_modes, display->num_display_modes,
   659                   sizeof(SDL_DisplayMode), cmpmodes);
   660     }
   661     return display->num_display_modes;
   662 }
   663 
   664 int
   665 SDL_GetNumDisplayModes(int displayIndex)
   666 {
   667     CHECK_DISPLAY_INDEX(displayIndex, -1);
   668 
   669     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
   670 }
   671 
   672 int
   673 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
   674 {
   675     SDL_VideoDisplay *display;
   676 
   677     CHECK_DISPLAY_INDEX(displayIndex, -1);
   678 
   679     display = &_this->displays[displayIndex];
   680     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
   681         SDL_SetError("index must be in the range of 0 - %d",
   682                      SDL_GetNumDisplayModesForDisplay(display) - 1);
   683         return -1;
   684     }
   685     if (mode) {
   686         *mode = display->display_modes[index];
   687     }
   688     return 0;
   689 }
   690 
   691 int
   692 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   693 {
   694     SDL_VideoDisplay *display;
   695 
   696     CHECK_DISPLAY_INDEX(displayIndex, -1);
   697 
   698     display = &_this->displays[displayIndex];
   699     if (mode) {
   700         *mode = display->desktop_mode;
   701     }
   702     return 0;
   703 }
   704 
   705 int
   706 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   707 {
   708     SDL_VideoDisplay *display;
   709 
   710     CHECK_DISPLAY_INDEX(displayIndex, -1);
   711 
   712     display = &_this->displays[displayIndex];
   713     if (mode) {
   714         *mode = display->current_mode;
   715     }
   716     return 0;
   717 }
   718 
   719 static SDL_DisplayMode *
   720 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
   721                                     const SDL_DisplayMode * mode,
   722                                     SDL_DisplayMode * closest)
   723 {
   724     Uint32 target_format;
   725     int target_refresh_rate;
   726     int i;
   727     SDL_DisplayMode *current, *match;
   728 
   729     if (!mode || !closest) {
   730         SDL_SetError("Missing desired mode or closest mode parameter");
   731         return NULL;
   732     }
   733 
   734     /* Default to the desktop format */
   735     if (mode->format) {
   736         target_format = mode->format;
   737     } else {
   738         target_format = display->desktop_mode.format;
   739     }
   740 
   741     /* Default to the desktop refresh rate */
   742     if (mode->refresh_rate) {
   743         target_refresh_rate = mode->refresh_rate;
   744     } else {
   745         target_refresh_rate = display->desktop_mode.refresh_rate;
   746     }
   747 
   748     match = NULL;
   749     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
   750         current = &display->display_modes[i];
   751 
   752         if (current->w && (current->w < mode->w)) {
   753             /* Out of sorted modes large enough here */
   754             break;
   755         }
   756         if (current->h && (current->h < mode->h)) {
   757             if (current->w && (current->w == mode->w)) {
   758                 /* Out of sorted modes large enough here */
   759                 break;
   760             }
   761             /* Wider, but not tall enough, due to a different
   762                aspect ratio. This mode must be skipped, but closer
   763                modes may still follow. */
   764             continue;
   765         }
   766         if (!match || current->w < match->w || current->h < match->h) {
   767             match = current;
   768             continue;
   769         }
   770         if (current->format != match->format) {
   771             /* Sorted highest depth to lowest */
   772             if (current->format == target_format ||
   773                 (SDL_BITSPERPIXEL(current->format) >=
   774                  SDL_BITSPERPIXEL(target_format)
   775                  && SDL_PIXELTYPE(current->format) ==
   776                  SDL_PIXELTYPE(target_format))) {
   777                 match = current;
   778             }
   779             continue;
   780         }
   781         if (current->refresh_rate != match->refresh_rate) {
   782             /* Sorted highest refresh to lowest */
   783             if (current->refresh_rate >= target_refresh_rate) {
   784                 match = current;
   785             }
   786         }
   787     }
   788     if (match) {
   789         if (match->format) {
   790             closest->format = match->format;
   791         } else {
   792             closest->format = mode->format;
   793         }
   794         if (match->w && match->h) {
   795             closest->w = match->w;
   796             closest->h = match->h;
   797         } else {
   798             closest->w = mode->w;
   799             closest->h = mode->h;
   800         }
   801         if (match->refresh_rate) {
   802             closest->refresh_rate = match->refresh_rate;
   803         } else {
   804             closest->refresh_rate = mode->refresh_rate;
   805         }
   806         closest->driverdata = match->driverdata;
   807 
   808         /*
   809          * Pick some reasonable defaults if the app and driver don't
   810          * care
   811          */
   812         if (!closest->format) {
   813             closest->format = SDL_PIXELFORMAT_RGB888;
   814         }
   815         if (!closest->w) {
   816             closest->w = 640;
   817         }
   818         if (!closest->h) {
   819             closest->h = 480;
   820         }
   821         return closest;
   822     }
   823     return NULL;
   824 }
   825 
   826 SDL_DisplayMode *
   827 SDL_GetClosestDisplayMode(int displayIndex,
   828                           const SDL_DisplayMode * mode,
   829                           SDL_DisplayMode * closest)
   830 {
   831     SDL_VideoDisplay *display;
   832 
   833     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   834 
   835     display = &_this->displays[displayIndex];
   836     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
   837 }
   838 
   839 int
   840 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
   841 {
   842     SDL_DisplayMode display_mode;
   843     SDL_DisplayMode current_mode;
   844 
   845     if (mode) {
   846         display_mode = *mode;
   847 
   848         /* Default to the current mode */
   849         if (!display_mode.format) {
   850             display_mode.format = display->current_mode.format;
   851         }
   852         if (!display_mode.w) {
   853             display_mode.w = display->current_mode.w;
   854         }
   855         if (!display_mode.h) {
   856             display_mode.h = display->current_mode.h;
   857         }
   858         if (!display_mode.refresh_rate) {
   859             display_mode.refresh_rate = display->current_mode.refresh_rate;
   860         }
   861 
   862         /* Get a good video mode, the closest one possible */
   863         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
   864             SDL_SetError("No video mode large enough for %dx%d",
   865                          display_mode.w, display_mode.h);
   866             return -1;
   867         }
   868     } else {
   869         display_mode = display->desktop_mode;
   870     }
   871 
   872     /* See if there's anything left to do */
   873     current_mode = display->current_mode;
   874     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   875         return 0;
   876     }
   877 
   878     /* Actually change the display mode */
   879     if (!_this->SetDisplayMode) {
   880         SDL_SetError("Video driver doesn't support changing display mode");
   881         return -1;
   882     }
   883     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
   884         return -1;
   885     }
   886     display->current_mode = display_mode;
   887     return 0;
   888 }
   889 
   890 int
   891 SDL_GetWindowDisplay(SDL_Window * window)
   892 {
   893     int displayIndex;
   894     int i, dist;
   895     int closest = -1;
   896     int closest_dist = 0x7FFFFFFF;
   897     SDL_Point center;
   898     SDL_Point delta;
   899     SDL_Rect rect;
   900 
   901     CHECK_WINDOW_MAGIC(window, -1);
   902 
   903     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
   904         SDL_WINDOWPOS_ISCENTERED(window->x)) {
   905         displayIndex = (window->x & 0xFFFF);
   906         if (displayIndex >= _this->num_displays) {
   907             displayIndex = 0;
   908         }
   909         return displayIndex;
   910     }
   911     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
   912         SDL_WINDOWPOS_ISCENTERED(window->y)) {
   913         displayIndex = (window->y & 0xFFFF);
   914         if (displayIndex >= _this->num_displays) {
   915             displayIndex = 0;
   916         }
   917         return displayIndex;
   918     }
   919 
   920     /* Find the display containing the window */
   921     center.x = window->x + window->w / 2;
   922     center.y = window->y + window->h / 2;
   923     for (i = 0; i < _this->num_displays; ++i) {
   924         SDL_VideoDisplay *display = &_this->displays[i];
   925 
   926         SDL_GetDisplayBounds(i, &rect);
   927         if (display->fullscreen_window == window || SDL_EnclosePoints(&center, 1, &rect, NULL)) {
   928             return i;
   929         }
   930 
   931         delta.x = center.x - (rect.x + rect.w / 2);
   932         delta.y = center.y - (rect.y + rect.h / 2);
   933         dist = (delta.x*delta.x + delta.y*delta.y);
   934         if (dist < closest_dist) {
   935             closest = i;
   936             closest_dist = dist;
   937         }
   938     }
   939     if (closest < 0) {
   940         SDL_SetError("Couldn't find any displays");
   941     }
   942     return closest;
   943 }
   944 
   945 SDL_VideoDisplay *
   946 SDL_GetDisplayForWindow(SDL_Window *window)
   947 {
   948     int displayIndex = SDL_GetWindowDisplay(window);
   949     if (displayIndex >= 0) {
   950         return &_this->displays[displayIndex];
   951     } else {
   952         return NULL;
   953     }
   954 }
   955 
   956 int
   957 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
   958 {
   959     CHECK_WINDOW_MAGIC(window, -1);
   960 
   961     if (mode) {
   962         window->fullscreen_mode = *mode;
   963     } else {
   964         SDL_zero(window->fullscreen_mode);
   965     }
   966     return 0;
   967 }
   968 
   969 int
   970 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
   971 {
   972     SDL_DisplayMode fullscreen_mode;
   973 
   974     CHECK_WINDOW_MAGIC(window, -1);
   975 
   976     fullscreen_mode = window->fullscreen_mode;
   977     if (!fullscreen_mode.w) {
   978         fullscreen_mode.w = window->w;
   979     }
   980     if (!fullscreen_mode.h) {
   981         fullscreen_mode.h = window->h;
   982     }
   983 
   984     if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
   985                                              &fullscreen_mode,
   986                                              &fullscreen_mode)) {
   987         SDL_SetError("Couldn't find display mode match");
   988         return -1;
   989     }
   990 
   991     if (mode) {
   992         *mode = fullscreen_mode;
   993     }
   994     return 0;
   995 }
   996 
   997 Uint32
   998 SDL_GetWindowPixelFormat(SDL_Window * window)
   999 {
  1000     SDL_VideoDisplay *display;
  1001 
  1002     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
  1003 
  1004     display = SDL_GetDisplayForWindow(window);
  1005     return display->current_mode.format;
  1006 }
  1007 
  1008 static void
  1009 SDL_UpdateFullscreenMode(SDL_Window * window)
  1010 {
  1011     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1012     SDL_Window *other;
  1013 
  1014     if (FULLSCREEN_VISIBLE(window)) {
  1015         /* Hide any other fullscreen windows */
  1016         if (display->fullscreen_window &&
  1017             display->fullscreen_window != window) {
  1018             SDL_MinimizeWindow(display->fullscreen_window);
  1019         }
  1020     }
  1021 
  1022     /* See if anything needs to be done now */
  1023     if ((display->fullscreen_window == window) == FULLSCREEN_VISIBLE(window)) {
  1024         return;
  1025     }
  1026 
  1027     /* See if there are any fullscreen windows */
  1028     for (other = _this->windows; other; other = other->next) {
  1029         if (FULLSCREEN_VISIBLE(other) &&
  1030             SDL_GetDisplayForWindow(other) == display) {
  1031             SDL_DisplayMode fullscreen_mode;
  1032             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1033                 SDL_bool resized = SDL_TRUE;
  1034 
  1035                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1036                     resized = SDL_FALSE;
  1037                 }
  1038 
  1039                 SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
  1040                 if (_this->SetWindowFullscreen) {
  1041                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1042                 }
  1043                 display->fullscreen_window = other;
  1044 
  1045                 /* Generate a mode change event here */
  1046                 if (resized) {
  1047                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1048                                         fullscreen_mode.w, fullscreen_mode.h);
  1049                 } else {
  1050                     SDL_OnWindowResized(other);
  1051                 }
  1052                 return;
  1053             }
  1054         }
  1055     }
  1056 
  1057     /* Nope, restore the desktop mode */
  1058     SDL_SetDisplayModeForDisplay(display, NULL);
  1059 
  1060     if (_this->SetWindowFullscreen) {
  1061         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1062     }
  1063     display->fullscreen_window = NULL;
  1064 
  1065     /* Generate a mode change event here */
  1066     SDL_OnWindowResized(window);
  1067 }
  1068 
  1069 SDL_Window *
  1070 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1071 {
  1072     const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN |
  1073                                   SDL_WINDOW_OPENGL |
  1074                                   SDL_WINDOW_BORDERLESS |
  1075                                   SDL_WINDOW_RESIZABLE |
  1076                                   SDL_WINDOW_INPUT_GRABBED);
  1077     SDL_Window *window;
  1078 
  1079     if (!_this) {
  1080         /* Initialize the video system if needed */
  1081         if (SDL_VideoInit(NULL) < 0) {
  1082             return NULL;
  1083         }
  1084     }
  1085 
  1086     /* Some platforms have OpenGL enabled by default */
  1087 #if (SDL_VIDEO_OPENGL && __MACOSX__) || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  1088     flags |= SDL_WINDOW_OPENGL;
  1089 #endif
  1090     if (flags & SDL_WINDOW_OPENGL) {
  1091         if (!_this->GL_CreateContext) {
  1092             SDL_SetError("No OpenGL support in video driver");
  1093             return NULL;
  1094         }
  1095         SDL_GL_LoadLibrary(NULL);
  1096     }
  1097     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1098     window->magic = &_this->window_magic;
  1099     window->id = _this->next_object_id++;
  1100     window->x = x;
  1101     window->y = y;
  1102     window->w = w;
  1103     window->h = h;
  1104     window->flags = (flags & allowed_flags);
  1105     window->next = _this->windows;
  1106     if (_this->windows) {
  1107         _this->windows->prev = window;
  1108     }
  1109     _this->windows = window;
  1110 
  1111     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1112         SDL_DestroyWindow(window);
  1113         return NULL;
  1114     }
  1115 
  1116     if (title) {
  1117         SDL_SetWindowTitle(window, title);
  1118     }
  1119     if (flags & SDL_WINDOW_MAXIMIZED) {
  1120         SDL_MaximizeWindow(window);
  1121     }
  1122     if (flags & SDL_WINDOW_MINIMIZED) {
  1123         SDL_MinimizeWindow(window);
  1124     }
  1125     if (flags & SDL_WINDOW_SHOWN) {
  1126         SDL_ShowWindow(window);
  1127     }
  1128     SDL_UpdateWindowGrab(window);
  1129 
  1130     return window;
  1131 }
  1132 
  1133 SDL_Window *
  1134 SDL_CreateWindowFrom(const void *data)
  1135 {
  1136     SDL_Window *window;
  1137 
  1138     if (!_this) {
  1139         SDL_UninitializedVideo();
  1140         return NULL;
  1141     }
  1142     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1143     window->magic = &_this->window_magic;
  1144     window->id = _this->next_object_id++;
  1145     window->flags = SDL_WINDOW_FOREIGN;
  1146     window->next = _this->windows;
  1147     if (_this->windows) {
  1148         _this->windows->prev = window;
  1149     }
  1150     _this->windows = window;
  1151 
  1152     if (!_this->CreateWindowFrom ||
  1153         _this->CreateWindowFrom(_this, window, data) < 0) {
  1154         SDL_DestroyWindow(window);
  1155         return NULL;
  1156     }
  1157     return window;
  1158 }
  1159 
  1160 int
  1161 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1162 {
  1163     const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN |
  1164                                   SDL_WINDOW_OPENGL |
  1165                                   SDL_WINDOW_BORDERLESS |
  1166                                   SDL_WINDOW_RESIZABLE |
  1167                                   SDL_WINDOW_INPUT_GRABBED |
  1168                                   SDL_WINDOW_FOREIGN);
  1169     char *title = window->title;
  1170 
  1171     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1172         SDL_SetError("No OpenGL support in video driver");
  1173         return -1;
  1174     }
  1175 
  1176     if (window->flags & SDL_WINDOW_FOREIGN) {
  1177         /* Can't destroy and re-create foreign windows, hrm */
  1178         flags |= SDL_WINDOW_FOREIGN;
  1179     } else {
  1180         flags &= ~SDL_WINDOW_FOREIGN;
  1181     }
  1182 
  1183     /* Restore video mode, etc. */
  1184     SDL_HideWindow(window);
  1185 
  1186     /* Tear down the old native window */
  1187     if (window->surface) {
  1188         window->surface->flags &= ~SDL_DONTFREE;
  1189         SDL_FreeSurface(window->surface);
  1190     }
  1191     if (_this->DestroyWindowFramebuffer) {
  1192         _this->DestroyWindowFramebuffer(_this, window);
  1193     }
  1194     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1195         _this->DestroyWindow(_this, window);
  1196     }
  1197 
  1198     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1199         if (flags & SDL_WINDOW_OPENGL) {
  1200             SDL_GL_LoadLibrary(NULL);
  1201         } else {
  1202             SDL_GL_UnloadLibrary();
  1203         }
  1204     }
  1205 
  1206     window->title = NULL;
  1207     window->flags = (flags & allowed_flags);
  1208 
  1209     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1210         if (_this->CreateWindow(_this, window) < 0) {
  1211             if (flags & SDL_WINDOW_OPENGL) {
  1212                 SDL_GL_UnloadLibrary();
  1213             }
  1214             return -1;
  1215         }
  1216     }
  1217 
  1218     if (title) {
  1219         SDL_SetWindowTitle(window, title);
  1220         SDL_free(title);
  1221     }
  1222     if (flags & SDL_WINDOW_MAXIMIZED) {
  1223         SDL_MaximizeWindow(window);
  1224     }
  1225     if (flags & SDL_WINDOW_MINIMIZED) {
  1226         SDL_MinimizeWindow(window);
  1227     }
  1228     if (flags & SDL_WINDOW_SHOWN) {
  1229         SDL_ShowWindow(window);
  1230     }
  1231     SDL_UpdateWindowGrab(window);
  1232 
  1233     return 0;
  1234 }
  1235 
  1236 Uint32
  1237 SDL_GetWindowID(SDL_Window * window)
  1238 {
  1239     CHECK_WINDOW_MAGIC(window, 0);
  1240 
  1241     return window->id;
  1242 }
  1243 
  1244 SDL_Window *
  1245 SDL_GetWindowFromID(Uint32 id)
  1246 {
  1247     SDL_Window *window;
  1248 
  1249     if (!_this) {
  1250         return NULL;
  1251     }
  1252     for (window = _this->windows; window; window = window->next) {
  1253         if (window->id == id) {
  1254             return window;
  1255         }
  1256     }
  1257     return NULL;
  1258 }
  1259 
  1260 Uint32
  1261 SDL_GetWindowFlags(SDL_Window * window)
  1262 {
  1263     CHECK_WINDOW_MAGIC(window, 0);
  1264 
  1265     return window->flags;
  1266 }
  1267 
  1268 void
  1269 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1270 {
  1271     CHECK_WINDOW_MAGIC(window, );
  1272 
  1273     if (title == window->title) {
  1274         return;
  1275     }
  1276     if (window->title) {
  1277         SDL_free(window->title);
  1278     }
  1279     if (title && *title) {
  1280         window->title = SDL_strdup(title);
  1281     } else {
  1282         window->title = NULL;
  1283     }
  1284 
  1285     if (_this->SetWindowTitle) {
  1286         _this->SetWindowTitle(_this, window);
  1287     }
  1288 }
  1289 
  1290 const char *
  1291 SDL_GetWindowTitle(SDL_Window * window)
  1292 {
  1293     CHECK_WINDOW_MAGIC(window, "");
  1294 
  1295     return window->title ? window->title : "";
  1296 }
  1297 
  1298 void
  1299 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1300 {
  1301     CHECK_WINDOW_MAGIC(window, );
  1302 
  1303     if (!icon) {
  1304         return;
  1305     }
  1306 
  1307     if (_this->SetWindowIcon) {
  1308         _this->SetWindowIcon(_this, window, icon);
  1309     }
  1310 }
  1311 
  1312 void*
  1313 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1314 {
  1315     SDL_WindowUserData *prev, *data;
  1316 
  1317     CHECK_WINDOW_MAGIC(window, NULL);
  1318 
  1319     /* See if the named data already exists */
  1320     prev = NULL;
  1321     for (data = window->data; data; prev = data, data = data->next) {
  1322         if (SDL_strcmp(data->name, name) == 0) {
  1323             void *last_value = data->data;
  1324 
  1325             if (userdata) {
  1326                 /* Set the new value */
  1327                 data->data = userdata;
  1328             } else {
  1329                 /* Delete this value */
  1330                 if (prev) {
  1331                     prev->next = data->next;
  1332                 } else {
  1333                     window->data = data->next;
  1334                 }
  1335                 SDL_free(data->name);
  1336                 SDL_free(data);
  1337             }
  1338             return last_value;
  1339         }
  1340     }
  1341 
  1342     /* Add new data to the window */
  1343     if (userdata) {
  1344         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1345         data->name = SDL_strdup(name);
  1346         data->data = userdata;
  1347         data->next = window->data;
  1348         window->data = data;
  1349     }
  1350     return NULL;
  1351 }
  1352 
  1353 void *
  1354 SDL_GetWindowData(SDL_Window * window, const char *name)
  1355 {
  1356     SDL_WindowUserData *data;
  1357 
  1358     CHECK_WINDOW_MAGIC(window, NULL);
  1359 
  1360     for (data = window->data; data; data = data->next) {
  1361         if (SDL_strcmp(data->name, name) == 0) {
  1362             return data->data;
  1363         }
  1364     }
  1365     return NULL;
  1366 }
  1367 
  1368 void
  1369 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1370 {
  1371     CHECK_WINDOW_MAGIC(window, );
  1372 
  1373     if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1374         window->x = x;
  1375     }
  1376     if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1377         window->y = y;
  1378     }
  1379     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1380         if (_this->SetWindowPosition) {
  1381             _this->SetWindowPosition(_this, window);
  1382         }
  1383         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1384     }
  1385 }
  1386 
  1387 void
  1388 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1389 {
  1390     /* Clear the values */
  1391     if (x) {
  1392         *x = 0;
  1393     }
  1394     if (y) {
  1395         *y = 0;
  1396     }
  1397 
  1398     CHECK_WINDOW_MAGIC(window, );
  1399 
  1400     /* Fullscreen windows are always at their display's origin */
  1401     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1402     } else {
  1403         if (x) {
  1404             *x = window->x;
  1405         }
  1406         if (y) {
  1407             *y = window->y;
  1408         }
  1409     }
  1410 }
  1411 
  1412 void
  1413 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1414 {
  1415     CHECK_WINDOW_MAGIC(window, );
  1416 
  1417     /* FIXME: Should this change fullscreen modes? */
  1418     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1419         window->w = w;
  1420         window->h = h;
  1421         if (_this->SetWindowSize) {
  1422             _this->SetWindowSize(_this, window);
  1423         }
  1424         if (window->w == w && window->h == h) {
  1425             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1426             SDL_OnWindowResized(window);
  1427         }
  1428     }
  1429 }
  1430 
  1431 void
  1432 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1433 {
  1434     int dummy;
  1435 
  1436     if (!w) {
  1437         w = &dummy;
  1438     }
  1439     if (!h) {
  1440         h = &dummy;
  1441     }
  1442 
  1443     *w = 0;
  1444     *h = 0;
  1445 
  1446     CHECK_WINDOW_MAGIC(window, );
  1447 
  1448     if (_this && window && window->magic == &_this->window_magic) {
  1449         if (w) {
  1450             *w = window->w;
  1451         }
  1452         if (h) {
  1453             *h = window->h;
  1454         }
  1455     } else {
  1456         if (w) {
  1457             *w = 0;
  1458         }
  1459         if (h) {
  1460             *h = 0;
  1461         }
  1462     }
  1463 }
  1464 
  1465 void
  1466 SDL_ShowWindow(SDL_Window * window)
  1467 {
  1468     CHECK_WINDOW_MAGIC(window, );
  1469 
  1470     if (window->flags & SDL_WINDOW_SHOWN) {
  1471         return;
  1472     }
  1473 
  1474     if (_this->ShowWindow) {
  1475         _this->ShowWindow(_this, window);
  1476     }
  1477     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1478 }
  1479 
  1480 void
  1481 SDL_HideWindow(SDL_Window * window)
  1482 {
  1483     CHECK_WINDOW_MAGIC(window, );
  1484 
  1485     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1486         return;
  1487     }
  1488 
  1489     if (_this->HideWindow) {
  1490         _this->HideWindow(_this, window);
  1491     }
  1492     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1493 }
  1494 
  1495 void
  1496 SDL_RaiseWindow(SDL_Window * window)
  1497 {
  1498     CHECK_WINDOW_MAGIC(window, );
  1499 
  1500     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1501         return;
  1502     }
  1503     if (_this->RaiseWindow) {
  1504         _this->RaiseWindow(_this, window);
  1505     } else {
  1506         /* FIXME: What we really want is a way to request focus */
  1507         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
  1508     }
  1509 }
  1510 
  1511 void
  1512 SDL_MaximizeWindow(SDL_Window * window)
  1513 {
  1514     CHECK_WINDOW_MAGIC(window, );
  1515 
  1516     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1517         return;
  1518     }
  1519 
  1520     if (_this->MaximizeWindow) {
  1521         _this->MaximizeWindow(_this, window);
  1522     }
  1523     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
  1524 }
  1525 
  1526 void
  1527 SDL_MinimizeWindow(SDL_Window * window)
  1528 {
  1529     CHECK_WINDOW_MAGIC(window, );
  1530 
  1531     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1532         return;
  1533     }
  1534 
  1535     if (_this->MinimizeWindow) {
  1536         _this->MinimizeWindow(_this, window);
  1537     }
  1538     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
  1539 }
  1540 
  1541 void
  1542 SDL_RestoreWindow(SDL_Window * window)
  1543 {
  1544     CHECK_WINDOW_MAGIC(window, );
  1545 
  1546     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1547         return;
  1548     }
  1549 
  1550     if (_this->RestoreWindow) {
  1551         _this->RestoreWindow(_this, window);
  1552     }
  1553     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
  1554 }
  1555 
  1556 int
  1557 SDL_SetWindowFullscreen(SDL_Window * window, SDL_bool fullscreen)
  1558 {
  1559     CHECK_WINDOW_MAGIC(window, -1);
  1560 
  1561     if (fullscreen) {
  1562         fullscreen = SDL_WINDOW_FULLSCREEN;
  1563     }
  1564     if ((window->flags & SDL_WINDOW_FULLSCREEN) == fullscreen) {
  1565         return 0;
  1566     }
  1567     if (fullscreen) {
  1568         window->flags |= SDL_WINDOW_FULLSCREEN;
  1569     } else {
  1570         window->flags &= ~SDL_WINDOW_FULLSCREEN;
  1571     }
  1572     SDL_UpdateFullscreenMode(window);
  1573 
  1574     return 0;
  1575 }
  1576 
  1577 static SDL_Surface *
  1578 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1579 {
  1580     Uint32 format;
  1581     void *pixels;
  1582     int pitch;
  1583     int bpp;
  1584     Uint32 Rmask, Gmask, Bmask, Amask;
  1585 
  1586     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1587         return NULL;
  1588     }
  1589 
  1590     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1591         return NULL;
  1592     }
  1593 
  1594     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1595         return NULL;
  1596     }
  1597 
  1598     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1599 }
  1600 
  1601 SDL_Surface *
  1602 SDL_GetWindowSurface(SDL_Window * window)
  1603 {
  1604     CHECK_WINDOW_MAGIC(window, NULL);
  1605 
  1606     if (!window->surface_valid) {
  1607         if (window->surface) {
  1608             window->surface->flags &= ~SDL_DONTFREE;
  1609             SDL_FreeSurface(window->surface);
  1610         }
  1611         window->surface = SDL_CreateWindowFramebuffer(window);
  1612         if (window->surface) {
  1613             window->surface_valid = SDL_TRUE;
  1614             window->surface->flags |= SDL_DONTFREE;
  1615         }
  1616     }
  1617     return window->surface;
  1618 }
  1619 
  1620 int
  1621 SDL_UpdateWindowSurface(SDL_Window * window)
  1622 {
  1623     SDL_Rect full_rect;
  1624 
  1625     CHECK_WINDOW_MAGIC(window, -1);
  1626 
  1627     full_rect.x = 0;
  1628     full_rect.y = 0;
  1629     full_rect.w = window->w;
  1630     full_rect.h = window->h;
  1631     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1632 }
  1633 
  1634 int
  1635 SDL_UpdateWindowSurfaceRects(SDL_Window * window, SDL_Rect * rects,
  1636                              int numrects)
  1637 {
  1638     CHECK_WINDOW_MAGIC(window, -1);
  1639 
  1640     if (!window->surface_valid) {
  1641         SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1642         return -1;
  1643     }
  1644 
  1645     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1646 }
  1647 
  1648 void
  1649 SDL_SetWindowGrab(SDL_Window * window, int mode)
  1650 {
  1651     CHECK_WINDOW_MAGIC(window, );
  1652 
  1653     if ((!!mode == !!(window->flags & SDL_WINDOW_INPUT_GRABBED))) {
  1654         return;
  1655     }
  1656     if (mode) {
  1657         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1658     } else {
  1659         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1660     }
  1661     SDL_UpdateWindowGrab(window);
  1662 }
  1663 
  1664 static void
  1665 SDL_UpdateWindowGrab(SDL_Window * window)
  1666 {
  1667     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
  1668         _this->SetWindowGrab(_this, window);
  1669     }
  1670 }
  1671 
  1672 int
  1673 SDL_GetWindowGrab(SDL_Window * window)
  1674 {
  1675     CHECK_WINDOW_MAGIC(window, 0);
  1676 
  1677     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1678 }
  1679 
  1680 void
  1681 SDL_OnWindowShown(SDL_Window * window)
  1682 {
  1683     SDL_RaiseWindow(window);
  1684     SDL_UpdateFullscreenMode(window);
  1685 }
  1686 
  1687 void
  1688 SDL_OnWindowHidden(SDL_Window * window)
  1689 {
  1690     SDL_UpdateFullscreenMode(window);
  1691 }
  1692 
  1693 void
  1694 SDL_OnWindowResized(SDL_Window * window)
  1695 {
  1696     window->surface_valid = SDL_FALSE;
  1697     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  1698 }
  1699 
  1700 void
  1701 SDL_OnWindowMinimized(SDL_Window * window)
  1702 {
  1703     SDL_UpdateFullscreenMode(window);
  1704 }
  1705 
  1706 void
  1707 SDL_OnWindowRestored(SDL_Window * window)
  1708 {
  1709     SDL_RaiseWindow(window);
  1710     SDL_UpdateFullscreenMode(window);
  1711 }
  1712 
  1713 void
  1714 SDL_OnWindowFocusGained(SDL_Window * window)
  1715 {
  1716     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
  1717         && _this->SetWindowGrab) {
  1718         _this->SetWindowGrab(_this, window);
  1719     }
  1720 }
  1721 
  1722 void
  1723 SDL_OnWindowFocusLost(SDL_Window * window)
  1724 {
  1725     /* If we're fullscreen on a single-head system and lose focus, minimize */
  1726     if ((window->flags & SDL_WINDOW_FULLSCREEN) &&
  1727         _this->num_displays == 1) {
  1728         SDL_MinimizeWindow(window);
  1729     }
  1730 
  1731     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
  1732         && _this->SetWindowGrab) {
  1733         _this->SetWindowGrab(_this, window);
  1734     }
  1735 }
  1736 
  1737 SDL_Window *
  1738 SDL_GetFocusWindow(void)
  1739 {
  1740     SDL_Window *window;
  1741 
  1742     if (!_this) {
  1743         return NULL;
  1744     }
  1745     for (window = _this->windows; window; window = window->next) {
  1746         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1747             return window;
  1748         }
  1749     }
  1750     return NULL;
  1751 }
  1752 
  1753 void
  1754 SDL_DestroyWindow(SDL_Window * window)
  1755 {
  1756     SDL_VideoDisplay *display;
  1757 
  1758     CHECK_WINDOW_MAGIC(window, );
  1759 
  1760     /* Restore video mode, etc. */
  1761     SDL_HideWindow(window);
  1762 
  1763     if (window->surface) {
  1764         window->surface->flags &= ~SDL_DONTFREE;
  1765         SDL_FreeSurface(window->surface);
  1766     }
  1767     if (_this->DestroyWindowFramebuffer) {
  1768         _this->DestroyWindowFramebuffer(_this, window);
  1769     }
  1770     if (_this->DestroyWindow) {
  1771         _this->DestroyWindow(_this, window);
  1772     }
  1773     if (window->flags & SDL_WINDOW_OPENGL) {
  1774         SDL_GL_UnloadLibrary();
  1775     }
  1776 
  1777     display = SDL_GetDisplayForWindow(window);
  1778     if (display->fullscreen_window == window) {
  1779         display->fullscreen_window = NULL;
  1780     }
  1781 
  1782     /* Now invalidate magic */
  1783     window->magic = NULL;
  1784 
  1785     /* Free memory associated with the window */
  1786     if (window->title) {
  1787         SDL_free(window->title);
  1788     }
  1789     while (window->data) {
  1790         SDL_WindowUserData *data = window->data;
  1791 
  1792         window->data = data->next;
  1793         SDL_free(data->name);
  1794         SDL_free(data);
  1795     }
  1796 
  1797     /* Unlink the window from the list */
  1798     if (window->next) {
  1799         window->next->prev = window->prev;
  1800     }
  1801     if (window->prev) {
  1802         window->prev->next = window->next;
  1803     } else {
  1804         _this->windows = window->next;
  1805     }
  1806 
  1807     SDL_free(window);
  1808 }
  1809 
  1810 SDL_bool
  1811 SDL_IsScreenSaverEnabled()
  1812 {
  1813     if (!_this) {
  1814         return SDL_TRUE;
  1815     }
  1816     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  1817 }
  1818 
  1819 void
  1820 SDL_EnableScreenSaver()
  1821 {
  1822     if (!_this) {
  1823         return;
  1824     }
  1825     if (!_this->suspend_screensaver) {
  1826         return;
  1827     }
  1828     _this->suspend_screensaver = SDL_FALSE;
  1829     if (_this->SuspendScreenSaver) {
  1830         _this->SuspendScreenSaver(_this);
  1831     }
  1832 }
  1833 
  1834 void
  1835 SDL_DisableScreenSaver()
  1836 {
  1837     if (!_this) {
  1838         return;
  1839     }
  1840     if (_this->suspend_screensaver) {
  1841         return;
  1842     }
  1843     _this->suspend_screensaver = SDL_TRUE;
  1844     if (_this->SuspendScreenSaver) {
  1845         _this->SuspendScreenSaver(_this);
  1846     }
  1847 }
  1848 
  1849 void
  1850 SDL_VideoQuit(void)
  1851 {
  1852     int i, j;
  1853 
  1854     if (!_this) {
  1855         return;
  1856     }
  1857 
  1858     /* Halt event processing before doing anything else */
  1859     SDL_QuitQuit();
  1860     SDL_MouseQuit();
  1861     SDL_KeyboardQuit();
  1862     SDL_StopEventLoop();
  1863 
  1864     SDL_EnableScreenSaver();
  1865 
  1866     /* Clean up the system video */
  1867     while (_this->windows) {
  1868         SDL_DestroyWindow(_this->windows);
  1869     }
  1870     _this->VideoQuit(_this);
  1871 
  1872     for (i = _this->num_displays; i--;) {
  1873         SDL_VideoDisplay *display = &_this->displays[i];
  1874         for (j = display->num_display_modes; j--;) {
  1875             if (display->display_modes[j].driverdata) {
  1876                 SDL_free(display->display_modes[j].driverdata);
  1877                 display->display_modes[j].driverdata = NULL;
  1878             }
  1879         }
  1880         if (display->display_modes) {
  1881             SDL_free(display->display_modes);
  1882             display->display_modes = NULL;
  1883         }
  1884         if (display->desktop_mode.driverdata) {
  1885             SDL_free(display->desktop_mode.driverdata);
  1886             display->desktop_mode.driverdata = NULL;
  1887         }
  1888         if (display->driverdata) {
  1889             SDL_free(display->driverdata);
  1890             display->driverdata = NULL;
  1891         }
  1892     }
  1893     if (_this->displays) {
  1894         SDL_free(_this->displays);
  1895         _this->displays = NULL;
  1896     }
  1897     if (_this->clipboard_text) {
  1898         SDL_free(_this->clipboard_text);
  1899         _this->clipboard_text = NULL;
  1900     }
  1901     _this->free(_this);
  1902     _this = NULL;
  1903 }
  1904 
  1905 int
  1906 SDL_GL_LoadLibrary(const char *path)
  1907 {
  1908     int retval;
  1909 
  1910     if (!_this) {
  1911         SDL_UninitializedVideo();
  1912         return -1;
  1913     }
  1914     if (_this->gl_config.driver_loaded) {
  1915         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  1916             SDL_SetError("OpenGL library already loaded");
  1917             return -1;
  1918         }
  1919         retval = 0;
  1920     } else {
  1921         if (!_this->GL_LoadLibrary) {
  1922             SDL_SetError("No dynamic GL support in video driver");
  1923             return -1;
  1924         }
  1925         retval = _this->GL_LoadLibrary(_this, path);
  1926     }
  1927     if (retval == 0) {
  1928         ++_this->gl_config.driver_loaded;
  1929     }
  1930     return (retval);
  1931 }
  1932 
  1933 void *
  1934 SDL_GL_GetProcAddress(const char *proc)
  1935 {
  1936     void *func;
  1937 
  1938     if (!_this) {
  1939         SDL_UninitializedVideo();
  1940         return NULL;
  1941     }
  1942     func = NULL;
  1943     if (_this->GL_GetProcAddress) {
  1944         if (_this->gl_config.driver_loaded) {
  1945             func = _this->GL_GetProcAddress(_this, proc);
  1946         } else {
  1947             SDL_SetError("No GL driver has been loaded");
  1948         }
  1949     } else {
  1950         SDL_SetError("No dynamic GL support in video driver");
  1951     }
  1952     return func;
  1953 }
  1954 
  1955 void
  1956 SDL_GL_UnloadLibrary(void)
  1957 {
  1958     if (!_this) {
  1959         SDL_UninitializedVideo();
  1960         return;
  1961     }
  1962     if (_this->gl_config.driver_loaded > 0) {
  1963         if (--_this->gl_config.driver_loaded > 0) {
  1964             return;
  1965         }
  1966         if (_this->GL_UnloadLibrary) {
  1967             _this->GL_UnloadLibrary(_this);
  1968         }
  1969     }
  1970 }
  1971 
  1972 SDL_bool
  1973 SDL_GL_ExtensionSupported(const char *extension)
  1974 {
  1975 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  1976     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  1977     const char *extensions;
  1978     const char *start;
  1979     const char *where, *terminator;
  1980 
  1981     /* Extension names should not have spaces. */
  1982     where = SDL_strchr(extension, ' ');
  1983     if (where || *extension == '\0') {
  1984         return SDL_FALSE;
  1985     }
  1986     /* See if there's an environment variable override */
  1987     start = SDL_getenv(extension);
  1988     if (start && *start == '0') {
  1989         return SDL_FALSE;
  1990     }
  1991     /* Lookup the available extensions */
  1992     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  1993     if (glGetStringFunc) {
  1994         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  1995     } else {
  1996         extensions = NULL;
  1997     }
  1998     if (!extensions) {
  1999         return SDL_FALSE;
  2000     }
  2001     /*
  2002      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2003      * extensions string. Don't be fooled by sub-strings, etc.
  2004      */
  2005 
  2006     start = extensions;
  2007 
  2008     for (;;) {
  2009         where = SDL_strstr(start, extension);
  2010         if (!where)
  2011             break;
  2012 
  2013         terminator = where + SDL_strlen(extension);
  2014         if (where == start || *(where - 1) == ' ')
  2015             if (*terminator == ' ' || *terminator == '\0')
  2016                 return SDL_TRUE;
  2017 
  2018         start = terminator;
  2019     }
  2020     return SDL_FALSE;
  2021 #else
  2022     return SDL_FALSE;
  2023 #endif
  2024 }
  2025 
  2026 int
  2027 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2028 {
  2029 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2030     int retval;
  2031 
  2032     if (!_this) {
  2033         SDL_UninitializedVideo();
  2034         return -1;
  2035     }
  2036     retval = 0;
  2037     switch (attr) {
  2038     case SDL_GL_RED_SIZE:
  2039         _this->gl_config.red_size = value;
  2040         break;
  2041     case SDL_GL_GREEN_SIZE:
  2042         _this->gl_config.green_size = value;
  2043         break;
  2044     case SDL_GL_BLUE_SIZE:
  2045         _this->gl_config.blue_size = value;
  2046         break;
  2047     case SDL_GL_ALPHA_SIZE:
  2048         _this->gl_config.alpha_size = value;
  2049         break;
  2050     case SDL_GL_DOUBLEBUFFER:
  2051         _this->gl_config.double_buffer = value;
  2052         break;
  2053     case SDL_GL_BUFFER_SIZE:
  2054         _this->gl_config.buffer_size = value;
  2055         break;
  2056     case SDL_GL_DEPTH_SIZE:
  2057         _this->gl_config.depth_size = value;
  2058         break;
  2059     case SDL_GL_STENCIL_SIZE:
  2060         _this->gl_config.stencil_size = value;
  2061         break;
  2062     case SDL_GL_ACCUM_RED_SIZE:
  2063         _this->gl_config.accum_red_size = value;
  2064         break;
  2065     case SDL_GL_ACCUM_GREEN_SIZE:
  2066         _this->gl_config.accum_green_size = value;
  2067         break;
  2068     case SDL_GL_ACCUM_BLUE_SIZE:
  2069         _this->gl_config.accum_blue_size = value;
  2070         break;
  2071     case SDL_GL_ACCUM_ALPHA_SIZE:
  2072         _this->gl_config.accum_alpha_size = value;
  2073         break;
  2074     case SDL_GL_STEREO:
  2075         _this->gl_config.stereo = value;
  2076         break;
  2077     case SDL_GL_MULTISAMPLEBUFFERS:
  2078         _this->gl_config.multisamplebuffers = value;
  2079         break;
  2080     case SDL_GL_MULTISAMPLESAMPLES:
  2081         _this->gl_config.multisamplesamples = value;
  2082         break;
  2083     case SDL_GL_ACCELERATED_VISUAL:
  2084         _this->gl_config.accelerated = value;
  2085         break;
  2086     case SDL_GL_RETAINED_BACKING:
  2087         _this->gl_config.retained_backing = value;
  2088         break;
  2089     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2090         _this->gl_config.major_version = value;
  2091         break;
  2092     case SDL_GL_CONTEXT_MINOR_VERSION:
  2093         _this->gl_config.minor_version = value;
  2094         break;
  2095     default:
  2096         SDL_SetError("Unknown OpenGL attribute");
  2097         retval = -1;
  2098         break;
  2099     }
  2100     return retval;
  2101 #else
  2102     SDL_Unsupported();
  2103     return -1;
  2104 #endif /* SDL_VIDEO_OPENGL */
  2105 }
  2106 
  2107 int
  2108 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2109 {
  2110 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2111     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2112     GLenum(APIENTRY * glGetErrorFunc) (void);
  2113     GLenum attrib = 0;
  2114     GLenum error = 0;
  2115 
  2116     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2117     if (!glGetIntegervFunc) {
  2118         return -1;
  2119     }
  2120 
  2121     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2122     if (!glGetErrorFunc) {
  2123         return -1;
  2124     }
  2125 
  2126     /* Clear value in any case */
  2127     *value = 0;
  2128 
  2129     switch (attr) {
  2130     case SDL_GL_RED_SIZE:
  2131         attrib = GL_RED_BITS;
  2132         break;
  2133     case SDL_GL_BLUE_SIZE:
  2134         attrib = GL_BLUE_BITS;
  2135         break;
  2136     case SDL_GL_GREEN_SIZE:
  2137         attrib = GL_GREEN_BITS;
  2138         break;
  2139     case SDL_GL_ALPHA_SIZE:
  2140         attrib = GL_ALPHA_BITS;
  2141         break;
  2142     case SDL_GL_DOUBLEBUFFER:
  2143 #if SDL_VIDEO_OPENGL
  2144         attrib = GL_DOUBLEBUFFER;
  2145         break;
  2146 #else
  2147         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2148         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2149         /* SDL driver must set proper value after initialization              */
  2150         *value = _this->gl_config.double_buffer;
  2151         return 0;
  2152 #endif
  2153     case SDL_GL_DEPTH_SIZE:
  2154         attrib = GL_DEPTH_BITS;
  2155         break;
  2156     case SDL_GL_STENCIL_SIZE:
  2157         attrib = GL_STENCIL_BITS;
  2158         break;
  2159 #if SDL_VIDEO_OPENGL
  2160     case SDL_GL_ACCUM_RED_SIZE:
  2161         attrib = GL_ACCUM_RED_BITS;
  2162         break;
  2163     case SDL_GL_ACCUM_GREEN_SIZE:
  2164         attrib = GL_ACCUM_GREEN_BITS;
  2165         break;
  2166     case SDL_GL_ACCUM_BLUE_SIZE:
  2167         attrib = GL_ACCUM_BLUE_BITS;
  2168         break;
  2169     case SDL_GL_ACCUM_ALPHA_SIZE:
  2170         attrib = GL_ACCUM_ALPHA_BITS;
  2171         break;
  2172     case SDL_GL_STEREO:
  2173         attrib = GL_STEREO;
  2174         break;
  2175 #else
  2176     case SDL_GL_ACCUM_RED_SIZE:
  2177     case SDL_GL_ACCUM_GREEN_SIZE:
  2178     case SDL_GL_ACCUM_BLUE_SIZE:
  2179     case SDL_GL_ACCUM_ALPHA_SIZE:
  2180     case SDL_GL_STEREO:
  2181         /* none of these are supported in OpenGL ES */
  2182         *value = 0;
  2183         return 0;
  2184 #endif
  2185     case SDL_GL_MULTISAMPLEBUFFERS:
  2186 #if SDL_VIDEO_OPENGL
  2187         attrib = GL_SAMPLE_BUFFERS_ARB;
  2188 #else
  2189         attrib = GL_SAMPLE_BUFFERS;
  2190 #endif
  2191         break;
  2192     case SDL_GL_MULTISAMPLESAMPLES:
  2193 #if SDL_VIDEO_OPENGL
  2194         attrib = GL_SAMPLES_ARB;
  2195 #else
  2196         attrib = GL_SAMPLES;
  2197 #endif
  2198         break;
  2199     case SDL_GL_BUFFER_SIZE:
  2200         {
  2201             GLint bits = 0;
  2202             GLint component;
  2203 
  2204             /*
  2205              * there doesn't seem to be a single flag in OpenGL
  2206              * for this!
  2207              */
  2208             glGetIntegervFunc(GL_RED_BITS, &component);
  2209             bits += component;
  2210             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2211             bits += component;
  2212             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2213             bits += component;
  2214             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2215             bits += component;
  2216 
  2217             *value = bits;
  2218             return 0;
  2219         }
  2220     case SDL_GL_ACCELERATED_VISUAL:
  2221         {
  2222             /* FIXME: How do we get this information? */
  2223             *value = (_this->gl_config.accelerated != 0);
  2224             return 0;
  2225         }
  2226     case SDL_GL_RETAINED_BACKING:
  2227         {
  2228             *value = _this->gl_config.retained_backing;
  2229             return 0;
  2230         }
  2231     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2232         {
  2233             *value = _this->gl_config.major_version;
  2234             return 0;
  2235         }
  2236     case SDL_GL_CONTEXT_MINOR_VERSION:
  2237         {
  2238             *value = _this->gl_config.minor_version;
  2239             return 0;
  2240         }
  2241     default:
  2242         SDL_SetError("Unknown OpenGL attribute");
  2243         return -1;
  2244     }
  2245 
  2246     glGetIntegervFunc(attrib, (GLint *) value);
  2247     error = glGetErrorFunc();
  2248     if (error != GL_NO_ERROR) {
  2249         switch (error) {
  2250         case GL_INVALID_ENUM:
  2251             {
  2252                 SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2253             }
  2254             break;
  2255         case GL_INVALID_VALUE:
  2256             {
  2257                 SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2258             }
  2259             break;
  2260         default:
  2261             {
  2262                 SDL_SetError("OpenGL error: %08X", error);
  2263             }
  2264             break;
  2265         }
  2266         return -1;
  2267     }
  2268     return 0;
  2269 #else
  2270     SDL_Unsupported();
  2271     return -1;
  2272 #endif /* SDL_VIDEO_OPENGL */
  2273 }
  2274 
  2275 SDL_GLContext
  2276 SDL_GL_CreateContext(SDL_Window * window)
  2277 {
  2278     CHECK_WINDOW_MAGIC(window, NULL);
  2279 
  2280     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2281         SDL_SetError("The specified window isn't an OpenGL window");
  2282         return NULL;
  2283     }
  2284     return _this->GL_CreateContext(_this, window);
  2285 }
  2286 
  2287 int
  2288 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext context)
  2289 {
  2290     CHECK_WINDOW_MAGIC(window, -1);
  2291 
  2292     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2293         SDL_SetError("The specified window isn't an OpenGL window");
  2294         return -1;
  2295     }
  2296     if (!context) {
  2297         window = NULL;
  2298     }
  2299     return _this->GL_MakeCurrent(_this, window, context);
  2300 }
  2301 
  2302 int
  2303 SDL_GL_SetSwapInterval(int interval)
  2304 {
  2305     if (!_this) {
  2306         SDL_UninitializedVideo();
  2307         return -1;
  2308     }
  2309     if (_this->GL_SetSwapInterval) {
  2310         return _this->GL_SetSwapInterval(_this, interval);
  2311     } else {
  2312         SDL_SetError("Setting the swap interval is not supported");
  2313         return -1;
  2314     }
  2315 }
  2316 
  2317 int
  2318 SDL_GL_GetSwapInterval(void)
  2319 {
  2320     if (!_this) {
  2321         SDL_UninitializedVideo();
  2322         return -1;
  2323     }
  2324     if (_this->GL_GetSwapInterval) {
  2325         return _this->GL_GetSwapInterval(_this);
  2326     } else {
  2327         SDL_SetError("Getting the swap interval is not supported");
  2328         return -1;
  2329     }
  2330 }
  2331 
  2332 void
  2333 SDL_GL_SwapWindow(SDL_Window * window)
  2334 {
  2335     CHECK_WINDOW_MAGIC(window, );
  2336 
  2337     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2338         SDL_SetError("The specified window isn't an OpenGL window");
  2339         return;
  2340     }
  2341     _this->GL_SwapWindow(_this, window);
  2342 }
  2343 
  2344 void
  2345 SDL_GL_DeleteContext(SDL_GLContext context)
  2346 {
  2347     if (!_this || !_this->gl_data || !context) {
  2348         return;
  2349     }
  2350     _this->GL_MakeCurrent(_this, NULL, NULL);
  2351     _this->GL_DeleteContext(_this, context);
  2352 }
  2353 
  2354 #if 0                           // FIXME
  2355 /*
  2356  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2357  * & 2 for alpha channel.
  2358  */
  2359 static void
  2360 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2361 {
  2362     int x, y;
  2363     Uint32 colorkey;
  2364 #define SET_MASKBIT(icon, x, y, mask) \
  2365 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2366 
  2367     colorkey = icon->format->colorkey;
  2368     switch (icon->format->BytesPerPixel) {
  2369     case 1:
  2370         {
  2371             Uint8 *pixels;
  2372             for (y = 0; y < icon->h; ++y) {
  2373                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2374                 for (x = 0; x < icon->w; ++x) {
  2375                     if (*pixels++ == colorkey) {
  2376                         SET_MASKBIT(icon, x, y, mask);
  2377                     }
  2378                 }
  2379             }
  2380         }
  2381         break;
  2382 
  2383     case 2:
  2384         {
  2385             Uint16 *pixels;
  2386             for (y = 0; y < icon->h; ++y) {
  2387                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2388                 for (x = 0; x < icon->w; ++x) {
  2389                     if ((flags & 1) && *pixels == colorkey) {
  2390                         SET_MASKBIT(icon, x, y, mask);
  2391                     } else if ((flags & 2)
  2392                                && (*pixels & icon->format->Amask) == 0) {
  2393                         SET_MASKBIT(icon, x, y, mask);
  2394                     }
  2395                     pixels++;
  2396                 }
  2397             }
  2398         }
  2399         break;
  2400 
  2401     case 4:
  2402         {
  2403             Uint32 *pixels;
  2404             for (y = 0; y < icon->h; ++y) {
  2405                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2406                 for (x = 0; x < icon->w; ++x) {
  2407                     if ((flags & 1) && *pixels == colorkey) {
  2408                         SET_MASKBIT(icon, x, y, mask);
  2409                     } else if ((flags & 2)
  2410                                && (*pixels & icon->format->Amask) == 0) {
  2411                         SET_MASKBIT(icon, x, y, mask);
  2412                     }
  2413                     pixels++;
  2414                 }
  2415             }
  2416         }
  2417         break;
  2418     }
  2419 }
  2420 
  2421 /*
  2422  * Sets the window manager icon for the display window.
  2423  */
  2424 void
  2425 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2426 {
  2427     if (icon && _this->SetIcon) {
  2428         /* Generate a mask if necessary, and create the icon! */
  2429         if (mask == NULL) {
  2430             int mask_len = icon->h * (icon->w + 7) / 8;
  2431             int flags = 0;
  2432             mask = (Uint8 *) SDL_malloc(mask_len);
  2433             if (mask == NULL) {
  2434                 return;
  2435             }
  2436             SDL_memset(mask, ~0, mask_len);
  2437             if (icon->flags & SDL_SRCCOLORKEY)
  2438                 flags |= 1;
  2439             if (icon->flags & SDL_SRCALPHA)
  2440                 flags |= 2;
  2441             if (flags) {
  2442                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2443             }
  2444             _this->SetIcon(_this, icon, mask);
  2445             SDL_free(mask);
  2446         } else {
  2447             _this->SetIcon(_this, icon, mask);
  2448         }
  2449     }
  2450 }
  2451 #endif
  2452 
  2453 SDL_bool
  2454 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  2455 {
  2456     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2457 
  2458     if (!info) {
  2459         return SDL_FALSE;
  2460     }
  2461     info->subsystem = SDL_SYSWM_UNKNOWN;
  2462 
  2463     if (!_this->GetWindowWMInfo) {
  2464         return SDL_FALSE;
  2465     }
  2466     return (_this->GetWindowWMInfo(_this, window, info));
  2467 }
  2468 
  2469 void
  2470 SDL_StartTextInput(void)
  2471 {
  2472     if (_this && _this->StartTextInput) {
  2473         _this->StartTextInput(_this);
  2474     }
  2475     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  2476     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  2477 }
  2478 
  2479 void
  2480 SDL_StopTextInput(void)
  2481 {
  2482     if (_this && _this->StopTextInput) {
  2483         _this->StopTextInput(_this);
  2484     }
  2485     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  2486     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  2487 }
  2488 
  2489 void
  2490 SDL_SetTextInputRect(SDL_Rect *rect)
  2491 {
  2492     if (_this && _this->SetTextInputRect) {
  2493         _this->SetTextInputRect(_this, rect);
  2494     }
  2495 }
  2496 
  2497 /* vi: set ts=4 sw=4 expandtab: */