src/video/emscripten/SDL_emscriptenvideo.c
author Boris Gjenero
Tue, 13 Sep 2016 00:03:54 -0700
changeset 10332 359290a75710
parent 10331 710c2ae96681
child 10333 a0495857c42f
permissions -rw-r--r--
Fix full screen mode in Firefox, which was broken by 9d4beb2
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_EMSCRIPTEN
    24 
    25 #include "SDL_video.h"
    26 #include "SDL_mouse.h"
    27 #include "SDL_hints.h"
    28 #include "../SDL_sysvideo.h"
    29 #include "../SDL_pixels_c.h"
    30 #include "../SDL_egl_c.h"
    31 #include "../../events/SDL_events_c.h"
    32 
    33 #include "SDL_emscriptenvideo.h"
    34 #include "SDL_emscriptenopengles.h"
    35 #include "SDL_emscriptenframebuffer.h"
    36 #include "SDL_emscriptenevents.h"
    37 #include "SDL_emscriptenmouse.h"
    38 
    39 #define EMSCRIPTENVID_DRIVER_NAME "emscripten"
    40 
    41 /* Initialization/Query functions */
    42 static int Emscripten_VideoInit(_THIS);
    43 static int Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
    44 static void Emscripten_VideoQuit(_THIS);
    45 
    46 static int Emscripten_CreateWindow(_THIS, SDL_Window * window);
    47 static void Emscripten_SetWindowSize(_THIS, SDL_Window * window);
    48 static void Emscripten_DestroyWindow(_THIS, SDL_Window * window);
    49 static void Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
    50 static void Emscripten_PumpEvents(_THIS);
    51 static void Emscripten_SetWindowTitle(_THIS, SDL_Window * window);
    52 
    53 
    54 /* Emscripten driver bootstrap functions */
    55 
    56 static int
    57 Emscripten_Available(void)
    58 {
    59     return (1);
    60 }
    61 
    62 static void
    63 Emscripten_DeleteDevice(SDL_VideoDevice * device)
    64 {
    65     SDL_free(device);
    66 }
    67 
    68 static SDL_VideoDevice *
    69 Emscripten_CreateDevice(int devindex)
    70 {
    71     SDL_VideoDevice *device;
    72 
    73     /* Initialize all variables that we clean on shutdown */
    74     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
    75     if (!device) {
    76         SDL_OutOfMemory();
    77         return (0);
    78     }
    79 
    80     /* Firefox sends blur event which would otherwise prevent full screen */
    81     SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
    82 
    83     /* Set the function pointers */
    84     device->VideoInit = Emscripten_VideoInit;
    85     device->VideoQuit = Emscripten_VideoQuit;
    86     device->SetDisplayMode = Emscripten_SetDisplayMode;
    87 
    88 
    89     device->PumpEvents = Emscripten_PumpEvents;
    90 
    91     device->CreateWindow = Emscripten_CreateWindow;
    92     /*device->CreateWindowFrom = Emscripten_CreateWindowFrom;*/
    93     device->SetWindowTitle = Emscripten_SetWindowTitle;
    94     /*device->SetWindowIcon = Emscripten_SetWindowIcon;
    95     device->SetWindowPosition = Emscripten_SetWindowPosition;*/
    96     device->SetWindowSize = Emscripten_SetWindowSize;
    97     /*device->ShowWindow = Emscripten_ShowWindow;
    98     device->HideWindow = Emscripten_HideWindow;
    99     device->RaiseWindow = Emscripten_RaiseWindow;
   100     device->MaximizeWindow = Emscripten_MaximizeWindow;
   101     device->MinimizeWindow = Emscripten_MinimizeWindow;
   102     device->RestoreWindow = Emscripten_RestoreWindow;
   103     device->SetWindowGrab = Emscripten_SetWindowGrab;*/
   104     device->DestroyWindow = Emscripten_DestroyWindow;
   105     device->SetWindowFullscreen = Emscripten_SetWindowFullscreen;
   106 
   107     device->CreateWindowFramebuffer = Emscripten_CreateWindowFramebuffer;
   108     device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer;
   109     device->DestroyWindowFramebuffer = Emscripten_DestroyWindowFramebuffer;
   110 
   111     device->GL_LoadLibrary = Emscripten_GLES_LoadLibrary;
   112     device->GL_GetProcAddress = Emscripten_GLES_GetProcAddress;
   113     device->GL_UnloadLibrary = Emscripten_GLES_UnloadLibrary;
   114     device->GL_CreateContext = Emscripten_GLES_CreateContext;
   115     device->GL_MakeCurrent = Emscripten_GLES_MakeCurrent;
   116     device->GL_SetSwapInterval = Emscripten_GLES_SetSwapInterval;
   117     device->GL_GetSwapInterval = Emscripten_GLES_GetSwapInterval;
   118     device->GL_SwapWindow = Emscripten_GLES_SwapWindow;
   119     device->GL_DeleteContext = Emscripten_GLES_DeleteContext;
   120     device->GL_GetDrawableSize = Emscripten_GLES_GetDrawableSize;
   121 
   122     device->free = Emscripten_DeleteDevice;
   123 
   124     return device;
   125 }
   126 
   127 VideoBootStrap Emscripten_bootstrap = {
   128     EMSCRIPTENVID_DRIVER_NAME, "SDL emscripten video driver",
   129     Emscripten_Available, Emscripten_CreateDevice
   130 };
   131 
   132 
   133 int
   134 Emscripten_VideoInit(_THIS)
   135 {
   136     SDL_DisplayMode mode;
   137     double css_w, css_h;
   138 
   139     /* Use a fake 32-bpp desktop mode */
   140     mode.format = SDL_PIXELFORMAT_RGB888;
   141 
   142     emscripten_get_element_css_size(NULL, &css_w, &css_h);
   143 
   144     mode.w = css_w;
   145     mode.h = css_h;
   146 
   147     mode.refresh_rate = 0;
   148     mode.driverdata = NULL;
   149     if (SDL_AddBasicVideoDisplay(&mode) < 0) {
   150         return -1;
   151     }
   152 
   153     SDL_zero(mode);
   154     SDL_AddDisplayMode(&_this->displays[0], &mode);
   155 
   156     Emscripten_InitMouse();
   157 
   158     /* We're done! */
   159     return 0;
   160 }
   161 
   162 static int
   163 Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   164 {
   165     /* can't do this */
   166     return 0;
   167 }
   168 
   169 static void
   170 Emscripten_VideoQuit(_THIS)
   171 {
   172     Emscripten_FiniMouse();
   173 }
   174 
   175 static void
   176 Emscripten_PumpEvents(_THIS)
   177 {
   178     /* do nothing. */
   179 }
   180 
   181 static int
   182 Emscripten_CreateWindow(_THIS, SDL_Window * window)
   183 {
   184     SDL_WindowData *wdata;
   185     double scaled_w, scaled_h;
   186     double css_w, css_h;
   187 
   188     /* Allocate window internal data */
   189     wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
   190     if (wdata == NULL) {
   191         return SDL_OutOfMemory();
   192     }
   193 
   194     if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
   195         wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
   196     } else {
   197         wdata->pixel_ratio = 1.0f;
   198     }
   199 
   200     scaled_w = SDL_floor(window->w * wdata->pixel_ratio);
   201     scaled_h = SDL_floor(window->h * wdata->pixel_ratio);
   202 
   203     emscripten_set_canvas_size(scaled_w, scaled_h);
   204 
   205     emscripten_get_element_css_size(NULL, &css_w, &css_h);
   206 
   207     wdata->external_size = css_w != scaled_w || css_h != scaled_h;
   208 
   209     if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) {
   210         /* external css has resized us */
   211         scaled_w = css_w * wdata->pixel_ratio;
   212         scaled_h = css_h * wdata->pixel_ratio;
   213 
   214         emscripten_set_canvas_size(scaled_w, scaled_h);
   215         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, css_w, css_h);
   216     }
   217 
   218     /* if the size is not being controlled by css, we need to scale down for hidpi */
   219     if (!wdata->external_size) {
   220         if (wdata->pixel_ratio != 1.0f) {
   221             /*scale canvas down*/
   222             emscripten_set_element_css_size(NULL, window->w, window->h);
   223         }
   224     }
   225 
   226     if (window->flags & SDL_WINDOW_OPENGL) {
   227         if (!_this->egl_data) {
   228             if (SDL_GL_LoadLibrary(NULL) < 0) {
   229                 return -1;
   230             }
   231         }
   232         wdata->egl_surface = SDL_EGL_CreateSurface(_this, 0);
   233 
   234         if (wdata->egl_surface == EGL_NO_SURFACE) {
   235             return SDL_SetError("Could not create GLES window surface");
   236         }
   237     }
   238 
   239     wdata->window = window;
   240 
   241     /* Setup driver data for this window */
   242     window->driverdata = wdata;
   243 
   244     /* One window, it always has focus */
   245     SDL_SetMouseFocus(window);
   246     SDL_SetKeyboardFocus(window);
   247 
   248     Emscripten_RegisterEventHandlers(wdata);
   249 
   250     /* Window has been successfully created */
   251     return 0;
   252 }
   253 
   254 static void Emscripten_SetWindowSize(_THIS, SDL_Window * window)
   255 {
   256     SDL_WindowData *data;
   257 
   258     if (window->driverdata) {
   259         data = (SDL_WindowData *) window->driverdata;
   260         emscripten_set_canvas_size(window->w * data->pixel_ratio, window->h * data->pixel_ratio);
   261 
   262         /*scale canvas down*/
   263         if (!data->external_size && data->pixel_ratio != 1.0f) {
   264             emscripten_set_element_css_size(NULL, window->w, window->h);
   265         }
   266     }
   267 }
   268 
   269 static void
   270 Emscripten_DestroyWindow(_THIS, SDL_Window * window)
   271 {
   272     SDL_WindowData *data;
   273 
   274     if(window->driverdata) {
   275         data = (SDL_WindowData *) window->driverdata;
   276 
   277         Emscripten_UnregisterEventHandlers(data);
   278         if (data->egl_surface != EGL_NO_SURFACE) {
   279             SDL_EGL_DestroySurface(_this, data->egl_surface);
   280             data->egl_surface = EGL_NO_SURFACE;
   281         }
   282         SDL_free(window->driverdata);
   283         window->driverdata = NULL;
   284     }
   285 }
   286 
   287 static void
   288 Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   289 {
   290     SDL_WindowData *data;
   291     if(window->driverdata) {
   292         data = (SDL_WindowData *) window->driverdata;
   293 
   294         if(fullscreen) {
   295             EmscriptenFullscreenStrategy strategy;
   296             SDL_bool is_desktop_fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
   297 
   298             strategy.scaleMode = is_desktop_fullscreen ? EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH : EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT;
   299 
   300             if(!is_desktop_fullscreen) {
   301                 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE;
   302             } else if(window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
   303                 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
   304             } else {
   305                 strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
   306             }
   307 
   308             strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
   309 
   310             strategy.canvasResizedCallback = Emscripten_HandleCanvasResize;
   311             strategy.canvasResizedCallbackUserData = data;
   312 
   313             data->requested_fullscreen_mode = window->flags & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
   314             data->fullscreen_resize = is_desktop_fullscreen;
   315             /*unset the fullscreen flags as we're not actually fullscreen yet*/
   316             window->flags &= ~(SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN);
   317 
   318             emscripten_request_fullscreen_strategy(NULL, 1, &strategy);
   319         }
   320         else
   321             emscripten_exit_fullscreen();
   322     }
   323 }
   324 
   325 static void
   326 Emscripten_SetWindowTitle(_THIS, SDL_Window * window) {
   327     EM_ASM_INT({
   328       if (typeof Module['setWindowTitle'] !== 'undefined') {
   329         Module['setWindowTitle'](Module['Pointer_stringify']($0));
   330       }
   331       return 0;
   332     }, window->title);
   333 }
   334 
   335 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
   336 
   337 /* vi: set ts=4 sw=4 expandtab: */