Skip to content

Latest commit

 

History

History
1188 lines (1068 loc) · 57.3 KB

Usage.md

File metadata and controls

1188 lines (1068 loc) · 57.3 KB

Introduction

This Emscripten/webassembly port of GLFW tries to implement as much of the GLFW API that is possible to implement in the context of a web browser. See the list of all functions with some notes for details. This page documents the most important aspects of the library.

Main concept

This port, as well as other library ports (like SDL), associates the concept of a "window" (in this instance a GLFWwindow) to an HTML "canvas". The framebuffer size of the window is the size of the canvas (canvas.width x canvas.height) and this is what you use for your viewport. The size of the window is the CSS style size of the canvas (which in the case of Hi DPI is different). The opacity is the CSS style opacity, etc...

Important

Once the canvas is associated with the window, the library takes control over it and sets various listeners and CSS styles on the canvas. In particular, the width and height are controlled by the library and as a result this implementation offers another mechanism for the user to be able to resize the canvas.

How to associate the window with the canvas?

Natively, GLFW doesn't know anything about the concept of a canvas. So there needs to be a way to make this association. This library offers 2 ways depending on your needs:

1. Using JavaScript/Module

Every Emscripten application needs to define a Module variable in JavaScript (see example). By convention in Emscripten, the Module["canvas"] field represents the canvas associated to the window. To be backward compatible with this option, this library supports it, and it is the default. Obviously, this can only work if there is only one window, which is why there is another method.

2. Using emscripten::glfw3::SetNextWindowCanvasSelector

This implementation offers an alternative way of specifying which canvas to associate to which window: the function emscripten::glfw3::SetNextWindowCanvasSelector which must be called prior to calling glfwCreateWindow. The single argument to the function is a CSS path selector to the canvas.

Example:

#include <GLFW/emscripten_glfw3.h> // contains the definitions

emscripten::glfw3::SetNextWindowCanvasSelector("#canvas1");
auto window1 = glfwCreateWindow(300, 200, "hello world", nullptr, nullptr);

This function is required if you use more than one window since the Module solution only supports 1 canvas. It also offers the advantage of defining the association in C/C++ as opposed to HTML/JavaScript.

How to make the canvas resizable by the user?

GLFW deals with windows. Windows, in the context of a desktop application, are usually resizable by the user (note that the GLFW window hint/attribute GLFW_RESIZABLE lets you disable this feature). So how does this translate into the HTML/canvas world?

To make the canvas resizable, and behave more like a "traditional" window, this implementation offers a convenient API: emscripten::glfw3::MakeCanvasResizable:

int MakeCanvasResizable(GLFWwindow *window,
                        std::string_view canvasResizeSelector,
                        std::optional<std::string_view> handleSelector = std::nullopt);

Since this library takes control of the canvas size, the idea behind this function is to specify which other (HTML) element dictates the size of the canvas. The parameter canvasResizeSelector defines the (CSS path) selector to this element.

The 3 typical use cases are:

1. Full window

The canvas fills the entire browser window, in which case the parameter canvasResizeSelector should simply be set to "window" and the handleSelector is std::nullopt. This use case can be found in application like ImGui where the canvas is the window.

Example code:

<!-- html -->
<canvas id="canvas1"></canvas>
// cpp
emscripten::glfw3::SetNextWindowCanvasSelector("#canvas1");
auto window = glfwCreateWindow(300, 200, "hello world", nullptr, nullptr);
emscripten::glfw3::MakeCanvasResizable(window, "window");

2. Container (div)

The canvas is inside a div, in which case the div acts as a "container" and the div size is defined by CSS rules, like for example: width: 75vw so that when the page/browser gets resized, the div is resized automatically, which then triggers the canvas to be resized. In this case, the parameter canvasResizeSelector is the (CSS path) selector to this div and handleSelector is std::nullopt.

Example code:

<!-- html -->
<style>
  #canvas1-container {
    width: 75vw;
    height: 50vh;
  }
</style>
<div id="canvas1-container">
  <canvas id="canvas1"></canvas>
</div>
// cpp
emscripten::glfw3::SetNextWindowCanvasSelector("#canvas1");
auto window = glfwCreateWindow(300, 200, "hello world", nullptr, nullptr);
emscripten::glfw3::MakeCanvasResizable(window, "#canvas1-container");

3. Container + handle

Same as 2. but the div is made resizable dynamically via a little "handle" (which ends up behaving like a normal desktop window).

Example code:

<!-- html -->
<style>
  #canvas1-container {
    position: relative;
  <!-- . . . -->
  }

  #canvas1-handle {
    position: absolute;
    bottom: 0;
    right: 0;
    margin-bottom: 1px;
    margin-right: 1px;
    border-left: 20px solid transparent;
    border-bottom: 20px solid rgba(102, 102, 102, 0.5);
    width: 0;
    height: 0;
    cursor: nwse-resize;
    z-index: 1;
  }
</style>
<div id="canvas1-container">
  <div id="canvas1-handle" class="handle"></div>
  <canvas id="canvas1"></canvas>
</div>
// cpp
emscripten::glfw3::SetNextWindowCanvasSelector("#canvas1");
auto window = glfwCreateWindow(300, 200, "hello world", nullptr, nullptr);
emscripten::glfw3::MakeCanvasResizable(window, "#canvas1-container", "canvas1-handle");

Tip

If you do not want the canvas to be resizable by the user, you can simply set its size during window creation (glfwCreateWindow) or with glfwSetWindowSize and don't do anything else.

Fullscreen support

GLFW has a concept of a fullscreen window. This is quite tricky for this implementation due to the restrictions imposed by browsers to go fullscreen. Historically, Emscripten has offered a way to do it from JavaScript by the means of a function that gets added automatically to the Module called requestFullscreen.

This implementation adds another JavaScript function Module.glfwRequestFullscreen(target, lockPointer, resizeCanvas) with

  • target being which canvas need to be fullscreen
  • lockPointer: boolean to enable/disable grabbing the mouse pointer (equivalent to calling glfwSetInputMode(GLFW_CURSOR, xxx))
  • resizeCanvas: boolean to resize (or not) the canvas to the fullscreen size

To be backward compatible with the current Emscripten/GLFW/JavaScript implementation, you can also call Module.requestFullscreen(lockPointer, resizeCanvas) and the library does its best to determine which canvas to target.

This implementation also offers a CPP and C version of this API:

void emscripten::glfw3::RequestFullscreen(GLFWwindow *window, bool lockPointer, bool resizeCanvas);
void emscripten_glfw_request_fullscreen(GLFWwindow *window, bool lockPointer, bool resizeCanvas);

Tip

To avoid any error while switching to fullscreen, you should always trigger this api from within a user event like a mouse click (callback set via glfwSetMouseButtonCallback) or a keyboard key press (callback set via glfwSetKeyCallback)

At this moment, this implementation does not support creating a window in fullscreen mode due to the same browser restrictions mentioned previously. If you want to create a fullscreen window, create a window with a fixed size, then from a user event call Module.glfwRequestFullscreen.

Hi DPI support

This implementation supports Hi DPI awareness. What this means is that if the browser window is on a screen that is Hi DPI/4k, then it will properly adjust the dimension of the canvas to match the scale of the screen. If the window gets moved to a screen that is lower resolution, it will automatically change the scaling. You can set a callback to be notified of the changes (glfwSetWindowContentScaleCallback) or call the direct API glfwGetWindowContentScale.

By default, this feature is enabled and can be turned off like this:

// before creating a window (to turn Hi DPI Awareness OFF)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
auto window = glfwCreateWindow(...);

// after window creation, it can be dynamically changed
glfwSetWindowAttrib(window, GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); // for enabling Hi DPI awareness
glfwSetWindowAttrib(window, GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); // for disabling Hi DPI awareness

Note

The constant GLFW_SCALE_FRAMEBUFFER was introduced in GLFW 3.4. The constant GLFW_SCALE_TO_MONITOR which was used prior to GLFW 3.4, can still be used to trigger Hi DPI Awareness, but is less descriptive and as a result it is deprecated, and it is preferable to use GLFW_SCALE_FRAMEBUFFER.

Tip

Almost all GLFW apis deal with screen coordinates which are independent of scaling. The only one that doesn't is glfwGetFramebufferSize which returns the actual size of the surface which takes into account the scaling factor. As a result, for most low-level APIs (like OpenGL/webgl) you would use this call to set the viewport size.

Here is an example:

int width = 0, height = 0;
glfwGetFramebufferSize(fWindow, &width, &height);
glViewport(0, 0, width, height);

Keyboard support

This implementation supports the keyboard and uses the same mapping defined in Emscripten for scancodes. You can check KeyboardMapping.h for the full mapping. This implementation uses KeyboardEvent.key to compute an accurate codepoint (provided to the GLFWcharfun callback) and not the deprecated KeyboardEvent.charcode like other implementations.

Internally, the library uses the keyboard events provided by JavaScript and calls e.preventDefault() on all keyboard events except for the 3 keyboard shortcuts associated with cut, copy and paste (based on the runtime platform: ⌘ + C, ⌘ + X + ⌘ + V, for macOS and ^ + C, ^ + X, ^ + V for the other platforms).

In particular, this allows an application written using this library to automatically ignore ^ + F (resp. ⌘ + F) which displays a "Find in page" interface, which is usually not desirable nor useful (a canvas is not searchable).

In the event you want to change this behavior, you can add your own callback by calling emscripten::glfw3::AddBrowserKeyCallback() or entirely replace it with emscripten::glfw3::SetBrowserKeyCallback(). The callback is called on key down, key repeat and key up and should return true for the event to bubble up to the browser (e.preventDefault() will not be called).

Here is an example:

// Allow the F12 key to bubble up to the browser (open developer tools in Chrome):
emscripten::glfw3::AddBrowserKeyCallback([](GLFWwindow* window, int key, int scancode, int action, int mods) {
  return mods == 0 && action == GLFW_PRESS && key == GLFW_KEY_F12;
});

Note

At this time, GLFW_MOD_CAPS_LOCK and GLFW_MOD_NUM_LOCK are not supported.

The problem of the "Super" key

The key called "Super" by the GLFW library (also known as Meta or Command) exhibits an issue in the context of the browser: pressing any other regular key (like the key A) while "Super" is being held, properly triggers down and repeat events, but never triggers the up event.

This library implements a workaround to detect this scenario by setting internal timeouts. These values can be read and modified via the emscripten::glfw3::GetSuperPlusKeyTimeouts() and emscripten::glfw3::SetSuperPlusKeyTimeouts() APIs.

In addition to timeouts, when the "Super" key is released, all keys are also released.

Tip

It is strongly recommended for your application to set a key callback (glfwSetKeyCallback) since you get notifications on key down and key repeat, based on the values set at the OS level instead of trying to implement key repeat manually.

Joystick/Gamepad support

This implementation uses the JavaScript Gamepad API as defined in the specification which is widely supported by most current browsers.

Important

Due to the nature of the Gamepad API, polling is required, so you must ensure to call glfwPollEvents on each loop iteration.

If you want to disable joystick support entirely (and save some resources), you can use the disableJoystick=true option if you use the port (or set the EMSCRIPTEN_GLFW3_DISABLE_JOYSTICK compilation define).

This image, represents the mapping returned by this API (as defined here):

Gamepad Mapping

  • If you use the glfwGetJoystickAxes and glfwGetJoystickButtons functions, you get exactly this mapping
  • The function glfwGetJoystickGUID returns Gamepad.mapping and glfwJoystickIsGamepad returns GLFW_TRUE when the mapping is "standard"
  • The function glfwGetJoystickHats maps the standard gamepad mapping to the GLFW_HAT_XXX bitfield

Caution

The function glfwGetGamepadState returns the same information that glfwGetJoystickAxes and glfwGetJoystickButtons but with the mapping specified by GLFW. Although very close to the Gamepad mapping, there are differences, so make sure you use the API that suits your needs. For example GLFW_GAMEPAD_BUTTON_GUIDE is 8 but the Gamepad guide is 16! Example:

int count;
auto buttons = glfwGetJoystickButtons(jid, &count);
auto isGuidePressed = count > 16 && buttons[16];
// versus
GLFWgamepadstate state;
auto isGuidePressed = glfwGetGamepadState(jid, &state) == GLFW_TRUE && state.buttons[GLFW_GAMEPAD_BUTTON_GUIDE];

Clipboard support

In the context of the browser, getting access to the clipboard is a bit tricky as there are restrictions imposed by the browser for obvious security reasons.

This implementation maintains an "internal" clipboard, one that is always available whether the browser is authorized or not to access the external clipboard.

In addition, the library registers clipboard event listeners to properly handle cut, copy and paste from outside. What this means in practice is that if your application calls glfwGetClipboardString (resp. glfwSetClipboardString) after detecting the same browser keyboard shortcuts for cut/copy and paste, it simply works.

Tip

With ImGui, you can write something like this:

ImGui::GetIO().ConfigMacOSXBehaviors = emscripten::glfw3::IsRuntimePlatformApple();

Clipboard limitations

It is crucial to understand that glfwGetClipboardString does not access the clipboard live but simply returns the value pasted by using the keyboard shortcut. This limitation is due to the way the clipboard JavaScript API (navigator.clipboard.readText) works, for several reasons:

  • the JavaScript API is asynchronous and glfwGetClipboardString is not
  • calling the JavaScript API results in various (purposely) intrusive popups from the browser
  • these popups lead to issues (for example, Firefox shows a little "Paste" popup every time this API is called and suppresses all keyboard events, leading to missing key up events)

As a consequence, this library does not use navigator.clipboard.readText and instead rely on the paste event.

The proper approach for your code to handle paste, is to call glfwGetClipboardString when the paste keyboard event has been detected, for example:

void onKeyChange(GLFWwindow* window, int key, int scancode, int action, int mods) {
  static auto kActionModifier = emscripten::glfw3::IsRuntimePlatformApple() ? GLFW_MOD_SUPER : GLFW_MOD_CONTROL;
  if(action == GLFW_PRESS && (mods & kActionModifier)) {
    switch(key) {
      case GLFW_KEY_V: // paste
        auto clipboard = glfwGetClipboardString(window);
        // handle paste ....
        break;
      default:
        // ignored
        break;
    }
  }
}

// from main...
glfwSetKeyCallback(window, onKeyChange);

Secondly, calling glfwSetClipboardString first sets the internal clipboard to the value provided, then attempts to write to the external clipboard (navigator.clipboard.writeText). In order for this latter call to succeed, you should always call this API from a user-generated event. For example:

void onKeyChange(GLFWwindow* window, int key, int scancode, int action, int mods) {
  static auto kActionModifier = emscripten::glfw3::IsRuntimePlatformApple() ? GLFW_MOD_SUPER : GLFW_MOD_CONTROL;
  if(action == GLFW_PRESS && (mods & kActionModifier)) {
    switch(key) {
      case GLFW_KEY_X: // cut
      case GLFW_KEY_C: // copy
        auto selection = "..."; // compute what is currently selected
        glfwSetClipboardString(window, selection);
        break;
      default:
        // ignored
        break;
    }
  }
}

// from main...
glfwSetKeyCallback(window, onKeyChange);

Tip

Using ImGui, if you set the keyboard behavior properly, then cut/copy and paste will work as expected on all platforms

// during initialization
ImGui::GetIO().ConfigMacOSXBehaviors = emscripten::glfw3::IsRuntimePlatformApple();

// loop
ImGui::InputText("input", buffer); // cut/copy/paste work in the widget

if(ImGui::Button("Copy to clipboard"))
  ImGui::SetClipboardText("..."); // this works as well

// Note that this will NOT work well because it bypasses the paste event and as a result
// only the content of the internal clipboard is accessible!
if(ImGui::MenuItem("Paste"))
  ImGui::GetClipboardText();

Extensions

This implementation offers a few extensions to the normal GLFW api necessary for this specific platform.

CPP extensions

As explained previously, some CPP functions are defined in <GLFW/emscripten_glfw3.h>

Note

All functions are defined in the emscripten::glfw3 namespace

Function Notes
SetNextWindowCanvasSelector to specify the association window <-> canvas
MakeCanvasResizable to make the canvas resizable
UnmakeCanvasResizable to revert MakeCanvasResizable
IsWindowFullscreen to check if the window is fullscreen
RequestFullscreen to request fullscreen
OpenURL to open a URL
IsRuntimePlatformApple to check if the platform is Apple (ex: for keyboard shortcuts)
AddBrowserKeyCallback to add a callback to bubble keys up
SetBrowserKeyCallback to set a callback to bubble keys up
GetPlatformBrowserKeyCallback to get the default callback for the platform
GetSuperPlusKeyTimeouts to retrieve the timeouts used for the Super + key workaround
SetSuperPlusKeyTimeouts to set the timeouts used for the Super + key workaround

C extensions

Similar to the CPP functions, C functions are defined in <GLFW/emscripten_glfw3.h>, with a C-like syntax

Function Notes
emscripten_glfw_set_next_window_canvas_selector to specify the association window <-> canvas
emscripten_glfw_make_canvas_resizable to make the canvas resizable
emscripten_glfw_unmake_canvas_resizable to revert emscripten_glfw_make_canvas_resizable
emscripten_glfw_is_window_fullscreen to check if the window is fullscreen
emscripten_glfw_request_fullscreen to request fullscreen
emscripten_glfw_open_url to open a URL
emscripten_glfw_is_runtime_platform_apple to check if the platform is Apple (ex: for keyboard shortcuts)

You can either include this file, or use an extern "C" {} section in your own code to define them

JavaScript extensions

This implementation adds the following functions to the Module:

Function Notes
requestFullscreen(lockPointer, resizeCanvas) Same function added by the other Emscripten implementations (for backward compatibility purposes)
glfwRequestFullscreen(target, lockPointer, resizeCanvas) The version specific to this implementation with the additional target argument (can be a canvas selector, a HTMLCanvasElement or a GLFWwindow)
glfwGetWindow(any) Returns the GLFWwindow pointer associated to the canvas (any can be a canvas selector or a HTMLCanvasElement)
glfwGetCanvas(any) Returns the canvas associated to the window (any can be a canvas selector or a GLFWwindow)
glfwGetCanvasSelector(any) Returns the canvas selector associated to the window (any can be a canvas selector or a GLFWwindow)
glfwMakeCanvasResizable(any, resizableSelector, handleSelector) Same functionality as MakeCanvasResizable (any can be a canvas selector or a GLFWwindow or a HTMLCanvasElement
glfwUnmakeCanvasResizable(any) To revert Module.glfwMakeCanvasResizable
glfwIsRuntimePlatformApple() To check if the platform is Apple (ex: for keyboard shortcuts)

In addition, this implementation will check if the function Module.glfwOnWindowCreated(glfwWindow, selector) is defined in which case it will be called once the window is created. This allows writing code like this:

Module = {
  // ...
  glfwOnWindowCreated: (glfwWindow, selector) => {
    if(selector === '#canvas2') {
      Module.glfwMakeCanvasResizable(glfwWindow, '#canvas2-container');
    }
  },
  // ...
};

Implementation size

This implementation being in C++ and implementing far more features than the library_glfw.js Emscripten implementation, it has an impact on size. As of initial release, I ran the following experiment on both implementations using example_minimal

Mode library_glfw.js This implementation Delta
Debug js: 170775, wasm: 75789, total: 246564 js: 99559, wasm: 4492007, total: 4591566 18.8x
Release js: 135433, wasm: 8448, total: 143881 js: 81285, wasm: 80506, total: 161791 1.12x
Release (minimal) - js: 79402, wasm: 71195, total: 150197 1.04x
  • From these numbers, and for obvious reasons, there is more wasm code than JavaScript code in this implementation (which is a good thing).
  • Although the size is pretty terrible in Debug mode (almost a 19x size increase), in Release mode it is actually only a 12% increase which shows that wasm optimizes quite well :)
  • The last entry in the table shows the same results when compiling with all disable options turned on (EMSCRIPTEN_GLFW3_DISABLE_JOYSTICK, EMSCRIPTEN_GLFW3_DISABLE_MULTI_WINDOW_SUPPORT and EMSCRIPTEN_GLFW3_DISABLE_WARNING) for an even smaller footprint
  • Lastly, .wasm files compress extremely well, so it is worth serving them compressed

Implementation size (update)

emscripten - 3.1.69 emscripten-glfw-3.4.0.20241004

> cd examples/example_minimal
# using library_glfw.js
> emcc -sUSE_GLFW=3 main.cpp -O2 -o /tmp/build/index.html
# using contrib.glfw3
> emcc --use-port=contrib.glfw3 main.cpp -O2 -o /tmp/build/index.html
# using contrib.glfw3 (minimal)
> emcc --use-port=contrib.glfw3:disableWarning=true:disableJoystick=true:disableMultiWindow=true main.cpp -O2 -o /tmp/build/index.html
Mode library_glfw.js This implementation Delta
Release js: 103908, wasm: 13903, total: 117811 js: 59019, wasm: 73839, total: 132858 1.13x
Release (minimal) - js: 56795, wasm: 66456, total: 123251 1.04x

Note

The good news is that Emscripten is improving and this implementation is benefitting from it.

GLFW functions

This table contains the list of all the GLFW functions API and whether they are supported by this implementation (and the built-in implementation) with a few relevant notes

Note

GLFW 3.4 introduced the concept of a platform. This implementation adds the GLFW_PLATFORM_EMSCRIPTEN define in empscriptem-glfw3.h: the value is reserved (in a comment), but it is not defined in glfw3.h.

Function emscripten-glfw
(this implementation)
library_glfw.js
(built-in implementation)
glfwCreateCursor Yes Custom cursors are supported No
glfwCreateStandardCursor Yes All GLFW cursors are supported: uses the CSS style cursor on the canvas No
glfwCreateWindow Yes Support as many windows as you want: see the section describing the association of a window and a canvas Yes Support only a single window
glfwDefaultWindowHints Yes Yes
glfwDestroyCursor Yes No
glfwDestroyWindow Yes Reverts all changes (event listeners, CSS style, ...) set by this library Yes
glfwExtensionSupported Yes Same implementation as library_glfw.js Yes
glfwFocusWindow Yes Calls JavaScript HTMLElement.focus() on the canvas No
glfwGetClipboardString Yes See the Clipboard Support section No
glfwGetCurrentContext Yes Only available if glfwMakeContextCurrent was called previously Yes
glfwGetCursorPos Yes Hi DPI aware Yes
glfwGetError Yes No 3.3.x+
glfwGetFramebufferSize Yes Hi DPI aware Yes Hi DPI aware
glfwGetGammaRamp No (no access from JavaScript) Exception
glfwGetGamepadName Yes If gamepad, corresponds to Gamepad.id in JavaScript No 3.3.x+
glfwGetGamepadState Yes If gamepad, then Gamepad.axes and Gamepad.buttons (js) remapped for GLFW No 3.3.x+
glfwGetInputMode Yes Supports only GLFW_CURSOR, GLFW_STICKY_KEYS and GLFW_STICKY_MOUSE_BUTTONS Yes Supports only GLFW_CURSOR
glfwGetJoystickAxes Yes Corresponds to Gamepad.axes in JavaScript Yes
glfwGetJoystickButtons Yes Corresponds to Gamepad.buttons[x].value in JavaScript Yes
glfwGetJoystickGUID Yes Corresponds to Gamepad.mapping in JavaScript Exception
glfwGetJoystickHats Yes If gamepad, corresponds to Gamepad.buttons[x].pressed in JavaScript remapped for GLFW Exception
glfwGetJoystickName Yes Corresponds to Gamepad.id in JavaScript (limited to 64 characters due to Emscripten limitation) Yes
glfwGetJoystickUserPointer Yes Exception
glfwGetKey Yes Support GLFW_STICKY_KEYS as well Yes No sticky support / Broken Meta Key
glfwGetKeyName Yes All names start with DOM_PK_: example, DOM_PK_F1. Exception
glfwGetKeyScancode Yes See KeyboardMapping.h for actual mapping Exception
glfwGetMonitorContentScale Yes Corresponds to window.devicePixelRatio in JavaScript Yes
glfwGetMonitorName Yes The constant "Browser" Yes The constant "HTML5 WebGL Canvas"
glfwGetMonitorPos Yes Always 0/0 Yes Always 0/0
glfwGetMonitorPhysicalSize No (no access from JavaScript) No
glfwGetMonitors Yes Due to JavaScript restrictions, always only 1 monitor Yes 1 monitor
glfwGetMonitorUserPointer Yes No 3.3.x+
glfwGetMonitorWorkarea Yes 0x0 for position, screen.widthxscreen.height for size Yes 0x0 for position, screen.availWidthxscreen.availHeight for size
glfwGetMouseButton Yes Support GLFW_STICKY_MOUSE_BUTTONS as well Yes No sticky mouse button support
glfwGetPlatform Yes GLFW_PLATFORM_EMSCRIPTEN (see note above) No 3.4.x+
glfwGetPrimaryMonitor Yes The single monitor returned in glfwGetMonitors Yes Same
glfwGetProcAddress Yes Implemented by Emscripten GL Yes Implemented by Emscripten GL
glfwGetRequiredInstanceExtensions No Exception
glfwGetTime Yes Yes
glfwGetTimerFrequency Yes Always 1000 Exception
glfwGetTimerValue Yes Corresponds to performance.now() in JavaScript Exception
glfwGetVersion Yes Yes 3.2.1
glfwGetVersionString Yes "Emscripten/WebAssembly GLFW " + GLFW version Yes "3.2.1 JS WebGL Emscripten"
glfwGetVideoMode No No
glfwGetVideoModes No No
glfwGetWindowAttrib Yes Supports for
  • GLFW_VISIBLE
  • GLFW_HOVERED
  • GLFW_FOCUSED
  • GLFW_FOCUS_ON_SHOW
  • GLFW_SCALE_FRAMEBUFFER
  • GLFW_SCALE_TO_MONITOR
  • GLFW_RESIZABLE
Yes GLFW_SCALE_TO_MONITOR only
glfwGetWindowContentScale Yes If HiDPI aware (GLFW_SCALE_FRAMEBUFFER is GLFW_TRUE), then current monitor scale, otherwise 1.0 Yes Similar
glfwGetWindowFrameSize Yes Because a window is a canvas in this implementation, there is no edge => all 0 Exception
glfwGetWindowMonitor Yes The single monitor returned in glfwGetMonitors Yes Same
glfwGetWindowOpacity Yes No Always 1.0
glfwGetWindowPos Yes The position of the canvas in the page getBoundingClientRect(canvas).x&y No Whatever was set in glfwSetWindowPos, so not the actual position
glfwGetWindowSize Yes The size of the window/canvas Yes Same
glfwGetWindowTitle Yes The title of the window/canvas No 3.4.x
glfwGetWindowUserPointer Yes Yes
glfwHideWindow Yes Set CSS property to display: none for the canvas No
glfwIconifyWindow No No
glfwInit Yes Set a listener to monitor content scale change (ex: moving browser to different resolution screen) Yes
glfwInitAllocator No (due to JavaScript, memory cannot be managed) No 3.4.x
glfwInitHint Yes GLFW_PLATFORM with value GLFW_ANY_PLATFORM or GLFW_PLATFORM_EMSCRIPTEN No 3.3.x
glfwJoystickIsGamepad Yes Returns GLFW_TRUE when the joystick mapping (Gamepad.mapping) is "standard" Exception
glfwJoystickPresent Yes Listens to gamepadconnected and gamepaddisconnected events to determine the presence. Yes
glfwMakeContextCurrent Yes Since this implementation supports multiple windows, it is important to call this if using OpenGL Yes Since there is only 1 window, it does nothing
glfwMaximizeWindow No No
glfwPlatformSupported Yes GLFW_TRUE for GLFW_PLATFORM_EMSCRIPTEN only (see note above) No 3.4.x
glfwPollEvents Yes Polls for joysticks only (can be disabled with disableJoystick=true port option or EMSCRIPTEN_GLFW3_DISABLE_JOYSTICK define) No
glfwPostEmptyEvent No No
glfwRawMouseMotionSupported Yes Always GLFW_FALSE (not supported) Yes Same
glfwRequestWindowAttention No No
glfwRestoreWindow No No
glfwSetCharCallback Yes Uses KeyboardEvent.key to compute the proper codepoint. Note that `GLFW_MOD_CAPS_LOCK` and `GLFW_MOD_NUM_LOCK` are **not** supported Yes
glfwSetCharModsCallback No (deprecated in GLFW) Exception
glfwSetClipboardString Yes Uses navigator.clipboard.writeText. See the Clipboard Support section. No
glfwSetCursor Yes Uses CSS style cursor: xxx for the canvas No
glfwSetCursorEnterCallback Yes Listeners to mouseenter and mouseleave events Yes
glfwSetCursorPos No (JavaScript does not allow the cursor to be positioned) No
glfwSetCursorPosCallback Yes Hi DPI aware Yes
glfwSetDropCallback No (JavaScript only gives access to filename, so it is pointless) Yes (Copies the entire file(s) in memory)
glfwSetErrorCallback Yes Yes This call stores the pointer but never uses it as this implementation is not handling errors compliantly
glfwSetFramebufferSizeCallback Yes Hi DPI aware Yes Same
glfwSetGamma No No
glfwSetGammaRamp No Exception
glfwSetInputMode Yes Supports only GLFW_CURSOR, GLFW_STICKY_KEYS and GLFW_STICKY_MOUSE_BUTTONS Yes Supports only GLFW_CURSOR
glfwSetJoystickCallback Yes Yes
glfwSetJoystickUserPointer Yes Exception
glfwSetKeyCallback Yes Yes
glfwSetMonitorCallback Yes Callback is never called Yes Same
glfwSetMonitorUserPointer Yes No 3.3.x
glfwSetMouseButtonCallback Yes Yes
glfwSetScrollCallback Yes Listens to mousewheel events Yes
glfwSetTime Yes Yes
glfwSetWindowAspectRatio Yes Only works if the user is controlling the canvas size (spec does not define one way or another) No
glfwSetWindowAttrib Yes See glfwGetWindowAttrib Yes See glfwGetWindowAttrib
glfwSetWindowCloseCallback No There is no concept of "closing" a canvas Yes Called on window destroyed.
glfwSetWindowContentScaleCallback Yes Callback only called if Hi DPI aware (GLFW_SCALE_FRAMEBUFFER is GLFW_TRUE) Yes Same
glfwSetWindowFocusCallback Yes No Callback pointer is stored but never used
glfwSetWindowIcon No (icon could be mapped to favicon but beyond 1.0 scope) No
glfwSetWindowIconifyCallback No No
glfwSetWindowMaximizeCallback No No
glfwSetWindowMonitor No Exception
glfwSetWindowOpacity Yes Uses CSS style opacity: xxx for the canvas No
glfwSetWindowPos No (there is no generic way to set a canvas position) No
glfwSetWindowPosCallback Yes Uses top/left of the value returned by getBoundingClientRect(canvas)) No
glfwSetWindowRefreshCallback No Returns callback provided: callback is never called No Callback stored but never called
glfwSetWindowShouldClose Yes Yes
glfwSetWindowSize Yes Hi DPI Aware: set the size of the canvas (canvas.width = size * scale) + CSS style (style.width = size) Yes
glfwSetWindowSizeCallback Yes Yes
glfwSetWindowSizeLimits Yes Only works if the user is controlling the canvas size (spec does not define one way or another) No
glfwSetWindowTitle Yes Corresponds to document.title in JavaScript Yes
glfwSetWindowUserPointer Yes Yes
glfwShowWindow Yes Removes CSS style display: none for the canvas No
glfwSwapBuffers No No
glfwSwapInterval Yes Uses emscripten_set_main_loop_timing Yes Same
glfwTerminate Yes Tries to properly clean up everything that was set during the course of the app (listeners, CSS styles, ...) Yes
glfwUpdateGamepadMappings No No 3.3.x
glfwWaitEvents No No
glfwWaitEventsTimeout No No
glfwVulkanSupported Yes Always return GLFW_FALSE Yes Same
glfwWindowHint Yes
  • GLFW_CLIENT_API
  • GLFW_SCALE_FRAMEBUFFER
  • GLFW_SCALE_TO_MONITOR
  • GLFW_FOCUS_ON_SHOW
  • GLFW_VISIBLE
  • GLFW_FOCUSED
  • GLFW_RESIZABLE
  • GLFW_ALPHA_BITS
  • GLFW_DEPTH_BITS
  • GLFW_STENCIL_BITS
  • GLFW_SAMPLES
Yes Anything (no check on argument)
glfwWindowHintString No No
glfwWindowShouldClose Yes Yes

Note

For non-supported functions, this library logs a warning the first time they are called (which can be disabled via disableWarning=true port option or EMSCRIPTEN_GLFW3_DISABLE_WARNING define) and are doing nothing, returning the most "sensible" value (like nullptr) if there is an expected return value. Calling any of these will not break the library.