From 57fa135629516705be13774405a844dbef482ed6 Mon Sep 17 00:00:00 2001 From: dkorpel Date: Mon, 10 Aug 2020 16:59:41 +0200 Subject: [PATCH] Initial release --- .gitignore | 19 + LICENSE.md | 22 + README.md | 164 + dub.sdl | 120 + example/app.d | 150 + example/dub.sdl | 11 + source/glfw3/api.d | 5807 +++++++++++++++++++++++++++++++++ source/glfw3/apinative.d | 473 +++ source/glfw3/context.d | 748 +++++ source/glfw3/directinput8.d | 1141 +++++++ source/glfw3/egl_context.d | 926 ++++++ source/glfw3/glx_context.d | 803 +++++ source/glfw3/init.d | 332 ++ source/glfw3/input.d | 1294 ++++++++ source/glfw3/internal.d | 711 ++++ source/glfw3/linux_joystick.d | 511 +++ source/glfw3/linuxinput.d | 796 +++++ source/glfw3/mappings.d | 478 +++ source/glfw3/monitor.d | 515 +++ source/glfw3/null_init.d | 51 + source/glfw3/null_joystick.d | 44 + source/glfw3/null_monitor.d | 68 + source/glfw3/null_platform.d | 64 + source/glfw3/null_window.d | 260 ++ source/glfw3/osmesa_context.d | 404 +++ source/glfw3/package.d | 6 + source/glfw3/posix_thread.d | 121 + source/glfw3/posix_time.d | 85 + source/glfw3/vulkan.d | 324 ++ source/glfw3/wayland.d | 1231 +++++++ source/glfw3/wgl_context.d | 910 ++++++ source/glfw3/win32_init.d | 631 ++++ source/glfw3/win32_joystick.d | 756 +++++ source/glfw3/win32_monitor.d | 513 +++ source/glfw3/win32_platform.d | 392 +++ source/glfw3/win32_thread.d | 94 + source/glfw3/win32_time.d | 76 + source/glfw3/win32_window.d | 2146 ++++++++++++ source/glfw3/window.d | 1028 ++++++ source/glfw3/wl_init.d | 1234 +++++++ source/glfw3/wl_monitor.d | 194 ++ source/glfw3/wl_platform.d | 363 +++ source/glfw3/wl_window.d | 1746 ++++++++++ source/glfw3/x11_header.d | 4957 ++++++++++++++++++++++++++++ source/glfw3/x11_init.d | 1092 +++++++ source/glfw3/x11_monitor.d | 591 ++++ source/glfw3/x11_platform.d | 455 +++ source/glfw3/x11_window.d | 3081 +++++++++++++++++ source/glfw3/xinput.d | 243 ++ source/glfw3/xkb_unicode.d | 945 ++++++ 50 files changed, 39126 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 dub.sdl create mode 100644 example/app.d create mode 100644 example/dub.sdl create mode 100644 source/glfw3/api.d create mode 100644 source/glfw3/apinative.d create mode 100644 source/glfw3/context.d create mode 100644 source/glfw3/directinput8.d create mode 100644 source/glfw3/egl_context.d create mode 100644 source/glfw3/glx_context.d create mode 100644 source/glfw3/init.d create mode 100644 source/glfw3/input.d create mode 100644 source/glfw3/internal.d create mode 100644 source/glfw3/linux_joystick.d create mode 100644 source/glfw3/linuxinput.d create mode 100644 source/glfw3/mappings.d create mode 100644 source/glfw3/monitor.d create mode 100644 source/glfw3/null_init.d create mode 100644 source/glfw3/null_joystick.d create mode 100644 source/glfw3/null_monitor.d create mode 100644 source/glfw3/null_platform.d create mode 100644 source/glfw3/null_window.d create mode 100644 source/glfw3/osmesa_context.d create mode 100644 source/glfw3/package.d create mode 100644 source/glfw3/posix_thread.d create mode 100644 source/glfw3/posix_time.d create mode 100644 source/glfw3/vulkan.d create mode 100644 source/glfw3/wayland.d create mode 100644 source/glfw3/wgl_context.d create mode 100644 source/glfw3/win32_init.d create mode 100644 source/glfw3/win32_joystick.d create mode 100644 source/glfw3/win32_monitor.d create mode 100644 source/glfw3/win32_platform.d create mode 100644 source/glfw3/win32_thread.d create mode 100644 source/glfw3/win32_time.d create mode 100644 source/glfw3/win32_window.d create mode 100644 source/glfw3/window.d create mode 100644 source/glfw3/wl_init.d create mode 100644 source/glfw3/wl_monitor.d create mode 100644 source/glfw3/wl_platform.d create mode 100644 source/glfw3/wl_window.d create mode 100644 source/glfw3/x11_header.d create mode 100644 source/glfw3/x11_init.d create mode 100644 source/glfw3/x11_monitor.d create mode 100644 source/glfw3/x11_platform.d create mode 100644 source/glfw3/x11_window.d create mode 100644 source/glfw3/xinput.d create mode 100644 source/glfw3/xkb_unicode.d diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b8624a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +.dub +docs.json +__dummy.html +docs/ +/glfwd +glfwd.so +glfwd.dylib +glfwd.dll +glfwd.a +glfwd.lib +glfwd-test-* +*.exe +*.o +*.obj +*.lst +build/ +reference/ +dub.selections.json +example/dub.selections.json diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..acdac20 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2002-2006 Marcus Geelnard +Copyright (c) 2006-2016 Camilla Löwy + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would + be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e35501 --- /dev/null +++ b/README.md @@ -0,0 +1,164 @@ +# GLFW-D +A translation from C to D of [GLFW](https://github.com/glfw/glfw) version 3.3.2. + +GLFW is a multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input. +(See also: [what is GLFW](https://www.glfw.org/faq.html#11---what-is-glfw)) + +GLFW has 5 targets, but currently only three are availabe in this translation. + +| GLFW Target | Translated | Primarily used for | +|--------------------------------------------------------------------------------|------------|--------------------------| +| Win32 | ✔️ Yes | Windows | +| [X11](https://en.wikipedia.org/wiki/X_Window_System) | ✔️ Yes | Linux (older) | +| [Cocoa](https://en.wikipedia.org/wiki/Cocoa_(API)) | ❌ No | macOS | +| [Wayland](https://en.wikipedia.org/wiki/Wayland_%28display_server_protocol%29) | ❌ No | Linux (newer) | +| Osmesa | ✔️ Yes | Off-screen rendering (?) | + +The translation sticks close to the C source code, so all uses of e.g. `memcpy`, `printf` and pointer arithmetic are intact and not replaced with idiomatic D. +The Doxygen documentation in `glfw.h` and `glfwnative.h` (here `glfw3/api.d` and `glfw3/apinative.d`) is translated to use DDoc `Params:` and `Returns:` sections. + +The translation is licensed under the [zlib/libpng license](http://www.glfw.org/license.html) like the original code. +The translation is not affiliated with the original project. + +## Basic usage + +If you are using dub, add this package as a dependency. +In `dub.sdl`: +``` +dependency "glfw-d" version="~>1.0.0" +``` +In `dub.json`: +``` +"dependencies": { + "glfw-d": "~>1.0.0" +} +``` + +Then you should be ready to go. +```D +import glfw3.api; + +void main() { + // call GLFW functions, such as: + glfwInit(); + glfwTerminate(); +} +``` +Check out the [example subpackage](https://github.com/dkorpel/glfw-d/tree/master/example) for an example of a GLFW application that creates a window and reads input: +``` +dub run glfw-d:example +``` +Note that you probably want to use OpenGL / Vulkan bindings ([bindbc-opengl](https://code.dlang.org/packages/bindbc-opengl) or [erupted](https://code.dlang.org/packages/erupted)) in order to actually display anything in your window. + +See also: the [tutorial on glfw.org](https://www.glfw.org/docs/latest/quick.html) + +## Reasons for using it +Using GLFW in your D project usually involves depending on a binding to the C-library, (such as [bindbc-glfw](https://github.com/BindBC/bindbc-glfw) or [derelict-glfw3](https://github.com/DerelictOrg/DerelictGLFW3)). +You'd then include a `glfw3.dll` with your releases for Windows users, and ask Linux users to install glfw using their package manager. +Your application then has to call a function that loads the function pointers at runtime, and then you check whether that succeeded or whether the shared library was missing or corrupted. + +If you statically linked to GLFW, you don't have the hassle of run-time loading: everything you need is in the executable itself. +You could add pre-compiled static libraries to your repository, but you need to have one for each combination of settings you want: Windows / Linux, 32-bit / 64-bit, debug / release, etc. +You also need to make sure to link the correct C runtime library (e.g. `libcmt.lib` / `msvcrt.dll`). +It's very easy for issues to arise: +- [linker warnings and errors with bindbc-glfw](https://forum.dlang.org/post/sfihgdqopuwkqsvpsvos@forum.dlang.org) +- [Static link of glfw3 library fails for me](https://forum.dlang.org/post/vhttrhodifisvtgsrizz@forum.dlang.org) + +With this translation, you can simply use Dub, and your D compiler settings (C runtime, optimization flags, debug info) also apply to GLFW. + +Compile times are pretty short. +I get these results from the 'total' time of `time dub build glfw-d --force` on Debian Linux: + +| build type | time (s) | +|--------------|----------| +| dmd debug | 0.5 | +| dmd release | 1.1 | +| ldc2 debug | 1.0 | +| ldc2 release | 2.7 | + +Dub caches builds, so these compile times only apply the first time. + +### Disadvantages +- The C sources are more battle-tested. +There is a chance the translation introduced new bugs. +- While GLFW is pretty stable, it is still being maintained by a group of contributors and new releases with new features and fixes come out. +Once GLFW 3.4 comes out, this translation will lag behind for who knows how long. +However, you can always switch back to compiling the C sources. + +### Todo +- Thoroughly test on platforms +So far I used this library for my own OpenGL application and succesfully ran it on Debian Linux with X11 and Windows 7, but there are aspects that are not yet tested. +I have not used this with Vulkan or OpenGL ES. +I haven't used the native api (`glfw3/apinative.d` here) or functions for custom cursor creation yet. + +- Add Wayland support +This platform needs to be translated still. + +- Add Cocoa support. +This is low priority though since I don't have a computer that runs macOS and have little personal interest in this platform. + +## Advanced usage + +### Adding glfw-d to an existing D application using GLFW +If you are already using different static bindings to GLFW (e.g. [bindbc-glfw](https://code.dlang.org/packages/bindbc-glfw) with `BindGLFW_Static`), you can still use those with this package: +You don't have to change `import bindbc.glfw;` to `import glfw3.api;`. +Simply add the dependency to glfw-d and remove the linkage with the C library from `libs`, `sourceFiles` or `lflags` in your dub file. + +### Configurations +Dub should automatically pick a configuration based on your operating system. +If you are on Linux but don't want to use the x11 target, you can e.g. add to your `dub.sdl`: +``` +subConfiguration "glfw-d" "osmesa" +``` +Or `dub.json`: +``` +"subConfigurations": { + "glfw-d": "osmesa" +} +``` + +To expose the native API, set the appropriate version identifiers. +The available window API versions are: +- `GLFW_EXPOSE_NATIVE_WIN32` +- `GLFW_EXPOSE_NATIVE_COCOA` +- `GLFW_EXPOSE_NATIVE_X11` +- `GLFW_EXPOSE_NATIVE_WAYLAND` + +The available context API versions are: +- `GLFW_EXPOSE_NATIVE_WGL` +- `GLFW_EXPOSE_NATIVE_NSGL` +- `GLFW_EXPOSE_NATIVE_GLX` +- `GLFW_EXPOSE_NATIVE_EGL` +- `GLFW_EXPOSE_NATIVE_OSMESA` + +Example `dub.sdl`: +``` +versions "GLFW_EXPOSE_NATIVE_WIN32" "GLFW_EXPOSE_NATIVE_WGL" +``` + +`dub.json`: +``` +"versions": ["GLFW_EXPOSE_NATIVE_WIN32", "GLFW_EXPOSE_NATIVE_WGL"] +``` + +### Compiling manually +If you don't want to use dub, it is not hard to compile it manually since all source files you need are in a single folder: `source/glfw3`. +Look in `dub.sdl` which source files and version identifier your desired platform uses, then pass them to a D compiler: +``` +# from the root of this repository +cd source/glfw3 +dmd -version=_GLFW_WIN32 -I../ -m64 -lib -of=../../build/glfw.lib context.d init.d input.d monitor.d vulkan.d window.d mappings.d internal.d api.d win32_platform.d win32_init.d win32_joystick.d win32_monitor.d win32_time.d win32_thread.d win32_window.d wgl_context.d egl_context.d osmesa_context.d directinput8.d +``` + +### BetterC +Since it's a direct translation of a C codebase, it might compile [with `-betterC`](https://dlang.org/spec/betterc.html), but there might be linking errors because of certain C macros that are functions in druntime, such as: +``` +core.sys.posix.sys.select.FD_SET +core.sys.posix.sys.select.FD_ZERO +``` +This might or might not give linker errors in your application, depending on your compiler and settings. + +## Building a shared library DLL +Building a shared library from the D sources should be possible, but I haven't tried it yet. +It may be as simple as adding `export` to functions that had `GLFWAPI` in the C sources, and adding a configuration with `targetType "sharedLibrary"` in `dub.sdl`, +but it also may be more difficult than that. diff --git a/dub.sdl b/dub.sdl new file mode 100644 index 0000000..c994880 --- /dev/null +++ b/dub.sdl @@ -0,0 +1,120 @@ +name "glfw-d" +description "D translation of GLFW, a multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input" +authors "dkorpel" +copyright "Copyright © 2020, dkorpel" +license "Zlib" +targetName "glfw-d" +targetPath "build" +targetType "library" + +subPackage "example" + +dflags "-preview=dip1000" "-preview=dip25" +dflags "-preview=fieldwise" +dflags "-preview=markdown" +dflags "-preview=fixAliasThis" +dflags "-preview=intpromote" +dflags "-preview=dtorfields" +dflags "-mixin=build/mixin.d" + +sourcePaths // by default dub includes everything in source/, which we don't want here +sourceFiles "source/glfw3/context.d" +sourceFiles "source/glfw3/init.d" +sourceFiles "source/glfw3/input.d" +sourceFiles "source/glfw3/monitor.d" +sourceFiles "source/glfw3/vulkan.d" +sourceFiles "source/glfw3/window.d" +sourceFiles "source/glfw3/mappings.d" +sourceFiles "source/glfw3/internal.d" // dmd wants to have _GLFWmapping.init even though it should be 0 +sourceFiles "source/glfw3/api.d" // GLFWGamepadState.init + +configuration "x11" { + platforms "linux" + versions "_GLFW_X11" + libs "X11" platform="linux" + sourceFiles "source/glfw3/x11_header.d" + buildOptions "betterC" + + sourceFiles "source/glfw3/x11_platform.d" + sourceFiles "source/glfw3/x11_init.d" + sourceFiles "source/glfw3/x11_monitor.d" + sourceFiles "source/glfw3/x11_window.d" + sourceFiles "source/glfw3/xkb_unicode.d" + sourceFiles "source/glfw3/posix_time.d" + sourceFiles "source/glfw3/posix_thread.d" + sourceFiles "source/glfw3/glx_context.d" + sourceFiles "source/glfw3/egl_context.d" + sourceFiles "source/glfw3/osmesa_context.d" + sourceFiles "source/glfw3/linux_joystick.d" +} + +configuration "windows" { + platforms "windows" + versions "_GLFW_WIN32" + buildOptions "betterC" + + sourceFiles "source/glfw3/win32_platform.d" + sourceFiles "source/glfw3/win32_init.d" + sourceFiles "source/glfw3/win32_joystick.d" + sourceFiles "source/glfw3/win32_monitor.d" + sourceFiles "source/glfw3/win32_time.d" + sourceFiles "source/glfw3/win32_thread.d" + sourceFiles "source/glfw3/win32_window.d" + sourceFiles "source/glfw3/wgl_context.d" + sourceFiles "source/glfw3/egl_context.d" + sourceFiles "source/glfw3/osmesa_context.d" + sourceFiles "source/glfw3/directinput8.d" + + libs "Gdi32" "User32" + + // For cross-compiling: + // dflags "-mtriple=x86_64-windows-msvc" platform="ldc2" +} + +configuration "wayland" { + platforms "linux" + versions "_GLFW_WAYLAND" + //buildOptions "betterC" + //dependency "wayland" version="0.2.0" + //dependency "wayland:client" version="0.2.0" + //dependency "wayland:client" path="../wayland-d/" + dependency "xkbcommon-d" version="0.5.1" + + sourceFiles "source/glfw3/wl_platform.d" + sourceFiles "source/glfw3/wl_init.d" + sourceFiles "source/glfw3/wl_monitor.d" + sourceFiles "source/glfw3/wl_window.d" + sourceFiles "source/glfw3/linux_joystick.d" + sourceFiles "source/glfw3/posix_time.d" + sourceFiles "source/glfw3/posix_thread.d" + sourceFiles "source/glfw3/xkb_unicode.d" + sourceFiles "source/glfw3/egl_context.d" + sourceFiles "source/glfw3/osmesa_context.d" +} + +configuration "osmesa" { + platforms "linux" + versions "_GLFW_OSMESA" + sourceFiles "source/glfw3/null_init.c" + sourceFiles "source/glfw3/null_monitor.c" + sourceFiles "source/glfw3/null_window.c" + sourceFiles "source/glfw3/null_joystick.c" + sourceFiles "source/glfw3/posix_time.c" + sourceFiles "source/glfw3/posix_thread.c" + sourceFiles "source/glfw3/osmesa_context.c" +} + +configuration "cocoa" { + platforms "osx" // probably not the right identifier + versions "_GLFW_COCOA" + sourceFiles "source/glfw3/cocoa_platform.d" + sourceFiles "source/glfw3/cocoa_init.d" + sourceFiles "source/glfw3/cocoa_joystick.d" + sourceFiles "source/glfw3/cocoa_monitor.d" + sourceFiles "source/glfw3/cocoa_time.d" + sourceFiles "source/glfw3/cocoa_window.d" + sourceFiles "source/glfw3/posix_thread.d" + sourceFiles "source/glfw3/nsgl_context.d" + sourceFiles "source/glfw3/egl_context.d" + sourceFiles "source/glfw3/osmesa_context.d" +} diff --git a/example/app.d b/example/app.d new file mode 100644 index 0000000..bba15f9 --- /dev/null +++ b/example/app.d @@ -0,0 +1,150 @@ +/// Simple example of a GLFW application that creates a black window and reads some input and output +/// +/// Does not load OpenGL / Vulkan. +module app; + +import glfw3.api; +import core.stdc.stdio; + +int main() { + GLFWwindow* window; + glfwSetErrorCallback(&errorCallback); + + if (!glfwInit()) { + return -1; + } + scope(exit) glfwTerminate(); + + printClipboardState(); + printJoystickState(); + printMonitorState(); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + + WindowData data; + window = glfwCreateWindow(800, 600, "Black window - press F11 to toggle fullscreen, press ESC to exit", null, null); + scope(exit) glfwDestroyWindow(window); + if (!window) { + glfwTerminate(); + return -1; + } + glfwSetWindowUserPointer(window, &data); + + glfwSetKeyCallback(window, &keyCallback); + glfwMakeContextCurrent(window); + glfwSwapInterval(1); // Set vsync on so glfwSwapBuffers will wait for monitor updates. + // note: 1 is not a boolean! Set e.g. to 2 to run at half the monitor refresh rate. + + double oldTime = glfwGetTime(); + while (!glfwWindowShouldClose(window)) { + const newTime = glfwGetTime(); + const elapsedTime = newTime - oldTime; + oldTime = newTime; + + glfwSwapBuffers(window); + glfwPollEvents(); + } + return 0; +} + +/// Data stored in the window's user pointer +/// +/// Note: assuming you only have one window, you could make these global variables. +struct WindowData { + // These are stored in the window's user data so that when exiting fullscreen, + // the window can be set to the position where it was before entering fullscreen + // instead of resetting to e.g. (0, 0) + int xpos; + int ypos; + int width; + int height; + + @nogc nothrow void update(GLFWwindow* window) { + glfwGetWindowPos(window, &this.xpos, &this.ypos); + glfwGetWindowSize(window, &this.width, &this.height); + } +} + +extern(C) @nogc nothrow void errorCallback(int error, const(char)* description) { + fprintf(stderr, "Error: %s\n", description); +} + +extern(C) @nogc nothrow void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (action == GLFW_PRESS) { + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + case GLFW_KEY_F11: + toggleFullScreen(window); + break; + default: break; + } + } +} + +@nogc nothrow void toggleFullScreen(GLFWwindow* window) { + WindowData* wd = cast(WindowData*) glfwGetWindowUserPointer(window); + assert(wd); + if (glfwGetWindowMonitor(window)) { + glfwSetWindowMonitor(window, null, wd.xpos, wd.ypos, wd.width, wd.height, 0); + } else { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + if (monitor) { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + wd.update(window); + glfwSetWindowMonitor(window, monitor, 0, 0, mode.width, mode.height, mode.refreshRate); + } + } +} + +void printClipboardState() { + printf("Clipboard contents: `%s.80`\n", glfwGetClipboardString(null)); +} + +void printMonitorState() { + int monitorsLength; + GLFWmonitor** monitorsPtr = glfwGetMonitors(&monitorsLength); + GLFWmonitor*[] monitors = monitorsPtr[0..monitorsLength]; + + foreach(GLFWmonitor* mt; monitors) { + int widthMM, heightMM; + int xpos, ypos, width, height; + glfwGetMonitorPos(mt, &xpos, &ypos); + glfwGetMonitorPhysicalSize(mt, &widthMM, &heightMM); + const(GLFWvidmode)* mode = glfwGetVideoMode(mt); + printf("Monitor `%s` has size %dx%d mm\n", glfwGetMonitorName(mt), widthMM, heightMM); + printf(" current video mode: %dx%d %dHz r%dg%db%d\n", mode.width, mode.height, mode.refreshRate, mode.redBits, mode.greenBits, mode.blueBits); + printf(" position: %d, %d\n", xpos, ypos); + glfwGetMonitorWorkarea(mt, &xpos, &ypos, &width, &height); + printf(" work area: %d, %d to %d, %d\n", xpos, ypos, width, height); + } +} + +void printJoystickState() { + for (int js = GLFW_JOYSTICK_1; js <= GLFW_JOYSTICK_LAST; js++) { + if (glfwJoystickPresent(js)) { + printf("Joystick %d has name `%s` and GUID `%s`\n", js, glfwGetJoystickName(js), glfwGetJoystickGUID(js)); + int buttonsLength, axesLength, hatsLength; + const(ubyte)* buttonsPtr = glfwGetJoystickButtons(js, &buttonsLength); + const(float)* axesPtr = glfwGetJoystickAxes(js, &axesLength); + const(ubyte)* hatsPtr = glfwGetJoystickHats(js, &hatsLength); + const(ubyte)[] buttons = buttonsPtr[0..buttonsLength]; + const(float)[] axes = axesPtr[0..axesLength]; + const(ubyte)[] hats = hatsPtr[0..hatsLength]; + + if (glfwJoystickIsGamepad(js)) { + printf(" It is a gamepad with name `%s`\n", glfwGetGamepadName(js)); + GLFWgamepadstate state; + if (glfwGetGamepadState(js, &state)) { + // + printf("Left stick: %f,%f\n", state.axes[GLFW_GAMEPAD_AXIS_LEFT_X], state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]); + printf("A: %d, B: %d\n", state.buttons[GLFW_GAMEPAD_BUTTON_A], state.buttons[GLFW_GAMEPAD_BUTTON_B]); + } + } + } else { + //printf("Joystick %d not present\n", js); + } + } +} diff --git a/example/dub.sdl b/example/dub.sdl new file mode 100644 index 0000000..2f12d5b --- /dev/null +++ b/example/dub.sdl @@ -0,0 +1,11 @@ +name "example" +description "opens a GLFW window" +authors "dkorpel" +copyright "Copyright © 2020, dkorpel" +license "Zlib" +targetType "executable" +targetName "glfw-example" +targetPath "../build" +dependency "glfw-d" path="../" +sourceFiles "app.d" +//buildOptions "betterC" \ No newline at end of file diff --git a/source/glfw3/api.d b/source/glfw3/api.d new file mode 100644 index 0000000..1f2e4f4 --- /dev/null +++ b/source/glfw3/api.d @@ -0,0 +1,5807 @@ +/** + * The cross-platform GLFW 3 API, translated from `glfw3.h` + * + * This is the header file of the GLFW 3 API. + * It defines all types and functions that are used on all platforms. + * For platform-specific public definitions, refer to `glfw3.apinative`. + */ +module glfw3.api; + +extern(C): @nogc: nothrow: __gshared: +/************************************************************************* + * GLFW 3.3 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2019 Camilla Löwy + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +/** @defgroup context Context reference + * Functions and types related to OpenGL and OpenGL ES contexts. + * + * This is the reference documentation for OpenGL and OpenGL ES context related + * functions. For more task-oriented information, see the @ref context_guide. + */ +/** @defgroup vulkan Vulkan reference + * Functions and types related to Vulkan. + * + * This is the reference documentation for Vulkan related functions and types. + * For more task-oriented information, see the @ref vulkan_guide. + */ +/** @defgroup init Initialization, version and error reference + * Functions and types related to initialization and error handling. + * + * This is the reference documentation for initialization and termination of + * the library, version management and error handling. For more task-oriented + * information, see the @ref intro_guide. + */ +/** @defgroup input Input reference + * Functions and types related to input handling. + * + * This is the reference documentation for input related functions and types. + * For more task-oriented information, see the @ref input_guide. + */ +/** @defgroup monitor Monitor reference + * Functions and types related to monitors. + * + * This is the reference documentation for monitor related functions and types. + * For more task-oriented information, see the @ref monitor_guide. + */ +/** @defgroup window Window reference + * Functions and types related to windows. + * + * This is the reference documentation for window related functions and types, + * including creation, deletion and event polling. For more task-oriented + * information, see the @ref window_guide. + */ + + +/************************************************************************* + * Compiler- and platform-specific preprocessor work + *************************************************************************/ + +/* Include because most Windows GLU headers need wchar_t and + * the macOS OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. + */ +import core.stdc.stddef; + +/* Include because it is needed by Vulkan and related functions. + * Include it unconditionally to avoid surprising side-effects. + */ +import core.stdc.stdint; + +/************************************************************************* + * GLFW API tokens + *************************************************************************/ + +/** @name GLFW version macros + * @{ */ +/** The major version number of the GLFW library. + * + * This is incremented when the API is changed in non-compatible ways. + * Ingroup: init + */ +enum GLFW_VERSION_MAJOR = 3; +/** The minor version number of the GLFW library. + * + * This is incremented when features are added to the API but it remains + * backward-compatible. + * Ingroup: init + */ +enum GLFW_VERSION_MINOR = 3; +/** The revision number of the GLFW library. + * + * This is incremented when a bug fix release is made that does not contain any + * API changes. + * Ingroup: init + */ +enum GLFW_VERSION_REVISION = 2; +/** @} */ + +/** One. + * + * This is only semantic sugar for the number 1. You can instead use `1` or + * `true` or `_True` or `GL_TRUE` or `VK_TRUE` or anything else that is equal + * to one. + * + * Ingroup: init + */ +enum GLFW_TRUE = 1; +/** Zero. + * + * This is only semantic sugar for the number 0. You can instead use `0` or + * `false` or `_False` or `GL_FALSE` or `VK_FALSE` or anything else that is + * equal to zero. + * + * Ingroup: init + */ +enum GLFW_FALSE = 0; + +/** @name Key and button actions + * @{ */ +/** The key or mouse button was released. + * + * The key or mouse button was released. + * + * Ingroup: input + */ +enum GLFW_RELEASE = 0; +/** The key or mouse button was pressed. + * + * The key or mouse button was pressed. + * + * Ingroup: input + */ +enum GLFW_PRESS = 1; +/** The key was held down until it repeated. + * + * The key was held down until it repeated. + * + * Ingroup: input + */ +enum GLFW_REPEAT = 2; +/** @} */ + +/** @defgroup hat_state Joystick hat states + * Joystick hat states. + * + * See [joystick hat input](@ref joystick_hat) for how these are used. + * + * Ingroup: input + * @{ */ +enum GLFW_HAT_CENTERED = 0; +enum GLFW_HAT_UP = 1; +enum GLFW_HAT_RIGHT = 2; +enum GLFW_HAT_DOWN = 4; +enum GLFW_HAT_LEFT = 8; +enum GLFW_HAT_RIGHT_UP = (GLFW_HAT_RIGHT | GLFW_HAT_UP); +enum GLFW_HAT_RIGHT_DOWN = (GLFW_HAT_RIGHT | GLFW_HAT_DOWN); +enum GLFW_HAT_LEFT_UP = (GLFW_HAT_LEFT | GLFW_HAT_UP); +enum GLFW_HAT_LEFT_DOWN = (GLFW_HAT_LEFT | GLFW_HAT_DOWN); +/** @} */ + +/** @defgroup keys Keyboard keys + * Keyboard key IDs. + * + * See [key input](@ref input_key) for how these are used. + * + * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * + * The naming of the key codes follow these rules: + * - The US keyboard layout is used + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc.) + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not + * correspond to the Unicode standard (usually for brevity) + * - Keys that lack a clear US mapping are named "WORLD_x" + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc.) + * + * Ingroup: input + * @{ + */ + +/* The unknown key */ +enum GLFW_KEY_UNKNOWN = -1; + +/** Printable keys */ +enum GLFW_KEY_SPACE = 32; +enum GLFW_KEY_APOSTROPHE = 39 /* ' */; +enum GLFW_KEY_COMMA = 44 /* , */; +enum GLFW_KEY_MINUS = 45 /* - */; +enum GLFW_KEY_PERIOD = 46 /* . */; +enum GLFW_KEY_SLASH = 47 /* / */; +enum GLFW_KEY_0 = 48; +enum GLFW_KEY_1 = 49; +enum GLFW_KEY_2 = 50; +enum GLFW_KEY_3 = 51; +enum GLFW_KEY_4 = 52; +enum GLFW_KEY_5 = 53; +enum GLFW_KEY_6 = 54; +enum GLFW_KEY_7 = 55; +enum GLFW_KEY_8 = 56; +enum GLFW_KEY_9 = 57; +enum GLFW_KEY_SEMICOLON = 59 /* ; */; +enum GLFW_KEY_EQUAL = 61 /* = */; +enum GLFW_KEY_A = 65; +enum GLFW_KEY_B = 66; +enum GLFW_KEY_C = 67; +enum GLFW_KEY_D = 68; +enum GLFW_KEY_E = 69; +enum GLFW_KEY_F = 70; +enum GLFW_KEY_G = 71; +enum GLFW_KEY_H = 72; +enum GLFW_KEY_I = 73; +enum GLFW_KEY_J = 74; +enum GLFW_KEY_K = 75; +enum GLFW_KEY_L = 76; +enum GLFW_KEY_M = 77; +enum GLFW_KEY_N = 78; +enum GLFW_KEY_O = 79; +enum GLFW_KEY_P = 80; +enum GLFW_KEY_Q = 81; +enum GLFW_KEY_R = 82; +enum GLFW_KEY_S = 83; +enum GLFW_KEY_T = 84; +enum GLFW_KEY_U = 85; +enum GLFW_KEY_V = 86; +enum GLFW_KEY_W = 87; +enum GLFW_KEY_X = 88; +enum GLFW_KEY_Y = 89; +enum GLFW_KEY_Z = 90; +enum GLFW_KEY_LEFT_BRACKET = 91 /* [ */; +enum GLFW_KEY_BACKSLASH = 92 /* \ */; +enum GLFW_KEY_RIGHT_BRACKET = 93 /* ] */; +enum GLFW_KEY_GRAVE_ACCENT = 96 /* ` */; +enum GLFW_KEY_WORLD_1 = 161 /* non-US #1 */; +enum GLFW_KEY_WORLD_2 = 162 /* non-US #2 */; + +/* Function keys */ +enum GLFW_KEY_ESCAPE = 256; +enum GLFW_KEY_ENTER = 257; +enum GLFW_KEY_TAB = 258; +enum GLFW_KEY_BACKSPACE = 259; +enum GLFW_KEY_INSERT = 260; +enum GLFW_KEY_DELETE = 261; +enum GLFW_KEY_RIGHT = 262; +enum GLFW_KEY_LEFT = 263; +enum GLFW_KEY_DOWN = 264; +enum GLFW_KEY_UP = 265; +enum GLFW_KEY_PAGE_UP = 266; +enum GLFW_KEY_PAGE_DOWN = 267; +enum GLFW_KEY_HOME = 268; +enum GLFW_KEY_END = 269; +enum GLFW_KEY_CAPS_LOCK = 280; +enum GLFW_KEY_SCROLL_LOCK = 281; +enum GLFW_KEY_NUM_LOCK = 282; +enum GLFW_KEY_PRINT_SCREEN = 283; +enum GLFW_KEY_PAUSE = 284; +enum GLFW_KEY_F1 = 290; +enum GLFW_KEY_F2 = 291; +enum GLFW_KEY_F3 = 292; +enum GLFW_KEY_F4 = 293; +enum GLFW_KEY_F5 = 294; +enum GLFW_KEY_F6 = 295; +enum GLFW_KEY_F7 = 296; +enum GLFW_KEY_F8 = 297; +enum GLFW_KEY_F9 = 298; +enum GLFW_KEY_F10 = 299; +enum GLFW_KEY_F11 = 300; +enum GLFW_KEY_F12 = 301; +enum GLFW_KEY_F13 = 302; +enum GLFW_KEY_F14 = 303; +enum GLFW_KEY_F15 = 304; +enum GLFW_KEY_F16 = 305; +enum GLFW_KEY_F17 = 306; +enum GLFW_KEY_F18 = 307; +enum GLFW_KEY_F19 = 308; +enum GLFW_KEY_F20 = 309; +enum GLFW_KEY_F21 = 310; +enum GLFW_KEY_F22 = 311; +enum GLFW_KEY_F23 = 312; +enum GLFW_KEY_F24 = 313; +enum GLFW_KEY_F25 = 314; +enum GLFW_KEY_KP_0 = 320; +enum GLFW_KEY_KP_1 = 321; +enum GLFW_KEY_KP_2 = 322; +enum GLFW_KEY_KP_3 = 323; +enum GLFW_KEY_KP_4 = 324; +enum GLFW_KEY_KP_5 = 325; +enum GLFW_KEY_KP_6 = 326; +enum GLFW_KEY_KP_7 = 327; +enum GLFW_KEY_KP_8 = 328; +enum GLFW_KEY_KP_9 = 329; +enum GLFW_KEY_KP_DECIMAL = 330; +enum GLFW_KEY_KP_DIVIDE = 331; +enum GLFW_KEY_KP_MULTIPLY = 332; +enum GLFW_KEY_KP_SUBTRACT = 333; +enum GLFW_KEY_KP_ADD = 334; +enum GLFW_KEY_KP_ENTER = 335; +enum GLFW_KEY_KP_EQUAL = 336; +enum GLFW_KEY_LEFT_SHIFT = 340; +enum GLFW_KEY_LEFT_CONTROL = 341; +enum GLFW_KEY_LEFT_ALT = 342; +enum GLFW_KEY_LEFT_SUPER = 343; +enum GLFW_KEY_RIGHT_SHIFT = 344; +enum GLFW_KEY_RIGHT_CONTROL = 345; +enum GLFW_KEY_RIGHT_ALT = 346; +enum GLFW_KEY_RIGHT_SUPER = 347; +enum GLFW_KEY_MENU = 348; + +enum GLFW_KEY_LAST = GLFW_KEY_MENU; + +/** @} */ + +/** @defgroup mods Modifier key flags + * Modifier key flags. + * + * See [key input](@ref input_key) for how these are used. + * + * Ingroup: input + * @{ */ + +/** If this bit is set one or more Shift keys were held down. + * + * If this bit is set one or more Shift keys were held down. + */ +enum GLFW_MOD_SHIFT = 0x0001; +/** If this bit is set one or more Control keys were held down. + * + * If this bit is set one or more Control keys were held down. + */ +enum GLFW_MOD_CONTROL = 0x0002; +/** If this bit is set one or more Alt keys were held down. + * + * If this bit is set one or more Alt keys were held down. + */ +enum GLFW_MOD_ALT = 0x0004; +/** If this bit is set one or more Super keys were held down. + * + * If this bit is set one or more Super keys were held down. + */ +enum GLFW_MOD_SUPER = 0x0008; +/** If this bit is set the Caps Lock key is enabled. + * + * If this bit is set the Caps Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +enum GLFW_MOD_CAPS_LOCK = 0x0010; +/** If this bit is set the Num Lock key is enabled. + * + * If this bit is set the Num Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +enum GLFW_MOD_NUM_LOCK = 0x0020; + +/** @} */ + +/** @defgroup buttons Mouse buttons + * Mouse button IDs. + * + * See [mouse button input](@ref input_mouse_button) for how these are used. + * + * Ingroup: input + * @{ */ +enum GLFW_MOUSE_BUTTON_1 = 0; +enum GLFW_MOUSE_BUTTON_2 = 1; +enum GLFW_MOUSE_BUTTON_3 = 2; +enum GLFW_MOUSE_BUTTON_4 = 3; +enum GLFW_MOUSE_BUTTON_5 = 4; +enum GLFW_MOUSE_BUTTON_6 = 5; +enum GLFW_MOUSE_BUTTON_7 = 6; +enum GLFW_MOUSE_BUTTON_8 = 7; +enum GLFW_MOUSE_BUTTON_LAST = GLFW_MOUSE_BUTTON_8; +enum GLFW_MOUSE_BUTTON_LEFT = GLFW_MOUSE_BUTTON_1; +enum GLFW_MOUSE_BUTTON_RIGHT = GLFW_MOUSE_BUTTON_2; +enum GLFW_MOUSE_BUTTON_MIDDLE = GLFW_MOUSE_BUTTON_3; +/** @} */ + +/** @defgroup joysticks Joysticks + * Joystick IDs. + * + * See [joystick input](@ref joystick) for how these are used. + * + * Ingroup: input + * @{ */ +enum GLFW_JOYSTICK_1 = 0; +enum GLFW_JOYSTICK_2 = 1; +enum GLFW_JOYSTICK_3 = 2; +enum GLFW_JOYSTICK_4 = 3; +enum GLFW_JOYSTICK_5 = 4; +enum GLFW_JOYSTICK_6 = 5; +enum GLFW_JOYSTICK_7 = 6; +enum GLFW_JOYSTICK_8 = 7; +enum GLFW_JOYSTICK_9 = 8; +enum GLFW_JOYSTICK_10 = 9; +enum GLFW_JOYSTICK_11 = 10; +enum GLFW_JOYSTICK_12 = 11; +enum GLFW_JOYSTICK_13 = 12; +enum GLFW_JOYSTICK_14 = 13; +enum GLFW_JOYSTICK_15 = 14; +enum GLFW_JOYSTICK_16 = 15; +enum GLFW_JOYSTICK_LAST = GLFW_JOYSTICK_16; +/** @} */ + +/** @defgroup gamepad_buttons Gamepad buttons + * Gamepad buttons. + * + * See @ref gamepad for how these are used. + * + * Ingroup: input + * @{ */ +enum GLFW_GAMEPAD_BUTTON_A = 0; +enum GLFW_GAMEPAD_BUTTON_B = 1; +enum GLFW_GAMEPAD_BUTTON_X = 2; +enum GLFW_GAMEPAD_BUTTON_Y = 3; +enum GLFW_GAMEPAD_BUTTON_LEFT_BUMPER = 4; +enum GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER = 5; +enum GLFW_GAMEPAD_BUTTON_BACK = 6; +enum GLFW_GAMEPAD_BUTTON_START = 7; +enum GLFW_GAMEPAD_BUTTON_GUIDE = 8; +enum GLFW_GAMEPAD_BUTTON_LEFT_THUMB = 9; +enum GLFW_GAMEPAD_BUTTON_RIGHT_THUMB = 10; +enum GLFW_GAMEPAD_BUTTON_DPAD_UP = 11; +enum GLFW_GAMEPAD_BUTTON_DPAD_RIGHT = 12; +enum GLFW_GAMEPAD_BUTTON_DPAD_DOWN = 13; +enum GLFW_GAMEPAD_BUTTON_DPAD_LEFT = 14; +enum GLFW_GAMEPAD_BUTTON_LAST = GLFW_GAMEPAD_BUTTON_DPAD_LEFT; + +enum GLFW_GAMEPAD_BUTTON_CROSS = GLFW_GAMEPAD_BUTTON_A; +enum GLFW_GAMEPAD_BUTTON_CIRCLE = GLFW_GAMEPAD_BUTTON_B; +enum GLFW_GAMEPAD_BUTTON_SQUARE = GLFW_GAMEPAD_BUTTON_X; +enum GLFW_GAMEPAD_BUTTON_TRIANGLE = GLFW_GAMEPAD_BUTTON_Y; +/** @} */ + +/** @defgroup gamepad_axes Gamepad axes + * Gamepad axes. + * + * See @ref gamepad for how these are used. + * + * Ingroup: input + * @{ */ +enum GLFW_GAMEPAD_AXIS_LEFT_X = 0; +enum GLFW_GAMEPAD_AXIS_LEFT_Y = 1; +enum GLFW_GAMEPAD_AXIS_RIGHT_X = 2; +enum GLFW_GAMEPAD_AXIS_RIGHT_Y = 3; +enum GLFW_GAMEPAD_AXIS_LEFT_TRIGGER = 4; +enum GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER = 5; +enum GLFW_GAMEPAD_AXIS_LAST = GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER; +/** @} */ + +/** @defgroup errors Error codes + * Error codes. + * + * See [error handling](@ref error_handling) for how these are used. + * + * Ingroup: init + * @{ */ +/** No error has occurred. + * + * No error has occurred. + * + * @analysis Yay. + */ +enum GLFW_NO_ERROR = 0; +/** GLFW has not been initialized. + * + * This occurs if a GLFW function was called that must not be called unless the + * library is [initialized](@ref intro_init). + * + * @analysis Application programmer error. Initialize GLFW before calling any + * function that requires initialization. + */ +enum GLFW_NOT_INITIALIZED = 0x00010001; +/** No context is current for this thread. + * + * This occurs if a GLFW function was called that needs and operates on the + * current OpenGL or OpenGL ES context but no context is current on the calling + * thread. One such function is @ref glfwSwapInterval. + * + * @analysis Application programmer error. Ensure a context is current before + * calling functions that require a current context. + */ +enum GLFW_NO_CURRENT_CONTEXT = 0x00010002; +/** One of the arguments to the function was an invalid enum value. + * + * One of the arguments to the function was an invalid enum value, for example + * requesting @ref GLFW_RED_BITS with @ref glfwGetWindowAttrib. + * + * @analysis Application programmer error. Fix the offending call. + */ +enum GLFW_INVALID_ENUM = 0x00010003; +/** One of the arguments to the function was an invalid value. + * + * One of the arguments to the function was an invalid value, for example + * requesting a non-existent OpenGL or OpenGL ES version like 2.7. + * + * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead + * result in a @ref GLFW_VERSION_UNAVAILABLE error. + * + * @analysis Application programmer error. Fix the offending call. + */ +enum GLFW_INVALID_VALUE = 0x00010004; +/** A memory allocation failed. + * + * A memory allocation failed. + * + * @analysis A bug in GLFW or the underlying operating system. Report the bug + * to our [issue tracker](https://github.com/glfw/glfw/issues). + */ +enum GLFW_OUT_OF_MEMORY = 0x00010005; +/** GLFW could not find support for the requested API on the system. + * + * GLFW could not find support for the requested API on the system. + * + * @analysis The installed graphics driver does not support the requested + * API, or does not support it via the chosen context creation backend. + * Below are a few examples. + * + * @par + * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only + * supports OpenGL ES via EGL, while Nvidia and Intel only support it via + * a WGL or GLX extension. macOS does not provide OpenGL ES at all. The Mesa + * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary + * driver. Older graphics drivers do not support Vulkan. + */ +enum GLFW_API_UNAVAILABLE = 0x00010006; +/** The requested OpenGL or OpenGL ES version is not available. + * + * The requested OpenGL or OpenGL ES version (including any requested context + * or framebuffer hints) is not available on this machine. + * + * @analysis The machine does not support your requirements. If your + * application is sufficiently flexible, downgrade your requirements and try + * again. Otherwise, inform the user that their machine does not match your + * requirements. + * + * @par + * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 + * comes out before the 4.x series gets that far, also fail with this error and + * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions + * will exist. + */ +enum GLFW_VERSION_UNAVAILABLE = 0x00010007; +/** A platform-specific error occurred that does not match any of the + * more specific categories. + * + * A platform-specific error occurred that does not match any of the more + * specific categories. + * + * @analysis A bug or configuration error in GLFW, the underlying operating + * system or its drivers, or a lack of required resources. Report the issue to + * our [issue tracker](https://github.com/glfw/glfw/issues). + */ +enum GLFW_PLATFORM_ERROR = 0x00010008; +/** The requested format is not supported or available. + * + * If emitted during window creation, the requested pixel format is not + * supported. + * + * If emitted when querying the clipboard, the contents of the clipboard could + * not be converted to the requested format. + * + * @analysis If emitted during window creation, one or more + * [hard constraints](@ref window_hints_hard) did not match any of the + * available pixel formats. If your application is sufficiently flexible, + * downgrade your requirements and try again. Otherwise, inform the user that + * their machine does not match your requirements. + * + * @par + * If emitted when querying the clipboard, ignore the error or report it to + * the user, as appropriate. + */ +enum GLFW_FORMAT_UNAVAILABLE = 0x00010009; +/** The specified window does not have an OpenGL or OpenGL ES context. + * + * A window that does not have an OpenGL or OpenGL ES context was passed to + * a function that requires it to have one. + * + * @analysis Application programmer error. Fix the offending call. + */ +enum GLFW_NO_WINDOW_CONTEXT = 0x0001000A; +/** @} */ + +/** @addtogroup window + * @{ */ +/** Input focus window hint and attribute + * + * Input focus [window hint](@ref GLFW_FOCUSED_hint) or + * [window attribute](@ref GLFW_FOCUSED_attrib). + */ +enum GLFW_FOCUSED = 0x00020001; +/** Window iconification window attribute + * + * Window iconification [window attribute](@ref GLFW_ICONIFIED_attrib). + */ +enum GLFW_ICONIFIED = 0x00020002; +/** Window resize-ability window hint and attribute + * + * Window resize-ability [window hint](@ref GLFW_RESIZABLE_hint) and + * [window attribute](@ref GLFW_RESIZABLE_attrib). + */ +enum GLFW_RESIZABLE = 0x00020003; +/** Window visibility window hint and attribute + * + * Window visibility [window hint](@ref GLFW_VISIBLE_hint) and + * [window attribute](@ref GLFW_VISIBLE_attrib). + */ +enum GLFW_VISIBLE = 0x00020004; +/** Window decoration window hint and attribute + * + * Window decoration [window hint](@ref GLFW_DECORATED_hint) and + * [window attribute](@ref GLFW_DECORATED_attrib). + */ +enum GLFW_DECORATED = 0x00020005; +/** Window auto-iconification window hint and attribute + * + * Window auto-iconification [window hint](@ref GLFW_AUTO_ICONIFY_hint) and + * [window attribute](@ref GLFW_AUTO_ICONIFY_attrib). + */ +enum GLFW_AUTO_ICONIFY = 0x00020006; +/** Window decoration window hint and attribute + * + * Window decoration [window hint](@ref GLFW_FLOATING_hint) and + * [window attribute](@ref GLFW_FLOATING_attrib). + */ +enum GLFW_FLOATING = 0x00020007; +/** Window maximization window hint and attribute + * + * Window maximization [window hint](@ref GLFW_MAXIMIZED_hint) and + * [window attribute](@ref GLFW_MAXIMIZED_attrib). + */ +enum GLFW_MAXIMIZED = 0x00020008; +/** Cursor centering window hint + * + * Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint). + */ +enum GLFW_CENTER_CURSOR = 0x00020009; +/** Window framebuffer transparency hint and attribute + * + * Window framebuffer transparency + * [window hint](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) and + * [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib). + */ +enum GLFW_TRANSPARENT_FRAMEBUFFER = 0x0002000A; +/** Mouse cursor hover window attribute. + * + * Mouse cursor hover [window attribute](@ref GLFW_HOVERED_attrib). + */ +enum GLFW_HOVERED = 0x0002000B; +/** Input focus on calling show window hint and attribute + * + * Input focus [window hint](@ref GLFW_FOCUS_ON_SHOW_hint) or + * [window attribute](@ref GLFW_FOCUS_ON_SHOW_attrib). + */ +enum GLFW_FOCUS_ON_SHOW = 0x0002000C; + +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_RED_BITS). + */ +enum GLFW_RED_BITS = 0x00021001; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_GREEN_BITS). + */ +enum GLFW_GREEN_BITS = 0x00021002; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_BLUE_BITS). + */ +enum GLFW_BLUE_BITS = 0x00021003; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ALPHA_BITS). + */ +enum GLFW_ALPHA_BITS = 0x00021004; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_DEPTH_BITS). + */ +enum GLFW_DEPTH_BITS = 0x00021005; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_STENCIL_BITS). + */ +enum GLFW_STENCIL_BITS = 0x00021006; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_RED_BITS). + */ +enum GLFW_ACCUM_RED_BITS = 0x00021007; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_GREEN_BITS). + */ +enum GLFW_ACCUM_GREEN_BITS = 0x00021008; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_BLUE_BITS). + */ +enum GLFW_ACCUM_BLUE_BITS = 0x00021009; +/** Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_ALPHA_BITS). + */ +enum GLFW_ACCUM_ALPHA_BITS = 0x0002100A; +/** Framebuffer auxiliary buffer hint. + * + * Framebuffer auxiliary buffer [hint](@ref GLFW_AUX_BUFFERS). + */ +enum GLFW_AUX_BUFFERS = 0x0002100B; +/** OpenGL stereoscopic rendering hint. + * + * OpenGL stereoscopic rendering [hint](@ref GLFW_STEREO). + */ +enum GLFW_STEREO = 0x0002100C; +/** Framebuffer MSAA samples hint. + * + * Framebuffer MSAA samples [hint](@ref GLFW_SAMPLES). + */ +enum GLFW_SAMPLES = 0x0002100D; +/** Framebuffer sRGB hint. + * + * Framebuffer sRGB [hint](@ref GLFW_SRGB_CAPABLE). + */ +enum GLFW_SRGB_CAPABLE = 0x0002100E; +/** Monitor refresh rate hint. + * + * Monitor refresh rate [hint](@ref GLFW_REFRESH_RATE). + */ +enum GLFW_REFRESH_RATE = 0x0002100F; +/** Framebuffer double buffering hint. + * + * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER). + */ +enum GLFW_DOUBLEBUFFER = 0x00021010; + +/** Context client API hint and attribute. + * + * Context client API [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +enum GLFW_CLIENT_API = 0x00022001; +/** Context client API major version hint and attribute. + * + * Context client API major version [hint](@ref GLFW_CONTEXT_VERSION_MAJOR_hint) + * and [attribute](@ref GLFW_CONTEXT_VERSION_MAJOR_attrib). + */ +enum GLFW_CONTEXT_VERSION_MAJOR = 0x00022002; +/** Context client API minor version hint and attribute. + * + * Context client API minor version [hint](@ref GLFW_CONTEXT_VERSION_MINOR_hint) + * and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib). + */ +enum GLFW_CONTEXT_VERSION_MINOR = 0x00022003; +/** Context client API revision number hint and attribute. + * + * Context client API revision number + * [attribute](@ref GLFW_CONTEXT_REVISION_attrib). + */ +enum GLFW_CONTEXT_REVISION = 0x00022004; +/** Context robustness hint and attribute. + * + * Context client API revision number [hint](@ref GLFW_CONTEXT_ROBUSTNESS_hint) + * and [attribute](@ref GLFW_CONTEXT_ROBUSTNESS_attrib). + */ +enum GLFW_CONTEXT_ROBUSTNESS = 0x00022005; +/** OpenGL forward-compatibility hint and attribute. + * + * OpenGL forward-compatibility [hint](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) + * and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib). + */ +enum GLFW_OPENGL_FORWARD_COMPAT = 0x00022006; +/** OpenGL debug context hint and attribute. + * + * OpenGL debug context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and + * [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib). + */ +enum GLFW_OPENGL_DEBUG_CONTEXT = 0x00022007; +/** OpenGL profile hint and attribute. + * + * OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and + * [attribute](@ref GLFW_OPENGL_PROFILE_attrib). + */ +enum GLFW_OPENGL_PROFILE = 0x00022008; +/** Context flush-on-release hint and attribute. + * + * Context flush-on-release [hint](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) and + * [attribute](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_attrib). + */ +enum GLFW_CONTEXT_RELEASE_BEHAVIOR = 0x00022009; +/** Context error suppression hint and attribute. + * + * Context error suppression [hint](@ref GLFW_CONTEXT_NO_ERROR_hint) and + * [attribute](@ref GLFW_CONTEXT_NO_ERROR_attrib). + */ +enum GLFW_CONTEXT_NO_ERROR = 0x0002200A; +/** Context creation API hint and attribute. + * + * Context creation API [hint](@ref GLFW_CONTEXT_CREATION_API_hint) and + * [attribute](@ref GLFW_CONTEXT_CREATION_API_attrib). + */ +enum GLFW_CONTEXT_CREATION_API = 0x0002200B; +/** Window content area scaling window + * [window hint](@ref GLFW_SCALE_TO_MONITOR). + */ +enum GLFW_SCALE_TO_MONITOR = 0x0002200C; +/** macOS specific + * [window hint](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint). + */ +enum GLFW_COCOA_RETINA_FRAMEBUFFER = 0x00023001; +/** macOS specific + * [window hint](@ref GLFW_COCOA_FRAME_NAME_hint). + */ +enum GLFW_COCOA_FRAME_NAME = 0x00023002; +/** macOS specific + * [window hint](@ref GLFW_COCOA_GRAPHICS_SWITCHING_hint). + */ +enum GLFW_COCOA_GRAPHICS_SWITCHING = 0x00023003; +/** X11 specific + * [window hint](@ref GLFW_X11_CLASS_NAME_hint). + */ +enum GLFW_X11_CLASS_NAME = 0x00024001; +/** X11 specific + * [window hint](@ref GLFW_X11_CLASS_NAME_hint). + */ +enum GLFW_X11_INSTANCE_NAME = 0x00024002; +/** @} */ + +enum GLFW_NO_API = 0; +enum GLFW_OPENGL_API = 0x00030001; +enum GLFW_OPENGL_ES_API = 0x00030002; + +enum GLFW_NO_ROBUSTNESS = 0; +enum GLFW_NO_RESET_NOTIFICATION = 0x00031001; +enum GLFW_LOSE_CONTEXT_ON_RESET = 0x00031002; + +enum GLFW_OPENGL_ANY_PROFILE = 0; +enum GLFW_OPENGL_CORE_PROFILE = 0x00032001; +enum GLFW_OPENGL_COMPAT_PROFILE = 0x00032002; + +enum GLFW_CURSOR = 0x00033001; +enum GLFW_STICKY_KEYS = 0x00033002; +enum GLFW_STICKY_MOUSE_BUTTONS = 0x00033003; +enum GLFW_LOCK_KEY_MODS = 0x00033004; +enum GLFW_RAW_MOUSE_MOTION = 0x00033005; + +enum GLFW_CURSOR_NORMAL = 0x00034001; +enum GLFW_CURSOR_HIDDEN = 0x00034002; +enum GLFW_CURSOR_DISABLED = 0x00034003; + +enum GLFW_ANY_RELEASE_BEHAVIOR = 0; +enum GLFW_RELEASE_BEHAVIOR_FLUSH = 0x00035001; +enum GLFW_RELEASE_BEHAVIOR_NONE = 0x00035002; + +enum GLFW_NATIVE_CONTEXT_API = 0x00036001; +enum GLFW_EGL_CONTEXT_API = 0x00036002; +enum GLFW_OSMESA_CONTEXT_API = 0x00036003; + +/** @defgroup shapes Standard cursor shapes + * Standard system cursor shapes. + * + * See [standard cursor creation](@ref cursor_standard) for how these are used. + * + * Ingroup: input + * @{ */ + +/** The regular arrow cursor shape. + * + * The regular arrow cursor. + */ +enum GLFW_ARROW_CURSOR = 0x00036001; +/** The text input I-beam cursor shape. + * + * The text input I-beam cursor shape. + */ +enum GLFW_IBEAM_CURSOR = 0x00036002; +/** The crosshair shape. + * + * The crosshair shape. + */ +enum GLFW_CROSSHAIR_CURSOR = 0x00036003; +/** The hand shape. + * + * The hand shape. + */ +enum GLFW_HAND_CURSOR = 0x00036004; +/** The horizontal resize arrow shape. + * + * The horizontal resize arrow shape. + */ +enum GLFW_HRESIZE_CURSOR = 0x00036005; +/** The vertical resize arrow shape. + * + * The vertical resize arrow shape. + */ +enum GLFW_VRESIZE_CURSOR = 0x00036006; +/** @} */ + +enum GLFW_CONNECTED = 0x00040001; +enum GLFW_DISCONNECTED = 0x00040002; + +/** @addtogroup init + * @{ */ +/** Joystick hat buttons init hint. + * + * Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS). + */ +enum GLFW_JOYSTICK_HAT_BUTTONS = 0x00050001; +/** macOS specific init hint. + * + * macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint). + */ +enum GLFW_COCOA_CHDIR_RESOURCES = 0x00051001; +/** macOS specific init hint. + * + * macOS specific [init hint](@ref GLFW_COCOA_MENUBAR_hint). + */ +enum GLFW_COCOA_MENUBAR = 0x00051002; +/** @} */ + +enum GLFW_DONT_CARE = -1; + + +/************************************************************************* + * GLFW API types + *************************************************************************/ + +/** Client API function pointer type. + * + * Generic function pointer used for returning client API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref context_glext + * @sa @ref glfwGetProcAddress + * + * Since: Added in version 3.0. + * + * Ingroup: context + */ +alias void function() GLFWglproc; + +/** Vulkan API function pointer type. + * + * Generic function pointer used for returning Vulkan API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref vulkan_proc + * @sa @ref glfwGetInstanceProcAddress + * + * Since: Added in version 3.2. + * + * Ingroup: vulkan + */ +alias void function() GLFWvkproc; + +/** Opaque monitor object. + * + * Opaque monitor object. + * + * @see @ref monitor_object + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +struct GLFWmonitor; + +/** Opaque window object. + * + * Opaque window object. + * + * @see @ref window_object + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +struct GLFWwindow; + +/** Opaque cursor object. + * + * Opaque cursor object. + * + * @see @ref cursor_object + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +struct GLFWcursor; + +/** The function pointer type for error callbacks. + * + * This is the function pointer type for error callbacks. An error callback + * function has the following signature: + * ``` + * void callback_name(int error_code, const char* description) + * ``` + * + * Params: + * error_code = An [error code](@ref errors). Future releases may add + * more error codes. + * description = A UTF-8 encoded string describing the error. + * + * Pointer_lifetime: The error description string is valid until the callback + * function returns. + * + * @sa @ref error_handling + * @sa @ref glfwSetErrorCallback + * + * Since: Added in version 3.0. + * + * Ingroup: init + */ +alias void function(int, const(char)*) GLFWerrorfun; + +/** The function pointer type for window position callbacks. + * + * This is the function pointer type for window position callbacks. A window + * position callback function has the following signature: + * ``` + * void callback_name(GLFWwindow* window, int xpos, int ypos) + * ``` + * + * Params: + * window = The window that was moved. + * xpos = The new x-coordinate, in screen coordinates, of the + * upper-left corner of the content area of the window. + * ypos = The new y-coordinate, in screen coordinates, of the + * upper-left corner of the content area of the window. + * + * @sa @ref window_pos + * @sa @ref glfwSetWindowPosCallback + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +alias void function(GLFWwindow*, int, int) GLFWwindowposfun; + +/** The function pointer type for window size callbacks. + * + * This is the function pointer type for window size callbacks. A window size + * callback function has the following signature: + * ``` + * void callback_name(GLFWwindow* window, int width, int height) + * ``` + * + * Params: + * window = The window that was resized. + * width = The new width, in screen coordinates, of the window. + * height = The new height, in screen coordinates, of the window. + * + * @sa @ref window_size + * @sa @ref glfwSetWindowSizeCallback + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +alias void function(GLFWwindow*, int, int) GLFWwindowsizefun; + +/** The function pointer type for window close callbacks. + * + * This is the function pointer type for window close callbacks. A window + * close callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window) + * ``` + * + * Params: + * window = The window that the user attempted to close. + * + * @sa @ref window_close + * @sa @ref glfwSetWindowCloseCallback + * + * Since: Added in version 2.5. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +alias void function(GLFWwindow*) GLFWwindowclosefun; + +/** The function pointer type for window content refresh callbacks. + * + * This is the function pointer type for window content refresh callbacks. + * A window content refresh callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window); + * ``` + * + * Params: + * window = The window whose content needs to be refreshed. + * + * @sa @ref window_refresh + * @sa @ref glfwSetWindowRefreshCallback + * + * Since: Added in version 2.5. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +alias void function(GLFWwindow*) GLFWwindowrefreshfun; + +/** The function pointer type for window focus callbacks. + * + * This is the function pointer type for window focus callbacks. A window + * focus callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, int focused) + * ``` + * + * Params: + * window = The window that gained or lost input focus. + * focused = `GLFW_TRUE` if the window was given input focus, or + * `GLFW_FALSE` if it lost it. + * + * @sa @ref window_focus + * @sa @ref glfwSetWindowFocusCallback + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +alias void function(GLFWwindow*, int) GLFWwindowfocusfun; + +/** The function pointer type for window iconify callbacks. + * + * This is the function pointer type for window iconify callbacks. A window + * iconify callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, int iconified) + * ``` + * + * Params: + * window = The window that was iconified or restored. + * iconified = `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. + * + * @sa @ref window_iconify + * @sa @ref glfwSetWindowIconifyCallback + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +alias void function(GLFWwindow*, int) GLFWwindowiconifyfun; + +/** The function pointer type for window maximize callbacks. + * + * This is the function pointer type for window maximize callbacks. A window + * maximize callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, int maximized) + * ``` + * + * Params: + * window = The window that was maximized or restored. + * iconified = `GLFW_TRUE` if the window was maximized, or + * `GLFW_FALSE` if it was restored. + * + * @sa @ref window_maximize + * @sa glfwSetWindowMaximizeCallback + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +alias void function(GLFWwindow*, int) GLFWwindowmaximizefun; + +/** The function pointer type for framebuffer size callbacks. + * + * This is the function pointer type for framebuffer size callbacks. + * A framebuffer size callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, int width, int height) + * ``` + * + * Params: + * window = The window whose framebuffer was resized. + * width = The new width, in pixels, of the framebuffer. + * height = The new height, in pixels, of the framebuffer. + * + * @sa @ref window_fbsize + * @sa @ref glfwSetFramebufferSizeCallback + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +alias void function(GLFWwindow*, int, int) GLFWframebuffersizefun; + +/** The function pointer type for window content scale callbacks. + * + * This is the function pointer type for window content scale callbacks. + * A window content scale callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, float xscale, float yscale) + * ``` + * + * Params: + * window = The window whose content scale changed. + * xscale = The new x-axis content scale of the window. + * yscale = The new y-axis content scale of the window. + * + * @sa @ref window_scale + * @sa @ref glfwSetWindowContentScaleCallback + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +alias void function(GLFWwindow*, float, float) GLFWwindowcontentscalefun; + +/** The function pointer type for mouse button callbacks. + * + * This is the function pointer type for mouse button callback functions. + * A mouse button callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, int button, int action, int mods) + * ``` + * + * Params: + * window = The window that received the event. + * button = The [mouse button](@ref buttons) that was pressed or + * released. + * action = One of `GLFW_PRESS` or `GLFW_RELEASE`. Future releases + * may add more actions. + * mods = Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_mouse_button + * @sa @ref glfwSetMouseButtonCallback + * + * Since: Added in version 1.0. + * @glfw3 Added window handle and modifier mask parameters. + * + * Ingroup: input + */ +alias void function(GLFWwindow*, int, int, int) GLFWmousebuttonfun; + +/** The function pointer type for cursor position callbacks. + * + * This is the function pointer type for cursor position callbacks. A cursor + * position callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, double xpos, double ypos); + * ``` + * + * Params: + * window = The window that received the event. + * xpos = The new cursor x-coordinate, relative to the left edge of + * the content area. + * ypos = The new cursor y-coordinate, relative to the top edge of the + * content area. + * + * @sa @ref cursor_pos + * @sa @ref glfwSetCursorPosCallback + * + * Since: Added in version 3.0. Replaces `GLFWmouseposfun`. + * + * Ingroup: input + */ +alias void function(GLFWwindow*, double, double) GLFWcursorposfun; + +/** The function pointer type for cursor enter/leave callbacks. + * + * This is the function pointer type for cursor enter/leave callbacks. + * A cursor enter/leave callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, int entered) + * ``` + * + * Params: + * window = The window that received the event. + * entered = `GLFW_TRUE` if the cursor entered the window's content + * area, or `GLFW_FALSE` if it left it. + * + * @sa @ref cursor_enter + * @sa @ref glfwSetCursorEnterCallback + * + * Since: Added in version 3.0. + * + * Ingroup: input + */ +alias void function(GLFWwindow*, int) GLFWcursorenterfun; + +/** The function pointer type for scroll callbacks. + * + * This is the function pointer type for scroll callbacks. A scroll callback + * function has the following signature: + * ``` + * void function_name(GLFWwindow* window, double xoffset, double yoffset) + * ``` + * + * Params: + * window = The window that received the event. + * xoffset = The scroll offset along the x-axis. + * yoffset = The scroll offset along the y-axis. + * + * @sa @ref scrolling + * @sa @ref glfwSetScrollCallback + * + * Since: Added in version 3.0. Replaces `GLFWmousewheelfun`. + * + * Ingroup: input + */ +alias void function(GLFWwindow*, double, double) GLFWscrollfun; + +/** The function pointer type for keyboard key callbacks. + * + * This is the function pointer type for keyboard key callbacks. A keyboard + * key callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, int key, int scancode, int action, int mods) + * ``` + * + * Params: + * window = The window that received the event. + * key = The [keyboard key](@ref keys) that was pressed or released. + * scancode = The system-specific scancode of the key. + * action = `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. Future + * releases may add more actions. + * mods = Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_key + * @sa @ref glfwSetKeyCallback + * + * Since: Added in version 1.0. + * @glfw3 Added window handle, scancode and modifier mask parameters. + * + * Ingroup: input + */ +alias void function(GLFWwindow*, int, int, int, int) GLFWkeyfun; + +/** The function pointer type for Unicode character callbacks. + * + * This is the function pointer type for Unicode character callbacks. + * A Unicode character callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, unsigned int codepoint) + * ``` + * + * Params: + * window = The window that received the event. + * codepoint = The Unicode code point of the character. + * + * @sa @ref input_char + * @sa @ref glfwSetCharCallback + * + * Since: Added in version 2.4. + * @glfw3 Added window handle parameter. + * + * Ingroup: input + */ +alias void function(GLFWwindow*, uint) GLFWcharfun; + +/** The function pointer type for Unicode character with modifiers + * callbacks. + * + * This is the function pointer type for Unicode character with modifiers + * callbacks. It is called for each input character, regardless of what + * modifier keys are held down. A Unicode character with modifiers callback + * function has the following signature: + * ``` + * void function_name(GLFWwindow* window, unsigned int codepoint, int mods) + * ``` + * + * Params: + * window = The window that received the event. + * codepoint = The Unicode code point of the character. + * mods = Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_char + * @sa @ref glfwSetCharModsCallback + * + * @deprecated Scheduled for removal in version 4.0. + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +alias void function(GLFWwindow*, uint, int) GLFWcharmodsfun; + +/** The function pointer type for path drop callbacks. + * + * This is the function pointer type for path drop callbacks. A path drop + * callback function has the following signature: + * ``` + * void function_name(GLFWwindow* window, int path_count, const char* paths[]) + * ``` + * + * Params: + * window = The window that received the event. + * path_count = The number of dropped paths. + * paths = The UTF-8 encoded file and/or directory path names. + * + * Pointer_lifetime: The path array and its strings are valid until the + * callback function returns. + * + * @sa @ref path_drop + * @sa @ref glfwSetDropCallback + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +alias void function(GLFWwindow*, int, const(char)**) GLFWdropfun; + +/** The function pointer type for monitor configuration callbacks. + * + * This is the function pointer type for monitor configuration callbacks. + * A monitor callback function has the following signature: + * ``` + * void function_name(GLFWmonitor* monitor, int event) + * ``` + * + * Params: + * monitor = The monitor that was connected or disconnected. + * event = One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Future + * releases may add more events. + * + * @sa @ref monitor_event + * @sa @ref glfwSetMonitorCallback + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +alias void function(GLFWmonitor*, int) GLFWmonitorfun; + +/** The function pointer type for joystick configuration callbacks. + * + * This is the function pointer type for joystick configuration callbacks. + * A joystick configuration callback function has the following signature: + * ``` + * void function_name(int jid, int event) + * ``` + * + * Params: + * jid = The joystick that was connected or disconnected. + * event = One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Future + * releases may add more events. + * + * @sa @ref joystick_event + * @sa @ref glfwSetJoystickCallback + * + * Since: Added in version 3.2. + * + * Ingroup: input + */ +alias void function(int, int) GLFWjoystickfun; + +/** Video mode type. + * + * This describes a single video mode. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoMode + * @sa @ref glfwGetVideoModes + * + * Since: Added in version 1.0. + * @glfw3 Added refresh rate member. + * + * Ingroup: monitor + */ +struct GLFWvidmode { + /** The width, in screen coordinates, of the video mode. + */ + int width; + /** The height, in screen coordinates, of the video mode. + */ + int height; + /** The bit depth of the red channel of the video mode. + */ + int redBits; + /** The bit depth of the green channel of the video mode. + */ + int greenBits; + /** The bit depth of the blue channel of the video mode. + */ + int blueBits; + /** The refresh rate, in Hz, of the video mode. + */ + int refreshRate; +}/+alias GLFWvidmode GLFWvidmode;+/ + +/** Gamma ramp. + * + * This describes the gamma ramp for a monitor. + * + * @sa @ref monitor_gamma + * @sa @ref glfwGetGammaRamp + * @sa @ref glfwSetGammaRamp + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +struct GLFWgammaramp { + /** An array of value describing the response of the red channel. + */ + ushort* red; + /** An array of value describing the response of the green channel. + */ + ushort* green; + /** An array of value describing the response of the blue channel. + */ + ushort* blue; + /** The number of elements in each array. + */ + uint size; +}/+alias GLFWgammaramp GLFWgammaramp;+/ + +/** Image data. + * + * This describes a single 2D image. See the documentation for each related + * function what the expected pixel format is. + * + * @sa @ref cursor_custom + * @sa @ref window_icon + * + * Since: Added in version 2.1. + * @glfw3 Removed format and bytes-per-pixel members. + * + * Ingroup: window + */ +struct GLFWimage { + /** The width, in pixels, of this image. + */ + int width; + /** The height, in pixels, of this image. + */ + int height; + /** The pixel data of this image, arranged left-to-right, top-to-bottom. + */ + ubyte* pixels; +}/+alias GLFWimage GLFWimage;+/ + +/** Gamepad input state + * + * This describes the input state of a gamepad. + * + * @sa @ref gamepad + * @sa @ref glfwGetGamepadState + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +struct GLFWgamepadstate { + /** The states of each [gamepad button](@ref gamepad_buttons), `GLFW_PRESS` + * or `GLFW_RELEASE`. + */ + ubyte[15] buttons; + /** The states of each [gamepad axis](@ref gamepad_axes), in the range -1.0 + * to 1.0 inclusive. + */ + float[6] axes; +}/+alias GLFWgamepadstate GLFWgamepadstate;+/ + + +/************************************************************************* + * GLFW API functions + *************************************************************************/ + +/** Initializes the GLFW library. + * + * This function initializes the GLFW library. Before most GLFW functions can + * be used, GLFW must be initialized, and before an application terminates GLFW + * should be terminated in order to free any resources allocated during or + * after initialization. + * + * If this function fails, it calls @ref glfwTerminate before returning. If it + * succeeds, you should call @ref glfwTerminate before the application exits. + * + * Additional calls to this function after successful initialization but before + * termination will return `GLFW_TRUE` immediately. + * + * Returns: `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark @macos This function will change the current directory of the + * application to the `Contents/Resources` subdirectory of the application's + * bundle, if present. This can be disabled with the @ref + * GLFW_COCOA_CHDIR_RESOURCES init hint. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref intro_init + * @sa @ref glfwTerminate + * + * Since: Added in version 1.0. + * + * Ingroup: init + */ +int glfwInit(); + +/** Terminates the GLFW library. + * + * This function destroys all remaining windows and cursors, restores any + * modified gamma ramps and frees any other allocated resources. Once this + * function is called, you must again call @ref glfwInit successfully before + * you will be able to use most GLFW functions. + * + * If GLFW has been successfully initialized, this function should be called + * before the application exits. If initialization fails, there is no need to + * call this function, as it is called by @ref glfwInit before it returns + * failure. + * + * Errors: Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark This function may be called before @ref glfwInit. + * + * @warning The contexts of any remaining windows must not be current on any + * other thread when this function is called. + * + * @reentrancy This function must not be called from a callback. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref intro_init + * @sa @ref glfwInit + * + * Since: Added in version 1.0. + * + * Ingroup: init + */ +void glfwTerminate(); + +/** Sets the specified init hint to the desired value. + * + * This function sets hints for the next initialization of GLFW. + * + * The values you set hints to are never reset by GLFW, but they only take + * effect during initialization. Once GLFW has been initialized, any values + * you set will be ignored until the library is terminated and initialized + * again. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * Params: + * hint = The [init hint](@ref init_hints) to set. + * value = The new value of the init hint. + * + * Errors: Possible errors include @ref GLFW_INVALID_ENUM and @ref + * GLFW_INVALID_VALUE. + * + * @remarks This function may be called before @ref glfwInit. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa init_hints + * @sa glfwInit + * + * Since: Added in version 3.3. + * + * Ingroup: init + */ +void glfwInitHint(int hint, int value); + +/** Retrieves the version of the GLFW library. + * + * This function retrieves the major, minor and revision numbers of the GLFW + * library. It is intended for when you are using GLFW as a shared library and + * want to ensure that you are using the minimum required version. + * + * Any or all of the version arguments may be `null`. + * + * Params: + * major = Where to store the major version number, or `null`. + * minor = Where to store the minor version number, or `null`. + * rev = Where to store the revision number, or `null`. + * + * Errors: None. + * + * @remark This function may be called before @ref glfwInit. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref intro_version + * @sa @ref glfwGetVersionString + * + * Since: Added in version 1.0. + * + * Ingroup: init + */ +void glfwGetVersion(int* major, int* minor, int* rev); + +/** Returns a string describing the compile-time configuration. + * + * This function returns the compile-time generated + * [version string](@ref intro_version_string) of the GLFW library binary. It + * describes the version, platform, compiler and any platform-specific + * compile-time options. It should not be confused with the OpenGL or OpenGL + * ES version string, queried with `glGetString`. + * + * __Do not use the version string__ to parse the GLFW library version. The + * @ref glfwGetVersion function provides the version of the running library + * binary in numerical format. + * + * Returns: The ASCII encoded GLFW version string. + * + * Errors: None. + * + * @remark This function may be called before @ref glfwInit. + * + * Pointer_lifetime: The returned string is static and compile-time generated. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref intro_version + * @sa @ref glfwGetVersion + * + * Since: Added in version 3.0. + * + * Ingroup: init + */ +const(char)* glfwGetVersionString(); + +/** Returns and clears the last error for the calling thread. + * + * This function returns and clears the [error code](@ref errors) of the last + * error that occurred on the calling thread, and optionally a UTF-8 encoded + * human-readable description of it. If no error has occurred since the last + * call, it returns @ref GLFW_NO_ERROR (zero) and the description pointer is + * set to `null`. + * + * Params: + * description = Where to store the error description pointer, or `null`. + * Returns: The last error code for the calling thread, or @ref GLFW_NO_ERROR + * (zero). + * + * Errors: None. + * + * Pointer_lifetime: The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * next error occurs or the library is terminated. + * + * @remark This function may be called before @ref glfwInit. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref error_handling + * @sa @ref glfwSetErrorCallback + * + * Since: Added in version 3.3. + * + * Ingroup: init + */ +int glfwGetError(const(char)** description); + +/** Sets the error callback. + * + * This function sets the error callback, which is called with an error code + * and a human-readable description each time a GLFW error occurs. + * + * The error code is set before the callback is called. Calling @ref + * glfwGetError from the error callback will return the same value as the error + * code argument. + * + * The error callback is called on the thread where the error occurred. If you + * are using GLFW from multiple threads, your error callback needs to be + * written accordingly. + * + * Because the description string may have been generated specifically for that + * error, it is not guaranteed to be valid after the callback has returned. If + * you wish to use it after the callback returns, you need to make a copy. + * + * Once set, the error callback remains set even after the library has been + * terminated. + * + * Params: + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set. + * + * @callback_signature + * ``` + * void callback_name(int error_code, const char* description) + * ``` + * For more information about the callback parameters, see the + * [callback pointer type](@ref GLFWerrorfun). + * + * Errors: None. + * + * @remark This function may be called before @ref glfwInit. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref error_handling + * @sa @ref glfwGetError + * + * Since: Added in version 3.0. + * + * Ingroup: init + */ +GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun callback); + +/** Returns the currently connected monitors. + * + * This function returns an array of handles for all currently connected + * monitors. The primary monitor is always first in the returned array. If no + * monitors were found, this function returns `null`. + * + * Params: + * count = Where to store the number of monitors in the returned + * array. This is set to zero if an error occurred. + * Returns: An array of monitor handles, or `null` if no monitors were found or + * if an [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Pointer_lifetime: The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * monitor configuration changes or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_monitors + * @sa @ref monitor_event + * @sa @ref glfwGetPrimaryMonitor + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +GLFWmonitor** glfwGetMonitors(int* count); + +/** Returns the primary monitor. + * + * This function returns the primary monitor. This is usually the monitor + * where elements like the task bar or global menu bar are located. + * + * Returns: The primary monitor, or `null` if no monitors were found or if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @remark The primary monitor is always first in the array returned by @ref + * glfwGetMonitors. + * + * @sa @ref monitor_monitors + * @sa @ref glfwGetMonitors + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +GLFWmonitor* glfwGetPrimaryMonitor(); + +/** Returns the position of the monitor's viewport on the virtual screen. + * + * This function returns the position, in screen coordinates, of the upper-left + * corner of the specified monitor. + * + * Any or all of the position arguments may be `null`. If an error occurs, all + * non-`null` position arguments will be set to zero. + * + * Params: + * monitor = The monitor to query. + * xpos = Where to store the monitor x-coordinate, or `null`. + * ypos = Where to store the monitor y-coordinate, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); + +/** Retrieves the work area of the monitor. + * + * This function returns the position, in screen coordinates, of the upper-left + * corner of the work area of the specified monitor along with the work area + * size in screen coordinates. The work area is defined as the area of the + * monitor not occluded by the operating system task bar where present. If no + * task bar exists then the work area is the monitor resolution in screen + * coordinates. + * + * Any or all of the position and size arguments may be `null`. If an error + * occurs, all non-`null` position and size arguments will be set to zero. + * + * Params: + * monitor = The monitor to query. + * xpos = Where to store the monitor x-coordinate, or `null`. + * ypos = Where to store the monitor y-coordinate, or `null`. + * width = Where to store the monitor width, or `null`. + * height = Where to store the monitor height, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_workarea + * + * Since: Added in version 3.3. + * + * Ingroup: monitor + */ +void glfwGetMonitorWorkarea(GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); + +/** Returns the physical size of the monitor. + * + * This function returns the size, in millimetres, of the display area of the + * specified monitor. + * + * Some systems do not provide accurate monitor size information, either + * because the monitor + * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) + * data is incorrect or because the driver does not report it accurately. + * + * Any or all of the size arguments may be `null`. If an error occurs, all + * non-`null` size arguments will be set to zero. + * + * Params: + * monitor = The monitor to query. + * widthMM = Where to store the width, in millimetres, of the + * monitor's display area, or `null`. + * heightMM = Where to store the height, in millimetres, of the + * monitor's display area, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @win32 calculates the returned physical size from the + * current resolution and system DPI instead of querying the monitor EDID data. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); + +/** Retrieves the content scale for the specified monitor. + * + * This function retrieves the content scale for the specified monitor. The + * content scale is the ratio between the current DPI and the platform's + * default DPI. This is especially important for text and any UI elements. If + * the pixel dimensions of your UI scaled by this look appropriate on your + * machine then it should appear at a reasonable size on other machines + * regardless of their DPI and scaling settings. This relies on the system DPI + * and scaling settings being somewhat correct. + * + * The content scale may depend on both the monitor resolution and pixel + * density and on user settings. It may be very different from the raw DPI + * calculated from the physical size and current resolution. + * + * Params: + * monitor = The monitor to query. + * xscale = Where to store the x-axis content scale, or `null`. + * yscale = Where to store the y-axis content scale, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_scale + * @sa @ref glfwGetWindowContentScale + * + * Since: Added in version 3.3. + * + * Ingroup: monitor + */ +void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, float* yscale); + +/** Returns the name of the specified monitor. + * + * This function returns a human-readable name, encoded as UTF-8, of the + * specified monitor. The name typically reflects the make and model of the + * monitor and is not guaranteed to be unique among the connected monitors. + * + * Params: + * monitor = The monitor to query. + * Returns: The UTF-8 encoded name of the monitor, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Pointer_lifetime: The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +const(char)* glfwGetMonitorName(GLFWmonitor* monitor); + +/** Sets the user pointer of the specified monitor. + * + * This function sets the user-defined pointer of the specified monitor. The + * current value is retained until the monitor is disconnected. The initial + * value is `null`. + * + * This function may be called from the monitor callback, even for a monitor + * that is being disconnected. + * + * Params: + * monitor = The monitor whose pointer to set. + * pointer = The new value. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref monitor_userptr + * @sa @ref glfwGetMonitorUserPointer + * + * Since: Added in version 3.3. + * + * Ingroup: monitor + */ +void glfwSetMonitorUserPointer(GLFWmonitor* monitor, void* pointer); + +/** Returns the user pointer of the specified monitor. + * + * This function returns the current value of the user-defined pointer of the + * specified monitor. The initial value is `null`. + * + * This function may be called from the monitor callback, even for a monitor + * that is being disconnected. + * + * Params: + * monitor = The monitor whose pointer to return. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref monitor_userptr + * @sa @ref glfwSetMonitorUserPointer + * + * Since: Added in version 3.3. + * + * Ingroup: monitor + */ +void* glfwGetMonitorUserPointer(GLFWmonitor* monitor); + +/** Sets the monitor configuration callback. + * + * This function sets the monitor configuration callback, or removes the + * currently set callback. This is called when a monitor is connected to or + * disconnected from the system. + * + * Params: + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWmonitor* monitor, int event) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWmonitorfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_event + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun callback); + +/** Returns the available video modes for the specified monitor. + * + * This function returns an array of all video modes supported by the specified + * monitor. The returned array is sorted in ascending order, first by color + * bit depth (the sum of all channel depths) and then by resolution area (the + * product of width and height). + * + * Params: + * monitor = The monitor to query. + * count = Where to store the number of video modes in the returned + * array. This is set to zero if an error occurred. + * Returns: An array of video modes, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected, this function is called again for that monitor or the library + * is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoMode + * + * Since: Added in version 1.0. + * @glfw3 Changed to return an array of modes for a specific monitor. + * + * Ingroup: monitor + */ +const(GLFWvidmode)* glfwGetVideoModes(GLFWmonitor* monitor, int* count); + +/** Returns the current mode of the specified monitor. + * + * This function returns the current video mode of the specified monitor. If + * you have created a full screen window for that monitor, the return value + * will depend on whether that window is iconified. + * + * Params: + * monitor = The monitor to query. + * Returns: The current mode of the monitor, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoModes + * + * Since: Added in version 3.0. Replaces `glfwGetDesktopMode`. + * + * Ingroup: monitor + */ +const(GLFWvidmode)* glfwGetVideoMode(GLFWmonitor* monitor); + +/** Generates a gamma ramp and sets it for the specified monitor. + * + * This function generates an appropriately sized gamma ramp from the specified + * exponent and then calls @ref glfwSetGammaRamp with it. The value must be + * a finite number greater than zero. + * + * The software controlled gamma ramp is applied _in addition_ to the hardware + * gamma correction, which today is usually an approximation of sRGB gamma. + * This means that setting a perfectly linear ramp, or gamma 1.0, will produce + * the default (usually sRGB-like) behavior. + * + * For gamma correct rendering with OpenGL or OpenGL ES, see the @ref + * GLFW_SRGB_CAPABLE hint. + * + * Params: + * monitor = The monitor whose gamma ramp to set. + * gamma = The desired exponent. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark @wayland Gamma handling is a privileged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +void glfwSetGamma(GLFWmonitor* monitor, float gamma); + +/** Returns the current gamma ramp for the specified monitor. + * + * This function returns the current gamma ramp of the specified monitor. + * + * Params: + * monitor = The monitor to query. + * Returns: The current gamma ramp, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland Gamma handling is a privileged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while + * returning `null`. + * + * Pointer_lifetime: The returned structure and its arrays are allocated and + * freed by GLFW. You should not free them yourself. They are valid until the + * specified monitor is disconnected, this function is called again for that + * monitor or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +const(GLFWgammaramp)* glfwGetGammaRamp(GLFWmonitor* monitor); + +/** Sets the current gamma ramp for the specified monitor. + * + * This function sets the current gamma ramp for the specified monitor. The + * original gamma ramp for that monitor is saved by GLFW the first time this + * function is called and is restored by @ref glfwTerminate. + * + * The software controlled gamma ramp is applied _in addition_ to the hardware + * gamma correction, which today is usually an approximation of sRGB gamma. + * This means that setting a perfectly linear ramp, or gamma 1.0, will produce + * the default (usually sRGB-like) behavior. + * + * For gamma correct rendering with OpenGL or OpenGL ES, see the @ref + * GLFW_SRGB_CAPABLE hint. + * + * Params: + * monitor = The monitor whose gamma ramp to set. + * ramp = The gamma ramp to use. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark The size of the specified gamma ramp should match the size of the + * current ramp for that monitor. + * + * @remark @win32 The gamma ramp size must be 256. + * + * @remark @wayland Gamma handling is a privileged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The specified gamma ramp is copied before this function + * returns. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * Since: Added in version 3.0. + * + * Ingroup: monitor + */ +void glfwSetGammaRamp(GLFWmonitor* monitor, const(GLFWgammaramp)* ramp); + +/** Resets all window hints to their default values. + * + * This function resets all window hints to their + * [default values](@ref window_hints_values). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa @ref glfwWindowHint + * @sa @ref glfwWindowHintString + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +void glfwDefaultWindowHints(); + +/** Sets the specified window hint to the desired value. + * + * This function sets hints for the next call to @ref glfwCreateWindow. The + * hints, once set, retain their values until changed by a call to this + * function or @ref glfwDefaultWindowHints, or until the library is terminated. + * + * Only integer value hints can be set with this function. String value hints + * are set with @ref glfwWindowHintString. + * + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * Params: + * hint = The [window hint](@ref window_hints) to set. + * value = The new value of the window hint. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa @ref glfwWindowHintString + * @sa @ref glfwDefaultWindowHints + * + * Since: Added in version 3.0. Replaces `glfwOpenWindowHint`. + * + * Ingroup: window + */ +void glfwWindowHint(int hint, int value); + +/** Sets the specified window hint to the desired value. + * + * This function sets hints for the next call to @ref glfwCreateWindow. The + * hints, once set, retain their values until changed by a call to this + * function or @ref glfwDefaultWindowHints, or until the library is terminated. + * + * Only string type hints can be set with this function. Integer value hints + * are set with @ref glfwWindowHint. + * + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * Params: + * hint = The [window hint](@ref window_hints) to set. + * value = The new value of the window hint. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * Pointer_lifetime: The specified string is copied before this function + * returns. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa @ref glfwWindowHint + * @sa @ref glfwDefaultWindowHints + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +void glfwWindowHintString(int hint, const(char)* value); + +/** Creates a window and its associated context. + * + * This function creates a window and its associated OpenGL or OpenGL ES + * context. Most of the options controlling how the window and its context + * should be created are specified with [window hints](@ref window_hints). + * + * Successful creation does not change which context is current. Before you + * can use the newly created context, you need to + * [make it current](@ref context_current). For information about the `share` + * parameter, see @ref context_sharing. + * + * The created window, framebuffer and context may differ from what you + * requested, as not all parameters and hints are + * [hard constraints](@ref window_hints_hard). This includes the size of the + * window, especially for full screen windows. To query the actual attributes + * of the created window, framebuffer and context, see @ref + * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. + * + * To create a full screen window, you need to specify the monitor the window + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. + * + * For full screen windows, the specified size becomes the resolution of the + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. + * + * Once you have created the window, you can switch it between windowed and + * full screen mode with @ref glfwSetWindowMonitor. This will not affect its + * OpenGL or OpenGL ES context. + * + * By default, newly created windows use the placement recommended by the + * window system. To create the window at a specific position, make it + * initially invisible using the [GLFW_VISIBLE](@ref GLFW_VISIBLE_hint) window + * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) + * it. + * + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. + * + * Window systems put limits on window sizes. Very large or very small window + * dimensions may be overridden by the window system on creation. Check the + * actual [size](@ref window_size) after creation. + * + * The [swap interval](@ref buffer_swap) is not set during window creation and + * the initial value may vary depending on driver settings and defaults. + * + * Params: + * width = The desired width, in screen coordinates, of the window. + * This must be greater than zero. + * height = The desired height, in screen coordinates, of the window. + * This must be greater than zero. + * title = The initial, UTF-8 encoded window title. + * monitor = The monitor to use for full screen mode, or `null` for + * windowed mode. + * share = The window whose context to share resources with, or `null` + * to not share resources. + * Returns: The handle of the created window, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @win32 Window creation will fail if the Microsoft GDI software + * OpenGL implementation is the only one available. + * + * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it + * will be set as the initial icon for the window. If no such icon is present, + * the `IDI_APPLICATION` icon will be used instead. To set a different icon, + * see @ref glfwSetWindowIcon. + * + * @remark @win32 The context to share resources with must not be current on + * any other thread. + * + * @remark @macos The OS only supports forward-compatible core profile contexts + * for OpenGL versions 3.2 and later. Before creating an OpenGL context of + * version 3.2 or later you must set the + * [GLFW_OPENGL_FORWARD_COMPAT](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) and + * [GLFW_OPENGL_PROFILE](@ref GLFW_OPENGL_PROFILE_hint) hints accordingly. + * OpenGL 3.0 and 3.1 contexts are not supported at all on macOS. + * + * @remark @macos The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remark @macos The first time a window is created the menu bar is created. + * If GLFW finds a `MainMenu.nib` it is loaded and assumed to contain a menu + * bar. Otherwise a minimal menu bar is created manually with common commands + * like Hide, Quit and About. The About entry opens a minimal about dialog + * with information from the application's bundle. Menu bar creation can be + * disabled entirely with the @ref GLFW_COCOA_MENUBAR init hint. + * + * @remark @macos On OS X 10.10 and later the window frame will not be rendered + * at full resolution on Retina displays unless the + * [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint) + * hint is `GLFW_TRUE` and the `NSHighResolutionCapable` key is enabled in the + * application bundle's `Info.plist`. For more information, see + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. The GLFW test and example programs use + * a custom `Info.plist` template for this, which can be found as + * `CMake/MacOSXBundleInfo.plist.in` in the source tree. + * + * @remark @macos When activating frame autosaving with + * [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified + * window size and position may be overridden by previously saved values. + * + * @remark @x11 Some window managers will not respect the placement of + * initially hidden windows. + * + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * a window to reach its requested state. This means you may not be able to + * query the final size, position or other attributes directly after window + * creation. + * + * @remark @x11 The class part of the `WM_CLASS` window property will by + * default be set to the window title passed to this function. The instance + * part will use the contents of the `RESOURCE_NAME` environment variable, if + * present and not empty, or fall back to the window title. Set the + * [GLFW_X11_CLASS_NAME](@ref GLFW_X11_CLASS_NAME_hint) and + * [GLFW_X11_INSTANCE_NAME](@ref GLFW_X11_INSTANCE_NAME_hint) window hints to + * override this. + * + * @remark @wayland Compositors should implement the xdg-decoration protocol + * for GLFW to decorate the window properly. If this protocol isn't + * supported, or if the compositor prefers client-side decorations, a very + * simple fallback frame will be drawn using the wp_viewporter protocol. A + * compositor can still emit close, maximize or fullscreen events, using for + * instance a keybind mechanism. If neither of these protocols is supported, + * the window won't be decorated. + * + * @remark @wayland A full screen window will not attempt to change the mode, + * no matter what the requested size or refresh rate. + * + * @remark @wayland Screensaver inhibition requires the idle-inhibit protocol + * to be implemented in the user's compositor. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_creation + * @sa @ref glfwDestroyWindow + * + * Since: Added in version 3.0. Replaces `glfwOpenWindow`. + * + * Ingroup: window + */ +GLFWwindow* glfwCreateWindow(int width, int height, const(char)* title, GLFWmonitor* monitor, GLFWwindow* share); + +/** Destroys the specified window and its context. + * + * This function destroys the specified window and its context. On calling + * this function, no further callbacks will be called for that window. + * + * If the context of the specified window is current on the main thread, it is + * detached before being destroyed. + * + * Params: + * window = The window to destroy. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @note The context of the specified window must not be current on any other + * thread when this function is called. + * + * @reentrancy This function must not be called from a callback. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_creation + * @sa @ref glfwCreateWindow + * + * Since: Added in version 3.0. Replaces `glfwCloseWindow`. + * + * Ingroup: window + */ +void glfwDestroyWindow(GLFWwindow* window); + +/** Checks the close flag of the specified window. + * + * This function returns the value of the close flag of the specified window. + * + * Params: + * window = The window to query. + * Returns: The value of the close flag. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +int glfwWindowShouldClose(GLFWwindow* window); + +/** Sets the close flag of the specified window. + * + * This function sets the value of the close flag of the specified window. + * This can be used to override the user's attempt to close the window, or + * to signal that it should be closed. + * + * Params: + * window = The window whose flag to change. + * value = The new value. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +void glfwSetWindowShouldClose(GLFWwindow* window, int value); + +/** Sets the title of the specified window. + * + * This function sets the window title, encoded as UTF-8, of the specified + * window. + * + * Params: + * window = The window whose title to change. + * title = The UTF-8 encoded window title. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos The window title will not be updated until the next time you + * process events. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_title + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +void glfwSetWindowTitle(GLFWwindow* window, const(char)* title); + +/** Sets the icon for the specified window. + * + * This function sets the icon of the specified window. If passed an array of + * candidate images, those of or closest to the sizes desired by the system are + * selected. If no images are specified, the window reverts to its default + * icon. + * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel with the red channel first. They are arranged canonically + * as packed sequential rows, starting from the top-left corner. + * + * The desired image sizes varies depending on platform and system settings. + * The selected images will be rescaled as needed. Good sizes include 16x16, + * 32x32 and 48x48. + * + * Params: + * window = The window whose icon to set. + * count = The number of images in the specified array, or zero to + * revert to the default window icon. + * images = The images to create the icon from. This is ignored if + * count is zero. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The specified image data is copied before this function + * returns. + * + * @remark @macos The GLFW window has no icon, as it is not a document + * window, so this function does nothing. The dock icon will be the same as + * the application bundle's icon. For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remark @wayland There is no existing protocol to change an icon, the + * window will thus inherit the one defined in the application's desktop file. + * This function always emits @ref GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_icon + * + * Since: Added in version 3.2. + * + * Ingroup: window + */ +void glfwSetWindowIcon(GLFWwindow* window, int count, const(GLFWimage)* images); + +/** Retrieves the position of the content area of the specified window. + * + * This function retrieves the position, in screen coordinates, of the + * upper-left corner of the content area of the specified window. + * + * Any or all of the position arguments may be `null`. If an error occurs, all + * non-`null` position arguments will be set to zero. + * + * Params: + * window = The window to query. + * xpos = Where to store the x-coordinate of the upper-left corner of + * the content area, or `null`. + * ypos = Where to store the y-coordinate of the upper-left corner of + * the content area, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no way for an application to retrieve the global + * position of its windows, this function will always emit @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_pos + * @sa @ref glfwSetWindowPos + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); + +/** Sets the position of the content area of the specified window. + * + * This function sets the position, in screen coordinates, of the upper-left + * corner of the content area of the specified windowed mode window. If the + * window is a full screen window, this function does nothing. + * + * __Do not use this function__ to move an already visible window unless you + * have very good reasons for doing so, as it will confuse and annoy the user. + * + * The window manager may put limits on what positions are allowed. GLFW + * cannot and should not override these limits. + * + * Params: + * window = The window to query. + * xpos = The x-coordinate of the upper-left corner of the content area. + * ypos = The y-coordinate of the upper-left corner of the content area. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no way for an application to set the global + * position of its windows, this function will always emit @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_pos + * @sa @ref glfwGetWindowPos + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); + +/** Retrieves the size of the content area of the specified window. + * + * This function retrieves the size, in screen coordinates, of the content area + * of the specified window. If you wish to retrieve the size of the + * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. + * + * Any or all of the size arguments may be `null`. If an error occurs, all + * non-`null` size arguments will be set to zero. + * + * Params: + * window = The window whose size to retrieve. + * width = Where to store the width, in screen coordinates, of the + * content area, or `null`. + * height = Where to store the height, in screen coordinates, of the + * content area, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_size + * @sa @ref glfwSetWindowSize + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); + +/** Sets the size limits of the specified window. + * + * This function sets the size limits of the content area of the specified + * window. If the window is full screen, the size limits only take effect + * once it is made windowed. If the window is not resizable, this function + * does nothing. + * + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. + * + * The maximum dimensions must be greater than or equal to the minimum + * dimensions and all must be greater than or equal to zero. + * + * Params: + * window = The window to set limits for. + * minwidth = The minimum width, in screen coordinates, of the content + * area, or `GLFW_DONT_CARE`. + * minheight = The minimum height, in screen coordinates, of the + * content area, or `GLFW_DONT_CARE`. + * maxwidth = The maximum width, in screen coordinates, of the content + * area, or `GLFW_DONT_CARE`. + * maxheight = The maximum height, in screen coordinates, of the + * content area, or `GLFW_DONT_CARE`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @remark @wayland The size limits will not be applied until the window is + * actually resized, either by the user or by the compositor. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa @ref glfwSetWindowAspectRatio + * + * Since: Added in version 3.2. + * + * Ingroup: window + */ +void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); + +/** Sets the aspect ratio of the specified window. + * + * This function sets the required aspect ratio of the content area of the + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this + * function does nothing. + * + * The aspect ratio is specified as a numerator and a denominator and both + * values must be greater than zero. For example, the common 16:9 aspect ratio + * is specified as 16 and 9, respectively. + * + * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect + * ratio limit is disabled. + * + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. + * + * Params: + * window = The window to set limits for. + * numer = The numerator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * denom = The denominator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @remark @wayland The aspect ratio will not be applied until the window is + * actually resized, either by the user or by the compositor. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa @ref glfwSetWindowSizeLimits + * + * Since: Added in version 3.2. + * + * Ingroup: window + */ +void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); + +/** Sets the size of the content area of the specified window. + * + * This function sets the size, in screen coordinates, of the content area of + * the specified window. + * + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. + * + * The window manager may put limits on what sizes are allowed. GLFW cannot + * and should not override these limits. + * + * Params: + * window = The window to resize. + * width = The desired width, in screen coordinates, of the window + * content area. + * height = The desired height, in screen coordinates, of the window + * content area. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland A full screen window will not attempt to change the mode, + * no matter what the requested size. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_size + * @sa @ref glfwGetWindowSize + * @sa @ref glfwSetWindowMonitor + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +void glfwSetWindowSize(GLFWwindow* window, int width, int height); + +/** Retrieves the size of the framebuffer of the specified window. + * + * This function retrieves the size, in pixels, of the framebuffer of the + * specified window. If you wish to retrieve the size of the window in screen + * coordinates, see @ref glfwGetWindowSize. + * + * Any or all of the size arguments may be `null`. If an error occurs, all + * non-`null` size arguments will be set to zero. + * + * Params: + * window = The window whose framebuffer to query. + * width = Where to store the width, in pixels, of the framebuffer, + * or `null`. + * height = Where to store the height, in pixels, of the framebuffer, + * or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * @sa @ref glfwSetFramebufferSizeCallback + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); + +/** Retrieves the size of the frame of the window. + * + * This function retrieves the size, in screen coordinates, of each edge of the + * frame of the specified window. This size includes the title bar, if the + * window has one. The size of the frame may vary depending on the + * [window-related hints](@ref window_hints_wnd) used to create it. + * + * Because this function retrieves the size of each window frame edge and not + * the offset along a particular coordinate axis, the retrieved values will + * always be zero or positive. + * + * Any or all of the size arguments may be `null`. If an error occurs, all + * non-`null` size arguments will be set to zero. + * + * Params: + * window = The window whose frame size to query. + * left = Where to store the size, in screen coordinates, of the left + * edge of the window frame, or `null`. + * top = Where to store the size, in screen coordinates, of the top + * edge of the window frame, or `null`. + * right = Where to store the size, in screen coordinates, of the + * right edge of the window frame, or `null`. + * bottom = Where to store the size, in screen coordinates, of the + * bottom edge of the window frame, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_size + * + * Since: Added in version 3.1. + * + * Ingroup: window + */ +void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); + +/** Retrieves the content scale for the specified window. + * + * This function retrieves the content scale for the specified window. The + * content scale is the ratio between the current DPI and the platform's + * default DPI. This is especially important for text and any UI elements. If + * the pixel dimensions of your UI scaled by this look appropriate on your + * machine then it should appear at a reasonable size on other machines + * regardless of their DPI and scaling settings. This relies on the system DPI + * and scaling settings being somewhat correct. + * + * On systems where each monitors can have its own content scale, the window + * content scale will depend on which monitor the system considers the window + * to be on. + * + * Params: + * window = The window to query. + * xscale = Where to store the x-axis content scale, or `null`. + * yscale = Where to store the y-axis content scale, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_scale + * @sa @ref glfwSetWindowContentScaleCallback + * @sa @ref glfwGetMonitorContentScale + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* yscale); + +/** Returns the opacity of the whole window. + * + * This function returns the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. If the system + * does not support whole window transparency, this function always returns one. + * + * The initial opacity value for newly created windows is one. + * + * Params: + * window = The window to query. + * Returns: The opacity value of the specified window. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwSetWindowOpacity + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +float glfwGetWindowOpacity(GLFWwindow* window); + +/** Sets the opacity of the whole window. + * + * This function sets the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. + * + * The initial opacity value for newly created windows is one. + * + * A window created with framebuffer transparency may not use whole window + * transparency. The results of doing this are undefined. + * + * Params: + * window = The window to set the opacity for. + * opacity = The desired opacity of the specified window. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwGetWindowOpacity + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +void glfwSetWindowOpacity(GLFWwindow* window, float opacity); + +/** Iconifies the specified window. + * + * This function iconifies (minimizes) the specified window if it was + * previously restored. If the window is already iconified, this function does + * nothing. + * + * If the specified window is a full screen window, the original monitor + * resolution is restored until the window is restored. + * + * Params: + * window = The window to iconify. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no concept of iconification in wl_shell, this + * function will emit @ref GLFW_PLATFORM_ERROR when using this deprecated + * protocol. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwRestoreWindow + * @sa @ref glfwMaximizeWindow + * + * Since: Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +void glfwIconifyWindow(GLFWwindow* window); + +/** Restores the specified window. + * + * This function restores the specified window if it was previously iconified + * (minimized) or maximized. If the window is already restored, this function + * does nothing. + * + * If the specified window is a full screen window, the resolution chosen for + * the window is restored on the selected monitor. + * + * Params: + * window = The window to restore. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwIconifyWindow + * @sa @ref glfwMaximizeWindow + * + * Since: Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +void glfwRestoreWindow(GLFWwindow* window); + +/** Maximizes the specified window. + * + * This function maximizes the specified window if it was previously not + * maximized. If the window is already maximized, this function does nothing. + * + * If the specified window is a full screen window, this function does nothing. + * + * Params: + * window = The window to maximize. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwIconifyWindow + * @sa @ref glfwRestoreWindow + * + * Since: Added in GLFW 3.2. + * + * Ingroup: window + */ +void glfwMaximizeWindow(GLFWwindow* window); + +/** Makes the specified window visible. + * + * This function makes the specified window visible if it was previously + * hidden. If the window is already visible or is in full screen mode, this + * function does nothing. + * + * By default, windowed mode windows are focused when shown + * Set the [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_hint) window hint + * to change this behavior for all newly created windows, or change the + * behavior for an existing window with @ref glfwSetWindowAttrib. + * + * Params: + * window = The window to make visible. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_hide + * @sa @ref glfwHideWindow + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +void glfwShowWindow(GLFWwindow* window); + +/** Hides the specified window. + * + * This function hides the specified window if it was previously visible. If + * the window is already hidden or is in full screen mode, this function does + * nothing. + * + * Params: + * window = The window to hide. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_hide + * @sa @ref glfwShowWindow + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +void glfwHideWindow(GLFWwindow* window); + +/** Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref GLFW_FOCUSED_hint) to + * disable this behavior. + * + * Also by default, windowed mode windows are focused when shown + * with @ref glfwShowWindow. Set the + * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_hint) to disable this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * For a less disruptive way of getting the user's attention, see + * [attention requests](@ref window_attention). + * + * Params: + * window = The window to give input focus. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland It is not possible for an application to bring its windows + * to front, this function will always emit @ref GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_focus + * @sa @ref window_attention + * + * Since: Added in version 3.2. + * + * Ingroup: window + */ +void glfwFocusWindow(GLFWwindow* window); + +/** Requests user attention to the specified window. + * + * This function requests user attention to the specified window. On + * platforms where this is not supported, attention is requested to the + * application as a whole. + * + * Once the user has given attention, usually by focusing the window or + * application, the system will end the request automatically. + * + * Params: + * window = The window to request attention to. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos Attention is requested to the application as a whole, not the + * specific window. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_attention + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +void glfwRequestWindowAttention(GLFWwindow* window); + +/** Returns the monitor that the window uses for full screen mode. + * + * This function returns the handle of the monitor that the specified window is + * in full screen on. + * + * Params: + * window = The window to query. + * Returns: The monitor, or `null` if the window is in windowed mode or an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref glfwSetWindowMonitor + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); + +/** Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `null`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `null`, the position, width and height are used to + * place the window content area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc. + * + * Params: + * window = The window whose monitor, size or video mode to set. + * monitor = The desired monitor, or `null` to set windowed mode. + * xpos = The desired x-coordinate of the upper-left corner of the + * content area. + * ypos = The desired y-coordinate of the upper-left corner of the + * content area. + * width = The desired with, in screen coordinates, of the content + * area or video mode. + * height = The desired height, in screen coordinates, of the content + * area or video mode. + * refreshRate = The desired refresh rate, in Hz, of the video mode, + * or `GLFW_DONT_CARE`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark The OpenGL or OpenGL ES context will not be destroyed or otherwise + * affected by any resizing or mode switching, although you may need to update + * your viewport if the framebuffer size has changed. + * + * @remark @wayland The desired window position is ignored, as there is no way + * for an application to set this property. + * + * @remark @wayland Setting the window to full screen will not attempt to + * change the mode, no matter what the requested size or refresh rate. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref window_full_screen + * @sa @ref glfwGetWindowMonitor + * @sa @ref glfwSetWindowSize + * + * Since: Added in version 3.2. + * + * Ingroup: window + */ +void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + +/** Returns an attribute of the specified window. + * + * This function returns the value of an attribute of the specified window or + * its OpenGL or OpenGL ES context. + * + * Params: + * window = The window to query. + * attrib = The [window attribute](@ref window_attribs) whose value to + * return. + * Returns: The value of the attribute, or zero if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark Framebuffer related hints are not window attributes. See @ref + * window_attribs_fb for more information. + * + * @remark Zero is a valid value for many window and context related + * attributes so you cannot use a return value of zero as an indication of + * errors. However, this function should not fail as long as it is passed + * valid arguments and the library has been [initialized](@ref intro_init). + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_attribs + * @sa @ref glfwSetWindowAttrib + * + * Since: Added in version 3.0. Replaces `glfwGetWindowParam` and + * `glfwGetGLVersion`. + * + * Ingroup: window + */ +int glfwGetWindowAttrib(GLFWwindow* window, int attrib); + +/** Sets an attribute of the specified window. + * + * This function sets the value of an attribute of the specified window. + * + * The supported attributes are [GLFW_DECORATED](@ref GLFW_DECORATED_attrib), + * [GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib), + * [GLFW_FLOATING](@ref GLFW_FLOATING_attrib), + * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) and + * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_attrib). + * + * Some of these attributes are ignored for full screen windows. The new + * value will take effect if the window is later made windowed. + * + * Some of these attributes are ignored for windowed mode windows. The new + * value will take effect if the window is later made full screen. + * + * Params: + * window = The window to set the attribute for. + * attrib = A supported window attribute. + * value = `GLFW_TRUE` or `GLFW_FALSE`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark Calling @ref glfwGetWindowAttrib will always return the latest + * value, even if that value is ignored by the current mode of the window. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_attribs + * @sa @ref glfwGetWindowAttrib + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +void glfwSetWindowAttrib(GLFWwindow* window, int attrib, int value); + +/** Sets the user pointer of the specified window. + * + * This function sets the user-defined pointer of the specified window. The + * current value is retained until the window is destroyed. The initial value + * is `null`. + * + * Params: + * window = The window whose pointer to set. + * pointer = The new value. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr + * @sa @ref glfwGetWindowUserPointer + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); + +/** Returns the user pointer of the specified window. + * + * This function returns the current value of the user-defined pointer of the + * specified window. The initial value is `null`. + * + * Params: + * window = The window whose pointer to return. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr + * @sa @ref glfwSetWindowUserPointer + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +void* glfwGetWindowUserPointer(GLFWwindow* window); + +/** Sets the position callback for the specified window. + * + * This function sets the position callback of the specified window, which is + * called when the window is moved. The callback is provided with the + * position, in screen coordinates, of the upper-left corner of the content + * area of the window. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int xpos, int ypos) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowposfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland This callback will never be called, as there is no way for + * an application to know its global position. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_pos + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun callback); + +/** Sets the size callback for the specified window. + * + * This function sets the size callback of the specified window, which is + * called when the window is resized. The callback is provided with the size, + * in screen coordinates, of the content area of the window. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int width, int height) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowsizefun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_size + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * Ingroup: window + */ +GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun callback); + +/** Sets the close callback for the specified window. + * + * This function sets the close callback of the specified window, which is + * called when the user attempts to close the window, for example by clicking + * the close widget in the title bar. + * + * The close flag is set before this callback is called, but you can modify it + * at any time with @ref glfwSetWindowShouldClose. + * + * The close callback is not triggered by @ref glfwDestroyWindow. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowclosefun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @macos Selecting Quit from the application menu will trigger the + * close callback for all windows. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_close + * + * Since: Added in version 2.5. + * @glfw3 Added window handle parameter and return value. + * + * Ingroup: window + */ +GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback); + +/** Sets the refresh callback for the specified window. + * + * This function sets the refresh callback of the specified window, which is + * called when the content area of the window needs to be redrawn, for example + * if the window has been exposed after having been covered by another window. + * + * On compositing window systems such as Aero, Compiz, Aqua or Wayland, where + * the window contents are saved off-screen, this callback may be called only + * very infrequently or never at all. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window); + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowrefreshfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_refresh + * + * Since: Added in version 2.5. + * @glfw3 Added window handle parameter and return value. + * + * Ingroup: window + */ +GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun callback); + +/** Sets the focus callback for the specified window. + * + * This function sets the focus callback of the specified window, which is + * called when the window gains or loses input focus. + * + * After the focus callback is called for a window that lost input focus, + * synthetic key and mouse button release events will be generated for all such + * that had been pressed. For more information, see @ref glfwSetKeyCallback + * and @ref glfwSetMouseButtonCallback. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int focused) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowfocusfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun callback); + +/** Sets the iconify callback for the specified window. + * + * This function sets the iconification callback of the specified window, which + * is called when the window is iconified or restored. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int iconified) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowiconifyfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland The wl_shell protocol has no concept of iconification, + * this callback will never be called when using this deprecated protocol. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_iconify + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun callback); + +/** Sets the maximize callback for the specified window. + * + * This function sets the maximization callback of the specified window, which + * is called when the window is maximized or restored. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int maximized) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowmaximizefun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_maximize + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun callback); + +/** Sets the framebuffer resize callback for the specified window. + * + * This function sets the framebuffer resize callback of the specified window, + * which is called when the framebuffer of the specified window is resized. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int width, int height) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWframebuffersizefun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * + * Since: Added in version 3.0. + * + * Ingroup: window + */ +GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun callback); + +/** Sets the window content scale callback for the specified window. + * + * This function sets the window content scale callback of the specified window, + * which is called when the content scale of the specified window changes. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, float xscale, float yscale) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowcontentscalefun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref window_scale + * @sa @ref glfwGetWindowContentScale + * + * Since: Added in version 3.3. + * + * Ingroup: window + */ +GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* window, GLFWwindowcontentscalefun callback); + +/** Processes all pending events. + * + * This function processes only those events that are already in the event + * queue and then returns immediately. Processing events will cause the window + * and input callbacks associated with those events to be called. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * Event processing is not required for joystick input to work. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwWaitEvents + * @sa @ref glfwWaitEventsTimeout + * + * Since: Added in version 1.0. + * + * Ingroup: window + */ +void glfwPollEvents(); + +/** Waits until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue. Once one or more events are available, + * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue + * are processed and the function then returns immediately. Processing events + * will cause the window and input callbacks associated with those events to be + * called. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * Event processing is not required for joystick input to work. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwPollEvents + * @sa @ref glfwWaitEventsTimeout + * + * Since: Added in version 2.5. + * + * Ingroup: window + */ +void glfwWaitEvents(); + +/** Waits with timeout until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue, or until the specified timeout is reached. If + * one or more events are available, it behaves exactly like @ref + * glfwPollEvents, i.e. the events in the queue are processed and the function + * then returns immediately. Processing events will cause the window and input + * callbacks associated with those events to be called. + * + * The timeout value must be a positive finite number. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * Event processing is not required for joystick input to work. + * + * Params: + * timeout = The maximum amount of time, in seconds, to wait. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwPollEvents + * @sa @ref glfwWaitEvents + * + * Since: Added in version 3.2. + * + * Ingroup: window + */ +void glfwWaitEventsTimeout(double timeout); + +/** Posts an empty event to the event queue. + * + * This function posts an empty event from the current thread to the event + * queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref events + * @sa @ref glfwWaitEvents + * @sa @ref glfwWaitEventsTimeout + * + * Since: Added in version 3.1. + * + * Ingroup: window + */ +void glfwPostEmptyEvent(); + +/** Returns the value of an input option for the specified window. + * + * This function returns the value of an input option for the specified window. + * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or + * @ref GLFW_RAW_MOUSE_MOTION. + * + * Params: + * window = The window to query. + * mode = One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or + * `GLFW_RAW_MOUSE_MOTION`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref glfwSetInputMode + * + * Since: Added in version 3.0. + * + * Ingroup: input + */ +int glfwGetInputMode(GLFWwindow* window, int mode); + +/** Sets an input option for the specified window. + * + * This function sets an input mode option for the specified window. The mode + * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or + * @ref GLFW_RAW_MOUSE_MOTION. + * + * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor + * modes: + * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. + * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the + * content area of the window but does not restrict the cursor from leaving. + * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual + * and unlimited cursor movement. This is useful for implementing for + * example 3D camera controls. + * + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to + * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are + * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` + * the next time it is called even if the key had been released before the + * call. This is useful when you are only interested in whether keys have been + * pressed but not when or in which order. + * + * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either + * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. + * If sticky mouse buttons are enabled, a mouse button press will ensure that + * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even + * if the mouse button had been released before the call. This is useful when + * you are only interested in whether mouse buttons have been pressed but not + * when or in which order. + * + * If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to + * enable lock key modifier bits, or `GLFW_FALSE` to disable them. If enabled, + * callbacks that receive modifier bits will also have the @ref + * GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on, + * and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on. + * + * If the mode is `GLFW_RAW_MOUSE_MOTION`, the value must be either `GLFW_TRUE` + * to enable raw (unscaled and unaccelerated) mouse motion when the cursor is + * disabled, or `GLFW_FALSE` to disable it. If raw motion is not supported, + * attempting to set this will emit @ref GLFW_PLATFORM_ERROR. Call @ref + * glfwRawMouseMotionSupported to check for support. + * + * Params: + * window = The window whose input mode to set. + * mode = One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or + * `GLFW_RAW_MOUSE_MOTION`. + * value = The new value of the specified input mode. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref glfwGetInputMode + * + * Since: Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. + * + * Ingroup: input + */ +void glfwSetInputMode(GLFWwindow* window, int mode, int value); + +/** Returns whether raw mouse motion is supported. + * + * This function returns whether raw mouse motion is supported on the current + * system. This status does not change after GLFW has been initialized so you + * only need to check this once. If you attempt to enable raw motion on + * a system that does not support it, @ref GLFW_PLATFORM_ERROR will be emitted. + * + * Raw mouse motion is closer to the actual motion of the mouse across + * a surface. It is not affected by the scaling and acceleration applied to + * the motion of the desktop cursor. That processing is suitable for a cursor + * while raw motion is better for controlling for example a 3D camera. Because + * of this, raw mouse motion is only provided when the cursor is disabled. + * + * Returns: `GLFW_TRUE` if raw mouse motion is supported on the current machine, + * or `GLFW_FALSE` otherwise. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref raw_mouse_motion + * @sa @ref glfwSetInputMode + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +int glfwRawMouseMotionSupported(); + +/** Returns the layout-specific name of the specified printable key. + * + * This function returns the name of the specified printable key, encoded as + * UTF-8. This is typically the character that key would produce without any + * modifier keys, intended for displaying key bindings to the user. For dead + * keys, it is typically the diacritic it would add to a character. + * + * __Do not use this function__ for [text input](@ref input_char). You will + * break text input for many languages even if it happens to work for yours. + * + * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used to identify the key, + * otherwise the scancode is ignored. If you specify a non-printable key, or + * `GLFW_KEY_UNKNOWN` and a scancode that maps to a non-printable key, this + * function returns `null` but does not emit an error. + * + * This behavior allows you to always pass in the arguments in the + * [key callback](@ref input_key) without modification. + * + * The printable keys are: + * - `GLFW_KEY_APOSTROPHE` + * - `GLFW_KEY_COMMA` + * - `GLFW_KEY_MINUS` + * - `GLFW_KEY_PERIOD` + * - `GLFW_KEY_SLASH` + * - `GLFW_KEY_SEMICOLON` + * - `GLFW_KEY_EQUAL` + * - `GLFW_KEY_LEFT_BRACKET` + * - `GLFW_KEY_RIGHT_BRACKET` + * - `GLFW_KEY_BACKSLASH` + * - `GLFW_KEY_WORLD_1` + * - `GLFW_KEY_WORLD_2` + * - `GLFW_KEY_0` to `GLFW_KEY_9` + * - `GLFW_KEY_A` to `GLFW_KEY_Z` + * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` + * - `GLFW_KEY_KP_DECIMAL` + * - `GLFW_KEY_KP_DIVIDE` + * - `GLFW_KEY_KP_MULTIPLY` + * - `GLFW_KEY_KP_SUBTRACT` + * - `GLFW_KEY_KP_ADD` + * - `GLFW_KEY_KP_EQUAL` + * + * Names for printable keys depend on keyboard layout, while names for + * non-printable keys are the same across layouts but depend on the application + * language and should be localized along with other user interface text. + * + * Params: + * key = The key to query, or `GLFW_KEY_UNKNOWN`. + * scancode = The scancode of the key to query. + * Returns: The UTF-8 encoded, layout-specific name of the key, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark The contents of the returned string may change when a keyboard + * layout change event is received. + * + * Pointer_lifetime: The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref input_key_name + * + * Since: Added in version 3.2. + * + * Ingroup: input + */ +const(char)* glfwGetKeyName(int key, int scancode); + +/** Returns the platform-specific scancode of the specified key. + * + * This function returns the platform-specific scancode of the specified key. + * + * If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this + * method will return `-1`. + * + * Params: + * key = Any [named key](@ref keys). + * Returns: The platform-specific scancode for the key, or `-1` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref input_key + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +int glfwGetKeyScancode(int key); + +/** Returns the last reported state of a keyboard key for the specified + * window. + * + * This function returns the last state reported for the specified key to the + * specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to + * the key callback. + * + * If the @ref GLFW_STICKY_KEYS input mode is enabled, this function returns + * `GLFW_PRESS` the first time you call it for a key that was pressed, even if + * that key has already been released. + * + * The key functions deal with physical keys, with [key tokens](@ref keys) + * named after their use on the standard US keyboard layout. If you want to + * input text, use the Unicode character callback instead. + * + * The [modifier key bit masks](@ref mods) are not key tokens and cannot be + * used with this function. + * + * __Do not use this function__ to implement [text input](@ref input_char). + * + * Params: + * window = The desired window. + * key = The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is + * not a valid key for this function. + * Returns: One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref input_key + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * Ingroup: input + */ +int glfwGetKey(GLFWwindow* window, int key); + +/** Returns the last reported state of a mouse button for the specified + * window. + * + * This function returns the last state reported for the specified mouse button + * to the specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. + * + * If the @ref GLFW_STICKY_MOUSE_BUTTONS input mode is enabled, this function + * returns `GLFW_PRESS` the first time you call it for a mouse button that was + * pressed, even if that mouse button has already been released. + * + * Params: + * window = The desired window. + * button = The desired [mouse button](@ref buttons). + * Returns: One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * Ingroup: input + */ +int glfwGetMouseButton(GLFWwindow* window, int button); + +/** Retrieves the position of the cursor relative to the content area of + * the window. + * + * This function returns the position of the cursor, in screen coordinates, + * relative to the upper-left corner of the content area of the specified + * window. + * + * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor + * position is unbounded and limited only by the minimum and maximum values of + * a `double`. + * + * The coordinate can be converted to their integer equivalents with the + * `floor` function. Casting directly to an integer type works for positive + * coordinates, but fails for negative ones. + * + * Any or all of the position arguments may be `null`. If an error occurs, all + * non-`null` position arguments will be set to zero. + * + * Params: + * window = The desired window. + * xpos = Where to store the cursor x-coordinate, relative to the + * left edge of the content area, or `null`. + * ypos = Where to store the cursor y-coordinate, relative to the to + * top edge of the content area, or `null`. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * @sa @ref glfwSetCursorPos + * + * Since: Added in version 3.0. Replaces `glfwGetMousePos`. + * + * Ingroup: input + */ +void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); + +/** Sets the position of the cursor, relative to the content area of the + * window. + * + * This function sets the position, in screen coordinates, of the cursor + * relative to the upper-left corner of the content area of the specified + * window. The window must have input focus. If the window does not have + * input focus when this function is called, it fails silently. + * + * __Do not use this function__ to implement things like camera controls. GLFW + * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the + * cursor, transparently re-centers it and provides unconstrained cursor + * motion. See @ref glfwSetInputMode for more information. + * + * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is + * unconstrained and limited only by the minimum and maximum values of + * a `double`. + * + * Params: + * window = The desired window. + * xpos = The desired x-coordinate, relative to the left edge of the + * content area. + * ypos = The desired y-coordinate, relative to the top edge of the + * content area. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland This function will only work when the cursor mode is + * `GLFW_CURSOR_DISABLED`, otherwise it will do nothing. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * @sa @ref glfwGetCursorPos + * + * Since: Added in version 3.0. Replaces `glfwSetMousePos`. + * + * Ingroup: input + */ +void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); + +/** Creates a custom cursor. + * + * Creates a new custom cursor image that can be set for a window with @ref + * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. + * Any remaining cursors are destroyed by @ref glfwTerminate. + * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel with the red channel first. They are arranged canonically + * as packed sequential rows, starting from the top-left corner. + * + * The cursor hotspot is specified in pixels, relative to the upper-left corner + * of the cursor image. Like all other coordinate systems in GLFW, the X-axis + * points to the right and the Y-axis points down. + * + * Params: + * image = The desired cursor image. + * xhot = The desired x-coordinate, in pixels, of the cursor hotspot. + * yhot = The desired y-coordinate, in pixels, of the cursor hotspot. + * Returns: The handle of the created cursor, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The specified image data is copied before this function + * returns. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwDestroyCursor + * @sa @ref glfwCreateStandardCursor + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +GLFWcursor* glfwCreateCursor(const(GLFWimage)* image, int xhot, int yhot); + +/** Creates a cursor with a standard shape. + * + * Returns a cursor with a [standard shape](@ref shapes), that can be set for + * a window with @ref glfwSetCursor. + * + * Params: + * shape = One of the [standard shapes](@ref shapes). + * Returns: A new cursor ready to use or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwCreateCursor + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +GLFWcursor* glfwCreateStandardCursor(int shape); + +/** Destroys a cursor. + * + * This function destroys a cursor previously created with @ref + * glfwCreateCursor. Any remaining cursors will be destroyed by @ref + * glfwTerminate. + * + * If the specified cursor is current for any window, that window will be + * reverted to the default cursor. This does not affect the cursor mode. + * + * Params: + * cursor = The cursor object to destroy. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwCreateCursor + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +void glfwDestroyCursor(GLFWcursor* cursor); + +/** Sets the cursor for the window. + * + * This function sets the cursor image to be used when the cursor is over the + * content area of the specified window. The set cursor will only be visible + * when the [cursor mode](@ref cursor_mode) of the window is + * `GLFW_CURSOR_NORMAL`. + * + * On some platforms, the set cursor may not be visible unless the window also + * has input focus. + * + * Params: + * window = The window to set the cursor for. + * cursor = The cursor to set, or `null` to switch back to the default + * arrow cursor. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref cursor_object + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); + +/** Sets the key callback. + * + * This function sets the key callback of the specified window, which is called + * when a key is pressed, repeated or released. + * + * The key functions deal with physical keys, with layout independent + * [key tokens](@ref keys) named after their values in the standard US keyboard + * layout. If you want to input text, use the + * [character callback](@ref glfwSetCharCallback) instead. + * + * When a window loses input focus, it will generate synthetic key release + * events for all pressed keys. You can tell these events from user-generated + * events by the fact that the synthetic ones are generated after the focus + * loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. + * + * The scancode of a key is specific to that platform or sometimes even to that + * machine. Scancodes are intended to allow users to bind keys that don't have + * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their + * state is not saved and so it cannot be queried with @ref glfwGetKey. + * + * Sometimes GLFW needs to generate synthetic key events, in which case the + * scancode may be zero. + * + * Params: + * window = The window whose callback to set. + * callback = The new key callback, or `null` to remove the currently + * set callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int key, int scancode, int action, int mods) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWkeyfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref input_key + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * Ingroup: input + */ +GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun callback); + +/** Sets the Unicode character callback. + * + * This function sets the character callback of the specified window, which is + * called when a Unicode character is input. + * + * The character callback is intended for Unicode text input. As it deals with + * characters, it is keyboard layout dependent, whereas the + * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 + * to physical keys, as a key may produce zero, one or more characters. If you + * want to know whether a specific physical key was pressed or released, see + * the key callback instead. + * + * The character callback behaves as system text input normally does and will + * not be called if modifier keys are held down that would prevent normal text + * input on that platform, for example a Super (Command) key on macOS or Alt key + * on Windows. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, unsigned int codepoint) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcharfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref input_char + * + * Since: Added in version 2.4. + * @glfw3 Added window handle parameter and return value. + * + * Ingroup: input + */ +GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun callback); + +/** Sets the Unicode character with modifiers callback. + * + * This function sets the character with modifiers callback of the specified + * window, which is called when a Unicode character is input regardless of what + * modifier keys are used. + * + * The character with modifiers callback is intended for implementing custom + * Unicode character input. For regular Unicode text input, see the + * [character callback](@ref glfwSetCharCallback). Like the character + * callback, the character with modifiers callback deals with characters and is + * keyboard layout dependent. Characters do not map 1:1 to physical keys, as + * a key may produce zero, one or more characters. If you want to know whether + * a specific physical key was pressed or released, see the + * [key callback](@ref glfwSetKeyCallback) instead. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or an + * [error](@ref error_handling) occurred. + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, unsigned int codepoint, int mods) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcharmodsfun). + * + * @deprecated Scheduled for removal in version 4.0. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref input_char + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun callback); + +/** Sets the mouse button callback. + * + * This function sets the mouse button callback of the specified window, which + * is called when a mouse button is pressed or released. + * + * When a window loses input focus, it will generate synthetic mouse button + * release events for all pressed mouse buttons. You can tell these events + * from user-generated events by the fact that the synthetic ones are generated + * after the focus loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int button, int action, int mods) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWmousebuttonfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * Ingroup: input + */ +GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun callback); + +/** Sets the cursor position callback. + * + * This function sets the cursor position callback of the specified window, + * which is called when the cursor is moved. The callback is provided with the + * position, in screen coordinates, relative to the upper-left corner of the + * content area of the window. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, double xpos, double ypos); + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcursorposfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * + * Since: Added in version 3.0. Replaces `glfwSetMousePosCallback`. + * + * Ingroup: input + */ +GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun callback); + +/** Sets the cursor enter/leave callback. + * + * This function sets the cursor boundary crossing callback of the specified + * window, which is called when the cursor enters or leaves the content area of + * the window. + * + * Params: + * window = The window whose callback to set. + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int entered) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcursorenterfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref cursor_enter + * + * Since: Added in version 3.0. + * + * Ingroup: input + */ +GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun callback); + +/** Sets the scroll callback. + * + * This function sets the scroll callback of the specified window, which is + * called when a scrolling device is used, such as a mouse wheel or scrolling + * area of a touchpad. + * + * The scroll callback receives all scrolling input, like that from a mouse + * wheel or a touchpad scrolling area. + * + * Params: + * window = The window whose callback to set. + * callback = The new scroll callback, or `null` to remove the + * currently set callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, double xoffset, double yoffset) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWscrollfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref scrolling + * + * Since: Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. + * + * Ingroup: input + */ +GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback); + +/** Sets the path drop callback. + * + * This function sets the path drop callback of the specified window, which is + * called when one or more dragged paths are dropped on the window. + * + * Because the path array and its strings may have been generated specifically + * for that event, they are not guaranteed to be valid after the callback has + * returned. If you wish to use them after the callback returns, you need to + * make a deep copy. + * + * Params: + * window = The window whose callback to set. + * callback = The new file drop callback, or `null` to remove the + * currently set callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(GLFWwindow* window, int path_count, const char* paths[]) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWdropfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland File drop is currently unimplemented. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref path_drop + * + * Since: Added in version 3.1. + * + * Ingroup: input + */ +GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback); + +/** Returns whether the specified joystick is present. + * + * This function returns whether the specified joystick is present. + * + * There is no need to call this function before other functions that accept + * a joystick ID, as they all check for presence before performing any other + * work. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * Returns: `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref joystick + * + * Since: Added in version 3.0. Replaces `glfwGetJoystickParam`. + * + * Ingroup: input + */ +int glfwJoystickPresent(int jid); + +/** Returns the values of all axes of the specified joystick. + * + * This function returns the values of all axes of the specified joystick. + * Each element in the array is a value between -1.0 and 1.0. + * + * If the specified joystick is not present this function will return `null` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * count = Where to store the number of axis values in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * Returns: An array of axis values, or `null` if the joystick is not present or + * an [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref joystick_axis + * + * Since: Added in version 3.0. Replaces `glfwGetJoystickPos`. + * + * Ingroup: input + */ +const(float)* glfwGetJoystickAxes(int jid, int* count); + +/** Returns the state of all buttons of the specified joystick. + * + * This function returns the state of all buttons of the specified joystick. + * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. + * + * For backward compatibility with earlier versions that did not have @ref + * glfwGetJoystickHats, the button array also includes all hats, each + * represented as four buttons. The hats are in the same order as returned by + * __glfwGetJoystickHats__ and are in the order _up_, _right_, _down_ and + * _left_. To disable these extra buttons, set the @ref + * GLFW_JOYSTICK_HAT_BUTTONS init hint before initialization. + * + * If the specified joystick is not present this function will return `null` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * count = Where to store the number of button states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * Returns: An array of button states, or `null` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref joystick_button + * + * Since: Added in version 2.2. + * @glfw3 Changed to return a dynamic array. + * + * Ingroup: input + */ +const(ubyte)* glfwGetJoystickButtons(int jid, int* count); + +/** Returns the state of all hats of the specified joystick. + * + * This function returns the state of all hats of the specified joystick. + * Each element in the array is one of the following values: + * + * Name | Value + * ---- | ----- + * `GLFW_HAT_CENTERED` | 0 + * `GLFW_HAT_UP` | 1 + * `GLFW_HAT_RIGHT` | 2 + * `GLFW_HAT_DOWN` | 4 + * `GLFW_HAT_LEFT` | 8 + * `GLFW_HAT_RIGHT_UP` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_UP` + * `GLFW_HAT_RIGHT_DOWN` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_DOWN` + * `GLFW_HAT_LEFT_UP` | `GLFW_HAT_LEFT` \| `GLFW_HAT_UP` + * `GLFW_HAT_LEFT_DOWN` | `GLFW_HAT_LEFT` \| `GLFW_HAT_DOWN` + * + * The diagonal directions are bitwise combinations of the primary (up, right, + * down and left) directions and you can test for these individually by ANDing + * it with the corresponding direction. + * + * ``` + * if (hats[2] & GLFW_HAT_RIGHT) + * { + * // State of hat 2 could be right-up, right or right-down + * } + * ``` + * + * If the specified joystick is not present this function will return `null` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * count = Where to store the number of hat states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * Returns: An array of hat states, or `null` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref joystick_hat + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +const(ubyte)* glfwGetJoystickHats(int jid, int* count); + +/** Returns the name of the specified joystick. + * + * This function returns the name, encoded as UTF-8, of the specified joystick. + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. + * + * If the specified joystick is not present this function will return `null` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * Returns: The UTF-8 encoded name of the joystick, or `null` if the joystick + * is not present or an [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref joystick_name + * + * Since: Added in version 3.0. + * + * Ingroup: input + */ +const(char)* glfwGetJoystickName(int jid); + +/** Returns the SDL compatible GUID of the specified joystick. + * + * This function returns the SDL compatible GUID, as a UTF-8 encoded + * hexadecimal string, of the specified joystick. The returned string is + * allocated and freed by GLFW. You should not free it yourself. + * + * The GUID is what connects a joystick to a gamepad mapping. A connected + * joystick will always have a GUID even if there is no gamepad mapping + * assigned to it. + * + * If the specified joystick is not present this function will return `null` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * The GUID uses the format introduced in SDL 2.0.5. This GUID tries to + * uniquely identify the make and model of a joystick but does not identify + * a specific unit, e.g. all wired Xbox 360 controllers will have the same + * GUID on that platform. The GUID for a unit may vary between platforms + * depending on what hardware information the platform specific APIs provide. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * Returns: The UTF-8 encoded GUID of the joystick, or `null` if the joystick + * is not present or an [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref gamepad + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +const(char)* glfwGetJoystickGUID(int jid); + +/** Sets the user pointer of the specified joystick. + * + * This function sets the user-defined pointer of the specified joystick. The + * current value is retained until the joystick is disconnected. The initial + * value is `null`. + * + * This function may be called from the joystick callback, even for a joystick + * that is being disconnected. + * + * Params: + * jid = The joystick whose pointer to set. + * pointer = The new value. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref joystick_userptr + * @sa @ref glfwGetJoystickUserPointer + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +void glfwSetJoystickUserPointer(int jid, void* pointer); + +/** Returns the user pointer of the specified joystick. + * + * This function returns the current value of the user-defined pointer of the + * specified joystick. The initial value is `null`. + * + * This function may be called from the joystick callback, even for a joystick + * that is being disconnected. + * + * Params: + * jid = The joystick whose pointer to return. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref joystick_userptr + * @sa @ref glfwSetJoystickUserPointer + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +void* glfwGetJoystickUserPointer(int jid); + +/** Returns whether the specified joystick has a gamepad mapping. + * + * This function returns whether the specified joystick is both present and has + * a gamepad mapping. + * + * If the specified joystick is present but does not have a gamepad mapping + * this function will return `GLFW_FALSE` but will not generate an error. Call + * @ref glfwJoystickPresent to check if a joystick is present regardless of + * whether it has a mapping. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * Returns: `GLFW_TRUE` if a joystick is both present and has a gamepad mapping, + * or `GLFW_FALSE` otherwise. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwGetGamepadState + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +int glfwJoystickIsGamepad(int jid); + +/** Sets the joystick configuration callback. + * + * This function sets the joystick configuration callback, or removes the + * currently set callback. This is called when a joystick is connected to or + * disconnected from the system. + * + * For joystick connection and disconnection events to be delivered on all + * platforms, you need to call one of the [event processing](@ref events) + * functions. Joystick disconnection may also be detected and the callback + * called by joystick functions. The function will then return whatever it + * returns if the joystick is not present. + * + * Params: + * callback = The new callback, or `null` to remove the currently set + * callback. + * Returns: The previously set callback, or `null` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * ``` + * void function_name(int jid, int event) + * ``` + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWjoystickfun). + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref joystick_event + * + * Since: Added in version 3.2. + * + * Ingroup: input + */ +GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun callback); + +/** Adds the specified SDL_GameControllerDB gamepad mappings. + * + * This function parses the specified ASCII encoded string and updates the + * internal list with any gamepad mappings it finds. This string may + * contain either a single gamepad mapping or many mappings separated by + * newlines. The parser supports the full format of the `gamecontrollerdb.txt` + * source file including empty lines and comments. + * + * See @ref gamepad_mapping for a description of the format. + * + * If there is already a gamepad mapping for a given GUID in the internal list, + * it will be replaced by the one passed to this function. If the library is + * terminated and re-initialized the internal list will revert to the built-in + * default. + * + * Params: + * string = The string containing the gamepad mappings. + * Returns: `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwJoystickIsGamepad + * @sa @ref glfwGetGamepadName + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +int glfwUpdateGamepadMappings(const(char)* string); + +/** Returns the human-readable gamepad name for the specified joystick. + * + * This function returns the human-readable name of the gamepad from the + * gamepad mapping assigned to the specified joystick. + * + * If the specified joystick is not present or does not have a gamepad mapping + * this function will return `null` but will not generate an error. Call + * @ref glfwJoystickPresent to check whether it is present regardless of + * whether it has a mapping. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * Returns: The UTF-8 encoded name of the gamepad, or `null` if the + * joystick is not present, does not have a mapping or an + * [error](@ref error_handling) occurred. + * + * Pointer_lifetime: The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, the gamepad mappings are updated or the library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwJoystickIsGamepad + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +const(char)* glfwGetGamepadName(int jid); + +/** Retrieves the state of the specified joystick remapped as a gamepad. + * + * This function retrieves the state of the specified joystick remapped to + * an Xbox-like gamepad. + * + * If the specified joystick is not present or does not have a gamepad mapping + * this function will return `GLFW_FALSE` but will not generate an error. Call + * @ref glfwJoystickPresent to check whether it is present regardless of + * whether it has a mapping. + * + * The Guide button may not be available for input as it is often hooked by the + * system or the Steam client. + * + * Not all devices have all the buttons or axes provided by @ref + * GLFWgamepadstate. Unavailable buttons and axes will always report + * `GLFW_RELEASE` and 0.0 respectively. + * + * Params: + * jid = The [joystick](@ref joysticks) to query. + * state = The gamepad input state of the joystick. + * Returns: `GLFW_TRUE` if successful, or `GLFW_FALSE` if no joystick is + * connected, it has no gamepad mapping or an [error](@ref error_handling) + * occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwUpdateGamepadMappings + * @sa @ref glfwJoystickIsGamepad + * + * Since: Added in version 3.3. + * + * Ingroup: input + */ +int glfwGetGamepadState(int jid, GLFWgamepadstate* state); + +/** Sets the clipboard to the specified string. + * + * This function sets the system clipboard to the specified, UTF-8 encoded + * string. + * + * Params: + * window = Deprecated. Any valid window or `null`. + * string = A UTF-8 encoded string. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The specified string is copied before this function + * returns. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa @ref glfwGetClipboardString + * + * Since: Added in version 3.0. + * + * Ingroup: input + */ +void glfwSetClipboardString(GLFWwindow* window, const(char)* string); + +/** Returns the contents of the clipboard as a string. + * + * This function returns the contents of the system clipboard, if it contains + * or is convertible to a UTF-8 encoded string. If the clipboard is empty or + * if its contents cannot be converted, `null` is returned and a @ref + * GLFW_FORMAT_UNAVAILABLE error is generated. + * + * Params: + * window = Deprecated. Any valid window or `null`. + * Returns: The contents of the clipboard as a UTF-8 encoded string, or `null` + * if an [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library + * is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa @ref glfwSetClipboardString + * + * Since: Added in version 3.0. + * + * Ingroup: input + */ +const(char)* glfwGetClipboardString(GLFWwindow* window); + +/** Returns the GLFW time. + * + * This function returns the current GLFW time, in seconds. Unless the time + * has been set using @ref glfwSetTime it measures time elapsed since GLFW was + * initialized. + * + * This function and @ref glfwSetTime are helper functions on top of @ref + * glfwGetTimerFrequency and @ref glfwGetTimerValue. + * + * The resolution of the timer is system dependent, but is usually on the order + * of a few micro- or nanoseconds. It uses the highest-resolution monotonic + * time source on each supported platform. + * + * Returns: The current time, in seconds, or zero if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. Reading and + * writing of the internal base time is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwSetTime. + * + * @sa @ref time + * + * Since: Added in version 1.0. + * + * Ingroup: input + */ +double glfwGetTime(); + +/** Sets the GLFW time. + * + * This function sets the current GLFW time, in seconds. The value must be + * a positive finite number less than or equal to 18446744073.0, which is + * approximately 584.5 years. + * + * This function and @ref glfwGetTime are helper functions on top of @ref + * glfwGetTimerFrequency and @ref glfwGetTimerValue. + * + * Params: + * time = The new value, in seconds. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @remark The upper limit of GLFW time is calculated as + * floor((264 - 1) / 109) and is due to implementations + * storing nanoseconds in 64 bits. The limit may be increased in the future. + * + * Thread_Safety: This function may be called from any thread. Reading and + * writing of the internal base time is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwGetTime. + * + * @sa @ref time + * + * Since: Added in version 2.2. + * + * Ingroup: input + */ +void glfwSetTime(double time); + +/** Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer, measured in + * 1 / frequency seconds. To get the frequency, call @ref + * glfwGetTimerFrequency. + * + * Returns: The value of the timer, or zero if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref time + * @sa @ref glfwGetTimerFrequency + * + * Since: Added in version 3.2. + * + * Ingroup: input + */ +ulong glfwGetTimerValue(); + +/** Returns the frequency, in Hz, of the raw timer. + * + * This function returns the frequency, in Hz, of the raw timer. + * + * Returns: The frequency of the timer, in Hz, or zero if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref time + * @sa @ref glfwGetTimerValue + * + * Since: Added in version 3.2. + * + * Ingroup: input + */ +ulong glfwGetTimerFrequency(); + +/** Makes the context of the specified window current for the calling + * thread. + * + * This function makes the OpenGL or OpenGL ES context of the specified window + * current on the calling thread. A context must only be made current on + * a single thread at a time and each thread can have only a single current + * context at a time. + * + * When moving a context between threads, you must make it non-current on the + * old thread before making it current on the new one. + * + * By default, making a context non-current implicitly forces a pipeline flush. + * On machines that support `GL_KHR_context_flush_control`, you can control + * whether a context performs this flush by setting the + * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) + * hint. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * Params: + * window = The window whose context to make current, or `null` to + * detach the current context. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref context_current + * @sa @ref glfwGetCurrentContext + * + * Since: Added in version 3.0. + * + * Ingroup: context + */ +void glfwMakeContextCurrent(GLFWwindow* window); + +/** Returns the window whose context is current on the calling thread. + * + * This function returns the window whose OpenGL or OpenGL ES context is + * current on the calling thread. + * + * Returns: The window whose context is current, or `null` if no window's + * context is current. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref context_current + * @sa @ref glfwMakeContextCurrent + * + * Since: Added in version 3.0. + * + * Ingroup: context + */ +GLFWwindow* glfwGetCurrentContext(); + +/** Swaps the front and back buffers of the specified window. + * + * This function swaps the front and back buffers of the specified window when + * rendering with OpenGL or OpenGL ES. If the swap interval is greater than + * zero, the GPU driver waits the specified number of screen updates before + * swapping the buffers. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see `vkQueuePresentKHR` instead. + * + * Params: + * window = The window whose buffers to swap. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark __EGL:__ The context of the specified window must be current on the + * calling thread. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref buffer_swap + * @sa @ref glfwSwapInterval + * + * Since: Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * Ingroup: window + */ +void glfwSwapBuffers(GLFWwindow* window); + +/** Sets the swap interval for the current context. + * + * This function sets the swap interval for the current OpenGL or OpenGL ES + * context, i.e. the number of screen updates to wait from the time @ref + * glfwSwapBuffers was called before swapping the buffers and returning. This + * is sometimes called _vertical synchronization_, _vertical retrace + * synchronization_ or just _vsync_. + * + * A context that supports either of the `WGL_EXT_swap_control_tear` and + * `GLX_EXT_swap_control_tear` extensions also accepts _negative_ swap + * intervals, which allows the driver to swap immediately even if a frame + * arrives a little bit late. You can check for these extensions with @ref + * glfwExtensionSupported. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see the present mode of your swapchain instead. + * + * Params: + * interval = The minimum number of screen updates to wait for + * until the buffers are swapped by @ref glfwSwapBuffers. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark This function is not called during context creation, leaving the + * swap interval set to whatever is the default on that platform. This is done + * because some swap interval extensions used by GLFW do not allow the swap + * interval to be reset to zero once it has been set to a non-zero value. + * + * @remark Some GPU drivers do not honor the requested swap interval, either + * because of a user setting that overrides the application's request or due to + * bugs in the driver. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref buffer_swap + * @sa @ref glfwSwapBuffers + * + * Since: Added in version 1.0. + * + * Ingroup: context + */ +void glfwSwapInterval(int interval); + +/** Returns whether the specified extension is available. + * + * This function returns whether the specified + * [API extension](@ref context_glext) is supported by the current OpenGL or + * OpenGL ES context. It searches both for client API extension and context + * creation API extensions. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * As this functions retrieves and searches one or more extension strings each + * call, it is recommended that you cache its results if it is going to be used + * frequently. The extension strings will not change during the lifetime of + * a context, so there is no danger in doing this. + * + * This function does not apply to Vulkan. If you are using Vulkan, see @ref + * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` + * and `vkEnumerateDeviceExtensionProperties` instead. + * + * Params: + * extension = The ASCII encoded name of the extension. + * Returns: `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` + * otherwise. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref + * GLFW_PLATFORM_ERROR. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref context_glext + * @sa @ref glfwGetProcAddress + * + * Since: Added in version 1.0. + * + * Ingroup: context + */ +int glfwExtensionSupported(const(char)* extension); + +/** Returns the address of the specified function for the current + * context. + * + * This function returns the address of the specified OpenGL or OpenGL ES + * [core or extension function](@ref context_glext), if it is supported + * by the current context. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and + * `vkGetDeviceProcAddr` instead. + * + * Params: + * procname = The ASCII encoded name of the function. + * Returns: The address of the function, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark The address of a given function is not guaranteed to be the same + * between contexts. + * + * @remark This function may return a non-`null` address despite the + * associated version or extension not being available. Always check the + * context version or extension string first. + * + * Pointer_lifetime: The returned function pointer is valid until the context + * is destroyed or the library is terminated. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref context_glext + * @sa @ref glfwExtensionSupported + * + * Since: Added in version 1.0. + * + * Ingroup: context + */ +GLFWglproc glfwGetProcAddress(const(char)* procname); + +/** Returns whether the Vulkan loader and an ICD have been found. + * + * This function returns whether the Vulkan loader and any minimally functional + * ICD have been found. + * + * The availability of a Vulkan loader and even an ICD does not by itself + * guarantee that surface creation or even instance creation is possible. + * For example, on Fermi systems Nvidia will install an ICD that provides no + * actual Vulkan support. Call @ref glfwGetRequiredInstanceExtensions to check + * whether the extensions necessary for Vulkan surface creation are available + * and @ref glfwGetPhysicalDevicePresentationSupport to check whether a queue + * family of a physical device supports image presentation. + * + * Returns: `GLFW_TRUE` if Vulkan is minimally available, or `GLFW_FALSE` + * otherwise. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref vulkan_support + * + * Since: Added in version 3.2. + * + * Ingroup: vulkan + */ +int glfwVulkanSupported(); + +/** Returns the Vulkan instance extensions required by GLFW. + * + * This function returns an array of names of Vulkan instance extensions required + * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the + * list will always contain `VK_KHR_surface`, so if you don't require any + * additional extensions you can pass this list directly to the + * `VkInstanceCreateInfo` struct. + * + * If Vulkan is not available on the machine, this function returns `null` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available. + * + * If Vulkan is available but no set of extensions allowing window surface + * creation was found, this function returns `null`. You may still use Vulkan + * for off-screen rendering and compute work. + * + * Params: + * count = Where to store the number of extensions in the returned + * array. This is set to zero if an error occurred. + * Returns: An array of ASCII encoded extension names, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @remark Additional extensions may be required by future versions of GLFW. + * You should check if any extensions you wish to enable are already in the + * returned array, as it is an error to specify an extension more than once in + * the `VkInstanceCreateInfo` struct. + * + * @remark @macos This function currently supports either the + * `VK_MVK_macos_surface` extension from MoltenVK or `VK_EXT_metal_surface` + * extension. + * + * Pointer_lifetime: The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * library is terminated. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref vulkan_ext + * @sa @ref glfwCreateWindowSurface + * + * Since: Added in version 3.2. + * + * Ingroup: vulkan + */ +const(char)** glfwGetRequiredInstanceExtensions(uint* count); + +version (VK_VERSION_1_0) { + +/** Returns the address of the specified Vulkan instance function. + * + * This function returns the address of the specified Vulkan core or extension + * function for the specified instance. If instance is set to `null` it can + * return any function exported from the Vulkan loader, including at least the + * following functions: + * + * - `vkEnumerateInstanceExtensionProperties` + * - `vkEnumerateInstanceLayerProperties` + * - `vkCreateInstance` + * - `vkGetInstanceProcAddr` + * + * If Vulkan is not available on the machine, this function returns `null` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available. + * + * This function is equivalent to calling `vkGetInstanceProcAddr` with + * a platform-specific query of the Vulkan loader as a fallback. + * + * Params: + * instance = The Vulkan instance to query, or `null` to retrieve + * functions related to instance creation. + * procname = The ASCII encoded name of the function. + * Returns: The address of the function, or `null` if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * Pointer_lifetime: The returned function pointer is valid until the library + * is terminated. + * + * Thread_Safety: This function may be called from any thread. + * + * @sa @ref vulkan_proc + * + * Since: Added in version 3.2. + * + * Ingroup: vulkan + */ +GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const(char)* procname); + +/** Returns whether the specified queue family can present images. + * + * This function returns whether the specified queue family of the specified + * physical device supports presentation to the platform GLFW was built for. + * + * If Vulkan or the required window surface creation instance extensions are + * not available on the machine, or if the specified instance was not created + * with the required extensions, this function returns `GLFW_FALSE` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available and @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * Params: + * instance = The instance that the physical device belongs to. + * device = The physical device that the queue family belongs to. + * queuefamily = The index of the queue family to query. + * Returns: `GLFW_TRUE` if the queue family supports presentation, or + * `GLFW_FALSE` otherwise. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @remark @macos This function currently always returns `GLFW_TRUE`, as the + * `VK_MVK_macos_surface` extension does not provide + * a `vkGetPhysicalDevice*PresentationSupport` type function. + * + * Thread_Safety: This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_present + * + * Since: Added in version 3.2. + * + * Ingroup: vulkan + */ +int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint queuefamily); + +/** Creates a Vulkan surface for the specified window. + * + * This function creates a Vulkan surface for the specified window. + * + * If the Vulkan loader or at least one minimally functional ICD were not found, + * this function returns `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref + * GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported to check whether + * Vulkan is at least minimally available. + * + * If the required window surface creation instance extensions are not + * available or if the specified instance was not created with these extensions + * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * The window surface cannot be shared with another API so the window must + * have been created with the [client api hint](@ref GLFW_CLIENT_API_attrib) + * set to `GLFW_NO_API` otherwise it generates a @ref GLFW_INVALID_VALUE error + * and returns `VK_ERROR_NATIVE_WINDOW_IN_USE_KHR`. + * + * The window surface must be destroyed before the specified Vulkan instance. + * It is the responsibility of the caller to destroy the window surface. GLFW + * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the + * surface. + * + * Params: + * instance = The Vulkan instance to create the surface in. + * window = The window to create the surface for. + * allocator = The allocator to use, or `null` to use the default + * allocator. + * surface = Where to store the handle of the surface. This is set + * to `VK_null_HANDLE` if an error occurred. + * Returns: `VK_SUCCESS` if successful, or a Vulkan error code if an + * [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE, @ref GLFW_PLATFORM_ERROR and @ref GLFW_INVALID_VALUE + * + * @remark If an error occurs before the creation call is made, GLFW returns + * the Vulkan error code most appropriate for the error. Appropriate use of + * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should + * eliminate almost all occurrences of these errors. + * + * @remark @macos This function currently only supports the + * `VK_MVK_macos_surface` extension from MoltenVK. + * + * @remark @macos This function creates and sets a `CAMetalLayer` instance for + * the window content view, which is required for MoltenVK to function. + * + * Thread_Safety: This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_surface + * @sa @ref glfwGetRequiredInstanceExtensions + * + * Since: Added in version 3.2. + * + * Ingroup: vulkan + */ +VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const(VkAllocationCallbacks)* allocator, VkSurfaceKHR* surface); + +} /*VK_VERSION_1_0*/ \ No newline at end of file diff --git a/source/glfw3/apinative.d b/source/glfw3/apinative.d new file mode 100644 index 0000000..f2c372b --- /dev/null +++ b/source/glfw3/apinative.d @@ -0,0 +1,473 @@ +/** + * The header of the native access functions, translated from `glfw3native.h` + * + * This is the header file of the native access functions. + */ +module glfw3.apinative; + +extern(C): @nogc: nothrow: __gshared: export: + +/************************************************************************* + * GLFW 3.3 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2018 Camilla Löwy + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +/** @defgroup native Native access + * Functions related to accessing native handles. + * + * **By using the native access functions you assert that you know what you're + * doing and how to fix problems caused by using them. If you don't, you + * shouldn't be using them.** + * + * Before the inclusion of @ref glfw3native.h, you may define zero or more + * window system API macro and zero or more context creation API macros. + * + * The chosen backends must match those the library was compiled for. Failure + * to do this will cause a link-time error. + * + * The available window API macros are: + * * `GLFW_EXPOSE_NATIVE_WIN32` + * * `GLFW_EXPOSE_NATIVE_COCOA` + * * `GLFW_EXPOSE_NATIVE_X11` + * * `GLFW_EXPOSE_NATIVE_WAYLAND` + * + * The available context API macros are: + * * `GLFW_EXPOSE_NATIVE_WGL` + * * `GLFW_EXPOSE_NATIVE_NSGL` + * * `GLFW_EXPOSE_NATIVE_GLX` + * * `GLFW_EXPOSE_NATIVE_EGL` + * * `GLFW_EXPOSE_NATIVE_OSMESA` + * + * These macros select which of the native access functions that are declared + * and which platform-specific headers to include. It is then up your (by + * definition platform-specific) code to handle which of these should be + * defined. + */ + +/************************************************************************* + * System headers and types + *************************************************************************/ + +// Omitted + +/************************************************************************* + * Functions + *************************************************************************/ + +version (GLFW_EXPOSE_NATIVE_WIN32) { +/** Returns the adapter device name of the specified monitor. + * + * Returns: The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) + * of the specified monitor, or `null` if an [error](@ref error_handling) + * occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.1. + * + * Ingroup: native + */ +const(char)* glfwGetWin32Adapter(GLFWmonitor* monitor); + +/** Returns the display device name of the specified monitor. + * + * Returns: The UTF-8 encoded display device name (for example + * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `null` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.1. + * + * Ingroup: native + */ +const(char)* glfwGetWin32Monitor(GLFWmonitor* monitor); + +/** Returns the `HWND` of the specified window. + * + * Returns: The `HWND` of the specified window, or `null` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +HWND glfwGetWin32Window(GLFWwindow* window); +} + +version (GLFW_EXPOSE_NATIVE_WGL) { +/** Returns the `HGLRC` of the specified window. + * + * Returns: The `HGLRC` of the specified window, or `null` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +HGLRC glfwGetWGLContext(GLFWwindow* window); +} + +version (GLFW_EXPOSE_NATIVE_COCOA) { +/** Returns the `CGDirectDisplayID` of the specified monitor. + * + * Returns: The `CGDirectDisplayID` of the specified monitor, or + * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.1. + * + * Ingroup: native + */ +CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); + +/** Returns the `NSWindow` of the specified window. + * + * Returns: The `NSWindow` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +id glfwGetCocoaWindow(GLFWwindow* window); +} + +version (GLFW_EXPOSE_NATIVE_NSGL) { +/** Returns the `NSOpenGLContext` of the specified window. + * + * Returns: The `NSOpenGLContext` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +id glfwGetNSGLContext(GLFWwindow* window); +} + +version (GLFW_EXPOSE_NATIVE_X11) { +/** Returns the `Display` used by GLFW. + * + * Returns: The `Display` used by GLFW, or `null` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +Display* glfwGetX11Display(); + +/** Returns the `RRCrtc` of the specified monitor. + * + * Returns: The `RRCrtc` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.1. + * + * Ingroup: native + */ +RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); + +/** Returns the `RROutput` of the specified monitor. + * + * Returns: The `RROutput` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.1. + * + * Ingroup: native + */ +RROutput glfwGetX11Monitor(GLFWmonitor* monitor); + +/** Returns the `Window` of the specified window. + * + * Returns: The `Window` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +Window glfwGetX11Window(GLFWwindow* window); + +/** Sets the current primary selection to the specified string. + * + * Params: + * string = A UTF-8 encoded string. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The specified string is copied before this function + * returns. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa glfwGetX11SelectionString + * @sa glfwSetClipboardString + * + * Since: Added in version 3.3. + * + * Ingroup: native + */ +void glfwSetX11SelectionString(const(char)* string_); + +/** Returns the contents of the current primary selection as a string. + * + * If the selection is empty or if its contents cannot be converted, `null` + * is returned and a @ref GLFW_FORMAT_UNAVAILABLE error is generated. + * + * Returns: The contents of the selection as a UTF-8 encoded string, or `null` + * if an [error](@ref error_handling) occurred. + * + * Errors: Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * Pointer_lifetime: The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetX11SelectionString or @ref glfwSetX11SelectionString, or until the + * library is terminated. + * + * Thread_Safety: This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa glfwSetX11SelectionString + * @sa glfwGetClipboardString + * + * Since: Added in version 3.3. + * + * Ingroup: native + */ +const(char)* glfwGetX11SelectionString(); +} + +version (GLFW_EXPOSE_NATIVE_GLX) { +/** Returns the `GLXContext` of the specified window. + * + * Returns: The `GLXContext` of the specified window, or `null` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +GLXContext glfwGetGLXContext(GLFWwindow* window); + +/** Returns the `GLXWindow` of the specified window. + * + * Returns: The `GLXWindow` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.2. + * + * Ingroup: native + */ +GLXWindow glfwGetGLXWindow(GLFWwindow* window); +} + +version (GLFW_EXPOSE_NATIVE_WAYLAND) { +/** Returns the `struct wl_display*` used by GLFW. + * + * Returns: The `struct wl_display*` used by GLFW, or `null` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.2. + * + * Ingroup: native + */ +wl_display* glfwGetWaylandDisplay(); + +/** Returns the `struct wl_output*` of the specified monitor. + * + * Returns: The `struct wl_output*` of the specified monitor, or `null` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.2. + * + * Ingroup: native + */ +wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); + +/** Returns the main `struct wl_surface*` of the specified window. + * + * Returns: The main `struct wl_surface*` of the specified window, or `null` if + * an [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.2. + * + * Ingroup: native + */ +wl_surface* glfwGetWaylandWindow(GLFWwindow* window); +} + +version (GLFW_EXPOSE_NATIVE_EGL) { +/** Returns the `EGLDisplay` used by GLFW. + * + * Returns: The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +EGLDisplay glfwGetEGLDisplay(); + +/** Returns the `EGLContext` of the specified window. + * + * Returns: The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +EGLContext glfwGetEGLContext(GLFWwindow* window); + +/** Returns the `EGLSurface` of the specified window. + * + * Returns: The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.0. + * + * Ingroup: native + */ +EGLSurface glfwGetEGLSurface(GLFWwindow* window); +} + +version (GLFW_EXPOSE_NATIVE_OSMESA) { +/** Retrieves the color buffer associated with the specified window. + * + * Params: + * window = The window whose color buffer to retrieve. + * width = Where to store the width of the color buffer, or `null`. + * height = Where to store the height of the color buffer, or `null`. + * format = Where to store the OSMesa pixel format of the color + * buffer, or `null`. + * buffer = Where to store the address of the color buffer, or + * `null`. + * Returns: `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.3. + * + * Ingroup: native + */ +int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height, int* format, void** buffer); + +/** Retrieves the depth buffer associated with the specified window. + * + * Params: + * window = The window whose depth buffer to retrieve. + * width = Where to store the width of the depth buffer, or `null`. + * height = Where to store the height of the depth buffer, or `null`. + * bytesPerValue = Where to store the number of bytes per depth + * buffer element, or `null`. + * buffer = Where to store the address of the depth buffer, or + * `null`. + * Returns: `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.3. + * + * Ingroup: native + */ +int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height, int* bytesPerValue, void** buffer); + +/** Returns the `OSMesaContext` of the specified window. + * + * Returns: The `OSMesaContext` of the specified window, or `null` if an + * [error](@ref error_handling) occurred. + * + * Thread_Safety: This function may be called from any thread. Access is not + * synchronized. + * + * Since: Added in version 3.3. + * + * Ingroup: native + */ +OSMesaContext glfwGetOSMesaContext(GLFWwindow* window); +} \ No newline at end of file diff --git a/source/glfw3/context.d b/source/glfw3/context.d new file mode 100644 index 0000000..550bbed --- /dev/null +++ b/source/glfw3/context.d @@ -0,0 +1,748 @@ +/// Translated from C to D +module context; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2016 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +import glfw3.internal; + +import core.stdc.assert_; +import core.stdc.stdio; +import core.stdc.string; +import core.stdc.limits; +import core.stdc.stdio; + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Checks whether the desired context attributes are valid +// +// This function checks things like whether the specified client API version +// exists and whether all relevant options have supported and non-conflicting +// values +// +GLFWbool _glfwIsValidContextConfig(const(_GLFWctxconfig)* ctxconfig) { + if (ctxconfig.share) + { + if (ctxconfig.client == GLFW_NO_API || + ctxconfig.share.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); + return GLFW_FALSE; + } + } + + if (ctxconfig.source != GLFW_NATIVE_CONTEXT_API && + ctxconfig.source != GLFW_EGL_CONTEXT_API && + ctxconfig.source != GLFW_OSMESA_CONTEXT_API) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context creation API 0x%08X", + ctxconfig.source); + return GLFW_FALSE; + } + + if (ctxconfig.client != GLFW_NO_API && + ctxconfig.client != GLFW_OPENGL_API && + ctxconfig.client != GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid client API 0x%08X", + ctxconfig.client); + return GLFW_FALSE; + } + + if (ctxconfig.client == GLFW_OPENGL_API) + { + if ((ctxconfig.major < 1 || ctxconfig.minor < 0) || + (ctxconfig.major == 1 && ctxconfig.minor > 5) || + (ctxconfig.major == 2 && ctxconfig.minor > 1) || + (ctxconfig.major == 3 && ctxconfig.minor > 3)) + { + // OpenGL 1.0 is the smallest valid version + // OpenGL 1.x series ended with version 1.5 + // OpenGL 2.x series ended with version 2.1 + // OpenGL 3.x series ended with version 3.3 + // For now, let everything else through + + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid OpenGL version %i.%i", + ctxconfig.major, ctxconfig.minor); + return GLFW_FALSE; + } + + if (ctxconfig.profile) + { + if (ctxconfig.profile != GLFW_OPENGL_CORE_PROFILE && + ctxconfig.profile != GLFW_OPENGL_COMPAT_PROFILE) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid OpenGL profile 0x%08X", + ctxconfig.profile); + return GLFW_FALSE; + } + + if (ctxconfig.major <= 2 || + (ctxconfig.major == 3 && ctxconfig.minor < 2)) + { + // Desktop OpenGL context profiles are only defined for version 3.2 + // and above + + _glfwInputError(GLFW_INVALID_VALUE, + "Context profiles are only defined for OpenGL version 3.2 and above"); + return GLFW_FALSE; + } + } + + if (ctxconfig.forward && ctxconfig.major <= 2) + { + // Forward-compatible contexts are only defined for OpenGL version 3.0 and above + _glfwInputError(GLFW_INVALID_VALUE, + "Forward-compatibility is only defined for OpenGL version 3.0 and above"); + return GLFW_FALSE; + } + } + else if (ctxconfig.client == GLFW_OPENGL_ES_API) + { + if (ctxconfig.major < 1 || ctxconfig.minor < 0 || + (ctxconfig.major == 1 && ctxconfig.minor > 1) || + (ctxconfig.major == 2 && ctxconfig.minor > 0)) + { + // OpenGL ES 1.0 is the smallest valid version + // OpenGL ES 1.x series ended with version 1.1 + // OpenGL ES 2.x series ended with version 2.0 + // For now, let everything else through + + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid OpenGL ES version %i.%i", + ctxconfig.major, ctxconfig.minor); + return GLFW_FALSE; + } + } + + if (ctxconfig.robustness) + { + if (ctxconfig.robustness != GLFW_NO_RESET_NOTIFICATION && + ctxconfig.robustness != GLFW_LOSE_CONTEXT_ON_RESET) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context robustness mode 0x%08X", + ctxconfig.robustness); + return GLFW_FALSE; + } + } + + if (ctxconfig.release) + { + if (ctxconfig.release != GLFW_RELEASE_BEHAVIOR_NONE && + ctxconfig.release != GLFW_RELEASE_BEHAVIOR_FLUSH) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context release behavior 0x%08X", + ctxconfig.release); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + +// Chooses the framebuffer config that best matches the desired one +// +const(_GLFWfbconfig)* _glfwChooseFBConfig(const(_GLFWfbconfig)* desired, const(_GLFWfbconfig)* alternatives, uint count) { + uint i; + uint missing;uint leastMissing = UINT_MAX; + uint colorDiff;uint leastColorDiff = UINT_MAX; + uint extraDiff;uint leastExtraDiff = UINT_MAX; + const(_GLFWfbconfig)* current; + const(_GLFWfbconfig)* closest = null; + + for (i = 0; i < count; i++) + { + current = alternatives + i; + + if (desired.stereo > 0 && current.stereo == 0) + { + // Stereo is a hard constraint + continue; + } + + if (desired.doublebuffer != current.doublebuffer) + { + // Double buffering is a hard constraint + continue; + } + + // Count number of missing buffers + { + missing = 0; + + if (desired.alphaBits > 0 && current.alphaBits == 0) + missing++; + + if (desired.depthBits > 0 && current.depthBits == 0) + missing++; + + if (desired.stencilBits > 0 && current.stencilBits == 0) + missing++; + + if (desired.auxBuffers > 0 && + current.auxBuffers < desired.auxBuffers) + { + missing += desired.auxBuffers - current.auxBuffers; + } + + if (desired.samples > 0 && current.samples == 0) + { + // Technically, several multisampling buffers could be + // involved, but that's a lower level implementation detail and + // not important to us here, so we count them as one + missing++; + } + + if (desired.transparent != current.transparent) + missing++; + } + + // These polynomials make many small channel size differences matter + // less than one large channel size difference + + // Calculate color channel size difference value + { + colorDiff = 0; + + if (desired.redBits != GLFW_DONT_CARE) + { + colorDiff += (desired.redBits - current.redBits) * + (desired.redBits - current.redBits); + } + + if (desired.greenBits != GLFW_DONT_CARE) + { + colorDiff += (desired.greenBits - current.greenBits) * + (desired.greenBits - current.greenBits); + } + + if (desired.blueBits != GLFW_DONT_CARE) + { + colorDiff += (desired.blueBits - current.blueBits) * + (desired.blueBits - current.blueBits); + } + } + + // Calculate non-color channel size difference value + { + extraDiff = 0; + + if (desired.alphaBits != GLFW_DONT_CARE) + { + extraDiff += (desired.alphaBits - current.alphaBits) * + (desired.alphaBits - current.alphaBits); + } + + if (desired.depthBits != GLFW_DONT_CARE) + { + extraDiff += (desired.depthBits - current.depthBits) * + (desired.depthBits - current.depthBits); + } + + if (desired.stencilBits != GLFW_DONT_CARE) + { + extraDiff += (desired.stencilBits - current.stencilBits) * + (desired.stencilBits - current.stencilBits); + } + + if (desired.accumRedBits != GLFW_DONT_CARE) + { + extraDiff += (desired.accumRedBits - current.accumRedBits) * + (desired.accumRedBits - current.accumRedBits); + } + + if (desired.accumGreenBits != GLFW_DONT_CARE) + { + extraDiff += (desired.accumGreenBits - current.accumGreenBits) * + (desired.accumGreenBits - current.accumGreenBits); + } + + if (desired.accumBlueBits != GLFW_DONT_CARE) + { + extraDiff += (desired.accumBlueBits - current.accumBlueBits) * + (desired.accumBlueBits - current.accumBlueBits); + } + + if (desired.accumAlphaBits != GLFW_DONT_CARE) + { + extraDiff += (desired.accumAlphaBits - current.accumAlphaBits) * + (desired.accumAlphaBits - current.accumAlphaBits); + } + + if (desired.samples != GLFW_DONT_CARE) + { + extraDiff += (desired.samples - current.samples) * + (desired.samples - current.samples); + } + + if (desired.sRGB && !current.sRGB) + extraDiff++; + } + + // Figure out if the current one is better than the best one found so far + // Least number of missing buffers is the most important heuristic, + // then color buffer size match and lastly size match for other buffers + + if (missing < leastMissing) + closest = current; + else if (missing == leastMissing) + { + if ((colorDiff < leastColorDiff) || + (colorDiff == leastColorDiff && extraDiff < leastExtraDiff)) + { + closest = current; + } + } + + if (current == closest) + { + leastMissing = missing; + leastColorDiff = colorDiff; + leastExtraDiff = extraDiff; + } + } + + return closest; +} + +// Retrieves the attributes of the current context +// +GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig) { + int i; + _GLFWwindow* previous; + const(char)* version_; + static immutable char*[4] prefixes = [ + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + null + ]; + + window.context.source = ctxconfig.source; + window.context.client = GLFW_OPENGL_API; + + previous = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); + glfwMakeContextCurrent(cast(GLFWwindow*) window); + + window.context.GetIntegerv = cast(PFNGLGETINTEGERVPROC) + window.context.getProcAddress("glGetIntegerv"); + window.context.GetString = cast(PFNGLGETSTRINGPROC) + window.context.getProcAddress("glGetString"); + if (!window.context.GetIntegerv || !window.context.GetString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); + glfwMakeContextCurrent(cast(GLFWwindow*) previous); + return GLFW_FALSE; + } + + version_ = cast(const(char)*) window.context.GetString(GL_VERSION); + if (!version_) + { + if (ctxconfig.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OpenGL version string retrieval is broken"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OpenGL ES version string retrieval is broken"); + } + + glfwMakeContextCurrent(cast(GLFWwindow*) previous); + return GLFW_FALSE; + } + + for (i = 0; prefixes[i]; i++) + { + const(size_t) length = strlen(prefixes[i]); + + if (strncmp(version_, prefixes[i], length) == 0) + { + version_ += length; + window.context.client = GLFW_OPENGL_ES_API; + break; + } + } + + if (!sscanf(version_, "%d.%d.%d", + &window.context.major, + &window.context.minor, + &window.context.revision)) + { + if (window.context.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "No version found in OpenGL version string"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "No version found in OpenGL ES version string"); + } + + glfwMakeContextCurrent(cast(GLFWwindow*) previous); + return GLFW_FALSE; + } + + if (window.context.major < ctxconfig.major || + (window.context.major == ctxconfig.major && + window.context.minor < ctxconfig.minor)) + { + // The desired OpenGL version is greater than the actual version + // This only happens if the machine lacks {GLX|WGL}_ARB_create_context + // /and/ the user has requested an OpenGL version greater than 1.0 + + // For API consistency, we emulate the behavior of the + // {GLX|WGL}_ARB_create_context extension and fail here + + if (window.context.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "Requested OpenGL version %i.%i, got version %i.%i", + ctxconfig.major, ctxconfig.minor, + window.context.major, window.context.minor); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "Requested OpenGL ES version %i.%i, got version %i.%i", + ctxconfig.major, ctxconfig.minor, + window.context.major, window.context.minor); + } + + glfwMakeContextCurrent(cast(GLFWwindow*) previous); + return GLFW_FALSE; + } + + if (window.context.major >= 3) + { + // OpenGL 3.0+ uses a different function for extension string retrieval + // We cache it here instead of in glfwExtensionSupported mostly to alert + // users as early as possible that their build may be broken + + window.context.GetStringi = cast(PFNGLGETSTRINGIPROC) + window.context.getProcAddress("glGetStringi"); + if (!window.context.GetStringi) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Entry point retrieval is broken"); + glfwMakeContextCurrent(cast(GLFWwindow*) previous); + return GLFW_FALSE; + } + } + + if (window.context.client == GLFW_OPENGL_API) + { + // Read back context flags (OpenGL 3.0 and above) + if (window.context.major >= 3) + { + GLint flags; + window.context.GetIntegerv(GL_CONTEXT_FLAGS, &flags); + + if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + window.context.forward = GLFW_TRUE; + + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + window.context.debug_ = GLFW_TRUE; + else if (glfwExtensionSupported("GL_ARB_debug_output") && + ctxconfig.debug_) + { + // HACK: This is a workaround for older drivers (pre KHR_debug) + // not setting the debug bit in the context flags for + // debug contexts + window.context.debug_ = GLFW_TRUE; + } + + if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR) + window.context.noerror = GLFW_TRUE; + } + + // Read back OpenGL context profile (OpenGL 3.2 and above) + if (window.context.major >= 4 || + (window.context.major == 3 && window.context.minor >= 2)) + { + GLint mask; + window.context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); + + if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + window.context.profile = GLFW_OPENGL_COMPAT_PROFILE; + else if (mask & GL_CONTEXT_CORE_PROFILE_BIT) + window.context.profile = GLFW_OPENGL_CORE_PROFILE; + else if (glfwExtensionSupported("GL_ARB_compatibility")) + { + // HACK: This is a workaround for the compatibility profile bit + // not being set in the context flags if an OpenGL 3.2+ + // context was created without having requested a specific + // version + window.context.profile = GLFW_OPENGL_COMPAT_PROFILE; + } + } + + // Read back robustness strategy + if (glfwExtensionSupported("GL_ARB_robustness")) + { + // NOTE: We avoid using the context flags for detection, as they are + // only present from 3.0 while the extension applies from 1.1 + + GLint strategy; + window.context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, + &strategy); + + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + window.context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; + else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + window.context.robustness = GLFW_NO_RESET_NOTIFICATION; + } + } + else + { + // Read back robustness strategy + if (glfwExtensionSupported("GL_EXT_robustness")) + { + // NOTE: The values of these constants match those of the OpenGL ARB + // one, so we can reuse them here + + GLint strategy; + window.context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, + &strategy); + + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + window.context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; + else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + window.context.robustness = GLFW_NO_RESET_NOTIFICATION; + } + } + + if (glfwExtensionSupported("GL_KHR_context_flush_control")) + { + GLint behavior; + window.context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior); + + if (behavior == GL_NONE) + window.context.release = GLFW_RELEASE_BEHAVIOR_NONE; + else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH) + window.context.release = GLFW_RELEASE_BEHAVIOR_FLUSH; + } + + // Clearing the front buffer to black to avoid garbage pixels left over from + // previous uses of our bit of VRAM + { + PFNGLCLEARPROC glClear = cast(PFNGLCLEARPROC) + window.context.getProcAddress("glClear"); + glClear(GL_COLOR_BUFFER_BIT); + window.context.swapBuffers(window); + } + + glfwMakeContextCurrent(cast(GLFWwindow*) previous); + return GLFW_TRUE; +} + +// Searches an extension string for the specified extension +// +GLFWbool _glfwStringInExtensionString(const(char)* string, const(char)* extensions) { + const(char)* start = extensions; + + for (;;) + { + const(char)* where; + const(char)* terminator; + + where = strstr(start, string); + if (!where) + return GLFW_FALSE; + + terminator = where + strlen(string); + if (where == start || *(where - 1) == ' ') + { + if (*terminator == ' ' || *terminator == '\0') + break; + } + + start = terminator; + } + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +void glfwMakeContextCurrent(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + _GLFWwindow* previous = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); + + mixin(_GLFW_REQUIRE_INIT); + + if (window && window.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, + "Cannot make current with a window that has no OpenGL or OpenGL ES context"); + return; + } + + if (previous) + { + if (!window || window.context.source != previous.context.source) + previous.context.makeCurrent(null); + } + + if (window) + window.context.makeCurrent(window); +} + +GLFWwindow* glfwGetCurrentContext() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return cast(GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); +} + +void glfwSwapBuffers(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + if (window.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, + "Cannot swap buffers of a window that has no OpenGL or OpenGL ES context"); + return; + } + + window.context.swapBuffers(window); +} + +void glfwSwapInterval(int interval) { + _GLFWwindow* window; + + mixin(_GLFW_REQUIRE_INIT); + + window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, + "Cannot set swap interval without a current OpenGL or OpenGL ES context"); + return; + } + + window.context.swapInterval(interval); +} + +int glfwExtensionSupported(const(char)* extension) { + _GLFWwindow* window; + assert(extension != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); + + window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, + "Cannot query extension without a current OpenGL or OpenGL ES context"); + return GLFW_FALSE; + } + + if (*extension == '\0') + { + _glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string"); + return GLFW_FALSE; + } + + if (window.context.major >= 3) + { + int i; + GLint count; + + // Check if extension is in the modern OpenGL extensions string list + + window.context.GetIntegerv(GL_NUM_EXTENSIONS, &count); + + for (i = 0; i < count; i++) + { + const(char)* en = cast(const(char)*) + window.context.GetStringi(GL_EXTENSIONS, i); + if (!en) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Extension string retrieval is broken"); + return GLFW_FALSE; + } + + if (strcmp(en, extension) == 0) + return GLFW_TRUE; + } + } + else + { + // Check if extension is in the old style OpenGL extensions string + + const(char)* extensions = cast(const(char)*) + window.context.GetString(GL_EXTENSIONS); + if (!extensions) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Extension string retrieval is broken"); + return GLFW_FALSE; + } + + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + // Check if extension is in the platform-specific string + return window.context.extensionSupported(extension); +} + +GLFWglproc glfwGetProcAddress(const(char)* procname) { + _GLFWwindow* window; + assert(procname != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, + "Cannot query entry point without a current OpenGL or OpenGL ES context"); + return null; + } + + return window.context.getProcAddress(procname); +} \ No newline at end of file diff --git a/source/glfw3/directinput8.d b/source/glfw3/directinput8.d new file mode 100644 index 0000000..a80dfa7 --- /dev/null +++ b/source/glfw3/directinput8.d @@ -0,0 +1,1141 @@ +/// Partial translation of dinput.h +/// +/// Assumes direct input version 8, so old versions of interfaces are not included +/// Also assumes `UNICODE`, so only the variants that end in W (using wchar) instead of A (using ascii char). +module glfw3.directinput8; + +extern(Windows): @nogc: nothrow: __gshared: + +import core.sys.windows.windows; +import core.sys.windows.objbase; + +alias IDirectInputDevice8 = IDirectInputDevice8W; +enum DIRECTINPUT_VERSION = 0x0800; + +struct _DIDATAFORMAT { + DWORD dwSize; + DWORD dwObjSize; + DWORD dwFlags; + DWORD dwDataSize; + DWORD dwNumObjs; + LPDIOBJECTDATAFORMAT rgodf; +}alias _DIDATAFORMAT DIDATAFORMAT;alias _DIDATAFORMAT* LPDIDATAFORMAT; +alias const(DIDATAFORMAT)* LPCDIDATAFORMAT; + +struct DIDEVICEOBJECTINSTANCEW { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR[MAX_PATH] tszName; + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +} +alias DIDEVICEOBJECTINSTANCEW* LPDIDEVICEOBJECTINSTANCEW; +alias const(DIDEVICEOBJECTINSTANCEW)* LPCDIDEVICEOBJECTINSTANCEW; + +enum DIDOI_FFACTUATOR = 0x00000001; +enum DIDOI_FFEFFECTTRIGGER = 0x00000002; +enum DIDOI_POLLED = 0x00008000; +enum DIDOI_ASPECTPOSITION = 0x00000100; +enum DIDOI_ASPECTVELOCITY = 0x00000200; +enum DIDOI_ASPECTACCEL = 0x00000300; +enum DIDOI_ASPECTFORCE = 0x00000400; +enum DIDOI_ASPECTMASK = 0x00000F00; +enum DIDOI_GUIDISUSAGE = 0x00010000; + +struct DIPROPHEADER { + DWORD dwSize; + DWORD dwHeaderSize; + DWORD dwObj; + DWORD dwHow; +} +alias DIPROPHEADER* LPDIPROPHEADER; +alias const(DIPROPHEADER)* LPCDIPROPHEADER; + +enum DIPH_DEVICE = 0; +enum DIPH_BYOFFSET = 1; +enum DIPH_BYID = 2; +enum DIPH_BYUSAGE = 3; + +struct DIPROPDWORD { + DIPROPHEADER diph; + DWORD dwData; +} +alias DIPROPDWORD* LPDIPROPDWORD; +alias const(DIPROPDWORD)* LPCDIPROPDWORD; + +struct DIPROPRANGE { + DIPROPHEADER diph; + LONG lMin; + LONG lMax; +} +alias DIPROPRANGE* LPDIPROPRANGE; +alias const(DIPROPRANGE)* LPCDIPROPRANGE; + +enum DIPROPRANGE_NOMIN = cast(LONG) 0x80000000; +enum DIPROPRANGE_NOMAX = cast(LONG) 0x7FFFFFFF; + +struct DIPROPCAL { + DIPROPHEADER diph; + LONG lMin; + LONG lCenter; + LONG lMax; +} +alias DIPROPCAL* LPDIPROPCAL; +alias const(DIPROPCAL)* LPCDIPROPCAL; + +struct DIPROPCALPOV { + DIPROPHEADER diph; + LONG[5] lMin; + LONG[5] lMax; +} +alias DIPROPCALPOV* LPDIPROPCALPOV; +alias const(DIPROPCALPOV)* LPCDIPROPCALPOV; + +struct DIPROPGUIDANDPATH { + DIPROPHEADER diph; + GUID guidClass; + WCHAR[MAX_PATH] wszPath; +} +alias DIPROPGUIDANDPATH* LPDIPROPGUIDANDPATH; +alias const(DIPROPGUIDANDPATH)* LPCDIPROPGUIDANDPATH; + +struct DIPROPSTRING { + DIPROPHEADER diph; + WCHAR[MAX_PATH] wsz; +} +alias DIPROPSTRING* LPDIPROPSTRING; +alias const(DIPROPSTRING)* LPCDIPROPSTRING; + +struct DIPROPPOINTER { + DIPROPHEADER diph; + UINT_PTR uData; +}/+alias DIPROPPOINTER DIPROPPOINTER;+/alias DIPROPPOINTER* LPDIPROPPOINTER; +alias const(DIPROPPOINTER)* LPCDIPROPPOINTER; + +auto MAKEDIPROP(int prop) {return cast(REFGUID) prop;} + +enum DIPROP_BUFFERSIZE = MAKEDIPROP(1); +enum DIPROP_AXISMODE = MAKEDIPROP(2); + +enum DIPROPAXISMODE_ABS = 0; +enum DIPROPAXISMODE_REL = 1; + +enum DIPROP_GRANULARITY = MAKEDIPROP(3); +enum DIPROP_RANGE = MAKEDIPROP(4); +enum DIPROP_DEADZONE = MAKEDIPROP(5); +enum DIPROP_SATURATION = MAKEDIPROP(6); +enum DIPROP_FFGAIN = MAKEDIPROP(7); +enum DIPROP_FFLOAD = MAKEDIPROP(8); +enum DIPROP_AUTOCENTER = MAKEDIPROP(9); + +enum DIPROPAUTOCENTER_OFF = 0; +enum DIPROPAUTOCENTER_ON = 1; + +enum DIPROP_CALIBRATIONMODE = MAKEDIPROP(10); + +enum DIPROPCALIBRATIONMODE_COOKED = 0; +enum DIPROPCALIBRATIONMODE_RAW = 1; + +enum DIPROP_CALIBRATION = MAKEDIPROP(11); +enum DIPROP_GUIDANDPATH = MAKEDIPROP(12); +enum DIPROP_INSTANCENAME = MAKEDIPROP(13); +enum DIPROP_PRODUCTNAME = MAKEDIPROP(14); + +enum DIPROP_JOYSTICKID = MAKEDIPROP(15); +enum DIPROP_GETPORTDISPLAYNAME = MAKEDIPROP(16); + +enum DIPROP_PHYSICALRANGE = MAKEDIPROP(18); +enum DIPROP_LOGICALRANGE = MAKEDIPROP(19); + +enum DIPROP_KEYNAME = MAKEDIPROP(20); +enum DIPROP_CPOINTS = MAKEDIPROP(21); +enum DIPROP_APPDATA = MAKEDIPROP(22); +enum DIPROP_SCANCODE = MAKEDIPROP(23); +enum DIPROP_VIDPID = MAKEDIPROP(24); +enum DIPROP_USERNAME = MAKEDIPROP(25); +enum DIPROP_TYPENAME = MAKEDIPROP(26); + +enum MAXCPOINTSNUM = 8; + +struct _CPOINT { + LONG lP; + DWORD dwLog; +}alias _CPOINT CPOINT;alias _CPOINT* PCPOINT; + +struct DIPROPCPOINTS { + DIPROPHEADER diph; + DWORD dwCPointsNum; + CPOINT[MAXCPOINTSNUM] cp; +}/+alias DIPROPCPOINTS DIPROPCPOINTS;+/alias DIPROPCPOINTS* LPDIPROPCPOINTS; +alias const(DIPROPCPOINTS)* LPCDIPROPCPOINTS; + +/* Device FF flags */ +enum DISFFC_RESET = 0x00000001; +enum DISFFC_STOPALL = 0x00000002; +enum DISFFC_PAUSE = 0x00000004; +enum DISFFC_CONTINUE = 0x00000008; +enum DISFFC_SETACTUATORSON = 0x00000010; +enum DISFFC_SETACTUATORSOFF = 0x00000020; + +enum DIGFFS_EMPTY = 0x00000001; +enum DIGFFS_STOPPED = 0x00000002; +enum DIGFFS_PAUSED = 0x00000004; +enum DIGFFS_ACTUATORSON = 0x00000010; +enum DIGFFS_ACTUATORSOFF = 0x00000020; +enum DIGFFS_POWERON = 0x00000040; +enum DIGFFS_POWEROFF = 0x00000080; +enum DIGFFS_SAFETYSWITCHON = 0x00000100; +enum DIGFFS_SAFETYSWITCHOFF = 0x00000200; +enum DIGFFS_USERFFSWITCHON = 0x00000400; +enum DIGFFS_USERFFSWITCHOFF = 0x00000800; +enum DIGFFS_DEVICELOST = 0x80000000; + +/* Effect flags */ +enum DIEFT_ALL = 0x00000000; + +enum DIEFT_CONSTANTFORCE = 0x00000001; +enum DIEFT_RAMPFORCE = 0x00000002; +enum DIEFT_PERIODIC = 0x00000003; +enum DIEFT_CONDITION = 0x00000004; +enum DIEFT_CUSTOMFORCE = 0x00000005; +enum DIEFT_HARDWARE = 0x000000FF; +enum DIEFT_FFATTACK = 0x00000200; +enum DIEFT_FFFADE = 0x00000400; +enum DIEFT_SATURATION = 0x00000800; +enum DIEFT_POSNEGCOEFFICIENTS = 0x00001000; +enum DIEFT_POSNEGSATURATION = 0x00002000; +enum DIEFT_DEADBAND = 0x00004000; +enum DIEFT_STARTDELAY = 0x00008000; +alias DIEFT_GETTYPE = LOBYTE; //auto DIEFT_GETTYPE(T)(T n) {return LOBYTE(n);} + +enum DIEFF_OBJECTIDS = 0x00000001; +enum DIEFF_OBJECTOFFSETS = 0x00000002; +enum DIEFF_CARTESIAN = 0x00000010; +enum DIEFF_POLAR = 0x00000020; +enum DIEFF_SPHERICAL = 0x00000040; + +enum DIEP_DURATION = 0x00000001; +enum DIEP_SAMPLEPERIOD = 0x00000002; +enum DIEP_GAIN = 0x00000004; +enum DIEP_TRIGGERBUTTON = 0x00000008; +enum DIEP_TRIGGERREPEATINTERVAL = 0x00000010; +enum DIEP_AXES = 0x00000020; +enum DIEP_DIRECTION = 0x00000040; +enum DIEP_ENVELOPE = 0x00000080; +enum DIEP_TYPESPECIFICPARAMS = 0x00000100; +enum DIEP_STARTDELAY = 0x00000200; +enum DIEP_ALLPARAMS_DX5 = 0x000001FF; +enum DIEP_ALLPARAMS = 0x000003FF; +enum DIEP_START = 0x20000000; +enum DIEP_NORESTART = 0x40000000; +enum DIEP_NODOWNLOAD = 0x80000000; +enum DIEB_NOTRIGGER = 0xFFFFFFFF; + +enum DIES_SOLO = 0x00000001; +enum DIES_NODOWNLOAD = 0x80000000; + +enum DIEGES_PLAYING = 0x00000001; +enum DIEGES_EMULATED = 0x00000002; + +enum DI_DEGREES = 100; +enum DI_FFNOMINALMAX = 10000; +enum DI_SECONDS = 1000000; + +struct DICONSTANTFORCE { + LONG lMagnitude; +} +alias DICONSTANTFORCE* LPDICONSTANTFORCE; +alias const(DICONSTANTFORCE)* LPCDICONSTANTFORCE; + +struct DIRAMPFORCE { + LONG lStart; + LONG lEnd; +} +alias DIRAMPFORCE* LPDIRAMPFORCE; +alias const(DIRAMPFORCE)* LPCDIRAMPFORCE; + +struct DIPERIODIC { + DWORD dwMagnitude; + LONG lOffset; + DWORD dwPhase; + DWORD dwPeriod; +} +alias DIPERIODIC* LPDIPERIODIC; +alias const(DIPERIODIC)* LPCDIPERIODIC; + +struct DICONDITION { + LONG lOffset; + LONG lPositiveCoefficient; + LONG lNegativeCoefficient; + DWORD dwPositiveSaturation; + DWORD dwNegativeSaturation; + LONG lDeadBand; +} +alias DICONDITION* LPDICONDITION; +alias const(DICONDITION)* LPCDICONDITION; + +struct DICUSTOMFORCE { + DWORD cChannels; + DWORD dwSamplePeriod; + DWORD cSamples; + LPLONG rglForceData; +} +alias DICUSTOMFORCE* LPDICUSTOMFORCE; +alias const(DICUSTOMFORCE)* LPCDICUSTOMFORCE; + +struct DIENVELOPE { + DWORD dwSize; + DWORD dwAttackLevel; + DWORD dwAttackTime; + DWORD dwFadeLevel; + DWORD dwFadeTime; +} +alias DIENVELOPE* LPDIENVELOPE; +alias const(DIENVELOPE)* LPCDIENVELOPE; + +struct DIEFFECT_DX5 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDuration; + DWORD dwSamplePeriod; + DWORD dwGain; + DWORD dwTriggerButton; + DWORD dwTriggerRepeatInterval; + DWORD cAxes; + LPDWORD rgdwAxes; + LPLONG rglDirection; + LPDIENVELOPE lpEnvelope; + DWORD cbTypeSpecificParams; + LPVOID lpvTypeSpecificParams; +} +alias DIEFFECT_DX5* LPDIEFFECT_DX5; +alias const(DIEFFECT_DX5)* LPCDIEFFECT_DX5; + +struct DIEFFECT { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDuration; + DWORD dwSamplePeriod; + DWORD dwGain; + DWORD dwTriggerButton; + DWORD dwTriggerRepeatInterval; + DWORD cAxes; + LPDWORD rgdwAxes; + LPLONG rglDirection; + LPDIENVELOPE lpEnvelope; + DWORD cbTypeSpecificParams; + LPVOID lpvTypeSpecificParams; + DWORD dwStartDelay; +} +alias DIEFFECT* LPDIEFFECT; +alias const(DIEFFECT)* LPCDIEFFECT; +alias DIEFFECT DIEFFECT_DX6; +alias LPDIEFFECT LPDIEFFECT_DX6; + +struct DIEFFECTINFOA { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + CHAR[MAX_PATH] tszName; +} +alias DIEFFECTINFOA* LPDIEFFECTINFOA; +alias const(DIEFFECTINFOA)* LPCDIEFFECTINFOA; + +struct DIEFFECTINFOW { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + WCHAR[MAX_PATH] tszName; +} +alias DIEFFECTINFOW* LPDIEFFECTINFOW; +alias const(DIEFFECTINFOW)* LPCDIEFFECTINFOW; + +struct DIEFFESCAPE { + DWORD dwSize; + DWORD dwCommand; + LPVOID lpvInBuffer; + DWORD cbInBuffer; + LPVOID lpvOutBuffer; + DWORD cbOutBuffer; +} +alias DIEFFESCAPE* LPDIEFFESCAPE; + +struct DIJOYSTATE { + LONG lX; + LONG lY; + LONG lZ; + LONG lRx; + LONG lRy; + LONG lRz; + LONG[2] rglSlider; + DWORD[4] rgdwPOV; + BYTE[32] rgbButtons; +} +alias DIJOYSTATE* LPDIJOYSTATE; + +struct DIJOYSTATE2 { + LONG lX; + LONG lY; + LONG lZ; + LONG lRx; + LONG lRy; + LONG lRz; + LONG[2] rglSlider; + DWORD[4] rgdwPOV; + BYTE[128] rgbButtons; + LONG lVX; /* 'v' as in velocity */ + LONG lVY; + LONG lVZ; + LONG lVRx; + LONG lVRy; + LONG lVRz; + LONG[2] rglVSlider; + LONG lAX; /* 'a' as in acceleration */ + LONG lAY; + LONG lAZ; + LONG lARx; + LONG lARy; + LONG lARz; + LONG[2] rglASlider; + LONG lFX; /* 'f' as in force */ + LONG lFY; + LONG lFZ; + LONG lFRx; /* 'fr' as in rotational force aka torque */ + LONG lFRy; + LONG lFRz; + LONG[2] rglFSlider; +} +alias DIJOYSTATE2* LPDIJOYSTATE2; + +enum DIJOFS_X = DIJOYSTATE.lX.offsetof; +enum DIJOFS_Y = DIJOYSTATE.lY.offsetof; +enum DIJOFS_Z = DIJOYSTATE.lZ.offsetof; +enum DIJOFS_RX = DIJOYSTATE.lRx.offsetof; +enum DIJOFS_RY = DIJOYSTATE.lRy.offsetof; +enum DIJOFS_RZ = DIJOYSTATE.lRz.offsetof; +pragma(inline, true) extern(D) int DIJOFS_SLIDER(int n) {return cast(int) (DIJOYSTATE.rglSlider.offsetof + n * LONG.sizeof);} +pragma(inline, true) extern(D) int DIJOFS_POV(int n) {return cast(int) (DIJOYSTATE.rgdwPOV.offsetof + n * DWORD.sizeof);} +pragma(inline, true) extern(D) int DIJOFS_BUTTON(int n) {return cast(int) (DIJOYSTATE.rgbButtons.offsetof + n);} +enum DIJOFS_BUTTON0 = DIJOFS_BUTTON(0); +enum DIJOFS_BUTTON1 = DIJOFS_BUTTON(1); +enum DIJOFS_BUTTON2 = DIJOFS_BUTTON(2); +enum DIJOFS_BUTTON3 = DIJOFS_BUTTON(3); +enum DIJOFS_BUTTON4 = DIJOFS_BUTTON(4); +enum DIJOFS_BUTTON5 = DIJOFS_BUTTON(5); +enum DIJOFS_BUTTON6 = DIJOFS_BUTTON(6); +enum DIJOFS_BUTTON7 = DIJOFS_BUTTON(7); +enum DIJOFS_BUTTON8 = DIJOFS_BUTTON(8); +enum DIJOFS_BUTTON9 = DIJOFS_BUTTON(9); +enum DIJOFS_BUTTON10 = DIJOFS_BUTTON(10); +enum DIJOFS_BUTTON11 = DIJOFS_BUTTON(11); +enum DIJOFS_BUTTON12 = DIJOFS_BUTTON(12); +enum DIJOFS_BUTTON13 = DIJOFS_BUTTON(13); +enum DIJOFS_BUTTON14 = DIJOFS_BUTTON(14); +enum DIJOFS_BUTTON15 = DIJOFS_BUTTON(15); +enum DIJOFS_BUTTON16 = DIJOFS_BUTTON(16); +enum DIJOFS_BUTTON17 = DIJOFS_BUTTON(17); +enum DIJOFS_BUTTON18 = DIJOFS_BUTTON(18); +enum DIJOFS_BUTTON19 = DIJOFS_BUTTON(19); +enum DIJOFS_BUTTON20 = DIJOFS_BUTTON(20); +enum DIJOFS_BUTTON21 = DIJOFS_BUTTON(21); +enum DIJOFS_BUTTON22 = DIJOFS_BUTTON(22); +enum DIJOFS_BUTTON23 = DIJOFS_BUTTON(23); +enum DIJOFS_BUTTON24 = DIJOFS_BUTTON(24); +enum DIJOFS_BUTTON25 = DIJOFS_BUTTON(25); +enum DIJOFS_BUTTON26 = DIJOFS_BUTTON(26); +enum DIJOFS_BUTTON27 = DIJOFS_BUTTON(27); +enum DIJOFS_BUTTON28 = DIJOFS_BUTTON(28); +enum DIJOFS_BUTTON29 = DIJOFS_BUTTON(29); +enum DIJOFS_BUTTON30 = DIJOFS_BUTTON(30); +enum DIJOFS_BUTTON31 = DIJOFS_BUTTON(31); + +enum DIK_ESCAPE = 0x01; +enum DIK_1 = 0x02; +enum DIK_2 = 0x03; +enum DIK_3 = 0x04; +enum DIK_4 = 0x05; +enum DIK_5 = 0x06; +enum DIK_6 = 0x07; +enum DIK_7 = 0x08; +enum DIK_8 = 0x09; +enum DIK_9 = 0x0A; +enum DIK_0 = 0x0B; +enum DIK_MINUS = 0x0C /* - on main keyboard */; +enum DIK_EQUALS = 0x0D; +enum DIK_BACK = 0x0E /* backspace */; +enum DIK_TAB = 0x0F; +enum DIK_Q = 0x10; +enum DIK_W = 0x11; +enum DIK_E = 0x12; +enum DIK_R = 0x13; +enum DIK_T = 0x14; +enum DIK_Y = 0x15; +enum DIK_U = 0x16; +enum DIK_I = 0x17; +enum DIK_O = 0x18; +enum DIK_P = 0x19; +enum DIK_LBRACKET = 0x1A; +enum DIK_RBRACKET = 0x1B; +enum DIK_RETURN = 0x1C /* Enter on main keyboard */; +enum DIK_LCONTROL = 0x1D; +enum DIK_A = 0x1E; +enum DIK_S = 0x1F; +enum DIK_D = 0x20; +enum DIK_F = 0x21; +enum DIK_G = 0x22; +enum DIK_H = 0x23; +enum DIK_J = 0x24; +enum DIK_K = 0x25; +enum DIK_L = 0x26; +enum DIK_SEMICOLON = 0x27; +enum DIK_APOSTROPHE = 0x28; +enum DIK_GRAVE = 0x29 /* accent grave */; +enum DIK_LSHIFT = 0x2A; +enum DIK_BACKSLASH = 0x2B; +enum DIK_Z = 0x2C; +enum DIK_X = 0x2D; +enum DIK_C = 0x2E; +enum DIK_V = 0x2F; +enum DIK_B = 0x30; +enum DIK_N = 0x31; +enum DIK_M = 0x32; +enum DIK_COMMA = 0x33; +enum DIK_PERIOD = 0x34 /* . on main keyboard */; +enum DIK_SLASH = 0x35 /* / on main keyboard */; +enum DIK_RSHIFT = 0x36; +enum DIK_MULTIPLY = 0x37 /* * on numeric keypad */; +enum DIK_LMENU = 0x38 /* left Alt */; +enum DIK_SPACE = 0x39; +enum DIK_CAPITAL = 0x3A; +enum DIK_F1 = 0x3B; +enum DIK_F2 = 0x3C; +enum DIK_F3 = 0x3D; +enum DIK_F4 = 0x3E; +enum DIK_F5 = 0x3F; +enum DIK_F6 = 0x40; +enum DIK_F7 = 0x41; +enum DIK_F8 = 0x42; +enum DIK_F9 = 0x43; +enum DIK_F10 = 0x44; +enum DIK_NUMLOCK = 0x45; +enum DIK_SCROLL = 0x46 /* Scroll Lock */; +enum DIK_NUMPAD7 = 0x47; +enum DIK_NUMPAD8 = 0x48; +enum DIK_NUMPAD9 = 0x49; +enum DIK_SUBTRACT = 0x4A /* - on numeric keypad */; +enum DIK_NUMPAD4 = 0x4B; +enum DIK_NUMPAD5 = 0x4C; +enum DIK_NUMPAD6 = 0x4D; +enum DIK_ADD = 0x4E /* + on numeric keypad */; +enum DIK_NUMPAD1 = 0x4F; +enum DIK_NUMPAD2 = 0x50; +enum DIK_NUMPAD3 = 0x51; +enum DIK_NUMPAD0 = 0x52; +enum DIK_DECIMAL = 0x53 /* . on numeric keypad */; +enum DIK_OEM_102 = 0x56 /* < > | on UK/Germany keyboards */; +enum DIK_F11 = 0x57; +enum DIK_F12 = 0x58; +enum DIK_F13 = 0x64 /* (NEC PC98) */; +enum DIK_F14 = 0x65 /* (NEC PC98) */; +enum DIK_F15 = 0x66 /* (NEC PC98) */; +enum DIK_KANA = 0x70 /* (Japanese keyboard) */; +enum DIK_ABNT_C1 = 0x73 /* / ? on Portugese (Brazilian) keyboards */; +enum DIK_CONVERT = 0x79 /* (Japanese keyboard) */; +enum DIK_NOCONVERT = 0x7B /* (Japanese keyboard) */; +enum DIK_YEN = 0x7D /* (Japanese keyboard) */; +enum DIK_ABNT_C2 = 0x7E /* Numpad . on Portugese (Brazilian) keyboards */; +enum DIK_NUMPADEQUALS = 0x8D /* = on numeric keypad (NEC PC98) */; +enum DIK_CIRCUMFLEX = 0x90 /* (Japanese keyboard) */; +enum DIK_AT = 0x91 /* (NEC PC98) */; +enum DIK_COLON = 0x92 /* (NEC PC98) */; +enum DIK_UNDERLINE = 0x93 /* (NEC PC98) */; +enum DIK_KANJI = 0x94 /* (Japanese keyboard) */; +enum DIK_STOP = 0x95 /* (NEC PC98) */; +enum DIK_AX = 0x96 /* (Japan AX) */; +enum DIK_UNLABELED = 0x97 /* (J3100) */; +enum DIK_NEXTTRACK = 0x99 /* Next Track */; +enum DIK_NUMPADENTER = 0x9C /* Enter on numeric keypad */; +enum DIK_RCONTROL = 0x9D; +enum DIK_MUTE = 0xA0 /* Mute */; +enum DIK_CALCULATOR = 0xA1 /* Calculator */; +enum DIK_PLAYPAUSE = 0xA2 /* Play / Pause */; +enum DIK_MEDIASTOP = 0xA4 /* Media Stop */; +enum DIK_VOLUMEDOWN = 0xAE /* Volume - */; +enum DIK_VOLUMEUP = 0xB0 /* Volume + */; +enum DIK_WEBHOME = 0xB2 /* Web home */; +enum DIK_NUMPADCOMMA = 0xB3 /* , on numeric keypad (NEC PC98) */; +enum DIK_DIVIDE = 0xB5 /* / on numeric keypad */; +enum DIK_SYSRQ = 0xB7; +enum DIK_RMENU = 0xB8 /* right Alt */; +enum DIK_PAUSE = 0xC5 /* Pause */; +enum DIK_HOME = 0xC7 /* Home on arrow keypad */; +enum DIK_UP = 0xC8 /* UpArrow on arrow keypad */; +enum DIK_PRIOR = 0xC9 /* PgUp on arrow keypad */; +enum DIK_LEFT = 0xCB /* LeftArrow on arrow keypad */; +enum DIK_RIGHT = 0xCD /* RightArrow on arrow keypad */; +enum DIK_END = 0xCF /* End on arrow keypad */; +enum DIK_DOWN = 0xD0 /* DownArrow on arrow keypad */; +enum DIK_NEXT = 0xD1 /* PgDn on arrow keypad */; +enum DIK_INSERT = 0xD2 /* Insert on arrow keypad */; +enum DIK_DELETE = 0xD3 /* Delete on arrow keypad */; +enum DIK_LWIN = 0xDB /* Left Windows key */; +enum DIK_RWIN = 0xDC /* Right Windows key */; +enum DIK_APPS = 0xDD /* AppMenu key */; +enum DIK_POWER = 0xDE; +enum DIK_SLEEP = 0xDF; +enum DIK_WAKE = 0xE3 /* System Wake */; +enum DIK_WEBSEARCH = 0xE5 /* Web Search */; +enum DIK_WEBFAVORITES = 0xE6 /* Web Favorites */; +enum DIK_WEBREFRESH = 0xE7 /* Web Refresh */; +enum DIK_WEBSTOP = 0xE8 /* Web Stop */; +enum DIK_WEBFORWARD = 0xE9 /* Web Forward */; +enum DIK_WEBBACK = 0xEA /* Web Back */; +enum DIK_MYCOMPUTER = 0xEB /* My Computer */; +enum DIK_MAIL = 0xEC /* Mail */; +enum DIK_MEDIASELECT = 0xED /* Media Select */; + +enum DIK_BACKSPACE = DIK_BACK /* backspace */; +enum DIK_NUMPADSTAR = DIK_MULTIPLY /* * on numeric keypad */; +enum DIK_LALT = DIK_LMENU /* left Alt */; +enum DIK_CAPSLOCK = DIK_CAPITAL /* CapsLock */; +enum DIK_NUMPADMINUS = DIK_SUBTRACT /* - on numeric keypad */; +enum DIK_NUMPADPLUS = DIK_ADD /* + on numeric keypad */; +enum DIK_NUMPADPERIOD = DIK_DECIMAL /* . on numeric keypad */; +enum DIK_NUMPADSLASH = DIK_DIVIDE /* / on numeric keypad */; +enum DIK_RALT = DIK_RMENU /* right Alt */; +enum DIK_UPARROW = DIK_UP /* UpArrow on arrow keypad */; +enum DIK_PGUP = DIK_PRIOR /* PgUp on arrow keypad */; +enum DIK_LEFTARROW = DIK_LEFT /* LeftArrow on arrow keypad */; +enum DIK_RIGHTARROW = DIK_RIGHT /* RightArrow on arrow keypad */; +enum DIK_DOWNARROW = DIK_DOWN /* DownArrow on arrow keypad */; +enum DIK_PGDN = DIK_NEXT /* PgDn on arrow keypad */; + +enum DIDFT_ALL = 0x00000000; +enum DIDFT_RELAXIS = 0x00000001; +enum DIDFT_ABSAXIS = 0x00000002; +enum DIDFT_AXIS = 0x00000003; +enum DIDFT_PSHBUTTON = 0x00000004; +enum DIDFT_TGLBUTTON = 0x00000008; +enum DIDFT_BUTTON = 0x0000000C; +enum DIDFT_POV = 0x00000010; +enum DIDFT_COLLECTION = 0x00000040; +enum DIDFT_NODATA = 0x00000080; +enum DIDFT_ANYINSTANCE = 0x00FFFF00; +enum DIDFT_INSTANCEMASK = DIDFT_ANYINSTANCE; + +enum DIERR_INSUFFICIENTPRIVS = 0x80040200L; +enum DIERR_DEVICEFULL = 0x80040201L; +enum DIERR_MOREDATA = 0x80040202L; +enum DIERR_NOTDOWNLOADED = 0x80040203L; +enum DIERR_HASEFFECTS = 0x80040204L; +enum DIERR_NOTEXCLUSIVEACQUIRED = 0x80040205L; +enum DIERR_INCOMPLETEEFFECT = 0x80040206L; +enum DIERR_NOTBUFFERED = 0x80040207L; +enum DIERR_EFFECTPLAYING = 0x80040208L; +enum DIERR_UNPLUGGED = 0x80040209L; +enum DIERR_REPORTFULL = 0x8004020AL; +enum DIERR_MAPFILEFAIL = 0x8004020BL; + +enum DIENUM_STOP = 0; +enum DIENUM_CONTINUE = 1; + +enum DIEDFL_ALLDEVICES = 0x00000000; +enum DIEDFL_ATTACHEDONLY = 0x00000001; +enum DIEDFL_FORCEFEEDBACK = 0x00000100; +enum DIEDFL_INCLUDEALIASES = 0x00010000; +enum DIEDFL_INCLUDEPHANTOMS = 0x00020000; +enum DIEDFL_INCLUDEHIDDEN = 0x00040000; + +enum DIDEVTYPE_DEVICE = 1; +enum DIDEVTYPE_MOUSE = 2; +enum DIDEVTYPE_KEYBOARD = 3; +enum DIDEVTYPE_JOYSTICK = 4; +enum DIDEVTYPE_HID = 0x00010000; + +enum DI8DEVCLASS_ALL = 0; +enum DI8DEVCLASS_DEVICE = 1; +enum DI8DEVCLASS_POINTER = 2; +enum DI8DEVCLASS_KEYBOARD = 3; +enum DI8DEVCLASS_GAMECTRL = 4; + +enum DI8DEVTYPE_DEVICE = 0x11; +enum DI8DEVTYPE_MOUSE = 0x12; +enum DI8DEVTYPE_KEYBOARD = 0x13; +enum DI8DEVTYPE_JOYSTICK = 0x14; +enum DI8DEVTYPE_GAMEPAD = 0x15; +enum DI8DEVTYPE_DRIVING = 0x16; +enum DI8DEVTYPE_FLIGHT = 0x17; +enum DI8DEVTYPE_1STPERSON = 0x18; +enum DI8DEVTYPE_DEVICECTRL = 0x19; +enum DI8DEVTYPE_SCREENPOINTER = 0x1A; +enum DI8DEVTYPE_REMOTE = 0x1B; +enum DI8DEVTYPE_SUPPLEMENTAL = 0x1C; + +enum DIDEVTYPEMOUSE_UNKNOWN = 1; +enum DIDEVTYPEMOUSE_TRADITIONAL = 2; +enum DIDEVTYPEMOUSE_FINGERSTICK = 3; +enum DIDEVTYPEMOUSE_TOUCHPAD = 4; +enum DIDEVTYPEMOUSE_TRACKBALL = 5; + +enum DIDEVTYPEKEYBOARD_UNKNOWN = 0; +enum DIDEVTYPEKEYBOARD_PCXT = 1; +enum DIDEVTYPEKEYBOARD_OLIVETTI = 2; +enum DIDEVTYPEKEYBOARD_PCAT = 3; +enum DIDEVTYPEKEYBOARD_PCENH = 4; +enum DIDEVTYPEKEYBOARD_NOKIA1050 = 5; +enum DIDEVTYPEKEYBOARD_NOKIA9140 = 6; +enum DIDEVTYPEKEYBOARD_NEC98 = 7; +enum DIDEVTYPEKEYBOARD_NEC98LAPTOP = 8; +enum DIDEVTYPEKEYBOARD_NEC98106 = 9; +enum DIDEVTYPEKEYBOARD_JAPAN106 = 10; +enum DIDEVTYPEKEYBOARD_JAPANAX = 11; +enum DIDEVTYPEKEYBOARD_J3100 = 12; + +enum DIDEVTYPEJOYSTICK_UNKNOWN = 1; +enum DIDEVTYPEJOYSTICK_TRADITIONAL = 2; +enum DIDEVTYPEJOYSTICK_FLIGHTSTICK = 3; +enum DIDEVTYPEJOYSTICK_GAMEPAD = 4; +enum DIDEVTYPEJOYSTICK_RUDDER = 5; +enum DIDEVTYPEJOYSTICK_WHEEL = 6; +enum DIDEVTYPEJOYSTICK_HEADTRACKER = 7; + +enum DI8DEVTYPEMOUSE_UNKNOWN = 1; +enum DI8DEVTYPEMOUSE_TRADITIONAL = 2; +enum DI8DEVTYPEMOUSE_FINGERSTICK = 3; +enum DI8DEVTYPEMOUSE_TOUCHPAD = 4; +enum DI8DEVTYPEMOUSE_TRACKBALL = 5; +enum DI8DEVTYPEMOUSE_ABSOLUTE = 6; + +enum DI8DEVTYPEKEYBOARD_UNKNOWN = 0; +enum DI8DEVTYPEKEYBOARD_PCXT = 1; +enum DI8DEVTYPEKEYBOARD_OLIVETTI = 2; +enum DI8DEVTYPEKEYBOARD_PCAT = 3; +enum DI8DEVTYPEKEYBOARD_PCENH = 4; +enum DI8DEVTYPEKEYBOARD_NOKIA1050 = 5; +enum DI8DEVTYPEKEYBOARD_NOKIA9140 = 6; +enum DI8DEVTYPEKEYBOARD_NEC98 = 7; +enum DI8DEVTYPEKEYBOARD_NEC98LAPTOP = 8; +enum DI8DEVTYPEKEYBOARD_NEC98106 = 9; +enum DI8DEVTYPEKEYBOARD_JAPAN106 = 10; +enum DI8DEVTYPEKEYBOARD_JAPANAX = 11; +enum DI8DEVTYPEKEYBOARD_J3100 = 12; + +enum DI8DEVTYPE_LIMITEDGAMESUBTYPE = 1; + +enum DI8DEVTYPEJOYSTICK_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE; +enum DI8DEVTYPEJOYSTICK_STANDARD = 2; + +enum DI8DEVTYPEGAMEPAD_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE; +enum DI8DEVTYPEGAMEPAD_STANDARD = 2; +enum DI8DEVTYPEGAMEPAD_TILT = 3; + +enum DI8DEVTYPEDRIVING_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE; +enum DI8DEVTYPEDRIVING_COMBINEDPEDALS = 2; +enum DI8DEVTYPEDRIVING_DUALPEDALS = 3; +enum DI8DEVTYPEDRIVING_THREEPEDALS = 4; +enum DI8DEVTYPEDRIVING_HANDHELD = 5; + +enum DI8DEVTYPEFLIGHT_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE; +enum DI8DEVTYPEFLIGHT_STICK = 2; +enum DI8DEVTYPEFLIGHT_YOKE = 3; +enum DI8DEVTYPEFLIGHT_RC = 4; + +enum DI8DEVTYPE1STPERSON_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE; +enum DI8DEVTYPE1STPERSON_UNKNOWN = 2; +enum DI8DEVTYPE1STPERSON_SIXDOF = 3; +enum DI8DEVTYPE1STPERSON_SHOOTER = 4; + +enum DI8DEVTYPESCREENPTR_UNKNOWN = 2; +enum DI8DEVTYPESCREENPTR_LIGHTGUN = 3; +enum DI8DEVTYPESCREENPTR_LIGHTPEN = 4; +enum DI8DEVTYPESCREENPTR_TOUCH = 5; + +enum DI8DEVTYPEREMOTE_UNKNOWN = 2; + +enum DI8DEVTYPEDEVICECTRL_UNKNOWN = 2; +enum DI8DEVTYPEDEVICECTRL_COMMSSELECTION = 3; +enum DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED = 4; + +enum DI8DEVTYPESUPPLEMENTAL_UNKNOWN = 2; +enum DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER = 3; +enum DI8DEVTYPESUPPLEMENTAL_HEADTRACKER = 4; +enum DI8DEVTYPESUPPLEMENTAL_HANDTRACKER = 5; +enum DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE = 6; +enum DI8DEVTYPESUPPLEMENTAL_SHIFTER = 7; +enum DI8DEVTYPESUPPLEMENTAL_THROTTLE = 8; +enum DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE = 9; +enum DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS = 10; +enum DI8DEVTYPESUPPLEMENTAL_DUALPEDALS = 11; +enum DI8DEVTYPESUPPLEMENTAL_THREEPEDALS = 12; +enum DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS = 13; + +struct DIDEVICEINSTANCEW { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR[MAX_PATH] tszInstanceName; + WCHAR[MAX_PATH] tszProductName; + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +} +alias DIDEVICEINSTANCEW* LPDIDEVICEINSTANCEW; +alias const(DIDEVICEINSTANCEW)* LPCDIDEVICEINSTANCEW; + +alias DIDEVICEINSTANCE = DIDEVICEINSTANCEW; + +enum DI_OK = S_OK; +enum DI_NOTATTACHED = S_FALSE; +enum DI_BUFFEROVERFLOW = S_FALSE; +enum DI_PROPNOEFFECT = S_FALSE; +enum DI_NOEFFECT = S_FALSE; +enum DI_POLLEDDEVICE = HRESULT(0x0002); +enum DI_DOWNLOADSKIPPED = HRESULT(0x0003); +enum DI_EFFECTRESTARTED = HRESULT(0x0004); +enum DI_TRUNCATED = HRESULT(0x0008); +enum DI_SETTINGSNOTSAVED = HRESULT(0x000B); +enum DI_TRUNCATEDANDRESTARTED = HRESULT(0x000C); +enum DI_WRITEPROTECT = HRESULT(0x0013); + +enum DIERR_OLDDIRECTINPUTVERSION = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_OLD_WIN_VERSION); +enum DIERR_BETADIRECTINPUTVERSION = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_RMODE_APP); +enum DIERR_BADDRIVERVER = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BAD_DRIVER_LEVEL); +enum DIERR_DEVICENOTREG = REGDB_E_CLASSNOTREG; +enum DIERR_NOTFOUND = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND); +enum DIERR_OBJECTNOTFOUND = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND); +enum DIERR_INVALIDPARAM = E_INVALIDARG; +enum DIERR_NOINTERFACE = E_NOINTERFACE; +enum DIERR_GENERIC = E_FAIL; +enum DIERR_OUTOFMEMORY = E_OUTOFMEMORY; +enum DIERR_UNSUPPORTED = E_NOTIMPL; +enum DIERR_NOTINITIALIZED = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_READY); +enum DIERR_ALREADYINITIALIZED = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_ALREADY_INITIALIZED); +enum DIERR_NOAGGREGATION = CLASS_E_NOAGGREGATION; +enum DIERR_OTHERAPPHASPRIO = E_ACCESSDENIED; +enum DIERR_INPUTLOST = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_READ_FAULT); +enum DIERR_ACQUIRED = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BUSY); +enum DIERR_NOTACQUIRED = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_ACCESS); +enum DIERR_READONLY = E_ACCESSDENIED; +enum DIERR_HANDLEEXISTS = E_ACCESSDENIED; +enum E_PENDING = 0x8000000AL; + +enum string DIDFT_MAKEINSTANCE(string n) = ` ((WORD)(n) << 8)`; +auto DIDFT_GETTYPE(T)(T a) {return LOBYTE(cast(ushort) a);} +enum string DIDFT_GETINSTANCE(string n) = ` LOWORD((n) >> 8)`; +enum DIDFT_FFACTUATOR = 0x01000000; +enum DIDFT_FFEFFECTTRIGGER = 0x02000000; +enum DIDFT_OUTPUT = 0x10000000; +enum DIDFT_VENDORDEFINED = 0x04000000; +enum DIDFT_ALIAS = 0x08000000; +enum DIDFT_OPTIONAL = 0x80000000; +enum string DIDFT_ENUMCOLLECTION(string n) = ` ((WORD)(n) << 8)`; +enum DIDFT_NOCOLLECTION = 0x00FFFF00; + +enum DIDF_ABSAXIS = 0x00000001; +enum DIDF_RELAXIS = 0x00000002; +enum DIGDD_PEEK = 0x00000001; + +enum string DISEQUENCE_COMPARE(string dwSq1,string cmp,string dwSq2) = ` ((int)((dwSq1) - (dwSq2)) cmp 0)`; + +struct DIDEVCAPS_DX3 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +} +alias DIDEVCAPS_DX3* LPDIDEVCAPS_DX3; + +struct DIDEVCAPS { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; + DWORD dwFFSamplePeriod; + DWORD dwFFMinTimeResolution; + DWORD dwFirmwareRevision; + DWORD dwHardwareRevision; + DWORD dwFFDriverVersion; +} +alias DIDEVCAPS* LPDIDEVCAPS; + +alias BOOL function(LPCDIDEVICEINSTANCEW, LPDIRECTINPUTDEVICE8W, DWORD, DWORD, LPVOID) LPDIENUMDEVICESBYSEMANTICSCBW; +alias LPDIENUMDEVICESBYSEMANTICSCB = LPDIENUMDEVICESBYSEMANTICSCBW; +alias LPDICONFIGUREDEVICESCALLBACK = extern(Windows) BOOL function(LPUNKNOWN, LPVOID); +alias LPDIENUMDEVICEOBJECTSCALLBACKW = extern(Windows) BOOL function(LPCDIDEVICEOBJECTINSTANCEW, LPVOID); +alias LPDIENUMDEVICEOBJECTSCALLBACK = LPDIENUMDEVICEOBJECTSCALLBACKW; +alias LPDIENUMEFFECTSCALLBACKW = extern(Windows) BOOL function(LPCDIEFFECTINFOW, LPVOID); +alias LPDIENUMDEVICESCALLBACKW = extern(Windows) BOOL function(LPCDIDEVICEINSTANCEW, LPVOID); + +alias LPDIENUMCREATEDEFFECTOBJECTSCALLBACK = BOOL function(LPDIRECTINPUTEFFECT, LPVOID); + +struct DIFILEEFFECT { +DWORD dwSize; +GUID GuidEffect; +LPCDIEFFECT lpDiEffect; +CHAR[MAX_PATH] szFriendlyName; +} +alias DIFILEEFFECT* LPDIFILEEFFECT; + +alias const(DIFILEEFFECT)* LPCDIFILEEFFECT; +alias BOOL function(LPCDIFILEEFFECT, LPVOID) LPDIENUMEFFECTSINFILECALLBACK; + +struct DIDEVICEOBJECTDATA { + DWORD dwOfs; + DWORD dwData; + DWORD dwTimeStamp; + DWORD dwSequence; + UINT_PTR uAppData; +} +alias DIDEVICEOBJECTDATA* LPDIDEVICEOBJECTDATA; +alias const(DIDEVICEOBJECTDATA)* LPCDIDEVICEOBJECTDATA; + +struct _DIOBJECTDATAFORMAT { + const(GUID)* pguid; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; +} +alias _DIOBJECTDATAFORMAT DIOBJECTDATAFORMAT; +alias _DIOBJECTDATAFORMAT* LPDIOBJECTDATAFORMAT; +alias const(DIOBJECTDATAFORMAT)* LPCDIOBJECTDATAFORMAT; + +struct IDirectInputW ;alias IDirectInputW* LPDIRECTINPUTW; +/*struct IDirectInput8W*/;alias IDirectInput8W* LPDIRECTINPUT8W; +struct IDirectInputDeviceW ;alias IDirectInputDeviceW* LPDIRECTINPUTDEVICEW; +/*struct IDirectInputDevice8W*/;alias IDirectInputDevice8W* LPDIRECTINPUTDEVICE8W; +struct IDirectInputEffect ;alias IDirectInputEffect* LPDIRECTINPUTEFFECT; + +struct _DIDEVICEIMAGEINFOW { + WCHAR[MAX_PATH] tszImagePath; + DWORD dwFlags; + DWORD dwViewID; + RECT rcOverlay; + DWORD dwObjID; + DWORD dwcValidPts; + POINT[5] rgptCalloutLine; + RECT rcCalloutRect; + DWORD dwTextAlign; +}alias _DIDEVICEIMAGEINFOW DIDEVICEIMAGEINFOW;alias _DIDEVICEIMAGEINFOW* LPDIDEVICEIMAGEINFOW; +alias const(DIDEVICEIMAGEINFOW)* LPCDIDEVICEIMAGEINFOW; + +struct _DIDEVICEIMAGEINFOHEADERW { + DWORD dwSize; + DWORD dwSizeImageInfo; + DWORD dwcViews; + DWORD dwcButtons; + DWORD dwcAxes; + DWORD dwcPOVs; + DWORD dwBufferSize; + DWORD dwBufferUsed; + LPDIDEVICEIMAGEINFOW lprgImageInfoArray; +}alias _DIDEVICEIMAGEINFOHEADERW DIDEVICEIMAGEINFOHEADERW;alias _DIDEVICEIMAGEINFOHEADERW* LPDIDEVICEIMAGEINFOHEADERW; +alias const(DIDEVICEIMAGEINFOHEADERW)* LPCDIDEVICEIMAGEINFOHEADERW; + +struct _DIACTIONW { + UINT_PTR uAppData; + DWORD dwSemantic; + DWORD dwFlags; + union { + LPCWSTR lptszActionName; + UINT uResIdString; + } + GUID guidInstance; + DWORD dwObjID; + DWORD dwHow; +} +alias DIACTIONW = _DIACTIONW; alias LPDIACTIONW = _DIACTIONW; +alias const(DIACTIONW)* LPCDIACTIONW; + +struct _DIACTIONFORMATW { + DWORD dwSize; + DWORD dwActionSize; + DWORD dwDataSize; + DWORD dwNumActions; + LPDIACTIONW rgoAction; + GUID guidActionMap; + DWORD dwGenre; + DWORD dwBufferSize; + LONG lAxisMin; + LONG lAxisMax; + HINSTANCE hInstString; + FILETIME ftTimeStamp; + DWORD dwCRC; + WCHAR[MAX_PATH] tszActionMap; +}alias _DIACTIONFORMATW DIACTIONFORMATW;alias _DIACTIONFORMATW* LPDIACTIONFORMATW; +alias const(DIACTIONFORMATW)* LPCDIACTIONFORMATW; + +struct IDirectInputDevice8W { + private alias THIS_ = typeof(this)*; + + // First member of struct is Vtable + // https://docs.microsoft.com/en-us/windows/win32/multimedia/virtual-function-tables + static struct Vtable { + import core.sys.windows.windows; + pure: nothrow: @nogc: extern(Windows): + /*** IUnknown methods ***/ + HRESULT function (THIS_, REFIID riid, void** ppvObject) QueryInterface; + ULONG function (THIS_,) AddRef; + ULONG function (THIS_,) Release; + /*** IDirectInputDeviceW methods ***/ + HRESULT function (THIS_, LPDIDEVCAPS lpDIDevCaps) GetCapabilities; + HRESULT function (THIS_, LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) EnumObjects; + HRESULT function (THIS_, REFGUID rguidProp, LPDIPROPHEADER pdiph) GetProperty; + HRESULT function (THIS_, REFGUID rguidProp, LPCDIPROPHEADER pdiph) SetProperty; + HRESULT function (THIS_,) Acquire; + HRESULT function (THIS_,) Unacquire; + HRESULT function (THIS_, DWORD cbData, LPVOID lpvData) GetDeviceState; + HRESULT function (THIS_, DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) GetDeviceData; + HRESULT function (THIS_, LPCDIDATAFORMAT lpdf) SetDataFormat; + HRESULT function (THIS_, HANDLE hEvent) SetEventNotification; + HRESULT function (THIS_, HWND hwnd, DWORD dwFlags) SetCooperativeLevel; + HRESULT function (THIS_, LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) GetObjectInfo; + HRESULT function (THIS_, LPDIDEVICEINSTANCEW pdidi) GetDeviceInfo; + HRESULT function (THIS_, HWND hwndOwner, DWORD dwFlags) RunControlPanel; + HRESULT function (THIS_, HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) Initialize; + /*** IDirectInputDevice2W methods ***/ + HRESULT function (THIS_, REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) CreateEffect; + HRESULT function (THIS_, LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) EnumEffects; + HRESULT function (THIS_, LPDIEFFECTINFOW pdei, REFGUID rguid) GetEffectInfo; + HRESULT function (THIS_, LPDWORD pdwOut) GetForceFeedbackState; + HRESULT function (THIS_, DWORD dwFlags) SendForceFeedbackCommand; + HRESULT function (THIS_, LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) EnumCreatedEffectObjects; + HRESULT function (THIS_, LPDIEFFESCAPE pesc) Escape; + HRESULT function (THIS_,) Poll; + HRESULT function (THIS_, DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) SendDeviceData; + /*** IDirectInputDevice7W methods ***/ + HRESULT function (THIS_, LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) EnumEffectsInFile; + HRESULT function (THIS_, LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) WriteEffectToFile; + /*** IDirectInputDevice8W methods ***/ + HRESULT function (THIS_, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) BuildActionMap; + HRESULT function (THIS_, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) SetActionMap; + HRESULT function (THIS_, LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) GetImageInfo; + } + Vtable* lpVtbl; +} + +/*** IUnknown methods **/ +auto IDirectInputDevice8_QueryInterface(T)(T* p, REFIID riid, void** ppvObject) {return p.lpVtbl.QueryInterface(p,riid,ppvObject);} +auto IDirectInputDevice8_AddRef(T)(T* p) {return p.lpVtbl.AddRef(p);} +auto IDirectInputDevice8_Release(T)(T* p) {return p.lpVtbl.Release(p);} +/*** IDirectInputDevice methods **/ +auto IDirectInputDevice8_GetCapabilities(T)(T* p, LPDIDEVCAPS a) {return p.lpVtbl.GetCapabilities(p,a);} +auto IDirectInputDevice8_EnumObjects(T)(T* p, LPDIENUMDEVICEOBJECTSCALLBACKW a,LPVOID b,DWORD c) {return p.lpVtbl.EnumObjects(p,a,b,c);} +auto IDirectInputDevice8_GetProperty(T)(T* p, REFGUID a,LPDIPROPHEADER b) {return p.lpVtbl.GetProperty(p,a,b);} +auto IDirectInputDevice8_SetProperty(T)(T* p, REFGUID a,LPCDIPROPHEADER b) {return p.lpVtbl.SetProperty(p,a,b);} +auto IDirectInputDevice8_Acquire(T)(T* p) {return p.lpVtbl.Acquire(p);} +auto IDirectInputDevice8_Unacquire(T)(T* p) {return p.lpVtbl.Unacquire(p);} +auto IDirectInputDevice8_GetDeviceState(T)(T* p, DWORD a,LPVOID b) {return p.lpVtbl.GetDeviceState(p,a,b);} +auto IDirectInputDevice8_GetDeviceData(T)(T* p, DWORD a, LPDIDEVICEOBJECTDATA b, LPDWORD c, DWORD d) {return p.lpVtbl.GetDeviceData(p,a,b,c,d);} +auto IDirectInputDevice8_SetDataFormat(T)(T* p, LPCDIDATAFORMAT a) {return p.lpVtbl.SetDataFormat(p,a);} +auto IDirectInputDevice8_SetEventNotification(T)(T* p, HANDLE a) {return p.lpVtbl.SetEventNotification(p,a);} +auto IDirectInputDevice8_SetCooperativeLevel(T)(T* p, HWND a,DWORD b) {return p.lpVtbl.SetCooperativeLevel(p,a,b);} +auto IDirectInputDevice8_GetObjectInfo(T)(T* p, LPDIDEVICEOBJECTINSTANCEW a,DWORD b,DWORD c) {return p.lpVtbl.GetObjectInfo(p,a,b,c);} +auto IDirectInputDevice8_GetDeviceInfo(T)(T* p, LPDIDEVICEINSTANCEW a) {return p.lpVtbl.GetDeviceInfo(p,a);} +auto IDirectInputDevice8_RunControlPanel(T)(T* p, HWND a,DWORD b) {return p.lpVtbl.RunControlPanel(p,a,b);} +auto IDirectInputDevice8_Initialize(T)(T* p, HINSTANCE a,DWORD b,REFGUID c) {return p.lpVtbl.Initialize(p,a,b,c);} +/*** IDirectInputDevice2 methods **/ +auto IDirectInputDevice8_CreateEffect(T)(T* p, REFGUID a,LPCDIEFFECT b,LPDIRECTINPUTEFFECT c,LPUNKNOWN d) {return p.lpVtbl.CreateEffect(p,a,b,c,d);} +auto IDirectInputDevice8_EnumEffects(T)(T* p, LPDIENUMEFFECTSCALLBACKW a,LPVOID b,DWORD c) {return p.lpVtbl.EnumEffects(p,a,b,c);} +auto IDirectInputDevice8_GetEffectInfo(T)(T* p, LPDIEFFECTINFOW a,REFGUID b) {return p.lpVtbl.GetEffectInfo(p,a,b);} +auto IDirectInputDevice8_GetForceFeedbackState(T)(T* p, LPDWORD a) {return p.lpVtbl.GetForceFeedbackState(p,a);} +auto IDirectInputDevice8_SendForceFeedbackCommand(T)(T* p, DWORD a) {return p.lpVtbl.SendForceFeedbackCommand(p,a);} +auto IDirectInputDevice8_EnumCreatedEffectObjects(T)(T* p, LPDIENUMCREATEDEFFECTOBJECTSCALLBACK a,LPVOID b,DWORD c) {return p.lpVtbl.EnumCreatedEffectObjects(p,a,b,c);} +auto IDirectInputDevice8_Escape(T)(T* p, LPDIEFFESCAPE a) {return p.lpVtbl.Escape(p,a);} +auto IDirectInputDevice8_Poll(T)(T* p) {return p.lpVtbl.Poll(p);} +auto IDirectInputDevice8_SendDeviceData(T)(T* p, DWORD a,LPCDIDEVICEOBJECTDATA b,LPDWORD c,DWORD d) {return p.lpVtbl.SendDeviceData(p,a,b,c,d);} +/*** IDirectInputDevice7 methods **/ +auto IDirectInputDevice8_EnumEffectsInFile(T)(T* p, LPCWSTR lpszFileName,LPDIENUMEFFECTSINFILECALLBACK pec,LPVOID pvRef,DWORD dwFlags) {return p.lpVtbl.EnumEffectsInFile(p,lpszFileName,pec,pvRef,dwFlags);} +auto IDirectInputDevice8_WriteEffectToFile(T)(T* p, LPCWSTR lpszFileName,DWORD dwEntries,LPDIFILEEFFECT rgDiFileEft,DWORD dwFlags) {return p.lpVtbl.WriteEffectToFile(p,lpszFileName,dwEntries,rgDiFileEft,dwFlags);} +/*** IDirectInputDevice8 methods **/ +auto IDirectInputDevice8_BuildActionMap(T)(T* p, LPDIACTIONFORMATW a,LPCWSTR b,DWORD c) {return p.lpVtbl.BuildActionMap(p,a,b,c);} +auto IDirectInputDevice8_SetActionMap(T)(T* p, LPDIACTIONFORMATW a,LPCWSTR b,DWORD c) {return p.lpVtbl.SetActionMap(p,a,b,c);} +auto IDirectInputDevice8_GetImageInfo(T)(T* p, LPDIDEVICEIMAGEINFOHEADERW a) {return p.lpVtbl.GetImageInfo(p,a);} + +alias DWORD D3DCOLOR; + +struct _DICOLORSET { + DWORD dwSize; + D3DCOLOR cTextFore; + D3DCOLOR cTextHighlight; + D3DCOLOR cCalloutLine; + D3DCOLOR cCalloutHighlight; + D3DCOLOR cBorder; + D3DCOLOR cControlFill; + D3DCOLOR cHighlightFill; + D3DCOLOR cAreaFill; +} +alias _DICOLORSET DICOLORSET; +alias _DICOLORSET* LPDICOLORSET; +alias const(DICOLORSET)* LPCDICOLORSET; + +struct _DICONFIGUREDEVICESPARAMSW { + DWORD dwSize; + DWORD dwcUsers; + LPWSTR lptszUserNames; + DWORD dwcFormats; + LPDIACTIONFORMATW lprgFormats; + HWND hwnd; + DICOLORSET dics; + LPUNKNOWN lpUnkDDSTarget; +} +alias _DICONFIGUREDEVICESPARAMSW DICONFIGUREDEVICESPARAMSW; +alias _DICONFIGUREDEVICESPARAMSW* LPDICONFIGUREDEVICESPARAMSW; +alias const(DICONFIGUREDEVICESPARAMSW)* LPCDICONFIGUREDEVICESPARAMSW; + +struct IDirectInput8W +{ + private alias THIS_ = typeof(this)*; + // First member of struct is Vtable + // https://docs.microsoft.com/en-us/windows/win32/multimedia/virtual-function-tables + static struct Vtable { + import core.sys.windows.windows; + pure: nothrow: @nogc: extern(Windows): + /*** IUnknown methods ***/ + HRESULT function(THIS_, REFIID riid, void** ppvObject) QueryInterface; + ULONG function(THIS_) AddRef; + ULONG function(THIS_) Release; + /*** IDirectInput8W methods ***/ + HRESULT function(THIS_, REFGUID rguid, LPDIRECTINPUTDEVICE8W* lplpDirectInputDevice, LPUNKNOWN pUnkOuter) CreateDevice; + HRESULT function(THIS_, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) EnumDevices; + HRESULT function(THIS_, REFGUID rguidInstance) GetDeviceStatus; + HRESULT function(THIS_, HWND hwndOwner, DWORD dwFlags) RunControlPanel; + HRESULT function(THIS_, HINSTANCE hinst, DWORD dwVersion) Initialize; + HRESULT function(THIS_, REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) FindDevice; + HRESULT function(THIS_, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, LPVOID pvRef, DWORD dwFlags) EnumDevicesBySemantics; + HRESULT function(THIS_, LPDICONFIGUREDEVICESCALLBACK, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) ConfigureDevices; + } + Vtable* lpVtble; +} + +/*** IUnknown methods ***/ +auto IDirectInput8_QueryInterface(T)(T* p,REFIID a,void** b) {return p.lpVtble.QueryInterface(p,a,b);} +auto IDirectInput8_AddRef(T)(T* p) {return p.lpVtble.AddRef(p);} +auto IDirectInput8_Release(T)(T* p) {return p.lpVtble.Release(p);} +/*** IDirectInput8 methods ***/ +auto IDirectInput8_CreateDevice(T)(T* p,REFGUID a,LPDIRECTINPUTDEVICE8W* b,LPUNKNOWN c) {return p.lpVtble.CreateDevice(p,a,b,c);} +auto IDirectInput8_EnumDevices(T)(T* p,DWORD a,LPDIENUMDEVICESCALLBACKW b,LPVOID c,DWORD d) {return p.lpVtble.EnumDevices(p,a,b,c,d);} +auto IDirectInput8_GetDeviceStatus(T)(T* p,REFGUID a) {return p.lpVtble.GetDeviceStatus(p,a);} +auto IDirectInput8_RunControlPanel(T)(T* p,HWND a,DWORD b) {return p.lpVtble.RunControlPanel(p,a,b);} +auto IDirectInput8_Initialize(T)(T* p,HINSTANCE a,DWORD b) {return p.lpVtble.Initialize(p,a,b);} +auto IDirectInput8_FindDevice(T)(T* p,REFGUID a,LPCWSTR b,LPGUID c) {return p.lpVtble.FindDevice(p,a,b,c);} +auto IDirectInput8_EnumDevicesBySemantics(T)(T* p,LPCWSTR a,LPDIACTIONFORMATW b,LPDIENUMDEVICESBYSEMANTICSCBW c,LPVOID d,DWORD e) {return p.lpVtble.EnumDevicesBySemantics(p,a,b,c,d,e);} +auto IDirectInput8_ConfigureDevices(T)(T* p,LPDICONFIGUREDEVICESCALLBACK a,LPDICONFIGUREDEVICESPARAMSW b,DWORD c,LPVOID d) {return p.lpVtble.ConfigureDevices(p,a,b,c,d);} diff --git a/source/glfw3/egl_context.d b/source/glfw3/egl_context.d new file mode 100644 index 0000000..f03192d --- /dev/null +++ b/source/glfw3/egl_context.d @@ -0,0 +1,926 @@ +/// Translated from C to D +module glfw3.egl_context; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 EGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +// HEADER +version (_GLFW_WIN32) { + alias EGLNativeDisplayType = HDC; + alias EGLNativeWindowType = HWND; +} else version (_GLFW_COCOA) { + alias EGLNativeDisplayType = void*; + alias EGLNativeWindowType = id ; +} else version (_GLFW_X11) { + alias EGLNativeDisplayType = Display*; + alias EGLNativeWindowType = Window; +} else version (_GLFW_WAYLAND) { + alias EGLNativeDisplayType = wl_display*; + alias EGLNativeWindowType = wl_egl_window*; +} else { + static assert(0, "No supported EGL platform selected"); +} + +enum EGL_SUCCESS = 0x3000; +enum EGL_NOT_INITIALIZED = 0x3001; +enum EGL_BAD_ACCESS = 0x3002; +enum EGL_BAD_ALLOC = 0x3003; +enum EGL_BAD_ATTRIBUTE = 0x3004; +enum EGL_BAD_CONFIG = 0x3005; +enum EGL_BAD_CONTEXT = 0x3006; +enum EGL_BAD_CURRENT_SURFACE = 0x3007; +enum EGL_BAD_DISPLAY = 0x3008; +enum EGL_BAD_MATCH = 0x3009; +enum EGL_BAD_NATIVE_PIXMAP = 0x300a; +enum EGL_BAD_NATIVE_WINDOW = 0x300b; +enum EGL_BAD_PARAMETER = 0x300c; +enum EGL_BAD_SURFACE = 0x300d; +enum EGL_CONTEXT_LOST = 0x300e; +enum EGL_COLOR_BUFFER_TYPE = 0x303f; +enum EGL_RGB_BUFFER = 0x308e; +enum EGL_SURFACE_TYPE = 0x3033; +enum EGL_WINDOW_BIT = 0x0004; +enum EGL_RENDERABLE_TYPE = 0x3040; +enum EGL_OPENGL_ES_BIT = 0x0001; +enum EGL_OPENGL_ES2_BIT = 0x0004; +enum EGL_OPENGL_BIT = 0x0008; +enum EGL_ALPHA_SIZE = 0x3021; +enum EGL_BLUE_SIZE = 0x3022; +enum EGL_GREEN_SIZE = 0x3023; +enum EGL_RED_SIZE = 0x3024; +enum EGL_DEPTH_SIZE = 0x3025; +enum EGL_STENCIL_SIZE = 0x3026; +enum EGL_SAMPLES = 0x3031; +enum EGL_OPENGL_ES_API = 0x30a0; +enum EGL_OPENGL_API = 0x30a2; +enum EGL_NONE = 0x3038; +enum EGL_EXTENSIONS = 0x3055; +enum EGL_CONTEXT_CLIENT_VERSION = 0x3098; +enum EGL_NATIVE_VISUAL_ID = 0x302e; +enum EGL_NO_SURFACE = (cast(EGLSurface) 0); +enum EGL_NO_DISPLAY = (cast(EGLDisplay) 0); +enum EGL_NO_CONTEXT = (cast(EGLContext) 0); +enum EGL_DEFAULT_DISPLAY = (cast(EGLNativeDisplayType) 0); + +enum EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR = 0x00000002; +enum EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR = 0x00000001; +enum EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR = 0x00000002; +enum EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR = 0x00000001; +enum EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR = 0x31bd; +enum EGL_NO_RESET_NOTIFICATION_KHR = 0x31be; +enum EGL_LOSE_CONTEXT_ON_RESET_KHR = 0x31bf; +enum EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR = 0x00000004; +enum EGL_CONTEXT_MAJOR_VERSION_KHR = 0x3098; +enum EGL_CONTEXT_MINOR_VERSION_KHR = 0x30fb; +enum EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR = 0x30fd; +enum EGL_CONTEXT_FLAGS_KHR = 0x30fc; +enum EGL_CONTEXT_OPENGL_NO_ERROR_KHR = 0x31b3; +enum EGL_GL_COLORSPACE_KHR = 0x309d; +enum EGL_GL_COLORSPACE_SRGB_KHR = 0x3089; +enum EGL_CONTEXT_RELEASE_BEHAVIOR_KHR = 0x2097; +enum EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR = 0; +enum EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR = 0x2098; + +alias int EGLint; +alias uint EGLBoolean; +alias uint EGLenum; +alias void* EGLConfig; +alias void* EGLContext; +alias void* EGLDisplay; +alias void* EGLSurface; + +// EGL function pointer typedefs +extern(System) { + alias EGLBoolean function(EGLDisplay, EGLConfig, EGLint, EGLint*) PFN_eglGetConfigAttrib; + alias EGLBoolean function(EGLDisplay, EGLConfig*, EGLint, EGLint*) PFN_eglGetConfigs; + alias EGLDisplay function(EGLNativeDisplayType) PFN_eglGetDisplay; + alias EGLint function() PFN_eglGetError; + alias EGLBoolean function(EGLDisplay, EGLint*, EGLint*) PFN_eglInitialize; + alias EGLBoolean function(EGLDisplay) PFN_eglTerminate; + alias EGLBoolean function(EGLenum) PFN_eglBindAPI; + alias EGLContext function(EGLDisplay, EGLConfig, EGLContext, const(EGLint)*) PFN_eglCreateContext; + alias EGLBoolean function(EGLDisplay, EGLSurface) PFN_eglDestroySurface; + alias EGLBoolean function(EGLDisplay, EGLContext) PFN_eglDestroyContext; + alias EGLSurface function(EGLDisplay, EGLConfig, EGLNativeWindowType, const(EGLint)*) PFN_eglCreateWindowSurface; + alias EGLBoolean function(EGLDisplay, EGLSurface, EGLSurface, EGLContext) PFN_eglMakeCurrent; + alias EGLBoolean function(EGLDisplay, EGLSurface) PFN_eglSwapBuffers; + alias EGLBoolean function(EGLDisplay, EGLint) PFN_eglSwapInterval; + alias const(char)* function(EGLDisplay, EGLint) PFN_eglQueryString; + alias GLFWglproc function(const(char)*) PFN_eglGetProcAddress; +} +alias eglGetConfigAttrib = _glfw.egl.GetConfigAttrib; +alias eglGetConfigs = _glfw.egl.GetConfigs; +alias eglGetDisplay = _glfw.egl.GetDisplay; +alias eglGetError = _glfw.egl.GetError; +alias eglInitialize = _glfw.egl.Initialize; +alias eglTerminate = _glfw.egl.Terminate; +alias eglBindAPI = _glfw.egl.BindAPI; +alias eglCreateContext = _glfw.egl.CreateContext; +alias eglDestroySurface = _glfw.egl.DestroySurface; +alias eglDestroyContext = _glfw.egl.DestroyContext; +alias eglCreateWindowSurface = _glfw.egl.CreateWindowSurface; +alias eglMakeCurrent = _glfw.egl.MakeCurrent; +alias eglSwapBuffers = _glfw.egl.SwapBuffers; +alias eglSwapInterval = _glfw.egl.SwapInterval; +alias eglQueryString = _glfw.egl.QueryString; +alias eglGetProcAddress = _glfw.egl.GetProcAddress; + +mixin template _GLFW_EGL_CONTEXT_STATE() { _GLFWcontextEGL egl;} +mixin template _GLFW_EGL_LIBRARY_CONTEXT_STATE() {_GLFWlibraryEGL egl;} + +// EGL-specific per-context data +// +struct _GLFWcontextEGL { + EGLConfig config; + EGLContext handle; + EGLSurface surface; + + void* client; + +}/+alias _GLFWcontextEGL _GLFWcontextEGL;+/ + +// EGL-specific global data +// +struct _GLFWlibraryEGL { + EGLDisplay display; + EGLint major;EGLint minor; + GLFWbool prefix; + + GLFWbool KHR_create_context; + GLFWbool KHR_create_context_no_error; + GLFWbool KHR_gl_colorspace; + GLFWbool KHR_get_all_proc_addresses; + GLFWbool KHR_context_flush_control; + + void* handle; + + PFN_eglGetConfigAttrib GetConfigAttrib; + PFN_eglGetConfigs GetConfigs; + PFN_eglGetDisplay GetDisplay; + PFN_eglGetError GetError; + PFN_eglInitialize Initialize; + PFN_eglTerminate Terminate; + PFN_eglBindAPI BindAPI; + PFN_eglCreateContext CreateContext; + PFN_eglDestroySurface DestroySurface; + PFN_eglDestroyContext DestroyContext; + PFN_eglCreateWindowSurface CreateWindowSurface; + PFN_eglMakeCurrent MakeCurrent; + PFN_eglSwapBuffers SwapBuffers; + PFN_eglSwapInterval SwapInterval; + PFN_eglQueryString QueryString; + PFN_eglGetProcAddress GetProcAddress; + +}/+alias _GLFWlibraryEGL _GLFWlibraryEGL;+/ + + +GLFWbool _glfwInitEGL(); +void _glfwTerminateEGL(); +GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig); +version (_GLFW_X11) { + GLFWbool _glfwChooseVisualEGL(const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig, Visual** visual, int* depth); +} /*_GLFW_X11*/ + +////////////////////// + +import glfw3.internal; + +import core.stdc.stdio; +import core.stdc.string; +import core.stdc.stdlib; +import core.stdc.assert_; +import core.stdc.stdint; + +// Return a description of the specified EGL error +// +static const(char)* getEGLErrorString(EGLint error) { + switch (error) + { + case EGL_SUCCESS: + return "Success"; + case EGL_NOT_INITIALIZED: + return "EGL is not or could not be initialized"; + case EGL_BAD_ACCESS: + return "EGL cannot access a requested resource"; + case EGL_BAD_ALLOC: + return "EGL failed to allocate resources for the requested operation"; + case EGL_BAD_ATTRIBUTE: + return "An unrecognized attribute or attribute value was passed in the attribute list"; + case EGL_BAD_CONTEXT: + return "An EGLContext argument does not name a valid EGL rendering context"; + case EGL_BAD_CONFIG: + return "An EGLConfig argument does not name a valid EGL frame buffer configuration"; + case EGL_BAD_CURRENT_SURFACE: + return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid"; + case EGL_BAD_DISPLAY: + return "An EGLDisplay argument does not name a valid EGL display connection"; + case EGL_BAD_SURFACE: + return "An EGLSurface argument does not name a valid surface configured for GL rendering"; + case EGL_BAD_MATCH: + return "Arguments are inconsistent"; + case EGL_BAD_PARAMETER: + return "One or more argument values are invalid"; + case EGL_BAD_NATIVE_PIXMAP: + return "A NativePixmapType argument does not refer to a valid native pixmap"; + case EGL_BAD_NATIVE_WINDOW: + return "A NativeWindowType argument does not refer to a valid native window"; + case EGL_CONTEXT_LOST: + return "The application must destroy all contexts and reinitialise"; + default: + return "ERROR: UNKNOWN EGL ERROR"; + } +} + +// Returns the specified attribute of the specified EGLConfig +// +static int getEGLConfigAttrib(EGLConfig config, int attrib) { + int value; + _glfw.egl.GetConfigAttrib(_glfw.egl.display, config, attrib, &value); + return value; +} + +// Return the EGLConfig most closely matching the specified hints +// +static GLFWbool chooseEGLConfig(const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* desired, EGLConfig* result) { + EGLConfig* nativeConfigs; + _GLFWfbconfig* usableConfigs; + const(_GLFWfbconfig)* closest; + int i;int nativeCount;int usableCount; + + _glfw.egl.GetConfigs(_glfw.egl.display, null, 0, &nativeCount); + if (!nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned"); + return GLFW_FALSE; + } + + nativeConfigs = cast(typeof(nativeConfigs)) calloc(nativeCount, EGLConfig.sizeof); + _glfw.egl.GetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); + + usableConfigs = cast(typeof(usableConfigs)) calloc(nativeCount, _GLFWfbconfig.sizeof); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + EGLConfig n = nativeConfigs[i]; + _GLFWfbconfig* u = usableConfigs + usableCount; + + // Only consider RGB(A) EGLConfigs + if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER) + continue; + + // Only consider window EGLConfigs + if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT)) + continue; + + version (_GLFW_X11) + { + XVisualInfo vi = XVisualInfo(null); + + // Only consider EGLConfigs with associated Visuals + vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!vi.visualid) + continue; + + if (desired.transparent) + { + int count; + XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count); + if (vis) + { + u.transparent = _glfwIsVisualTransparentX11(vis[0].visual); + XFree(vis); + } + } + } + + if (ctxconfig.client == GLFW_OPENGL_ES_API) + { + if (ctxconfig.major == 1) + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT)) + continue; + } + else + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT)) + continue; + } + } + else if (ctxconfig.client == GLFW_OPENGL_API) + { + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) + continue; + } + + u.redBits = getEGLConfigAttrib(n, EGL_RED_SIZE); + u.greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE); + u.blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE); + + u.alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE); + u.depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE); + u.stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE); + + u.samples = getEGLConfigAttrib(n, EGL_SAMPLES); + u.doublebuffer = GLFW_TRUE; + + u.handle = cast(uintptr_t) n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (closest) + *result = cast(EGLConfig) closest.handle; + + free(nativeConfigs); + free(usableConfigs); + + return closest != null; +} + +static void makeContextCurrentEGL(_GLFWwindow* window) { + if (window) + { + if (!_glfw.egl.MakeCurrent(_glfw.egl.display, + window.context.egl.surface, + window.context.egl.surface, + window.context.egl.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to make context current: %s", + getEGLErrorString(_glfw.egl.GetError())); + return; + } + } + else + { + if (!_glfw.egl.MakeCurrent(_glfw.egl.display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to clear current context: %s", + getEGLErrorString(_glfw.egl.GetError())); + return; + } + } + + _glfwPlatformSetTls(&_glfw.contextSlot, window); +} + +static void swapBuffersEGL(_GLFWwindow* window) { + if (window != _glfwPlatformGetTls(&_glfw.contextSlot)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: The context must be current on the calling thread when swapping buffers"); + return; + } + + _glfw.egl.SwapBuffers(_glfw.egl.display, window.context.egl.surface); +} + +static void swapIntervalEGL(int interval) { + _glfw.egl.SwapInterval(_glfw.egl.display, interval); +} + +static int extensionSupportedEGL(const(char)* extension) { + const(char)* extensions = _glfw.egl.QueryString(_glfw.egl.display, EGL_EXTENSIONS); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressEGL(const(char)* procname) { + auto window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); + + if (window.context.egl.client) + { + GLFWglproc proc = cast(GLFWglproc) _glfw_dlsym(window.context.egl.client, + procname); + if (proc) + return proc; + } + + return _glfw.egl.GetProcAddress(procname); +} + +static void destroyContextEGL(_GLFWwindow* window) { + // NOTE: Do not unload libGL.so.1 while the X11 display is still open, + // as it will make XCloseDisplay segfault + version (_GLFW_X11) { + const bool condition = window.context.client != GLFW_OPENGL_API; + } else { + const bool condition = true; + } + if (condition) + { + if (window.context.egl.client) + { + _glfw_dlclose(window.context.egl.client); + window.context.egl.client = null; + } + } + + if (window.context.egl.surface) + { + _glfw.egl.DestroySurface(_glfw.egl.display, window.context.egl.surface); + window.context.egl.surface = EGL_NO_SURFACE; + } + + if (window.context.egl.handle) + { + _glfw.egl.DestroyContext(_glfw.egl.display, window.context.egl.handle); + window.context.egl.handle = EGL_NO_CONTEXT; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize EGL +// +GLFWbool _glfwInitEGL() { + int i; + version(_GLFW_WIN32) { + static immutable char*[] sonames = ["libEGL.dll", "EGL.dll", null]; + } else version(_GLFW_COCOA) { + static immutable char*[] sonames = ["libEGL.dylib", null]; + } else version(Cygwin) { + static immutable char*[] sonames = ["libEGL-1.so", null]; + } else { + static immutable char*[] sonames = ["libEGL.so.1",null]; + } + + if (_glfw.egl.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.egl.handle = _glfw_dlopen(sonames[i]); + if (_glfw.egl.handle) + break; + } + + if (!_glfw.egl.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found"); + return GLFW_FALSE; + } + + _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0); + + _glfw.egl.GetConfigAttrib = cast(PFN_eglGetConfigAttrib) + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); + _glfw.egl.GetConfigs = cast(PFN_eglGetConfigs) + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs"); + _glfw.egl.GetDisplay = cast(PFN_eglGetDisplay) + _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay"); + _glfw.egl.GetError = cast(PFN_eglGetError) + _glfw_dlsym(_glfw.egl.handle, "eglGetError"); + _glfw.egl.Initialize = cast(PFN_eglInitialize) + _glfw_dlsym(_glfw.egl.handle, "eglInitialize"); + _glfw.egl.Terminate = cast(PFN_eglTerminate) + _glfw_dlsym(_glfw.egl.handle, "eglTerminate"); + _glfw.egl.BindAPI = cast(PFN_eglBindAPI) + _glfw_dlsym(_glfw.egl.handle, "eglBindAPI"); + _glfw.egl.CreateContext = cast(PFN_eglCreateContext) + _glfw_dlsym(_glfw.egl.handle, "eglCreateContext"); + _glfw.egl.DestroySurface = cast(PFN_eglDestroySurface) + _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface"); + _glfw.egl.DestroyContext = cast(PFN_eglDestroyContext) + _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext"); + _glfw.egl.CreateWindowSurface = cast(PFN_eglCreateWindowSurface) + _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface"); + _glfw.egl.MakeCurrent = cast(PFN_eglMakeCurrent) + _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent"); + _glfw.egl.SwapBuffers = cast(PFN_eglSwapBuffers) + _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers"); + _glfw.egl.SwapInterval = cast(PFN_eglSwapInterval) + _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval"); + _glfw.egl.QueryString = cast(PFN_eglQueryString) + _glfw_dlsym(_glfw.egl.handle, "eglQueryString"); + _glfw.egl.GetProcAddress = cast(PFN_eglGetProcAddress) + _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress"); + + if (!_glfw.egl.GetConfigAttrib || + !_glfw.egl.GetConfigs || + !_glfw.egl.GetDisplay || + !_glfw.egl.GetError || + !_glfw.egl.Initialize || + !_glfw.egl.Terminate || + !_glfw.egl.BindAPI || + !_glfw.egl.CreateContext || + !_glfw.egl.DestroySurface || + !_glfw.egl.DestroyContext || + !_glfw.egl.CreateWindowSurface || + !_glfw.egl.MakeCurrent || + !_glfw.egl.SwapBuffers || + !_glfw.egl.SwapInterval || + !_glfw.egl.QueryString || + !_glfw.egl.GetProcAddress) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to load required entry points"); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + _glfw.egl.display = _glfw.egl.GetDisplay(mixin(_GLFW_EGL_NATIVE_DISPLAY)); + if (_glfw.egl.display == EGL_NO_DISPLAY) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to get EGL display: %s", + getEGLErrorString(_glfw.egl.GetError())); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + if (!_glfw.egl.Initialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to initialize EGL: %s", + getEGLErrorString(_glfw.egl.GetError())); + + _glfwTerminateEGL(); + return GLFW_FALSE; + } + + _glfw.egl.KHR_create_context = + extensionSupportedEGL("EGL_KHR_create_context"); + _glfw.egl.KHR_create_context_no_error = + extensionSupportedEGL("EGL_KHR_create_context_no_error"); + _glfw.egl.KHR_gl_colorspace = + extensionSupportedEGL("EGL_KHR_gl_colorspace"); + _glfw.egl.KHR_get_all_proc_addresses = + extensionSupportedEGL("EGL_KHR_get_all_proc_addresses"); + _glfw.egl.KHR_context_flush_control = + extensionSupportedEGL("EGL_KHR_context_flush_control"); + + return GLFW_TRUE; +} + +// Terminate EGL +// +void _glfwTerminateEGL() { + if (_glfw.egl.display) + { + _glfw.egl.Terminate(_glfw.egl.display); + _glfw.egl.display = EGL_NO_DISPLAY; + } + + if (_glfw.egl.handle) + { + _glfw_dlclose(_glfw.egl.handle); + _glfw.egl.handle = null; + } +} + + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + EGLint[40] attribs; + int index = 0; + void setAttrib(EGLint a, EGLint v) { + assert((cast(size_t) index + 1) < attribs.length); + attribs[index++] = a; + attribs[index++] = v; + } + EGLConfig config; + EGLContext share = null; + + if (!_glfw.egl.display) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available"); + return GLFW_FALSE; + } + + if (ctxconfig.share) + share = cast(void*) ctxconfig.share.context.egl.handle; + + if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "EGL: Failed to find a suitable EGLConfig"); + return GLFW_FALSE; + } + + if (ctxconfig.client == GLFW_OPENGL_ES_API) + { + if (!_glfw.egl.BindAPI(EGL_OPENGL_ES_API)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to bind OpenGL ES: %s", + getEGLErrorString(_glfw.egl.GetError())); + return GLFW_FALSE; + } + } + else + { + if (!_glfw.egl.BindAPI(EGL_OPENGL_API)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to bind OpenGL: %s", + getEGLErrorString(_glfw.egl.GetError())); + return GLFW_FALSE; + } + } + + if (_glfw.egl.KHR_create_context) + { + int mask = 0;int flags = 0; + + if (ctxconfig.client == GLFW_OPENGL_API) + { + if (ctxconfig.forward) + flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + + if (ctxconfig.profile == GLFW_OPENGL_CORE_PROFILE) + mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; + else if (ctxconfig.profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; + } + + if (ctxconfig.debug_) + flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + + if (ctxconfig.robustness) + { + if (ctxconfig.robustness == GLFW_NO_RESET_NOTIFICATION) + { + setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_NO_RESET_NOTIFICATION_KHR); + } + else if (ctxconfig.robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_LOSE_CONTEXT_ON_RESET_KHR); + } + + flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; + } + + if (ctxconfig.noerror) + { + if (_glfw.egl.KHR_create_context_no_error) + setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); + } + + if (ctxconfig.major != 1 || ctxconfig.minor != 0) + { + setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig.major); + setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig.minor); + } + + if (mask) + setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); + + if (flags) + setAttrib(EGL_CONTEXT_FLAGS_KHR, flags); + } + else + { + if (ctxconfig.client == GLFW_OPENGL_ES_API) + setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig.major); + } + + if (_glfw.egl.KHR_context_flush_control) + { + if (ctxconfig.release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); + } + else if (ctxconfig.release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); + } + } + + setAttrib(EGL_NONE, EGL_NONE); + + window.context.egl.handle = _glfw.egl.CreateContext(_glfw.egl.display, + config, share, attribs.ptr); + + if (window.context.egl.handle == EGL_NO_CONTEXT) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "EGL: Failed to create context: %s", + getEGLErrorString(_glfw.egl.GetError())); + return GLFW_FALSE; + } + + // Set up attributes for surface creation + { + index = 0; + + if (fbconfig.sRGB) + { + if (_glfw.egl.KHR_gl_colorspace) + setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); + } + + setAttrib(EGL_NONE, EGL_NONE); + } + + window.context.egl.surface = + _glfw.egl.CreateWindowSurface(_glfw.egl.display, + config, + mixin(_GLFW_EGL_NATIVE_WINDOW), + attribs.ptr); + if (window.context.egl.surface == EGL_NO_SURFACE) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to create window surface: %s", + getEGLErrorString(_glfw.egl.GetError())); + return GLFW_FALSE; + } + + window.context.egl.config = config; + + // Load the appropriate client library + if (!_glfw.egl.KHR_get_all_proc_addresses) + { + int i; + const(char*)* sonames; + + version(_GLFW_WIN32) { + static immutable char*[3] es1sonames = ["GLESv1_CM.dll","libGLES_CM.dll", null]; + } else version(_GLFW_COCOA) { + static immutable char*[2] es1sonames = ["libGLESv1_CM.dylib", null]; + } else { + static immutable char*[3] es1sonames = ["libGLESv1_CM.so.1","libGLES_CM.so.1", null]; + } + + version(_GLFW_WIN32) { + static immutable char*[3] es2sonames = ["GLESv2.dll","libGLESv2.dll",null]; + } else version(_GLFW_COCOA) { + static immutable char*[2] es2sonames = ["libGLESv2.dylib",null]; + } else version(Cygwin) { + static immutable char*[2] es2sonames = ["libGLESv2-2.so",null]; + } else { + static immutable char*[2] es2sonames = ["libGLESv2.so.2",null]; + } + + version(_GLFW_WIN32) { + static immutable char*[1] glsonames = [null]; + } else version(_GLFW_COCOA) { + static immutable char*[1] glsonames = [null]; + } else { + static immutable char*[2] glsonames = ["libGL.so.1",null]; + } + + if (ctxconfig.client == GLFW_OPENGL_ES_API) + { + if (ctxconfig.major == 1) + sonames = es1sonames.ptr; + else + sonames = es2sonames.ptr; + } + else + sonames = glsonames.ptr; + + for (i = 0; sonames[i]; i++) + { + // HACK: Match presence of lib prefix to increase chance of finding + // a matching pair in the jungle that is Win32 EGL/GLES + if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0)) + continue; + + window.context.egl.client = _glfw_dlopen(sonames[i]); + if (window.context.egl.client) + break; + } + + if (!window.context.egl.client) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to load client library"); + return GLFW_FALSE; + } + } + + window.context.makeCurrent = &makeContextCurrentEGL; + window.context.swapBuffers = &swapBuffersEGL; + window.context.swapInterval = &swapIntervalEGL; + window.context.extensionSupported = &extensionSupportedEGL; + window.context.getProcAddress = &getProcAddressEGL; + window.context.destroy = &destroyContextEGL; + + return GLFW_TRUE; +} + +// Returns the Visual and depth of the chosen EGLConfig +// +version (_GLFW_X11) { +GLFWbool _glfwChooseVisualEGL( + const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, + const(_GLFWfbconfig)* fbconfig, Visual** visual, int* depth +) { + XVisualInfo* result; + XVisualInfo desired; + EGLConfig native; + EGLint visualID = 0;EGLint count = 0; + const(int) vimask = VisualScreenMask | VisualIDMask; + + if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "EGL: Failed to find a suitable EGLConfig"); + return GLFW_FALSE; + } + + _glfw.egl.GetConfigAttrib(_glfw.egl.display, native, + EGL_NATIVE_VISUAL_ID, &visualID); + + desired.screen = _glfw.x11.screen; + desired.visualid = visualID; + + result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count); + if (!result) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to retrieve Visual for EGLConfig"); + return GLFW_FALSE; + } + + *visual = result.visual; + *depth = result.depth; + + XFree(result); + return GLFW_TRUE; +} +} // _GLFW_X11 + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +EGLDisplay glfwGetEGLDisplay() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("EGL_NO_DISPLAY")); + return _glfw.egl.display; +} + +EGLContext glfwGetEGLContext(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("EGL_NO_CONTEXT")); + + if (window.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); + return EGL_NO_CONTEXT; + } + + return window.context.egl.handle; +} + +EGLSurface glfwGetEGLSurface(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("EGL_NO_SURFACE")); + + if (window.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); + return EGL_NO_SURFACE; + } + + return window.context.egl.surface; +} \ No newline at end of file diff --git a/source/glfw3/glx_context.d b/source/glfw3/glx_context.d new file mode 100644 index 0000000..1ac92d9 --- /dev/null +++ b/source/glfw3/glx_context.d @@ -0,0 +1,803 @@ +/// Translated from C to D +module glfw3.glx_context; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 GLX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +// HEADER + +enum GLX_VENDOR = 1; +enum GLX_RGBA_BIT = 0x00000001; +enum GLX_WINDOW_BIT = 0x00000001; +enum GLX_DRAWABLE_TYPE = 0x8010; +enum GLX_RENDER_TYPE = 0x8011; +enum GLX_RGBA_TYPE = 0x8014; +enum GLX_DOUBLEBUFFER = 5; +enum GLX_STEREO = 6; +enum GLX_AUX_BUFFERS = 7; +enum GLX_RED_SIZE = 8; +enum GLX_GREEN_SIZE = 9; +enum GLX_BLUE_SIZE = 10; +enum GLX_ALPHA_SIZE = 11; +enum GLX_DEPTH_SIZE = 12; +enum GLX_STENCIL_SIZE = 13; +enum GLX_ACCUM_RED_SIZE = 14; +enum GLX_ACCUM_GREEN_SIZE = 15; +enum GLX_ACCUM_BLUE_SIZE = 16; +enum GLX_ACCUM_ALPHA_SIZE = 17; +enum GLX_SAMPLES = 0x186a1; +enum GLX_VISUAL_ID = 0x800b; + +enum GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB = 0x20b2; +enum GLX_CONTEXT_DEBUG_BIT_ARB = 0x00000001; +enum GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002; +enum GLX_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001; +enum GLX_CONTEXT_PROFILE_MASK_ARB = 0x9126; +enum GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x00000002; +enum GLX_CONTEXT_MAJOR_VERSION_ARB = 0x2091; +enum GLX_CONTEXT_MINOR_VERSION_ARB = 0x2092; +enum GLX_CONTEXT_FLAGS_ARB = 0x2094; +enum GLX_CONTEXT_ES2_PROFILE_BIT_EXT = 0x00000004; +enum GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB = 0x00000004; +enum GLX_LOSE_CONTEXT_ON_RESET_ARB = 0x8252; +enum GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB = 0x8256; +enum GLX_NO_RESET_NOTIFICATION_ARB = 0x8261; +enum GLX_CONTEXT_RELEASE_BEHAVIOR_ARB = 0x2097; +enum GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB = 0; +enum GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB = 0x2098; +enum GLX_CONTEXT_OPENGL_NO_ERROR_ARB = 0x31b3; + +alias XID GLXWindow; +alias XID GLXDrawable; +struct __GLXFBConfig ;alias const(__GLXFBConfig)* GLXFBConfig; +struct __GLXcontext ; alias const(__GLXcontext)* GLXContext; +alias void function() __GLXextproc; + +alias int function(Display*, GLXFBConfig, int, int*) PFNGLXGETFBCONFIGATTRIBPROC; +alias const(char)* function(Display*, int) PFNGLXGETCLIENTSTRINGPROC; +alias Bool function(Display*, int*, int*) PFNGLXQUERYEXTENSIONPROC; +alias Bool function(Display*, int*, int*) PFNGLXQUERYVERSIONPROC; +alias void function(Display*, GLXContext) PFNGLXDESTROYCONTEXTPROC; +alias Bool function(Display*, GLXDrawable, GLXContext) PFNGLXMAKECURRENTPROC; +alias void function(Display*, GLXDrawable) PFNGLXSWAPBUFFERSPROC; +alias const(char)* function(Display*, int) PFNGLXQUERYEXTENSIONSSTRINGPROC; +alias GLXFBConfig* function(Display*, int, int*) PFNGLXGETFBCONFIGSPROC; +alias GLXContext function(Display*, GLXFBConfig, int, GLXContext, Bool) PFNGLXCREATENEWCONTEXTPROC; +alias __GLXextproc function(const(GLubyte)* procName) PFNGLXGETPROCADDRESSPROC; +alias void function(Display*, GLXDrawable, int) PFNGLXSWAPINTERVALEXTPROC; +alias XVisualInfo* function(Display*, GLXFBConfig) PFNGLXGETVISUALFROMFBCONFIGPROC; +alias GLXWindow function(Display*, GLXFBConfig, Window, const(int)*) PFNGLXCREATEWINDOWPROC; +alias void function(Display*, GLXWindow) PFNGLXDESTROYWINDOWPROC; + +alias int function(int) PFNGLXSWAPINTERVALMESAPROC; +alias int function(int) PFNGLXSWAPINTERVALSGIPROC; +alias GLXContext function(Display*, GLXFBConfig, GLXContext, Bool, const(int)*) PFNGLXCREATECONTEXTATTRIBSARBPROC; + +// libGL.so function pointer typedefs +alias glXGetFBConfigs = _glfw.glx.GetFBConfigs; +alias glXGetFBConfigAttrib = _glfw.glx.GetFBConfigAttrib; +alias glXGetClientString = _glfw.glx.GetClientString; +alias glXQueryExtension = _glfw.glx.QueryExtension; +alias glXQueryVersion = _glfw.glx.QueryVersion; +alias glXDestroyContext = _glfw.glx.DestroyContext; +alias glXMakeCurrent = _glfw.glx.MakeCurrent; +alias glXSwapBuffers = _glfw.glx.SwapBuffers; +alias glXQueryExtensionsString = _glfw.glx.QueryExtensionsString; +alias glXCreateNewContext = _glfw.glx.CreateNewContext; +alias glXGetVisualFromFBConfig = _glfw.glx.GetVisualFromFBConfig; +alias glXCreateWindow = _glfw.glx.CreateWindow; +alias glXDestroyWindow = _glfw.glx.DestroyWindow; + +mixin template _GLFW_PLATFORM_CONTEXT_STATE() { _GLFWcontextGLX glx;} +mixin template _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE() {_GLFWlibraryGLX glx;} + +// GLX-specific per-context data +// +struct _GLFWcontextGLX { + GLXContext handle; + GLXWindow window; + +}/+alias _GLFWcontextGLX _GLFWcontextGLX;+/ + +// GLX-specific global data +// +struct _GLFWlibraryGLX { + int major;int minor; + int eventBase; + int errorBase; + + // dlopen handle for libGL.so.1 + void* handle; + + // GLX 1.3 functions + PFNGLXGETFBCONFIGSPROC GetFBConfigs; + PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib; + PFNGLXGETCLIENTSTRINGPROC GetClientString; + PFNGLXQUERYEXTENSIONPROC QueryExtension; + PFNGLXQUERYVERSIONPROC QueryVersion; + PFNGLXDESTROYCONTEXTPROC DestroyContext; + PFNGLXMAKECURRENTPROC MakeCurrent; + PFNGLXSWAPBUFFERSPROC SwapBuffers; + PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString; + PFNGLXCREATENEWCONTEXTPROC CreateNewContext; + PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig; + PFNGLXCREATEWINDOWPROC CreateWindow; + PFNGLXDESTROYWINDOWPROC DestroyWindow; + + // GLX 1.4 and extension functions + PFNGLXGETPROCADDRESSPROC GetProcAddress; + PFNGLXGETPROCADDRESSPROC GetProcAddressARB; + PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; + PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; + PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLFWbool SGI_swap_control; + GLFWbool EXT_swap_control; + GLFWbool MESA_swap_control; + GLFWbool ARB_multisample; + GLFWbool ARB_framebuffer_sRGB; + GLFWbool EXT_framebuffer_sRGB; + GLFWbool ARB_create_context; + GLFWbool ARB_create_context_profile; + GLFWbool ARB_create_context_robustness; + GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_create_context_no_error; + GLFWbool ARB_context_flush_control; + +}/+alias _GLFWlibraryGLX _GLFWlibraryGLX;+/ + +GLFWbool _glfwInitGLX(); +void _glfwTerminateGLX(); +GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig); +void _glfwDestroyContextGLX(_GLFWwindow* window); +GLFWbool _glfwChooseVisualGLX(const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig, Visual** visual, int* depth); + +///////////////////////////////// + +import glfw3.internal; + +import core.stdc.string; +import core.stdc.stdlib; +import core.stdc.assert_; +import core.stdc.stdint; + +enum GLXBadProfileARB = 13; + +// Returns the specified attribute of the specified GLXFBConfig +// +static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) { + int value; + _glfw.glx.GetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); + return value; +} + +// Return the GLXFBConfig most closely matching the specified hints +// +static GLFWbool chooseGLXFBConfig(const(_GLFWfbconfig)* desired, GLXFBConfig* result) { + GLXFBConfig* nativeConfigs; + _GLFWfbconfig* usableConfigs; + const(_GLFWfbconfig)* closest; + int i;int nativeCount;int usableCount; + const(char)* vendor; + GLFWbool trustWindowBit = GLFW_TRUE; + + // HACK: This is a (hopefully temporary) workaround for Chromium + // (VirtualBox GL) not setting the window bit on any GLXFBConfigs + vendor = _glfw.glx.GetClientString(_glfw.x11.display, GLX_VENDOR); + if (vendor && strcmp(vendor, "Chromium") == 0) + trustWindowBit = GLFW_FALSE; + + nativeConfigs = + _glfw.glx.GetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount); + if (!nativeConfigs || !nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned"); + return GLFW_FALSE; + } + + usableConfigs = cast(typeof(usableConfigs)) calloc(nativeCount, _GLFWfbconfig.sizeof); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + GLXFBConfig n = nativeConfigs[i]; + _GLFWfbconfig* u = usableConfigs + usableCount; + + // Only consider RGBA GLXFBConfigs + if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) + continue; + + // Only consider window GLXFBConfigs + if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) + { + if (trustWindowBit) + continue; + } + + if (desired.transparent) + { + XVisualInfo* vi = _glfw.glx.GetVisualFromFBConfig(_glfw.x11.display, n); + if (vi) + { + u.transparent = _glfwIsVisualTransparentX11(vi.visual); + XFree(vi); + } + } + + u.redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); + u.greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); + u.blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); + + u.alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE); + u.depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE); + u.stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE); + + u.accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE); + u.accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE); + u.accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE); + u.accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); + + u.auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS); + + if (getGLXFBConfigAttrib(n, GLX_STEREO)) + u.stereo = GLFW_TRUE; + if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER)) + u.doublebuffer = GLFW_TRUE; + + if (_glfw.glx.ARB_multisample) + u.samples = getGLXFBConfigAttrib(n, GLX_SAMPLES); + + if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB) + u.sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); + + u.handle = cast(uintptr_t) n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (closest) + *result = cast(GLXFBConfig) closest.handle; + + XFree(nativeConfigs); + free(usableConfigs); + + return closest != null; +} + +// Create the OpenGL context using legacy API +// +static GLXContext createLegacyContextGLX(_GLFWwindow* window, GLXFBConfig fbconfig, GLXContext share) { + return _glfw.glx.CreateNewContext(_glfw.x11.display, + fbconfig, + GLX_RGBA_TYPE, + share, + True); +} + +static void makeContextCurrentGLX(_GLFWwindow* window) { + if (window) + { + if (!_glfw.glx.MakeCurrent(_glfw.x11.display, + window.context.glx.window, + window.context.glx.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to make context current"); + return; + } + } + else + { + if (!_glfw.glx.MakeCurrent(_glfw.x11.display, None, null)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to clear current context"); + return; + } + } + + _glfwPlatformSetTls(&_glfw.contextSlot, window); +} + +static void swapBuffersGLX(_GLFWwindow* window) { + _glfw.glx.SwapBuffers(_glfw.x11.display, window.context.glx.window); +} + +static void swapIntervalGLX(int interval) { + auto window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); + + if (_glfw.glx.EXT_swap_control) + { + _glfw.glx.SwapIntervalEXT(_glfw.x11.display, + window.context.glx.window, + interval); + } + else if (_glfw.glx.MESA_swap_control) + _glfw.glx.SwapIntervalMESA(interval); + else if (_glfw.glx.SGI_swap_control) + { + if (interval > 0) + _glfw.glx.SwapIntervalSGI(interval); + } +} + +static int extensionSupportedGLX(const(char)* extension) { + const(char)* extensions = _glfw.glx.QueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddressGLX(const(char)* procname) { + if (_glfw.glx.GetProcAddress) + return cast(typeof(return)) _glfw.glx.GetProcAddress(cast(const(GLubyte)*) procname); + else if (_glfw.glx.GetProcAddressARB) + return cast(typeof(return)) _glfw.glx.GetProcAddressARB(cast(const(GLubyte)*) procname); + else + return cast(typeof(return)) _glfw_dlsym(_glfw.glx.handle, procname); +} + +static void destroyContextGLX(_GLFWwindow* window) { + if (window.context.glx.window) + { + _glfw.glx.DestroyWindow(_glfw.x11.display, window.context.glx.window); + window.context.glx.window = None; + } + + if (window.context.glx.handle) + { + _glfw.glx.DestroyContext(_glfw.x11.display, window.context.glx.handle); + window.context.glx.handle = null; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize GLX +// +GLFWbool _glfwInitGLX() { + int i; + version(Cygwin) { + static immutable const(char)*[] sonames = ["libGL-1.so", "libGL.so.1","libGL.so",null]; + } else { + static immutable const(char)*[] sonames = ["libGL.so.1","libGL.so",null]; + } + + if (_glfw.glx.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.glx.handle = _glfw_dlopen(sonames[i]); + if (_glfw.glx.handle) + break; + } + + if (!_glfw.glx.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX"); + return GLFW_FALSE; + } + + _glfw.glx.GetFBConfigs = cast(PFNGLXGETFBCONFIGSPROC) _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigs"); + _glfw.glx.GetFBConfigAttrib = cast(PFNGLXGETFBCONFIGATTRIBPROC) _glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib"); + _glfw.glx.GetClientString = cast(PFNGLXGETCLIENTSTRINGPROC) _glfw_dlsym(_glfw.glx.handle, "glXGetClientString"); + _glfw.glx.QueryExtension = cast(PFNGLXQUERYEXTENSIONPROC) _glfw_dlsym(_glfw.glx.handle, "glXQueryExtension"); + _glfw.glx.QueryVersion = cast(PFNGLXQUERYVERSIONPROC) _glfw_dlsym(_glfw.glx.handle, "glXQueryVersion"); + _glfw.glx.DestroyContext = cast(PFNGLXDESTROYCONTEXTPROC) _glfw_dlsym(_glfw.glx.handle, "glXDestroyContext"); + _glfw.glx.MakeCurrent = cast(PFNGLXMAKECURRENTPROC) _glfw_dlsym(_glfw.glx.handle, "glXMakeCurrent"); + _glfw.glx.SwapBuffers = cast(PFNGLXSWAPBUFFERSPROC) _glfw_dlsym(_glfw.glx.handle, "glXSwapBuffers"); + _glfw.glx.QueryExtensionsString = cast(PFNGLXQUERYEXTENSIONSSTRINGPROC) _glfw_dlsym(_glfw.glx.handle, "glXQueryExtensionsString"); + _glfw.glx.CreateNewContext = cast(PFNGLXCREATENEWCONTEXTPROC) _glfw_dlsym(_glfw.glx.handle, "glXCreateNewContext"); + _glfw.glx.CreateWindow = cast(PFNGLXCREATEWINDOWPROC) _glfw_dlsym(_glfw.glx.handle, "glXCreateWindow"); + _glfw.glx.DestroyWindow = cast(PFNGLXDESTROYWINDOWPROC) _glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow"); + + _glfw.glx.GetProcAddress = cast(PFNGLXGETPROCADDRESSPROC) _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress"); + _glfw.glx.GetProcAddressARB = cast(PFNGLXGETPROCADDRESSPROC) _glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB"); + _glfw.glx.GetVisualFromFBConfig = cast(PFNGLXGETVISUALFROMFBCONFIGPROC) _glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); + + if (!_glfw.glx.GetFBConfigs || + !_glfw.glx.GetFBConfigAttrib || + !_glfw.glx.GetClientString || + !_glfw.glx.QueryExtension || + !_glfw.glx.QueryVersion || + !_glfw.glx.DestroyContext || + !_glfw.glx.MakeCurrent || + !_glfw.glx.SwapBuffers || + !_glfw.glx.QueryExtensionsString || + !_glfw.glx.CreateNewContext || + !_glfw.glx.CreateWindow || + !_glfw.glx.DestroyWindow || + !_glfw.glx.GetProcAddress || + !_glfw.glx.GetProcAddressARB || + !_glfw.glx.GetVisualFromFBConfig) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to load required entry points"); + return GLFW_FALSE; + } + + if (!_glfw.glx.QueryExtension(_glfw.x11.display, + &_glfw.glx.errorBase, + &_glfw.glx.eventBase)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found"); + return GLFW_FALSE; + } + + if (!_glfw.glx.QueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: Failed to query GLX version"); + return GLFW_FALSE; + } + + if (_glfw.glx.major == 1 && _glfw.glx.minor < 3) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: GLX version 1.3 is required"); + return GLFW_FALSE; + } + + if (extensionSupportedGLX("GLX_EXT_swap_control")) + { + _glfw.glx.SwapIntervalEXT = cast(PFNGLXSWAPINTERVALEXTPROC) + getProcAddressGLX("glXSwapIntervalEXT"); + + if (_glfw.glx.SwapIntervalEXT) + _glfw.glx.EXT_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_SGI_swap_control")) + { + _glfw.glx.SwapIntervalSGI = cast(PFNGLXSWAPINTERVALSGIPROC) + getProcAddressGLX("glXSwapIntervalSGI"); + + if (_glfw.glx.SwapIntervalSGI) + _glfw.glx.SGI_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_MESA_swap_control")) + { + _glfw.glx.SwapIntervalMESA = cast(PFNGLXSWAPINTERVALMESAPROC) + getProcAddressGLX("glXSwapIntervalMESA"); + + if (_glfw.glx.SwapIntervalMESA) + _glfw.glx.MESA_swap_control = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_ARB_multisample")) + _glfw.glx.ARB_multisample = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB")) + _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB")) + _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_create_context")) + { + _glfw.glx.CreateContextAttribsARB = cast(PFNGLXCREATECONTEXTATTRIBSARBPROC) + getProcAddressGLX("glXCreateContextAttribsARB"); + + if (_glfw.glx.CreateContextAttribsARB) + _glfw.glx.ARB_create_context = GLFW_TRUE; + } + + if (extensionSupportedGLX("GLX_ARB_create_context_robustness")) + _glfw.glx.ARB_create_context_robustness = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_create_context_profile")) + _glfw.glx.ARB_create_context_profile = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile")) + _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_create_context_no_error")) + _glfw.glx.ARB_create_context_no_error = GLFW_TRUE; + + if (extensionSupportedGLX("GLX_ARB_context_flush_control")) + _glfw.glx.ARB_context_flush_control = GLFW_TRUE; + + return GLFW_TRUE; +} + +// Terminate GLX +// +void _glfwTerminateGLX() { + // NOTE: This function must not call any X11 functions, as it is called + // after XCloseDisplay (see _glfwPlatformTerminate for details) + + if (_glfw.glx.handle) + { + _glfw_dlclose(_glfw.glx.handle); + _glfw.glx.handle = null; + } +} + + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + int[40] attribs; + int index; + void setAttrib(int a, int v) { + assert((cast(size_t) index + 1) < attribs.length); + attribs[index++] = a; + attribs[index++] = v; + } + GLXFBConfig native = null; + GLXContext share = null; + + if (ctxconfig.share) + share = ctxconfig.share.context.glx.handle; + + if (!chooseGLXFBConfig(fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "GLX: Failed to find a suitable GLXFBConfig"); + return GLFW_FALSE; + } + + if (ctxconfig.client == GLFW_OPENGL_ES_API) + { + if (!_glfw.glx.ARB_create_context || + !_glfw.glx.ARB_create_context_profile || + !_glfw.glx.EXT_create_context_es2_profile) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig.forward) + { + if (!_glfw.glx.ARB_create_context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig.profile) + { + if (!_glfw.glx.ARB_create_context || + !_glfw.glx.ARB_create_context_profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + + _glfwGrabErrorHandlerX11(); + + if (_glfw.glx.ARB_create_context) + { + index = 0; + int mask = 0;int flags = 0; + + if (ctxconfig.client == GLFW_OPENGL_API) + { + if (ctxconfig.forward) + flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (ctxconfig.profile == GLFW_OPENGL_CORE_PROFILE) + mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (ctxconfig.profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + else + mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (ctxconfig.debug_) + flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + + if (ctxconfig.robustness) + { + if (_glfw.glx.ARB_create_context_robustness) + { + if (ctxconfig.robustness == GLFW_NO_RESET_NOTIFICATION) + { + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_NO_RESET_NOTIFICATION_ARB); + } + else if (ctxconfig.robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB); + } + + flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (ctxconfig.release) + { + if (_glfw.glx.ARB_context_flush_control) + { + if (ctxconfig.release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig.release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + if (ctxconfig.noerror) + { + if (_glfw.glx.ARB_create_context_no_error) + setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + } + + // NOTE: Only request an explicitly versioned context when necessary, as + // explicitly requesting version 1.0 does not always return the + // highest version supported by the driver + if (ctxconfig.major != 1 || ctxconfig.minor != 0) + { + setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig.major); + setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig.minor); + } + + if (mask) + setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + + if (flags) + setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); + + setAttrib(None, None); + + window.context.glx.handle = + _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, + native, + share, + True, + attribs.ptr); + + // HACK: This is a fallback for broken versions of the Mesa + // implementation of GLX_ARB_create_context_profile that fail + // default 1.0 context creation with a GLXBadProfileARB error in + // violation of the extension spec + if (!window.context.glx.handle) + { + if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && + ctxconfig.client == GLFW_OPENGL_API && + ctxconfig.profile == GLFW_OPENGL_ANY_PROFILE && + ctxconfig.forward == GLFW_FALSE) + { + window.context.glx.handle = + createLegacyContextGLX(window, native, share); + } + } + } + else + { + window.context.glx.handle = + createLegacyContextGLX(window, native, share); + } + + _glfwReleaseErrorHandlerX11(); + + if (!window.context.glx.handle) + { + _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context"); + return GLFW_FALSE; + } + + window.context.glx.window = + _glfw.glx.CreateWindow(_glfw.x11.display, native, window.x11.handle, null); + if (!window.context.glx.window) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window"); + return GLFW_FALSE; + } + + window.context.makeCurrent = &makeContextCurrentGLX; + window.context.swapBuffers = &swapBuffersGLX; + window.context.swapInterval = &swapIntervalGLX; + window.context.extensionSupported = &extensionSupportedGLX; + window.context.getProcAddress = &getProcAddressGLX; + window.context.destroy = &destroyContextGLX; + + return GLFW_TRUE; +} + +// Returns the Visual and depth of the chosen GLXFBConfig +// +GLFWbool _glfwChooseVisualGLX(const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig, Visual** visual, int* depth) { + GLXFBConfig native; + XVisualInfo* result; + + if (!chooseGLXFBConfig(fbconfig, &native)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "GLX: Failed to find a suitable GLXFBConfig"); + return GLFW_FALSE; + } + + result = _glfw.glx.GetVisualFromFBConfig(_glfw.x11.display, native); + if (!result) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to retrieve Visual for GLXFBConfig"); + return GLFW_FALSE; + } + + *visual = result.visual; + *depth = result.depth; + + XFree(result); + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + + GLXContext glfwGetGLXContext(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("null")); + + if (window.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); + return null; + } + + return window.context.glx.handle; +} + +GLXWindow glfwGetGLXWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("None")); + + if (window.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); + return None; + } + + return window.context.glx.window; +} \ No newline at end of file diff --git a/source/glfw3/init.d b/source/glfw3/init.d new file mode 100644 index 0000000..dff13e2 --- /dev/null +++ b/source/glfw3/init.d @@ -0,0 +1,332 @@ +/// Translated from C to D +module glfw3.init; + +extern(C): nothrow: __gshared: +// @nogc: varargs + +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2018 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +import glfw3.internal; +import glfw3.mappings; + +import core.stdc.string; +import core.stdc.stdlib; +import core.stdc.stdio; +import core.stdc.stdarg; +import core.stdc.assert_; + +// The global variables below comprise all mutable global data in GLFW +// +// Any other global variable is a bug + +// Global state shared between compilation units of GLFW +// +_GLFWlibrary _glfw = _GLFWlibrary(GLFW_FALSE); + +// These are outside of _glfw so they can be used before initialization and +// after termination +// +static _GLFWerror _glfwMainThreadError; +static GLFWerrorfun _glfwErrorCallback; +static _GLFWinitconfig _glfwInitHints = _GLFWinitconfig( + GLFW_TRUE, // hat buttons + _GLFWinitconfig._Ns( + GLFW_TRUE, // macOS menu bar + GLFW_TRUE // macOS bundle chdir + ) +); + +// Terminate the library +// +static void terminate() { + int i; + + memset(&_glfw.callbacks, 0, typeof((_glfw.callbacks)).sizeof); + + while (_glfw.windowListHead) + glfwDestroyWindow(cast(GLFWwindow*) _glfw.windowListHead); + + while (_glfw.cursorListHead) + glfwDestroyCursor(cast(GLFWcursor*) _glfw.cursorListHead); + + for (i = 0; i < _glfw.monitorCount; i++) + { + _GLFWmonitor* monitor = _glfw.monitors[i]; + if (monitor.originalRamp.size) + _glfwPlatformSetGammaRamp(monitor, &monitor.originalRamp); + _glfwFreeMonitor(monitor); + } + + free(_glfw.monitors); + _glfw.monitors = null; + _glfw.monitorCount = 0; + + free(_glfw.mappings); + _glfw.mappings = null; + _glfw.mappingCount = 0; + + _glfwTerminateVulkan(); + _glfwPlatformTerminate(); + + _glfw.initialized = GLFW_FALSE; + + while (_glfw.errorListHead) + { + _GLFWerror* error = _glfw.errorListHead; + _glfw.errorListHead = error.next; + free(error); + } + + _glfwPlatformDestroyTls(&_glfw.contextSlot); + _glfwPlatformDestroyTls(&_glfw.errorSlot); + _glfwPlatformDestroyMutex(&_glfw.errorLock); + + memset(&_glfw, 0, typeof(_glfw).sizeof); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +char* _glfw_strdup(const(char)* source) { + const(size_t) length = strlen(source); + auto result = cast(char*) calloc(length + 1, 1); + strcpy(result, source); + return result; +} + +float _glfw_fminf(float a, float b) { + if (a != a) + return b; + else if (b != b) + return a; + else if (a < b) + return a; + else + return b; +} + +float _glfw_fmaxf(float a, float b) { + if (a != a) + return b; + else if (b != b) + return a; + else if (a > b) + return a; + else + return b; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +// Notifies shared code of an error +// +void _glfwInputError(int code, const(char)* format, ...) { + _GLFWerror* error; + char[_GLFW_MESSAGE_SIZE] description; + + if (format) + { + va_list vl; + va_start(vl, format); + vsnprintf(description.ptr, description.length, format, vl); + va_end(vl); + + description[$-1] = '\0'; + } + else + { + if (code == GLFW_NOT_INITIALIZED) + strcpy(description.ptr, "The GLFW library is not initialized"); + else if (code == GLFW_NO_CURRENT_CONTEXT) + strcpy(description.ptr, "There is no current context"); + else if (code == GLFW_INVALID_ENUM) + strcpy(description.ptr, "Invalid argument for enum parameter"); + else if (code == GLFW_INVALID_VALUE) + strcpy(description.ptr, "Invalid value for parameter"); + else if (code == GLFW_OUT_OF_MEMORY) + strcpy(description.ptr, "Out of memory"); + else if (code == GLFW_API_UNAVAILABLE) + strcpy(description.ptr, "The requested API is unavailable"); + else if (code == GLFW_VERSION_UNAVAILABLE) + strcpy(description.ptr, "The requested API version is unavailable"); + else if (code == GLFW_PLATFORM_ERROR) + strcpy(description.ptr, "A platform-specific error occurred"); + else if (code == GLFW_FORMAT_UNAVAILABLE) + strcpy(description.ptr, "The requested format is unavailable"); + else if (code == GLFW_NO_WINDOW_CONTEXT) + strcpy(description.ptr, "The specified window has no context"); + else + strcpy(description.ptr, "ERROR: UNKNOWN GLFW ERROR"); + } + + if (_glfw.initialized) + { + error = cast(_GLFWerror*) _glfwPlatformGetTls(&_glfw.errorSlot); + if (!error) + { + error = cast(_GLFWerror*) calloc(1, _GLFWerror.sizeof); + _glfwPlatformSetTls(&_glfw.errorSlot, error); + _glfwPlatformLockMutex(&_glfw.errorLock); + error.next = _glfw.errorListHead; + _glfw.errorListHead = error; + _glfwPlatformUnlockMutex(&_glfw.errorLock); + } + } + else + error = &_glfwMainThreadError; + + error.code = code; + strcpy(error.description.ptr, description.ptr); + + if (_glfwErrorCallback) + _glfwErrorCallback(code, description.ptr); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +int glfwInit() { + if (_glfw.initialized) + return GLFW_TRUE; + + memset(&_glfw, 0, typeof(_glfw).sizeof); + _glfw.hints.init = _glfwInitHints; + + if (!_glfwPlatformInit()) + { + terminate(); + return GLFW_FALSE; + } + + if (!_glfwPlatformCreateMutex(&_glfw.errorLock) || + !_glfwPlatformCreateTls(&_glfw.errorSlot) || + !_glfwPlatformCreateTls(&_glfw.contextSlot)) + { + terminate(); + return GLFW_FALSE; + } + + _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); + + _glfw.initialized = GLFW_TRUE; + _glfw.timer.offset = _glfwPlatformGetTimerValue(); + + glfwDefaultWindowHints(); + + { + int i; + + for (i = 0; _glfwDefaultMappings[i]; i++) + { + if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i])) + { + terminate(); + return GLFW_FALSE; + } + } + } + + return GLFW_TRUE; +} + +void glfwTerminate() { + if (!_glfw.initialized) + return; + + terminate(); +} + +void glfwInitHint(int hint, int value) { + switch (hint) + { + case GLFW_JOYSTICK_HAT_BUTTONS: + _glfwInitHints.hatButtons = value; + return; + case GLFW_COCOA_CHDIR_RESOURCES: + _glfwInitHints.ns.chdir = value; + return; + case GLFW_COCOA_MENUBAR: + _glfwInitHints.ns.menubar = value; + return; + default: break; + } + + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid init hint 0x%08X", hint); +} + +void glfwGetVersion(int* major, int* minor, int* rev) { + if (major != null) + *major = GLFW_VERSION_MAJOR; + if (minor != null) + *minor = GLFW_VERSION_MINOR; + if (rev != null) + *rev = GLFW_VERSION_REVISION; +} + +const(char)* glfwGetVersionString() { + return _glfwPlatformGetVersionString(); +} + +int glfwGetError(const(char)** description) { + _GLFWerror* error; + int code = GLFW_NO_ERROR; + + if (description) + *description = null; + + if (_glfw.initialized) + error = cast(_GLFWerror*) _glfwPlatformGetTls(&_glfw.errorSlot); + else + error = &_glfwMainThreadError; + + if (error) + { + code = error.code; + error.code = GLFW_NO_ERROR; + if (description && code) + *description = error.description.ptr; + } + + return code; +} + +GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) { + const old = _glfwErrorCallback; + _glfwErrorCallback = cbfun; + return old; +} \ No newline at end of file diff --git a/source/glfw3/input.d b/source/glfw3/input.d new file mode 100644 index 0000000..2e62a50 --- /dev/null +++ b/source/glfw3/input.d @@ -0,0 +1,1294 @@ +/// Translated from C to D +module glfw3.input; + +extern(C): @nogc: nothrow: __gshared: +import core.stdc.config: c_long, c_ulong; + +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +import glfw3.internal; + +import core.stdc.assert_; +import core.stdc.math; +import core.stdc.stdlib; +import core.stdc.string; + +// Internal key state used for sticky keys +enum _GLFW_STICK = 3; + +// Internal constants for gamepad mapping source types +enum _GLFW_JOYSTICK_AXIS = 1; +enum _GLFW_JOYSTICK_BUTTON = 2; +enum _GLFW_JOYSTICK_HATBIT = 3; + +// Finds a mapping based on joystick GUID +// +private _GLFWmapping* findMapping(const(char)* guid) { + int i; + + for (i = 0; i < _glfw.mappingCount; i++) + { + if (strcmp(_glfw.mappings[i].guid.ptr, guid) == 0) + return _glfw.mappings + i; + } + + return null; +} + +// Checks whether a gamepad mapping element is present in the hardware +// +private GLFWbool isValidElementForJoystick(const(_GLFWmapelement)* e, const(_GLFWjoystick)* js) { + if (e.type == _GLFW_JOYSTICK_HATBIT && (e.index >> 4) >= js.hatCount) + return GLFW_FALSE; + else if (e.type == _GLFW_JOYSTICK_BUTTON && e.index >= js.buttonCount) + return GLFW_FALSE; + else if (e.type == _GLFW_JOYSTICK_AXIS && e.index >= js.axisCount) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +// Finds a mapping based on joystick GUID and verifies element indices +// +private _GLFWmapping* findValidMapping(const(_GLFWjoystick)* js) { + _GLFWmapping* mapping = findMapping(js.guid.ptr); + if (mapping) + { + int i; + + for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) + { + if (!isValidElementForJoystick(mapping.buttons.ptr + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid button in gamepad mapping %s (%s)", + mapping.guid.ptr, + mapping.name.ptr); + return null; + } + } + + for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) + { + if (!isValidElementForJoystick(mapping.axes.ptr + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid axis in gamepad mapping %s (%s)", + mapping.guid.ptr, + mapping.name.ptr); + return null; + } + } + } + + return mapping; +} + +// Parses an SDL_GameControllerDB line and adds it to the mapping list +// +private GLFWbool parseMapping(_GLFWmapping* mapping, const(char)* string) { + const(char)* c = string; + size_t i;size_t length; + static struct Field { + const(char)* name; + _GLFWmapelement* element; + } + Field[22] fields = [ + Field("platform", null), + Field("a", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_A), + Field("b", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_B), + Field("x", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_X), + Field("y", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_Y), + Field("back", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_BACK), + Field("start", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_START), + Field("guide", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_GUIDE), + Field("leftshoulder", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_LEFT_BUMPER), + Field("rightshoulder", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER), + Field("leftstick", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_LEFT_THUMB), + Field("rightstick", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_RIGHT_THUMB), + Field("dpup", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_DPAD_UP), + Field("dpright", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_DPAD_RIGHT), + Field("dpdown", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_DPAD_DOWN), + Field("dpleft", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_DPAD_LEFT), + Field("lefttrigger", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_LEFT_TRIGGER), + Field("righttrigger", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER), + Field("leftx", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_LEFT_X), + Field("lefty", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_LEFT_Y), + Field("rightx", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_RIGHT_X), + Field("righty", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_RIGHT_Y), + ]; + + length = strcspn(c, ","); + if (length != 32 || c[length] != ',') + { + _glfwInputError(GLFW_INVALID_VALUE, null); + return GLFW_FALSE; + } + + memcpy(mapping.guid.ptr, c, length); + c += length + 1; + + length = strcspn(c, ","); + if (length >= typeof((mapping.name)).sizeof || c[length] != ',') + { + _glfwInputError(GLFW_INVALID_VALUE, null); + return GLFW_FALSE; + } + + memcpy(mapping.name.ptr, c, length); + c += length + 1; + + while (*c) + { + // TODO: Implement output modifiers + if (*c == '+' || *c == '-') + return GLFW_FALSE; + + for (i = 0; i < fields.sizeof / typeof((fields[0])).sizeof; i++) + { + length = strlen(fields[i].name); + if (strncmp(c, fields[i].name, length) != 0 || c[length] != ':') + continue; + + c += length + 1; + + if (fields[i].element) + { + _GLFWmapelement* e = fields[i].element; + byte minimum = -1; + byte maximum = 1; + + if (*c == '+') + { + minimum = 0; + c += 1; + } + else if (*c == '-') + { + maximum = 0; + c += 1; + } + + if (*c == 'a') + e.type = _GLFW_JOYSTICK_AXIS; + else if (*c == 'b') + e.type = _GLFW_JOYSTICK_BUTTON; + else if (*c == 'h') + e.type = _GLFW_JOYSTICK_HATBIT; + else + break; + + if (e.type == _GLFW_JOYSTICK_HATBIT) + { + const c_ulong hat = strtoul(c + 1, &c, 10); + const c_ulong bit = strtoul(c + 1, &c, 10); + e.index = cast(ubyte) ((hat << 4) | bit); + } + else + e.index = cast(ubyte) strtoul(c + 1, &c, 10); + + if (e.type == _GLFW_JOYSTICK_AXIS) + { + e.axisScale = 2 / (maximum - minimum); + e.axisOffset = cast(byte) -(maximum + minimum); + + if (*c == '~') + { + e.axisScale = cast(byte) -cast(int)e.axisScale; + e.axisOffset = cast(byte) -cast(int)e.axisOffset; + } + } + } + else + { + length = strlen(_GLFW_PLATFORM_MAPPING_NAME); + if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0) + return GLFW_FALSE; + } + + break; + } + + c += strcspn(c, ","); + c += strspn(c, ","); + } + + for (i = 0; i < 32; i++) + { + if (mapping.guid[i] >= 'A' && mapping.guid[i] <= 'F') + mapping.guid[i] += 'a' - 'A'; + } + + _glfwPlatformUpdateGamepadGUID(mapping.guid.ptr); + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +// Notifies shared code of a physical key event +// +void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) { + if (key >= 0 && key <= GLFW_KEY_LAST) + { + GLFWbool repeated = GLFW_FALSE; + + if (action == GLFW_RELEASE && window.keys[key] == GLFW_RELEASE) + return; + + if (action == GLFW_PRESS && window.keys[key] == GLFW_PRESS) + repeated = GLFW_TRUE; + + if (action == GLFW_RELEASE && window.stickyKeys) + window.keys[key] = _GLFW_STICK; + else + window.keys[key] = cast(char) action; + + if (repeated) + action = GLFW_REPEAT; + } + + if (!window.lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + + if (window.callbacks.key) + window.callbacks.key(cast(GLFWwindow*) window, key, scancode, action, mods); +} + +// Notifies shared code of a Unicode codepoint input event +// The 'plain' parameter determines whether to emit a regular character event +// +void _glfwInputChar(_GLFWwindow* window, uint codepoint, int mods, GLFWbool plain) { + if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) + return; + + if (!window.lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + + if (window.callbacks.charmods) + window.callbacks.charmods(cast(GLFWwindow*) window, codepoint, mods); + + if (plain) + { + if (window.callbacks.character) + window.callbacks.character(cast(GLFWwindow*) window, codepoint); + } +} + +// Notifies shared code of a scroll event +// +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) { + if (window.callbacks.scroll) + window.callbacks.scroll(cast(GLFWwindow*) window, xoffset, yoffset); +} + +// Notifies shared code of a mouse button click event +// +void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) { + if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) + return; + + if (!window.lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + + if (action == GLFW_RELEASE && window.stickyMouseButtons) + window.mouseButtons[button] = _GLFW_STICK; + else + window.mouseButtons[button] = cast(char) action; + + if (window.callbacks.mouseButton) + window.callbacks.mouseButton(cast(GLFWwindow*) window, button, action, mods); +} + +// Notifies shared code of a cursor motion event +// The position is specified in content area relative screen coordinates +// +void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) { + if (window.virtualCursorPosX == xpos && window.virtualCursorPosY == ypos) + return; + + window.virtualCursorPosX = xpos; + window.virtualCursorPosY = ypos; + + if (window.callbacks.cursorPos) + window.callbacks.cursorPos(cast(GLFWwindow*) window, xpos, ypos); +} + +// Notifies shared code of a cursor enter/leave event +// +void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) { + if (window.callbacks.cursorEnter) + window.callbacks.cursorEnter(cast(GLFWwindow*) window, entered); +} + +// Notifies shared code of files or directories dropped on a window +// +void _glfwInputDrop(_GLFWwindow* window, int count, const(char)** paths) { + if (window.callbacks.drop) + window.callbacks.drop(cast(GLFWwindow*) window, count, paths); +} + +// Notifies shared code of a joystick connection or disconnection +// +void _glfwInputJoystick(_GLFWjoystick* js, int event) { + const(int) jid = cast(int) (js - _glfw.joysticks.ptr); + + if (_glfw.callbacks.joystick) + _glfw.callbacks.joystick(jid, event); +} + +// Notifies shared code of the new value of a joystick axis +// +void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) { + js.axes[axis] = value; +} + +// Notifies shared code of the new value of a joystick button +// +void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) { + js.buttons[button] = value; +} + +// Notifies shared code of the new value of a joystick hat +// +void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) { + const(int) base = js.buttonCount + hat * 4; + + js.buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; + js.buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE; + js.buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE; + js.buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE; + + js.hats[hat] = value; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Returns an available joystick object with arrays and name allocated +// +_GLFWjoystick* _glfwAllocJoystick(const(char)* name, const(char)* guid, int axisCount, int buttonCount, int hatCount) { + int jid; + _GLFWjoystick* js; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (!_glfw.joysticks[jid].present) + break; + } + + if (jid > GLFW_JOYSTICK_LAST) + return null; + + js = _glfw.joysticks.ptr + jid; + js.present = GLFW_TRUE; + js.name = _glfw_strdup(name); + js.axes = cast(float*) calloc(axisCount, float.sizeof); + js.buttons = cast(ubyte*) calloc(buttonCount + cast(size_t) hatCount * 4, 1); + js.hats = cast(ubyte*) calloc(hatCount, 1); + js.axisCount = axisCount; + js.buttonCount = buttonCount; + js.hatCount = hatCount; + + strncpy(js.guid.ptr, guid, js.guid.length - 1); + js.mapping = findValidMapping(js); + + return js; +} + +// Frees arrays and name and flags the joystick object as unused +// +void _glfwFreeJoystick(_GLFWjoystick* js) { + free(js.name); + free(js.axes); + free(js.buttons); + free(js.hats); + memset(js, 0, _GLFWjoystick.sizeof); +} + +// Center the cursor in the content area of the specified window +// +void _glfwCenterCursorInContentArea(_GLFWwindow* window) { + int width;int height; + + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +int glfwGetInputMode(GLFWwindow* handle, int mode) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0"); + + switch (mode) + { + case GLFW_CURSOR: + return window.cursorMode; + case GLFW_STICKY_KEYS: + return window.stickyKeys; + case GLFW_STICKY_MOUSE_BUTTONS: + return window.stickyMouseButtons; + case GLFW_LOCK_KEY_MODS: + return window.lockKeyMods; + case GLFW_RAW_MOUSE_MOTION: + return window.rawMouseMotion; + default: break; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); + return 0; +} + +void glfwSetInputMode(GLFWwindow* handle, int mode, int value) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + if (mode == GLFW_CURSOR) + { + if (value != GLFW_CURSOR_NORMAL && + value != GLFW_CURSOR_HIDDEN && + value != GLFW_CURSOR_DISABLED) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid cursor mode 0x%08X", + value); + return; + } + + if (window.cursorMode == value) + return; + + window.cursorMode = value; + + _glfwPlatformGetCursorPos(window, + &window.virtualCursorPosX, + &window.virtualCursorPosY); + _glfwPlatformSetCursorMode(window, value); + } + else if (mode == GLFW_STICKY_KEYS) + { + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window.stickyKeys == value) + return; + + if (!value) + { + int i; + + // Release all sticky keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window.keys[i] == _GLFW_STICK) + window.keys[i] = GLFW_RELEASE; + } + } + + window.stickyKeys = value; + } + else if (mode == GLFW_STICKY_MOUSE_BUTTONS) + { + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window.stickyMouseButtons == value) + return; + + if (!value) + { + int i; + + // Release all sticky mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window.mouseButtons[i] == _GLFW_STICK) + window.mouseButtons[i] = GLFW_RELEASE; + } + } + + window.stickyMouseButtons = value; + } + else if (mode == GLFW_LOCK_KEY_MODS) + { + window.lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; + } + else if (mode == GLFW_RAW_MOUSE_MOTION) + { + if (!_glfwPlatformRawMouseMotionSupported()) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Raw mouse motion is not supported on this system"); + return; + } + + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window.rawMouseMotion == value) + return; + + window.rawMouseMotion = value; + _glfwPlatformSetRawMouseMotion(window, value); + } + else + _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); +} + +int glfwRawMouseMotionSupported() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); + return _glfwPlatformRawMouseMotionSupported(); +} + +const(char)* glfwGetKeyName(int key, int scancode) { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (key != GLFW_KEY_UNKNOWN) + { + if (key != GLFW_KEY_KP_EQUAL && + (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) && + (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2)) + { + return null; + } + + scancode = _glfwPlatformGetKeyScancode(key); + } + + return _glfwPlatformGetScancodeName(scancode); +} + +int glfwGetKeyScancode(int key) { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"-1"); + + if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); + return GLFW_RELEASE; + } + + return _glfwPlatformGetKeyScancode(key); +} + +int glfwGetKey(GLFWwindow* handle, int key) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_RELEASE"); + + if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); + return GLFW_RELEASE; + } + + if (window.keys[key] == _GLFW_STICK) + { + // Sticky mode: release key now + window.keys[key] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return cast(int) window.keys[key]; +} + +int glfwGetMouseButton(GLFWwindow* handle, int button) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_RELEASE"); + + if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button); + return GLFW_RELEASE; + } + + if (window.mouseButtons[button] == _GLFW_STICK) + { + // Sticky mode: release mouse button now + window.mouseButtons[button] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return cast(int) window.mouseButtons[button]; +} + +void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + mixin(_GLFW_REQUIRE_INIT); + + if (window.cursorMode == GLFW_CURSOR_DISABLED) + { + if (xpos) + *xpos = window.virtualCursorPosX; + if (ypos) + *ypos = window.virtualCursorPosY; + } + else + _glfwPlatformGetCursorPos(window, xpos, ypos); +} + +void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + if (xpos != xpos || xpos < -double.max || xpos > double.max || + ypos != ypos || ypos < -double.max || ypos > double.max) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid cursor position %f %f", + xpos, ypos); + return; + } + + if (!_glfwPlatformWindowFocused(window)) + return; + + if (window.cursorMode == GLFW_CURSOR_DISABLED) + { + // Only update the accumulated position if the cursor is disabled + window.virtualCursorPosX = xpos; + window.virtualCursorPosY = ypos; + } + else + { + // Update system cursor position + _glfwPlatformSetCursorPos(window, xpos, ypos); + } +} + +GLFWcursor* glfwCreateCursor(const(GLFWimage)* image, int xhot, int yhot) { + _GLFWcursor* cursor; + + assert(image != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + cursor = cast(_GLFWcursor*) calloc(1, _GLFWcursor.sizeof); + cursor.next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot)) + { + glfwDestroyCursor(cast(GLFWcursor*) cursor); + return null; + } + + return cast(GLFWcursor*) cursor; +} + +GLFWcursor* glfwCreateStandardCursor(int shape) { + _GLFWcursor* cursor; + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (shape != GLFW_ARROW_CURSOR && + shape != GLFW_IBEAM_CURSOR && + shape != GLFW_CROSSHAIR_CURSOR && + shape != GLFW_HAND_CURSOR && + shape != GLFW_HRESIZE_CURSOR && + shape != GLFW_VRESIZE_CURSOR) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); + return null; + } + + cursor = cast(_GLFWcursor*) calloc(1, _GLFWcursor.sizeof); + cursor.next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateStandardCursor(cursor, shape)) + { + glfwDestroyCursor(cast(GLFWcursor*) cursor); + return null; + } + + return cast(GLFWcursor*) cursor; +} + +void glfwDestroyCursor(GLFWcursor* handle) { + _GLFWcursor* cursor = cast(_GLFWcursor*) handle; + + mixin(_GLFW_REQUIRE_INIT); + + if (cursor == null) + return; + + // Make sure the cursor is not being used by any window + { + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window.next) + { + if (window.cursor == cursor) + glfwSetCursor(cast(GLFWwindow*) window, null); + } + } + + _glfwPlatformDestroyCursor(cursor); + + // Unlink cursor from global linked list + { + _GLFWcursor** prev = &_glfw.cursorListHead; + + while (*prev != cursor) + prev = &((*prev).next); + + *prev = cursor.next; + } + + free(cursor); +} + +void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) { + _GLFWwindow* window = cast(_GLFWwindow*) windowHandle; + _GLFWcursor* cursor = cast(_GLFWcursor*) cursorHandle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + window.cursor = cursor; + + _glfwPlatformSetCursor(window, cursor); +} + +GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.key, cbfun); + return cbfun; +} + +GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.character, cbfun); + return cbfun; +} + +GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.charmods, cbfun); + return cbfun; +} + +GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, GLFWmousebuttonfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.mouseButton, cbfun); + return cbfun; +} + +GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, GLFWcursorposfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.cursorPos, cbfun); + return cbfun; +} + +GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, GLFWcursorenterfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.cursorEnter, cbfun); + return cbfun; +} + +GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, GLFWscrollfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.scroll, cbfun); + return cbfun; +} + +GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.drop, cbfun); + return cbfun; +} + +int glfwJoystickPresent(int jid) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return GLFW_FALSE; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return GLFW_FALSE; + + return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); +} + +const(float)* glfwGetJoystickAxes(int jid, int* count) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(count != null); + + *count = 0; + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return null; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return null; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) + return null; + + *count = js.axisCount; + return js.axes; +} + +const(ubyte)* glfwGetJoystickButtons(int jid, int* count) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(count != null); + + *count = 0; + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return null; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return null; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) + return null; + + if (_glfw.hints.init.hatButtons) + *count = js.buttonCount + js.hatCount * 4; + else + *count = js.buttonCount; + + return js.buttons; +} + +const(ubyte)* glfwGetJoystickHats(int jid, int* count) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(count != null); + + *count = 0; + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return null; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return null; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) + return null; + + *count = js.hatCount; + return js.hats; +} + +const(char)* glfwGetJoystickName(int jid) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return null; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return null; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return null; + + return js.name; +} + +const(char)* glfwGetJoystickGUID(int jid) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return null; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return null; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return null; + + return js.guid.ptr; +} + +void glfwSetJoystickUserPointer(int jid, void* pointer) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + mixin(_GLFW_REQUIRE_INIT); + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return; + + js.userPointer = pointer; +} + +void* glfwGetJoystickUserPointer(int jid) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return null; + + return js.userPointer; +} + +GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun); + return cbfun; +} + +int glfwUpdateGamepadMappings(const(char)* string) { + int jid; + const(char)* c = string; + + assert(string != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); + + while (*c) + { + if ((*c >= '0' && *c <= '9') || + (*c >= 'a' && *c <= 'f') || + (*c >= 'A' && *c <= 'F')) + { + char[1024] line; + + const(size_t) length = strcspn(c, "\r\n"); + if (length < typeof(line).sizeof) + { + _GLFWmapping mapping = _GLFWmapping.init; + + memcpy(line.ptr, c, length); + line[length] = '\0'; + + if (parseMapping(&mapping, line.ptr)) + { + _GLFWmapping* previous = findMapping(mapping.guid.ptr); + if (previous) + *previous = mapping; + else + { + _glfw.mappingCount++; + _glfw.mappings = + cast(_GLFWmapping*) realloc(_glfw.mappings, + _GLFWmapping.sizeof * _glfw.mappingCount); + _glfw.mappings[_glfw.mappingCount - 1] = mapping; + } + } + } + + c += length; + } + else + { + c += strcspn(c, "\r\n"); + c += strspn(c, "\r\n"); + } + } + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks.ptr + jid; + if (js.present) + js.mapping = findValidMapping(js); + } + + return GLFW_TRUE; +} + +int glfwJoystickIsGamepad(int jid) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return GLFW_FALSE; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return GLFW_FALSE; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return GLFW_FALSE; + + return js.mapping != null; +} + +const(char)* glfwGetGamepadName(int jid) { + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return null; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return null; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + return null; + + if (!js.mapping) + return null; + + return js.mapping.name.ptr; +} + +int glfwGetGamepadState(int jid, GLFWgamepadstate* state) { + int i; + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + assert(state != null); + + memset(state, 0, GLFWgamepadstate.sizeof); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); + + if (jid < 0 || jid > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); + return GLFW_FALSE; + } + + js = _glfw.joysticks.ptr + jid; + if (!js.present) + return GLFW_FALSE; + + if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) + return GLFW_FALSE; + + if (!js.mapping) + return GLFW_FALSE; + + for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) + { + const(_GLFWmapelement)* e = js.mapping.buttons.ptr + i; + if (e.type == _GLFW_JOYSTICK_AXIS) + { + const(float) value = js.axes[e.index] * e.axisScale + e.axisOffset; + // HACK: This should be baked into the value transform + // TODO: Bake into transform when implementing output modifiers + if (e.axisOffset < 0 || (e.axisOffset == 0 && e.axisScale > 0)) + { + if (value >= 0.0f) + state.buttons[i] = GLFW_PRESS; + } + else + { + if (value <= 0.0f) + state.buttons[i] = GLFW_PRESS; + } + } + else if (e.type == _GLFW_JOYSTICK_HATBIT) + { + const(uint) hat = e.index >> 4; + const(uint) bit = e.index & 0xf; + if (js.hats[hat] & bit) + state.buttons[i] = GLFW_PRESS; + } + else if (e.type == _GLFW_JOYSTICK_BUTTON) + state.buttons[i] = js.buttons[e.index]; + } + + for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) + { + const(_GLFWmapelement)* e = js.mapping.axes.ptr + i; + if (e.type == _GLFW_JOYSTICK_AXIS) + { + const(float) value = js.axes[e.index] * e.axisScale + e.axisOffset; + state.axes[i] = _glfw_fminf(_glfw_fmaxf(value, -1.0f), 1.0f); + } + else if (e.type == _GLFW_JOYSTICK_HATBIT) + { + const(uint) hat = e.index >> 4; + const(uint) bit = e.index & 0xf; + if (js.hats[hat] & bit) + state.axes[i] = 1.0f; + else + state.axes[i] = -1.0f; + } + else if (e.type == _GLFW_JOYSTICK_BUTTON) + state.axes[i] = js.buttons[e.index] * 2.0f - 1.0f; + } + + return GLFW_TRUE; +} + +void glfwSetClipboardString(GLFWwindow* handle, const(char)* string) { + assert(string != null); + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformSetClipboardString(string); +} + +const(char)* glfwGetClipboardString(GLFWwindow* handle) { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return _glfwPlatformGetClipboardString(); +} + +double glfwGetTime() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0.0"); + return cast(double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) / + _glfwPlatformGetTimerFrequency(); +} + +void glfwSetTime(double time) { + mixin(_GLFW_REQUIRE_INIT); + + if (time != time || time < 0.0 || time > 18446744073.0) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); + return; + } + + _glfw.timer.offset = _glfwPlatformGetTimerValue() - + cast(ulong) (time * _glfwPlatformGetTimerFrequency()); +} + +ulong glfwGetTimerValue() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0"); + return _glfwPlatformGetTimerValue(); +} + +ulong glfwGetTimerFrequency() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0"); + return _glfwPlatformGetTimerFrequency(); +} \ No newline at end of file diff --git a/source/glfw3/internal.d b/source/glfw3/internal.d new file mode 100644 index 0000000..3405664 --- /dev/null +++ b/source/glfw3/internal.d @@ -0,0 +1,711 @@ +/// Translated from C to D +module glfw3.internal; + +extern(C): @nogc: nothrow: __gshared: + +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +public import glfw3.api; +import core.stdc.stdint; + +enum _GLFW_INSERT_FIRST = 0; +enum _GLFW_INSERT_LAST = 1; + +enum _GLFW_POLL_PRESENCE = 0; +enum _GLFW_POLL_AXES = 1; +enum _GLFW_POLL_BUTTONS = 2; +enum _GLFW_POLL_ALL = (_GLFW_POLL_AXES | _GLFW_POLL_BUTTONS); + +enum _GLFW_MESSAGE_SIZE = 1024; + +alias int GLFWbool; + +alias void function(_GLFWwindow*) _GLFWmakecontextcurrentfun; +alias void function(_GLFWwindow*) _GLFWswapbuffersfun; +alias void function(int) _GLFWswapintervalfun; +alias int function(const(char)*) _GLFWextensionsupportedfun; +alias GLFWglproc function(const(char)*) _GLFWgetprocaddressfun; +alias void function(_GLFWwindow*) _GLFWdestroycontextfun; + +enum GL_VERSION = 0x1f02; +enum GL_NONE = 0; +enum GL_COLOR_BUFFER_BIT = 0x00004000; +enum GL_UNSIGNED_BYTE = 0x1401; +enum GL_EXTENSIONS = 0x1f03; +enum GL_NUM_EXTENSIONS = 0x821d; +enum GL_CONTEXT_FLAGS = 0x821e; +enum GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT = 0x00000001; +enum GL_CONTEXT_FLAG_DEBUG_BIT = 0x00000002; +enum GL_CONTEXT_PROFILE_MASK = 0x9126; +enum GL_CONTEXT_COMPATIBILITY_PROFILE_BIT = 0x00000002; +enum GL_CONTEXT_CORE_PROFILE_BIT = 0x00000001; +enum GL_RESET_NOTIFICATION_STRATEGY_ARB = 0x8256; +enum GL_LOSE_CONTEXT_ON_RESET_ARB = 0x8252; +enum GL_NO_RESET_NOTIFICATION_ARB = 0x8261; +enum GL_CONTEXT_RELEASE_BEHAVIOR = 0x82fb; +enum GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH = 0x82fc; +enum GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR = 0x00000008; + +alias int GLint; +alias uint GLuint; +alias uint GLenum; +alias uint GLbitfield; +alias ubyte GLubyte; + +// APIENTRY +alias PFNGLCLEARPROC = extern(Windows) void function(GLbitfield); +alias PFNGLGETSTRINGPROC = extern(Windows) const(GLubyte)* function(GLenum); +alias PFNGLGETINTEGERVPROC = extern(Windows) void function(GLenum, GLint*); +alias PFNGLGETSTRINGIPROC = extern(Windows) const(GLubyte)* function(GLenum, GLuint); + +enum VK_NULL_HANDLE = 0; + +alias void* VkInstance; +alias void* VkPhysicalDevice; +alias ulong VkSurfaceKHR; +alias uint VkFlags; +alias uint VkBool32; + +enum VkStructureType{ + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, + VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, + VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +}/+alias VkStructureType VkStructureType;+/ + +enum VkResult { + VK_SUCCESS = 0, + VK_NOT_READY = 1, + VK_TIMEOUT = 2, + VK_EVENT_SET = 3, + VK_EVENT_RESET = 4, + VK_INCOMPLETE = 5, + VK_ERROR_OUT_OF_HOST_MEMORY = -1, + VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, + VK_ERROR_INITIALIZATION_FAILED = -3, + VK_ERROR_DEVICE_LOST = -4, + VK_ERROR_MEMORY_MAP_FAILED = -5, + VK_ERROR_LAYER_NOT_PRESENT = -6, + VK_ERROR_EXTENSION_NOT_PRESENT = -7, + VK_ERROR_FEATURE_NOT_PRESENT = -8, + VK_ERROR_INCOMPATIBLE_DRIVER = -9, + VK_ERROR_TOO_MANY_OBJECTS = -10, + VK_ERROR_FORMAT_NOT_SUPPORTED = -11, + VK_ERROR_SURFACE_LOST_KHR = -1000000000, + VK_SUBOPTIMAL_KHR = 1000001003, + VK_ERROR_OUT_OF_DATE_KHR = -1000001004, + VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, + VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, + VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, + VK_RESULT_MAX_ENUM = 0x7FFFFFFF +}/+alias VkResult VkResult;+/ + +struct VkAllocationCallbacks; + +struct VkExtensionProperties{ + char[256] extensionName; + uint specVersion; +}/+alias VkExtensionProperties VkExtensionProperties;+/ + +alias PFN_vkVoidFunction = void function(); + +version (_GLFW_VULKAN_STATIC) { + PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance, const(char)*); + VkResult vkEnumerateInstanceExtensionProperties(const(char)*, uint*, VkExtensionProperties*); +} else { + alias PFN_vkGetInstanceProcAddr = PFN_vkVoidFunction function(VkInstance,const(char)*); + alias PFN_vkEnumerateInstanceExtensionProperties = VkResult function(const(char)*,uint*,VkExtensionProperties*); + enum vkEnumerateInstanceExtensionProperties = "_glfw.vk.EnumerateInstanceExtensionProperties"; + enum vkGetInstanceProcAddr = "_glfw.vk.GetInstanceProcAddr"; +} + +version (_GLFW_COCOA) { + public import glfw3.cocoa_platform; +} else version (_GLFW_WIN32) { + public import glfw3.win32_platform; +} else version (_GLFW_X11) { + public import glfw3.x11_platform; +} else version (_GLFW_WAYLAND) { + public import glfw3.wl_platform; +} else version (_GLFW_OSMESA) { + public import glfw3.null_platform; +} else { + static assert(0, "No supported window creation API selected"); +} + +// Constructs a version number string from the public header macros +enum string _GLFW_CONCAT_VERSION(string m, string n, string r) = ` #m "." #n "." #r`; +enum string _GLFW_MAKE_VERSION(string m, string n, string r) = ` _GLFW_CONCAT_VERSION(m, n, r)`; +enum _GLFW_VERSION_NUMBER = + GLFW_VERSION_MAJOR.stringof ~ "." ~ GLFW_VERSION_MINOR.stringof ~ "." ~ GLFW_VERSION_REVISION.stringof; + +// Checks for whether the library has been initialized +enum string _GLFW_REQUIRE_INIT = ` + if (!_glfw.initialized) + { + _glfwInputError(GLFW_NOT_INITIALIZED, null); + return; + }`; +enum string _GLFW_REQUIRE_INIT_OR_RETURN(string x) = ` + if (!_glfw.initialized) + { + _glfwInputError(GLFW_NOT_INITIALIZED, null); + return `~x~`; + }`; + +// Swaps the provided pointers +void _GLFW_SWAP_POINTERS(T, U)(ref T x, ref U y) { + auto t = x; + x = y; + y = t; +} + +// Per-thread error structure +// +struct _GLFWerror +{ + _GLFWerror* next; + int code; + char[_GLFW_MESSAGE_SIZE] description; +} + +// Initialization configuration +// +// Parameters relating to the initialization of the library +// +struct _GLFWinitconfig +{ + GLFWbool hatButtons; + struct _Ns{ + GLFWbool menubar; + GLFWbool chdir; + }_Ns ns; +} + +// Window configuration +// +// Parameters relating to the creation of the window but not directly related +// to the framebuffer. This is used to pass window creation parameters from +// shared code to the platform API. +// +struct _GLFWwndconfig +{ + int width; + int height; + const(char)* title; + GLFWbool resizable; + GLFWbool visible; + GLFWbool decorated; + GLFWbool focused; + GLFWbool autoIconify; + GLFWbool floating; + GLFWbool maximized; + GLFWbool centerCursor; + GLFWbool focusOnShow; + GLFWbool scaleToMonitor; + struct _Ns{ + GLFWbool retina; + char[256] frameName = '\0'; + }_Ns ns; + struct _X11{ + char[256] className = '\0'; + char[256] instanceName = '\0'; + }_X11 x11; +} + +// Context configuration +// +// Parameters relating to the creation of the context but not directly related +// to the framebuffer. This is used to pass context creation parameters from +// shared code to the platform API. +// +struct _GLFWctxconfig +{ + int client; + int source; + int major; + int minor; + GLFWbool forward; + GLFWbool debug_; + GLFWbool noerror; + int profile; + int robustness; + int release; + _GLFWwindow* share; + struct _Nsgl{ + GLFWbool offline; + }_Nsgl nsgl; +} + +// Framebuffer configuration +// +// This describes buffers and their sizes. It also contains +// a platform-specific ID used to map back to the backend API object. +// +// It is used to pass framebuffer parameters from shared code to the platform +// API and also to enumerate and select available framebuffer configs. +// +struct _GLFWfbconfig +{ + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + GLFWbool stereo; + int samples; + GLFWbool sRGB; + GLFWbool doublebuffer; + GLFWbool transparent; + uintptr_t handle; +} + +// Context structure +// +struct _GLFWcontext +{ + int client; + int source; + int major;int minor;int revision; + GLFWbool forward;GLFWbool debug_;GLFWbool noerror; + int profile; + int robustness; + int release; + + PFNGLGETSTRINGIPROC GetStringi; + PFNGLGETINTEGERVPROC GetIntegerv; + PFNGLGETSTRINGPROC GetString; + + _GLFWmakecontextcurrentfun makeCurrent; + _GLFWswapbuffersfun swapBuffers; + _GLFWswapintervalfun swapInterval; + _GLFWextensionsupportedfun extensionSupported; + _GLFWgetprocaddressfun getProcAddress; + _GLFWdestroycontextfun destroy; + + // This is defined in the context API's context.h + mixin _GLFW_PLATFORM_CONTEXT_STATE; + // This is defined in egl_context.h + mixin _GLFW_EGL_CONTEXT_STATE; + // This is defined in osmesa_context.h + mixin _GLFW_OSMESA_CONTEXT_STATE; +} + +// Window and context structure +// +struct _GLFWwindow +{ + _GLFWwindow* next; + + // Window settings and state + GLFWbool resizable; + GLFWbool decorated; + GLFWbool autoIconify; + GLFWbool floating; + GLFWbool focusOnShow; + GLFWbool shouldClose; + void* userPointer; + GLFWvidmode videoMode; + _GLFWmonitor* monitor; + _GLFWcursor* cursor; + + int minwidth;int minheight; + int maxwidth;int maxheight; + int numer;int denom; + + GLFWbool stickyKeys; + GLFWbool stickyMouseButtons; + GLFWbool lockKeyMods; + int cursorMode; + char[GLFW_MOUSE_BUTTON_LAST + 1] mouseButtons = 0; + char[GLFW_KEY_LAST + 1] keys = 0; + // Virtual cursor position when cursor is disabled + double virtualCursorPosX;double virtualCursorPosY; + GLFWbool rawMouseMotion; + + _GLFWcontext context; + + struct _Callbacks{ + GLFWwindowposfun pos; + GLFWwindowsizefun size; + GLFWwindowclosefun close; + GLFWwindowrefreshfun refresh; + GLFWwindowfocusfun focus; + GLFWwindowiconifyfun iconify; + GLFWwindowmaximizefun maximize; + GLFWframebuffersizefun fbsize; + GLFWwindowcontentscalefun scale; + GLFWmousebuttonfun mouseButton; + GLFWcursorposfun cursorPos; + GLFWcursorenterfun cursorEnter; + GLFWscrollfun scroll; + GLFWkeyfun key; + GLFWcharfun character; + GLFWcharmodsfun charmods; + GLFWdropfun drop; + }_Callbacks callbacks; + + // This is defined in the window API's platform.h + mixin _GLFW_PLATFORM_WINDOW_STATE; +} + +// Monitor structure +// +struct _GLFWmonitor +{ + char* name; + void* userPointer; + + // Physical dimensions in millimeters. + int widthMM;int heightMM; + + // The window whose video mode is current on this monitor + _GLFWwindow* window; + + GLFWvidmode* modes; + int modeCount; + GLFWvidmode currentMode; + + GLFWgammaramp originalRamp; + GLFWgammaramp currentRamp; + + // This is defined in the window API's platform.h + mixin _GLFW_PLATFORM_MONITOR_STATE; +} + +// Cursor structure +// +struct _GLFWcursor +{ + _GLFWcursor* next; + + // This is defined in the window API's platform.h + mixin _GLFW_PLATFORM_CURSOR_STATE; +} + +// Gamepad mapping element structure +// +struct _GLFWmapelement +{ + ubyte type; + ubyte index; + byte axisScale; + byte axisOffset; +} + +// Gamepad mapping structure +// +struct _GLFWmapping +{ + char[128] name = '\0'; + char[33] guid = '\0'; + _GLFWmapelement[15] buttons; + _GLFWmapelement[6] axes; +} + +// Joystick structure +// +struct _GLFWjoystick +{ + GLFWbool present; + float* axes; + int axisCount; + ubyte* buttons; + int buttonCount; + ubyte* hats; + int hatCount; + char* name; + void* userPointer; + char[33] guid = '\0'; + _GLFWmapping* mapping; + + // This is defined in the joystick API's joystick.h + mixin _GLFW_PLATFORM_JOYSTICK_STATE; +} + +// Thread local storage structure +// +struct _GLFWtls +{ + // This is defined in the platform's thread.h + mixin _GLFW_PLATFORM_TLS_STATE; +} + +// Mutex structure +// +struct _GLFWmutex +{ + // This is defined in the platform's thread.h + mixin _GLFW_PLATFORM_MUTEX_STATE; +} + +// Library global data +// +struct _GLFWlibrary +{ + GLFWbool initialized; + + struct _Hints{ + _GLFWinitconfig init; + _GLFWfbconfig framebuffer; + _GLFWwndconfig window; + _GLFWctxconfig context; + int refreshRate; + }_Hints hints; + + _GLFWerror* errorListHead; + _GLFWcursor* cursorListHead; + _GLFWwindow* windowListHead; + + _GLFWmonitor** monitors; + int monitorCount; + + _GLFWjoystick[GLFW_JOYSTICK_LAST + 1] joysticks; + _GLFWmapping* mappings; + int mappingCount; + + _GLFWtls errorSlot; + _GLFWtls contextSlot; + _GLFWmutex errorLock; + + struct _Timer{ + ulong offset; + // This is defined in the platform's time.h + mixin _GLFW_PLATFORM_LIBRARY_TIMER_STATE; + }_Timer timer; + + struct _Vk{ + GLFWbool available; + void* handle; + char*[2] extensions; +version(_GLFW_VULKAN_STATIC) {} else { + PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; + PFN_vkGetInstanceProcAddr GetInstanceProcAddr; +} + GLFWbool KHR_surface; +version (_GLFW_WIN32) { + GLFWbool KHR_win32_surface; +} else version (_GLFW_COCOA) { + GLFWbool MVK_macos_surface; + GLFWbool EXT_metal_surface; +} else version (_GLFW_X11) { + GLFWbool KHR_xlib_surface; + GLFWbool KHR_xcb_surface; +} else version (_GLFW_WAYLAND) { + GLFWbool KHR_wayland_surface; +} + }_Vk vk; + + struct _Callbacks{ + GLFWmonitorfun monitor; + GLFWjoystickfun joystick; + }_Callbacks callbacks; + + // This is defined in the window API's platform.h + mixin _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; + // This is defined in the context API's context.h + mixin _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE; + // This is defined in the platform's joystick.h + mixin _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; + // This is defined in egl_context.h + mixin _GLFW_EGL_LIBRARY_CONTEXT_STATE; + // This is defined in osmesa_context.h + mixin _GLFW_OSMESA_LIBRARY_CONTEXT_STATE; +} + +// Global state shared between compilation units of GLFW +// +extern _GLFWlibrary _glfw; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(); +void _glfwPlatformTerminate(); +const(char)* _glfwPlatformGetVersionString(); + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos); +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); +void _glfwPlatformSetRawMouseMotion(_GLFWwindow* window, GLFWbool enabled); +GLFWbool _glfwPlatformRawMouseMotionSupported(); +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const(GLFWimage)* image, int xhot, int yhot); +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor); +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); + +const(char)* _glfwPlatformGetScancodeName(int scancode); +int _glfwPlatformGetKeyScancode(int key); + +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor); +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale); +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const(GLFWgammaramp)* ramp); + +void _glfwPlatformSetClipboardString(const(char)* string); +const(char)* _glfwPlatformGetClipboardString(); + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); +void _glfwPlatformUpdateGamepadGUID(char* guid); + +ulong _glfwPlatformGetTimerValue(); +ulong _glfwPlatformGetTimerFrequency(); + +int _glfwPlatformCreateWindow(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig); +void _glfwPlatformDestroyWindow(_GLFWwindow* window); +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const(char)* title); +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const(GLFWimage)* images); +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos); +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos); +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height); +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom); +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale); +void _glfwPlatformIconifyWindow(_GLFWwindow* window); +void _glfwPlatformRestoreWindow(_GLFWwindow* window); +void _glfwPlatformMaximizeWindow(_GLFWwindow* window); +void _glfwPlatformShowWindow(_GLFWwindow* window); +void _glfwPlatformHideWindow(_GLFWwindow* window); +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); +void _glfwPlatformFocusWindow(_GLFWwindow* window); +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); +int _glfwPlatformWindowFocused(_GLFWwindow* window); +int _glfwPlatformWindowIconified(_GLFWwindow* window); +int _glfwPlatformWindowVisible(_GLFWwindow* window); +int _glfwPlatformWindowMaximized(_GLFWwindow* window); +int _glfwPlatformWindowHovered(_GLFWwindow* window); +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity); + +void _glfwPlatformPollEvents(); +void _glfwPlatformWaitEvents(); +void _glfwPlatformWaitEventsTimeout(double timeout); +void _glfwPlatformPostEmptyEvent(); + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions); +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint queuefamily); +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const(VkAllocationCallbacks)* allocator, VkSurfaceKHR* surface); + +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls); +void _glfwPlatformDestroyTls(_GLFWtls* tls); +void* _glfwPlatformGetTls(_GLFWtls* tls); +void _glfwPlatformSetTls(_GLFWtls* tls, void* value); + +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex); +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex); +void _glfwPlatformLockMutex(_GLFWmutex* mutex); +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex); + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused); +void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos); +void _glfwInputWindowSize(_GLFWwindow* window, int width, int height); +void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); +void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale); +void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified); +void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized); +void _glfwInputWindowDamage(_GLFWwindow* window); +void _glfwInputWindowCloseRequest(_GLFWwindow* window); +void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); + +void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); +void _glfwInputChar(_GLFWwindow* window, uint codepoint, int mods, GLFWbool plain); +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset); +void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); +void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); +void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered); +void _glfwInputDrop(_GLFWwindow* window, int count, const(char)** names); +void _glfwInputJoystick(_GLFWjoystick* js, int event); +void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value); +void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value); +void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value); + +void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement); +void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window); + +static if (__VERSION__ >= 2092) { + pragma(printf) + void _glfwInputError(int code, const(char)* format, ...); +} else { + void _glfwInputError(int code, const(char)* format, ...); +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwStringInExtensionString(const(char)* string, const(char)* extensions); +const(_GLFWfbconfig)* _glfwChooseFBConfig(const(_GLFWfbconfig)* desired, const(_GLFWfbconfig)* alternatives, uint count); +GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig); +GLFWbool _glfwIsValidContextConfig(const(_GLFWctxconfig)* ctxconfig); + +const(GLFWvidmode)* _glfwChooseVideoMode(_GLFWmonitor* monitor, const(GLFWvidmode)* desired); +int _glfwCompareVideoModes(const(GLFWvidmode)* first, const(GLFWvidmode)* second); +_GLFWmonitor* _glfwAllocMonitor(const(char)* name, int widthMM, int heightMM); +void _glfwFreeMonitor(_GLFWmonitor* monitor); +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, uint size); +void _glfwFreeGammaArrays(GLFWgammaramp* ramp); +void _glfwSplitBPP(int bpp, int* red, int* green, int* blue); + +_GLFWjoystick* _glfwAllocJoystick(const(char)* name, const(char)* guid, int axisCount, int buttonCount, int hatCount); +void _glfwFreeJoystick(_GLFWjoystick* js); +void _glfwCenterCursorInContentArea(_GLFWwindow* window); + +GLFWbool _glfwInitVulkan(int mode); +void _glfwTerminateVulkan(); +const(char)* _glfwGetVulkanResultString(VkResult result); + +char* _glfw_strdup(const(char)* source); +float _glfw_fminf(float a, float b); +float _glfw_fmaxf(float a, float b); \ No newline at end of file diff --git a/source/glfw3/linux_joystick.d b/source/glfw3/linux_joystick.d new file mode 100644 index 0000000..78b3d07 --- /dev/null +++ b/source/glfw3/linux_joystick.d @@ -0,0 +1,511 @@ +/// Translated from C to D +module glfw3.linux_joystick; + +extern(C): @nogc: nothrow: __gshared: + +//======================================================================== +// GLFW 3.3 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +import core.sys.posix.sys.types; +import core.sys.posix.sys.stat; +import core.sys.linux.sys.inotify; +import core.sys.posix.fcntl; +import core.stdc.errno; +import core.sys.posix.dirent; +import core.stdc.stdio; +import core.stdc.stdlib; +import core.stdc.string; +import core.sys.posix.unistd; + +public import glfw3.linuxinput; +import core.stdc.limits; + +import core.sys.posix.sys.ioctl: ioctl; + +mixin template _GLFW_PLATFORM_JOYSTICK_STATE() { _GLFWjoystickLinux linjs; } +mixin template _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE() {_GLFWlibraryLinux linjs; } + +enum _GLFW_PLATFORM_MAPPING_NAME = "Linux"; + +// Linux-specific joystick data +// +struct _GLFWjoystickLinux { + int fd; + char[PATH_MAX] path = '\0'; + int[KEY_CNT - BTN_MISC] keyMap; + int[ABS_CNT] absMap; + input_absinfo[ABS_CNT] absInfo; + int[2][4] hats; +} + +// Linux-specific joystick API data +// +struct _GLFWlibraryLinux { + int inotify; + int watch; + version(none) { + regex_t regex; + } + GLFWbool dropped; +} + +version(none) { // < v2.6.39 kernel headers + // Workaround for CentOS-6, which is supported till 2020-11-30, but still on v2.6.32 + enum SYN_DROPPED = 3; +} + +// Apply an EV_KEY event to the specified joystick +// +private void handleKeyEvent(_GLFWjoystick* js, int code, int value) { + _glfwInputJoystickButton(js, + js.linjs.keyMap[code - BTN_MISC], + value ? GLFW_PRESS : GLFW_RELEASE); +} + +// Apply an EV_ABS event to the specified joystick +// +static void handleAbsEvent(_GLFWjoystick* js, int code, int value) { + const(int) index = js.linjs.absMap[code]; + + if (code >= ABS_HAT0X && code <= ABS_HAT3Y) + { + static const(char)[3][3] stateMap = [ + [ GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN ], + [ GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN ], + [ GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN ], + ]; + + const(int) hat = (code - ABS_HAT0X) / 2; + const(int) axis = (code - ABS_HAT0X) % 2; + int* state = js.linjs.hats[hat].ptr; + + // NOTE: Looking at several input drivers, it seems all hat events use + // -1 for left / up, 0 for centered and 1 for right / down + if (value == 0) + state[axis] = 0; + else if (value < 0) + state[axis] = 1; + else if (value > 0) + state[axis] = 2; + + _glfwInputJoystickHat(js, index, stateMap[state[0]][state[1]]); + } + else + { + input_absinfo* info = &js.linjs.absInfo[code]; + float normalized = value; + + const(int) range = info.maximum - info.minimum; + if (range) + { + // Normalize to 0.0 -> 1.0 + normalized = (normalized - info.minimum) / range; + // Normalize to -1.0 -> 1.0 + normalized = normalized * 2.0f - 1.0f; + } + + _glfwInputJoystickAxis(js, index, normalized); + } +} + +// Poll state of absolute axes +// +private void pollAbsState(_GLFWjoystick* js) { + for (int code = 0; code < ABS_CNT; code++) + { + if (js.linjs.absMap[code] < 0) + continue; + + input_absinfo* info = &js.linjs.absInfo[code]; + + if (ioctl(js.linjs.fd, EVIOCGABS(code), info) < 0) + continue; + + handleAbsEvent(js, code, info.value); + } +} + +// #define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8))) +enum string isBitSet(string bit, string arr) = ` (`~arr~`[(`~bit~`) / 8] & (1 << ((`~bit~`) % 8)))`; + +// Attempt to open the specified joystick device +// +private GLFWbool openJoystickDevice(const(char)* path) { + for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (!_glfw.joysticks[jid].present) + continue; + if (strcmp(_glfw.joysticks[jid].linjs.path.ptr, path) == 0) + return GLFW_FALSE; + } + + _GLFWjoystickLinux linjs = _GLFWjoystickLinux(0); + linjs.fd = open(path, O_RDONLY | O_NONBLOCK); + if (linjs.fd == -1) + return GLFW_FALSE; + + char[(EV_CNT + 7) / 8] evBits = '\0'; + char[(KEY_CNT + 7) / 8] keyBits = '\0'; + char[(ABS_CNT + 7) / 8] absBits = '\0'; + input_id id; + + if (ioctl(linjs.fd, EVIOCGBIT!(typeof(evBits) )( 0), evBits.ptr) < 0 || + ioctl(linjs.fd, EVIOCGBIT!(typeof(keyBits))(EV_KEY), keyBits.ptr) < 0 || + ioctl(linjs.fd, EVIOCGBIT!(typeof(absBits))(EV_ABS), absBits.ptr) < 0 || + ioctl(linjs.fd, EVIOCGID, &id) < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to query input device: %s", + strerror(errno)); + close(linjs.fd); + return GLFW_FALSE; + } + + // Ensure this device supports the events expected of a joystick + if (!mixin(isBitSet!("EV_KEY", "evBits")) || !mixin(isBitSet!("EV_ABS", "evBits"))) + { + close(linjs.fd); + return GLFW_FALSE; + } + + char[256] name = ""; + + if (ioctl(linjs.fd, EVIOCGNAME!(typeof(name))(), name.ptr) < 0) + strncpy(name.ptr, "Unknown", name.length); + + char[33] guid = ""; + + // Generate a joystick GUID that matches the SDL 2.0.5+ one + if (id.vendor && id.product && id.version_) + { + sprintf(guid.ptr, "%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000", + id.bustype & 0xff, id.bustype >> 8, + id.vendor & 0xff, id.vendor >> 8, + id.product & 0xff, id.product >> 8, + id.version_ & 0xff, id.version_ >> 8); + } + else + { + sprintf(guid.ptr, "%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", + id.bustype & 0xff, id.bustype >> 8, + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7], + name[8], name[9], name[10]); + } + + int axisCount = 0;int buttonCount = 0;int hatCount = 0; + + for (int code = BTN_MISC; code < KEY_CNT; code++) + { + if (!mixin(isBitSet!("code", "keyBits"))) + continue; + + linjs.keyMap[code - BTN_MISC] = buttonCount; + buttonCount++; + } + + for (int code = 0; code < ABS_CNT; code++) + { + linjs.absMap[code] = -1; + if (!mixin(isBitSet!("code", "absBits"))) + continue; + + if (code >= ABS_HAT0X && code <= ABS_HAT3Y) + { + linjs.absMap[code] = hatCount; + hatCount++; + // Skip the Y axis + code++; + } + else + { + if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0) + continue; + + linjs.absMap[code] = axisCount; + axisCount++; + } + } + + _GLFWjoystick* js = _glfwAllocJoystick(name.ptr, guid.ptr, axisCount, buttonCount, hatCount); + if (!js) + { + close(linjs.fd); + return GLFW_FALSE; + } + + strncpy(linjs.path.ptr, path, linjs.path.length - 1); + memcpy(&js.linjs, &linjs, linjs.sizeof); // twab: wrong size, linjs.path.length + + pollAbsState(js); + + _glfwInputJoystick(js, GLFW_CONNECTED); + return GLFW_TRUE; +} + +// Frees all resources associated with the specified joystick +// +private void closeJoystick(_GLFWjoystick* js) { + close(js.linjs.fd); + _glfwFreeJoystick(js); + _glfwInputJoystick(js, GLFW_DISCONNECTED); +} + +// Lexically compare joysticks by name; used by qsort +// +private int compareJoysticks(const(void)* fp, const(void)* sp) { + auto fj = cast(const(_GLFWjoystick)*) fp; + auto sj = cast(const(_GLFWjoystick)*) sp; + return strcmp(fj.linjs.path.ptr, sj.linjs.path.ptr); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +/// Returns: `true` if `str` matches the regex `^event[0-9]\\+$` +private extern(D) bool isEventFile(const(char)* str) { + import core.stdc.string: strlen; + const len = strlen(str); + if (len < "event0".length) { + return false; + } + if (str[0..5] != "event") { + return false; + } + foreach(i; 5..len) { + if (str[i] < '0' || str[i] > '9') { + return false; + } + } + return true; +} + +@("is event file") unittest { + assert(isEventFile("event0")); + assert(isEventFile("event1234567890")); + assert(!isEventFile("event")); + assert(!isEventFile("even0")); + assert(!isEventFile("event0A")); +} + +static if (__VERSION__ < 2094) { + // workaround for missing @nogc attribute in core.sys.linux.sys.inotify + // should be fixed in dmd 2.094 + extern(C) nothrow @nogc int inotify_init(); + extern(C) nothrow @nogc int inotify_init1(int flags); + extern(C) nothrow @nogc int inotify_add_watch(int fd, const(char)* name, uint mask); + extern(C) nothrow @nogc int inotify_rm_watch(int fd, uint wd); +} + +// Initialize joystick interface +// +GLFWbool _glfwInitJoysticksLinux() { + const(char)* dirname = "/dev/input"; + + _glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (_glfw.linjs.inotify > 0) + { + // HACK: Register for IN_ATTRIB to get notified when udev is done + // This works well in practice but the true way is libudev + + _glfw.linjs.watch = inotify_add_watch(_glfw.linjs.inotify, + dirname, + IN_CREATE | IN_ATTRIB | IN_DELETE); + } + + // Continue without device connection notifications if inotify fails + version(none) { + // remove regex dependency + if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); + return GLFW_FALSE; + } + } + + int count = 0; + + DIR* dir = opendir(dirname); + if (dir) + { + dirent* entry; + + while (true) + { + entry = readdir(dir); + if (!entry) { + break; + } + + version(none) { + regmatch_t match; + if (regexec(&_glfw.linjs.regex, entry.d_name, 1, &match, 0) != 0) + continue; + } else { + // remove regex dependency + if (!isEventFile(entry.d_name.ptr)) { + continue; + } + } + + char[PATH_MAX] path; + + snprintf(path.ptr, path.length, "%s/%s", dirname, entry.d_name.ptr); + + if (openJoystickDevice(path.ptr)) + count++; + } + + closedir(dir); + } + + // Continue with no joysticks if enumeration fails + + qsort(_glfw.joysticks.ptr, count, _GLFWjoystick.sizeof, &compareJoysticks); + return GLFW_TRUE; +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksLinux() { + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks.ptr + jid; + if (js.present) + closeJoystick(js); + } + + version(none) { + regfree(&_glfw.linjs.regex); + } + + if (_glfw.linjs.inotify > 0) + { + if (_glfw.linjs.watch > 0) + inotify_rm_watch(_glfw.linjs.inotify, _glfw.linjs.watch); + + close(_glfw.linjs.inotify); + } +} + +void _glfwDetectJoystickConnectionLinux() { + if (_glfw.linjs.inotify <= 0) + return; + + ssize_t offset = 0; + char[16384] buffer; + const(ssize_t) size = read(_glfw.linjs.inotify, buffer.ptr, typeof(buffer).sizeof); + + while (size > offset) + { + const(inotify_event)* e = cast(inotify_event*) (buffer.ptr + offset); + + offset += typeof(cast(inotify_event) + e.len).sizeof; + + version(none) { + regmatch_t match; + if (regexec(&_glfw.linjs.regex, e.name, 1, &match, 0) != 0) + continue; + } else { + if (!isEventFile(e.name.ptr)) { + continue; + } + } + + char[PATH_MAX] path; + snprintf(path.ptr, path.length, "/dev/input/%s", e.name.ptr); + + if (e.mask & (IN_CREATE | IN_ATTRIB)) + openJoystickDevice(path.ptr); + else if (e.mask & IN_DELETE) + { + for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (strcmp(_glfw.joysticks[jid].linjs.path.ptr, path.ptr) == 0) + { + closeJoystick(_glfw.joysticks.ptr + jid); + break; + } + } + } + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { + // Read all queued events (non-blocking) + for (;;) + { + input_event e; + + errno = 0; + if (read(js.linjs.fd, &e, typeof(e).sizeof) < 0) + { + // Reset the joystick slot if the device was disconnected + if (errno == ENODEV) + closeJoystick(js); + + break; + } + + if (e.type == EV_SYN) + { + if (e.code == SYN_DROPPED) + _glfw.linjs.dropped = GLFW_TRUE; + else if (e.code == SYN_REPORT) + { + _glfw.linjs.dropped = GLFW_FALSE; + pollAbsState(js); + } + } + + if (_glfw.linjs.dropped) + continue; + + if (e.type == EV_KEY) + handleKeyEvent(js, e.code, e.value); + else if (e.type == EV_ABS) + handleAbsEvent(js, e.code, e.value); + } + + return js.present; +} + +void _glfwPlatformUpdateGamepadGUID(char* guid) { +} \ No newline at end of file diff --git a/source/glfw3/linuxinput.d b/source/glfw3/linuxinput.d new file mode 100644 index 0000000..70e9902 --- /dev/null +++ b/source/glfw3/linuxinput.d @@ -0,0 +1,796 @@ +/// Needed C declarations taken out of /usr/include/linux/input.h +module glfw3.linuxinput; + +import core.sys.posix.sys.ioctl; + +struct input_absinfo { + int value; + int minimum; + int maximum; + int fuzz; + int flat; + int resolution; +} + +struct input_id { + ushort bustype; + ushort vendor; + ushort product; + ushort version_; +} + +struct input_event { + import core.sys.posix.sys.time: timeval; + timeval time; + ushort type; + ushort code; + int value; +} + +auto EVIOCGBIT(T)(int ev) { + return _IOC!T(_IOC_READ, 'E', 0x20 + (ev)); +} + +auto EVIOCGABS(T)(T abs) {return _IOR!input_absinfo('E', 0x40 + (abs));} +auto EVIOCSABS(T)(T abs) {return _IOW!input_absinfo('E', 0xc0 + (abs));} + +enum EVIOCGID = _IOR!input_id('E', 0x02); +auto EVIOCGNAME(T)() {return _IOC!T(_IOC_READ, 'E', 0x06);} + +// +// input-event-codes.h +// + +enum INPUT_PROP_POINTER = 0x00; +enum INPUT_PROP_DIRECT = 0x01; +enum INPUT_PROP_BUTTONPAD = 0x02; +enum INPUT_PROP_SEMI_MT = 0x03; +enum INPUT_PROP_TOPBUTTONPAD = 0x04; +enum INPUT_PROP_POINTING_STICK = 0x05; +enum INPUT_PROP_ACCELEROMETER = 0x06; + +enum INPUT_PROP_MAX = 0x1f; +enum INPUT_PROP_CNT = (INPUT_PROP_MAX + 1); + +enum EV_SYN = 0x00; +enum EV_KEY = 0x01; +enum EV_REL = 0x02; +enum EV_ABS = 0x03; +enum EV_MSC = 0x04; +enum EV_SW = 0x05; +enum EV_LED = 0x11; +enum EV_SND = 0x12; +enum EV_REP = 0x14; +enum EV_FF = 0x15; +enum EV_PWR = 0x16; +enum EV_FF_STATUS = 0x17; +enum EV_MAX = 0x1f; +enum EV_CNT = (EV_MAX+1); + +enum SYN_REPORT = 0; +enum SYN_CONFIG = 1; +enum SYN_MT_REPORT = 2; +enum SYN_DROPPED = 3; +enum SYN_MAX = 0xf; +enum SYN_CNT = (SYN_MAX+1); + +enum KEY_RESERVED = 0; +enum KEY_ESC = 1; +enum KEY_1 = 2; +enum KEY_2 = 3; +enum KEY_3 = 4; +enum KEY_4 = 5; +enum KEY_5 = 6; +enum KEY_6 = 7; +enum KEY_7 = 8; +enum KEY_8 = 9; +enum KEY_9 = 10; +enum KEY_0 = 11; +enum KEY_MINUS = 12; +enum KEY_EQUAL = 13; +enum KEY_BACKSPACE = 14; +enum KEY_TAB = 15; +enum KEY_Q = 16; +enum KEY_W = 17; +enum KEY_E = 18; +enum KEY_R = 19; +enum KEY_T = 20; +enum KEY_Y = 21; +enum KEY_U = 22; +enum KEY_I = 23; +enum KEY_O = 24; +enum KEY_P = 25; +enum KEY_LEFTBRACE = 26; +enum KEY_RIGHTBRACE = 27; +enum KEY_ENTER = 28; +enum KEY_LEFTCTRL = 29; +enum KEY_A = 30; +enum KEY_S = 31; +enum KEY_D = 32; +enum KEY_F = 33; +enum KEY_G = 34; +enum KEY_H = 35; +enum KEY_J = 36; +enum KEY_K = 37; +enum KEY_L = 38; +enum KEY_SEMICOLON = 39; +enum KEY_APOSTROPHE = 40; +enum KEY_GRAVE = 41; +enum KEY_LEFTSHIFT = 42; +enum KEY_BACKSLASH = 43; +enum KEY_Z = 44; +enum KEY_X = 45; +enum KEY_C = 46; +enum KEY_V = 47; +enum KEY_B = 48; +enum KEY_N = 49; +enum KEY_M = 50; +enum KEY_COMMA = 51; +enum KEY_DOT = 52; +enum KEY_SLASH = 53; +enum KEY_RIGHTSHIFT = 54; +enum KEY_KPASTERISK = 55; +enum KEY_LEFTALT = 56; +enum KEY_SPACE = 57; +enum KEY_CAPSLOCK = 58; +enum KEY_F1 = 59; +enum KEY_F2 = 60; +enum KEY_F3 = 61; +enum KEY_F4 = 62; +enum KEY_F5 = 63; +enum KEY_F6 = 64; +enum KEY_F7 = 65; +enum KEY_F8 = 66; +enum KEY_F9 = 67; +enum KEY_F10 = 68; +enum KEY_NUMLOCK = 69; +enum KEY_SCROLLLOCK = 70; +enum KEY_KP7 = 71; +enum KEY_KP8 = 72; +enum KEY_KP9 = 73; +enum KEY_KPMINUS = 74; +enum KEY_KP4 = 75; +enum KEY_KP5 = 76; +enum KEY_KP6 = 77; +enum KEY_KPPLUS = 78; +enum KEY_KP1 = 79; +enum KEY_KP2 = 80; +enum KEY_KP3 = 81; +enum KEY_KP0 = 82; +enum KEY_KPDOT = 83; + +enum KEY_ZENKAKUHANKAKU = 85; +enum KEY_102ND = 86; +enum KEY_F11 = 87; +enum KEY_F12 = 88; +enum KEY_RO = 89; +enum KEY_KATAKANA = 90; +enum KEY_HIRAGANA = 91; +enum KEY_HENKAN = 92; +enum KEY_KATAKANAHIRAGANA = 93; +enum KEY_MUHENKAN = 94; +enum KEY_KPJPCOMMA = 95; +enum KEY_KPENTER = 96; +enum KEY_RIGHTCTRL = 97; +enum KEY_KPSLASH = 98; +enum KEY_SYSRQ = 99; +enum KEY_RIGHTALT = 100; +enum KEY_LINEFEED = 101; +enum KEY_HOME = 102; +enum KEY_UP = 103; +enum KEY_PAGEUP = 104; +enum KEY_LEFT = 105; +enum KEY_RIGHT = 106; +enum KEY_END = 107; +enum KEY_DOWN = 108; +enum KEY_PAGEDOWN = 109; +enum KEY_INSERT = 110; +enum KEY_DELETE = 111; +enum KEY_MACRO = 112; +enum KEY_MUTE = 113; +enum KEY_VOLUMEDOWN = 114; +enum KEY_VOLUMEUP = 115; +enum KEY_POWER = 116; +enum KEY_KPEQUAL = 117; +enum KEY_KPPLUSMINUS = 118; +enum KEY_PAUSE = 119; +enum KEY_SCALE = 120; + +enum KEY_KPCOMMA = 121; +enum KEY_HANGEUL = 122; +enum KEY_HANGUEL = KEY_HANGEUL; +enum KEY_HANJA = 123; +enum KEY_YEN = 124; +enum KEY_LEFTMETA = 125; +enum KEY_RIGHTMETA = 126; +enum KEY_COMPOSE = 127; + +enum KEY_STOP = 128; +enum KEY_AGAIN = 129; +enum KEY_PROPS = 130; +enum KEY_UNDO = 131; +enum KEY_FRONT = 132; +enum KEY_COPY = 133; +enum KEY_OPEN = 134; +enum KEY_PASTE = 135; +enum KEY_FIND = 136; +enum KEY_CUT = 137; +enum KEY_HELP = 138; +enum KEY_MENU = 139; +enum KEY_CALC = 140; +enum KEY_SETUP = 141; +enum KEY_SLEEP = 142; +enum KEY_WAKEUP = 143; +enum KEY_FILE = 144; +enum KEY_SENDFILE = 145; +enum KEY_DELETEFILE = 146; +enum KEY_XFER = 147; +enum KEY_PROG1 = 148; +enum KEY_PROG2 = 149; +enum KEY_WWW = 150; +enum KEY_MSDOS = 151; +enum KEY_COFFEE = 152; +enum KEY_SCREENLOCK = KEY_COFFEE; +enum KEY_ROTATE_DISPLAY = 153; +enum KEY_DIRECTION = KEY_ROTATE_DISPLAY; +enum KEY_CYCLEWINDOWS = 154; +enum KEY_MAIL = 155; +enum KEY_BOOKMARKS = 156; +enum KEY_COMPUTER = 157; +enum KEY_BACK = 158; +enum KEY_FORWARD = 159; +enum KEY_CLOSECD = 160; +enum KEY_EJECTCD = 161; +enum KEY_EJECTCLOSECD = 162; +enum KEY_NEXTSONG = 163; +enum KEY_PLAYPAUSE = 164; +enum KEY_PREVIOUSSONG = 165; +enum KEY_STOPCD = 166; +enum KEY_RECORD = 167; +enum KEY_REWIND = 168; +enum KEY_PHONE = 169; +enum KEY_ISO = 170; +enum KEY_CONFIG = 171; +enum KEY_HOMEPAGE = 172; +enum KEY_REFRESH = 173; +enum KEY_EXIT = 174; +enum KEY_MOVE = 175; +enum KEY_EDIT = 176; +enum KEY_SCROLLUP = 177; +enum KEY_SCROLLDOWN = 178; +enum KEY_KPLEFTPAREN = 179; +enum KEY_KPRIGHTPAREN = 180; +enum KEY_NEW = 181; +enum KEY_REDO = 182; + +enum KEY_F13 = 183; +enum KEY_F14 = 184; +enum KEY_F15 = 185; +enum KEY_F16 = 186; +enum KEY_F17 = 187; +enum KEY_F18 = 188; +enum KEY_F19 = 189; +enum KEY_F20 = 190; +enum KEY_F21 = 191; +enum KEY_F22 = 192; +enum KEY_F23 = 193; +enum KEY_F24 = 194; + +enum KEY_PLAYCD = 200; +enum KEY_PAUSECD = 201; +enum KEY_PROG3 = 202; +enum KEY_PROG4 = 203; +enum KEY_DASHBOARD = 204; +enum KEY_SUSPEND = 205; +enum KEY_CLOSE = 206; +enum KEY_PLAY = 207; +enum KEY_FASTFORWARD = 208; +enum KEY_BASSBOOST = 209; +enum KEY_PRINT = 210; +enum KEY_HP = 211; +enum KEY_CAMERA = 212; +enum KEY_SOUND = 213; +enum KEY_QUESTION = 214; +enum KEY_EMAIL = 215; +enum KEY_CHAT = 216; +enum KEY_SEARCH = 217; +enum KEY_CONNECT = 218; +enum KEY_FINANCE = 219; +enum KEY_SPORT = 220; +enum KEY_SHOP = 221; +enum KEY_ALTERASE = 222; +enum KEY_CANCEL = 223; +enum KEY_BRIGHTNESSDOWN = 224; +enum KEY_BRIGHTNESSUP = 225; +enum KEY_MEDIA = 226; + +enum KEY_SWITCHVIDEOMODE = 227; +enum KEY_KBDILLUMTOGGLE = 228; +enum KEY_KBDILLUMDOWN = 229; +enum KEY_KBDILLUMUP = 230; + +enum KEY_SEND = 231; +enum KEY_REPLY = 232; +enum KEY_FORWARDMAIL = 233; +enum KEY_SAVE = 234; +enum KEY_DOCUMENTS = 235; + +enum KEY_BATTERY = 236; + +enum KEY_BLUETOOTH = 237; +enum KEY_WLAN = 238; +enum KEY_UWB = 239; + +enum KEY_UNKNOWN = 240; + +enum KEY_VIDEO_NEXT = 241; +enum KEY_VIDEO_PREV = 242; +enum KEY_BRIGHTNESS_CYCLE = 243; +enum KEY_BRIGHTNESS_AUTO = 244; +enum KEY_BRIGHTNESS_ZERO = KEY_BRIGHTNESS_AUTO; +enum KEY_DISPLAY_OFF = 245; + +enum KEY_WWAN = 246; +enum KEY_WIMAX = KEY_WWAN; +enum KEY_RFKILL = 247; + +enum KEY_MICMUTE = 248; + +enum BTN_MISC = 0x100; +enum BTN_0 = 0x100; +enum BTN_1 = 0x101; +enum BTN_2 = 0x102; +enum BTN_3 = 0x103; +enum BTN_4 = 0x104; +enum BTN_5 = 0x105; +enum BTN_6 = 0x106; +enum BTN_7 = 0x107; +enum BTN_8 = 0x108; +enum BTN_9 = 0x109; + +enum BTN_MOUSE = 0x110; +enum BTN_LEFT = 0x110; +enum BTN_RIGHT = 0x111; +enum BTN_MIDDLE = 0x112; +enum BTN_SIDE = 0x113; +enum BTN_EXTRA = 0x114; +enum BTN_FORWARD = 0x115; +enum BTN_BACK = 0x116; +enum BTN_TASK = 0x117; + +enum BTN_JOYSTICK = 0x120; +enum BTN_TRIGGER = 0x120; +enum BTN_THUMB = 0x121; +enum BTN_THUMB2 = 0x122; +enum BTN_TOP = 0x123; +enum BTN_TOP2 = 0x124; +enum BTN_PINKIE = 0x125; +enum BTN_BASE = 0x126; +enum BTN_BASE2 = 0x127; +enum BTN_BASE3 = 0x128; +enum BTN_BASE4 = 0x129; +enum BTN_BASE5 = 0x12a; +enum BTN_BASE6 = 0x12b; +enum BTN_DEAD = 0x12f; + +enum BTN_GAMEPAD = 0x130; +enum BTN_SOUTH = 0x130; +enum BTN_A = BTN_SOUTH; +enum BTN_EAST = 0x131; +enum BTN_B = BTN_EAST; +enum BTN_C = 0x132; +enum BTN_NORTH = 0x133; +enum BTN_X = BTN_NORTH; +enum BTN_WEST = 0x134; +enum BTN_Y = BTN_WEST; +enum BTN_Z = 0x135; +enum BTN_TL = 0x136; +enum BTN_TR = 0x137; +enum BTN_TL2 = 0x138; +enum BTN_TR2 = 0x139; +enum BTN_SELECT = 0x13a; +enum BTN_START = 0x13b; +enum BTN_MODE = 0x13c; +enum BTN_THUMBL = 0x13d; +enum BTN_THUMBR = 0x13e; + +enum BTN_DIGI = 0x140; +enum BTN_TOOL_PEN = 0x140; +enum BTN_TOOL_RUBBER = 0x141; +enum BTN_TOOL_BRUSH = 0x142; +enum BTN_TOOL_PENCIL = 0x143; +enum BTN_TOOL_AIRBRUSH = 0x144; +enum BTN_TOOL_FINGER = 0x145; +enum BTN_TOOL_MOUSE = 0x146; +enum BTN_TOOL_LENS = 0x147; +enum BTN_TOOL_QUINTTAP = 0x148; +enum BTN_TOUCH = 0x14a; +enum BTN_STYLUS = 0x14b; +enum BTN_STYLUS2 = 0x14c; +enum BTN_TOOL_DOUBLETAP = 0x14d; +enum BTN_TOOL_TRIPLETAP = 0x14e; +enum BTN_TOOL_QUADTAP = 0x14f; + +enum BTN_WHEEL = 0x150; +enum BTN_GEAR_DOWN = 0x150; +enum BTN_GEAR_UP = 0x151; + +enum KEY_OK = 0x160; +enum KEY_SELECT = 0x161; +enum KEY_GOTO = 0x162; +enum KEY_CLEAR = 0x163; +enum KEY_POWER2 = 0x164; +enum KEY_OPTION = 0x165; +enum KEY_INFO = 0x166; +enum KEY_TIME = 0x167; +enum KEY_VENDOR = 0x168; +enum KEY_ARCHIVE = 0x169; +enum KEY_PROGRAM = 0x16a; +enum KEY_CHANNEL = 0x16b; +enum KEY_FAVORITES = 0x16c; +enum KEY_EPG = 0x16d; +enum KEY_PVR = 0x16e; +enum KEY_MHP = 0x16f; +enum KEY_LANGUAGE = 0x170; +enum KEY_TITLE = 0x171; +enum KEY_SUBTITLE = 0x172; +enum KEY_ANGLE = 0x173; +enum KEY_ZOOM = 0x174; +enum KEY_MODE = 0x175; +enum KEY_KEYBOARD = 0x176; +enum KEY_SCREEN = 0x177; +enum KEY_PC = 0x178; +enum KEY_TV = 0x179; +enum KEY_TV2 = 0x17a; +enum KEY_VCR = 0x17b; +enum KEY_VCR2 = 0x17c; +enum KEY_SAT = 0x17d; +enum KEY_SAT2 = 0x17e; +enum KEY_CD = 0x17f; +enum KEY_TAPE = 0x180; +enum KEY_RADIO = 0x181; +enum KEY_TUNER = 0x182; +enum KEY_PLAYER = 0x183; +enum KEY_TEXT = 0x184; +enum KEY_DVD = 0x185; +enum KEY_AUX = 0x186; +enum KEY_MP3 = 0x187; +enum KEY_AUDIO = 0x188; +enum KEY_VIDEO = 0x189; +enum KEY_DIRECTORY = 0x18a; +enum KEY_LIST = 0x18b; +enum KEY_MEMO = 0x18c; +enum KEY_CALENDAR = 0x18d; +enum KEY_RED = 0x18e; +enum KEY_GREEN = 0x18f; +enum KEY_YELLOW = 0x190; +enum KEY_BLUE = 0x191; +enum KEY_CHANNELUP = 0x192; +enum KEY_CHANNELDOWN = 0x193; +enum KEY_FIRST = 0x194; +enum KEY_LAST = 0x195; +enum KEY_AB = 0x196; +enum KEY_NEXT = 0x197; +enum KEY_RESTART = 0x198; +enum KEY_SLOW = 0x199; +enum KEY_SHUFFLE = 0x19a; +enum KEY_BREAK = 0x19b; +enum KEY_PREVIOUS = 0x19c; +enum KEY_DIGITS = 0x19d; +enum KEY_TEEN = 0x19e; +enum KEY_TWEN = 0x19f; +enum KEY_VIDEOPHONE = 0x1a0; +enum KEY_GAMES = 0x1a1; +enum KEY_ZOOMIN = 0x1a2; +enum KEY_ZOOMOUT = 0x1a3; +enum KEY_ZOOMRESET = 0x1a4; +enum KEY_WORDPROCESSOR = 0x1a5; +enum KEY_EDITOR = 0x1a6; +enum KEY_SPREADSHEET = 0x1a7; +enum KEY_GRAPHICSEDITOR = 0x1a8; +enum KEY_PRESENTATION = 0x1a9; +enum KEY_DATABASE = 0x1aa; +enum KEY_NEWS = 0x1ab; +enum KEY_VOICEMAIL = 0x1ac; +enum KEY_ADDRESSBOOK = 0x1ad; +enum KEY_MESSENGER = 0x1ae; +enum KEY_DISPLAYTOGGLE = 0x1af; +enum KEY_BRIGHTNESS_TOGGLE = KEY_DISPLAYTOGGLE; +enum KEY_SPELLCHECK = 0x1b0; +enum KEY_LOGOFF = 0x1b1; + +enum KEY_DOLLAR = 0x1b2; +enum KEY_EURO = 0x1b3; + +enum KEY_FRAMEBACK = 0x1b4; +enum KEY_FRAMEFORWARD = 0x1b5; +enum KEY_CONTEXT_MENU = 0x1b6; +enum KEY_MEDIA_REPEAT = 0x1b7; +enum KEY_10CHANNELSUP = 0x1b8; +enum KEY_10CHANNELSDOWN = 0x1b9; +enum KEY_IMAGES = 0x1ba; + +enum KEY_DEL_EOL = 0x1c0; +enum KEY_DEL_EOS = 0x1c1; +enum KEY_INS_LINE = 0x1c2; +enum KEY_DEL_LINE = 0x1c3; + +enum KEY_FN = 0x1d0; +enum KEY_FN_ESC = 0x1d1; +enum KEY_FN_F1 = 0x1d2; +enum KEY_FN_F2 = 0x1d3; +enum KEY_FN_F3 = 0x1d4; +enum KEY_FN_F4 = 0x1d5; +enum KEY_FN_F5 = 0x1d6; +enum KEY_FN_F6 = 0x1d7; +enum KEY_FN_F7 = 0x1d8; +enum KEY_FN_F8 = 0x1d9; +enum KEY_FN_F9 = 0x1da; +enum KEY_FN_F10 = 0x1db; +enum KEY_FN_F11 = 0x1dc; +enum KEY_FN_F12 = 0x1dd; +enum KEY_FN_1 = 0x1de; +enum KEY_FN_2 = 0x1df; +enum KEY_FN_D = 0x1e0; +enum KEY_FN_E = 0x1e1; +enum KEY_FN_F = 0x1e2; +enum KEY_FN_S = 0x1e3; +enum KEY_FN_B = 0x1e4; + +enum KEY_BRL_DOT1 = 0x1f1; +enum KEY_BRL_DOT2 = 0x1f2; +enum KEY_BRL_DOT3 = 0x1f3; +enum KEY_BRL_DOT4 = 0x1f4; +enum KEY_BRL_DOT5 = 0x1f5; +enum KEY_BRL_DOT6 = 0x1f6; +enum KEY_BRL_DOT7 = 0x1f7; +enum KEY_BRL_DOT8 = 0x1f8; +enum KEY_BRL_DOT9 = 0x1f9; +enum KEY_BRL_DOT10 = 0x1fa; + +enum KEY_NUMERIC_0 = 0x200; +enum KEY_NUMERIC_1 = 0x201; +enum KEY_NUMERIC_2 = 0x202; +enum KEY_NUMERIC_3 = 0x203; +enum KEY_NUMERIC_4 = 0x204; +enum KEY_NUMERIC_5 = 0x205; +enum KEY_NUMERIC_6 = 0x206; +enum KEY_NUMERIC_7 = 0x207; +enum KEY_NUMERIC_8 = 0x208; +enum KEY_NUMERIC_9 = 0x209; +enum KEY_NUMERIC_STAR = 0x20a; +enum KEY_NUMERIC_POUND = 0x20b; +enum KEY_NUMERIC_A = 0x20c; +enum KEY_NUMERIC_B = 0x20d; +enum KEY_NUMERIC_C = 0x20e; +enum KEY_NUMERIC_D = 0x20f; + +enum KEY_CAMERA_FOCUS = 0x210; +enum KEY_WPS_BUTTON = 0x211; + +enum KEY_TOUCHPAD_TOGGLE = 0x212; +enum KEY_TOUCHPAD_ON = 0x213; +enum KEY_TOUCHPAD_OFF = 0x214; + +enum KEY_CAMERA_ZOOMIN = 0x215; +enum KEY_CAMERA_ZOOMOUT = 0x216; +enum KEY_CAMERA_UP = 0x217; +enum KEY_CAMERA_DOWN = 0x218; +enum KEY_CAMERA_LEFT = 0x219; +enum KEY_CAMERA_RIGHT = 0x21a; + +enum KEY_ATTENDANT_ON = 0x21b; +enum KEY_ATTENDANT_OFF = 0x21c; +enum KEY_ATTENDANT_TOGGLE = 0x21d; +enum KEY_LIGHTS_TOGGLE = 0x21e; + +enum BTN_DPAD_UP = 0x220; +enum BTN_DPAD_DOWN = 0x221; +enum BTN_DPAD_LEFT = 0x222; +enum BTN_DPAD_RIGHT = 0x223; + +enum KEY_ALS_TOGGLE = 0x230; + +enum KEY_BUTTONCONFIG = 0x240; +enum KEY_TASKMANAGER = 0x241; +enum KEY_JOURNAL = 0x242; +enum KEY_CONTROLPANEL = 0x243; +enum KEY_APPSELECT = 0x244; +enum KEY_SCREENSAVER = 0x245; +enum KEY_VOICECOMMAND = 0x246; + +enum KEY_BRIGHTNESS_MIN = 0x250; +enum KEY_BRIGHTNESS_MAX = 0x251; + +enum KEY_KBDINPUTASSIST_PREV = 0x260; +enum KEY_KBDINPUTASSIST_NEXT = 0x261; +enum KEY_KBDINPUTASSIST_PREVGROUP = 0x262; +enum KEY_KBDINPUTASSIST_NEXTGROUP = 0x263; +enum KEY_KBDINPUTASSIST_ACCEPT = 0x264; +enum KEY_KBDINPUTASSIST_CANCEL = 0x265; + +enum KEY_RIGHT_UP = 0x266; +enum KEY_RIGHT_DOWN = 0x267; +enum KEY_LEFT_UP = 0x268; +enum KEY_LEFT_DOWN = 0x269; + +enum KEY_ROOT_MENU = 0x26a; + +enum KEY_MEDIA_TOP_MENU = 0x26b; +enum KEY_NUMERIC_11 = 0x26c; +enum KEY_NUMERIC_12 = 0x26d; + +enum KEY_AUDIO_DESC = 0x26e; +enum KEY_3D_MODE = 0x26f; +enum KEY_NEXT_FAVORITE = 0x270; +enum KEY_STOP_RECORD = 0x271; +enum KEY_PAUSE_RECORD = 0x272; +enum KEY_VOD = 0x273; +enum KEY_UNMUTE = 0x274; +enum KEY_FASTREVERSE = 0x275; +enum KEY_SLOWREVERSE = 0x276; + +enum KEY_DATA = 0x277; + +enum BTN_TRIGGER_HAPPY = 0x2c0; +enum BTN_TRIGGER_HAPPY1 = 0x2c0; +enum BTN_TRIGGER_HAPPY2 = 0x2c1; +enum BTN_TRIGGER_HAPPY3 = 0x2c2; +enum BTN_TRIGGER_HAPPY4 = 0x2c3; +enum BTN_TRIGGER_HAPPY5 = 0x2c4; +enum BTN_TRIGGER_HAPPY6 = 0x2c5; +enum BTN_TRIGGER_HAPPY7 = 0x2c6; +enum BTN_TRIGGER_HAPPY8 = 0x2c7; +enum BTN_TRIGGER_HAPPY9 = 0x2c8; +enum BTN_TRIGGER_HAPPY10 = 0x2c9; +enum BTN_TRIGGER_HAPPY11 = 0x2ca; +enum BTN_TRIGGER_HAPPY12 = 0x2cb; +enum BTN_TRIGGER_HAPPY13 = 0x2cc; +enum BTN_TRIGGER_HAPPY14 = 0x2cd; +enum BTN_TRIGGER_HAPPY15 = 0x2ce; +enum BTN_TRIGGER_HAPPY16 = 0x2cf; +enum BTN_TRIGGER_HAPPY17 = 0x2d0; +enum BTN_TRIGGER_HAPPY18 = 0x2d1; +enum BTN_TRIGGER_HAPPY19 = 0x2d2; +enum BTN_TRIGGER_HAPPY20 = 0x2d3; +enum BTN_TRIGGER_HAPPY21 = 0x2d4; +enum BTN_TRIGGER_HAPPY22 = 0x2d5; +enum BTN_TRIGGER_HAPPY23 = 0x2d6; +enum BTN_TRIGGER_HAPPY24 = 0x2d7; +enum BTN_TRIGGER_HAPPY25 = 0x2d8; +enum BTN_TRIGGER_HAPPY26 = 0x2d9; +enum BTN_TRIGGER_HAPPY27 = 0x2da; +enum BTN_TRIGGER_HAPPY28 = 0x2db; +enum BTN_TRIGGER_HAPPY29 = 0x2dc; +enum BTN_TRIGGER_HAPPY30 = 0x2dd; +enum BTN_TRIGGER_HAPPY31 = 0x2de; +enum BTN_TRIGGER_HAPPY32 = 0x2df; +enum BTN_TRIGGER_HAPPY33 = 0x2e0; +enum BTN_TRIGGER_HAPPY34 = 0x2e1; +enum BTN_TRIGGER_HAPPY35 = 0x2e2; +enum BTN_TRIGGER_HAPPY36 = 0x2e3; +enum BTN_TRIGGER_HAPPY37 = 0x2e4; +enum BTN_TRIGGER_HAPPY38 = 0x2e5; +enum BTN_TRIGGER_HAPPY39 = 0x2e6; +enum BTN_TRIGGER_HAPPY40 = 0x2e7; + + +enum KEY_MIN_INTERESTING = KEY_MUTE; +enum KEY_MAX = 0x2ff; +enum KEY_CNT = (KEY_MAX+1); + +enum REL_X = 0x00; +enum REL_Y = 0x01; +enum REL_Z = 0x02; +enum REL_RX = 0x03; +enum REL_RY = 0x04; +enum REL_RZ = 0x05; +enum REL_HWHEEL = 0x06; +enum REL_DIAL = 0x07; +enum REL_WHEEL = 0x08; +enum REL_MISC = 0x09; +enum REL_MAX = 0x0f; +enum REL_CNT = (REL_MAX+1); +enum ABS_X = 0x00; +enum ABS_Y = 0x01; +enum ABS_Z = 0x02; +enum ABS_RX = 0x03; +enum ABS_RY = 0x04; +enum ABS_RZ = 0x05; +enum ABS_THROTTLE = 0x06; +enum ABS_RUDDER = 0x07; +enum ABS_WHEEL = 0x08; +enum ABS_GAS = 0x09; +enum ABS_BRAKE = 0x0a; +enum ABS_HAT0X = 0x10; +enum ABS_HAT0Y = 0x11; +enum ABS_HAT1X = 0x12; +enum ABS_HAT1Y = 0x13; +enum ABS_HAT2X = 0x14; +enum ABS_HAT2Y = 0x15; +enum ABS_HAT3X = 0x16; +enum ABS_HAT3Y = 0x17; +enum ABS_PRESSURE = 0x18; +enum ABS_DISTANCE = 0x19; +enum ABS_TILT_X = 0x1a; +enum ABS_TILT_Y = 0x1b; +enum ABS_TOOL_WIDTH = 0x1c; + +enum ABS_VOLUME = 0x20; + +enum ABS_MISC = 0x28; + +enum ABS_RESERVED = 0x2e; + +enum ABS_MT_SLOT = 0x2f; +enum ABS_MT_TOUCH_MAJOR = 0x30; +enum ABS_MT_TOUCH_MINOR = 0x31; +enum ABS_MT_WIDTH_MAJOR = 0x32; +enum ABS_MT_WIDTH_MINOR = 0x33; +enum ABS_MT_ORIENTATION = 0x34; +enum ABS_MT_POSITION_X = 0x35; +enum ABS_MT_POSITION_Y = 0x36; +enum ABS_MT_TOOL_TYPE = 0x37; +enum ABS_MT_BLOB_ID = 0x38; +enum ABS_MT_TRACKING_ID = 0x39; +enum ABS_MT_PRESSURE = 0x3a; +enum ABS_MT_DISTANCE = 0x3b; +enum ABS_MT_TOOL_X = 0x3c; +enum ABS_MT_TOOL_Y = 0x3d; + +enum ABS_MAX = 0x3f; +enum ABS_CNT = (ABS_MAX+1); + +enum SW_LID = 0x00; +enum SW_TABLET_MODE = 0x01; +enum SW_HEADPHONE_INSERT = 0x02; +enum SW_RFKILL_ALL = 0x03; +enum SW_RADIO = SW_RFKILL_ALL; +enum SW_MICROPHONE_INSERT = 0x04; +enum SW_DOCK = 0x05; +enum SW_LINEOUT_INSERT = 0x06; +enum SW_JACK_PHYSICAL_INSERT = 0x07; +enum SW_VIDEOOUT_INSERT = 0x08; +enum SW_CAMERA_LENS_COVER = 0x09; +enum SW_KEYPAD_SLIDE = 0x0a; +enum SW_FRONT_PROXIMITY = 0x0b; +enum SW_ROTATE_LOCK = 0x0c; +enum SW_LINEIN_INSERT = 0x0d; +enum SW_MUTE_DEVICE = 0x0e; +enum SW_PEN_INSERTED = 0x0f; +enum SW_MAX = 0x0f; +enum SW_CNT = (SW_MAX+1); + +enum MSC_SERIAL = 0x00; +enum MSC_PULSELED = 0x01; +enum MSC_GESTURE = 0x02; +enum MSC_RAW = 0x03; +enum MSC_SCAN = 0x04; +enum MSC_TIMESTAMP = 0x05; +enum MSC_MAX = 0x07; +enum MSC_CNT = (MSC_MAX+1); + +enum LED_NUML = 0x00; +enum LED_CAPSL = 0x01; +enum LED_SCROLLL = 0x02; +enum LED_COMPOSE = 0x03; +enum LED_KANA = 0x04; +enum LED_SLEEP = 0x05; +enum LED_SUSPEND = 0x06; +enum LED_MUTE = 0x07; +enum LED_MISC = 0x08; +enum LED_MAIL = 0x09; +enum LED_CHARGING = 0x0a; +enum LED_MAX = 0x0f; +enum LED_CNT = (LED_MAX+1); + +enum REP_DELAY = 0x00; +enum REP_PERIOD = 0x01; +enum REP_MAX = 0x01; +enum REP_CNT = (REP_MAX+1); + +enum SND_CLICK = 0x00; +enum SND_BELL = 0x01; +enum SND_TONE = 0x02; +enum SND_MAX = 0x07; +enum SND_CNT = (SND_MAX+1); diff --git a/source/glfw3/mappings.d b/source/glfw3/mappings.d new file mode 100644 index 0000000..fcf35e2 --- /dev/null +++ b/source/glfw3/mappings.d @@ -0,0 +1,478 @@ +/// Translated from C to D +module glfw3.mappings; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2018 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// As mappings.h.in, this file is used by CMake to produce the mappings.h +// header file. If you are adding a GLFW specific gamepad mapping, this is +// where to put it. +//======================================================================== +// As mappings.h, this provides all pre-defined gamepad mappings, including +// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad +// mappings not specific to GLFW should be submitted to SDL_GameControllerDB. +// This file can be re-generated from mappings.h.in and the upstream +// gamecontrollerdb.txt with the GenerateMappings.cmake script. +//======================================================================== + +// All gamepad mappings not labeled GLFW are copied from the +// SDL_GameControllerDB project under the following license: +// +// Simple DirectMedia Layer +// Copyright (C) 1997-2013 Sam Lantinga +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +immutable char*[412] _glfwDefaultMappings = [ +"03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,", +"03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", +"03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,", +"03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", +"03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,", +"030000008f0e00001200000000000000,Acme,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,", +"03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,", +"030000006b1400000055000000000000,bigben ps3padstreetnew,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", +"03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,", +"03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", +"030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", +"03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,", +"03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", +"03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", +"030000004f04000023b3000000000000,Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,", +"030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,", +"03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,", +"030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"03000000451300000010000000000000,Generic USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00005f00000000000000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00005e00000000000000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00006e00000000000000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00006600000000000000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f0000ee00000000000000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00004d00000000000000,HORIPAD3 A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,", +"030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows,", +"03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", +"03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", +"03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Windows,", +"03000000b50700001403000000000000,IMPACT BLACK,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,", +"030000006f0e00002401000000000000,INJUSTICE FightStick for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"03000000491900000204000000000000,Ipega PG-9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", +"030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,", +"030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700008433000000000000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700008483000000000000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b6,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700008532000000000000,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000008305000031b0000000000000,MaxfireBlaze3,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,", +"03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", +"03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", +"030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,", +"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,", +"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,", +"03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,", +"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,leftx:h0.6,lefty:h0.12,rightshoulder:b5,rightstick:a2,righttrigger:b7,rightx:h0.9,righty:h0.4,start:b9,x:b2,y:b3,platform:Windows,", +"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,", +"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,", +"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", +"03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000008f0e00007530000000000000,PS (R) Gamepad,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,", +"03000000100800000100000000000000,PS1 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", +"03000000100800000300000000000000,PS2 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", +"03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,", +"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,", +"03000000250900000500000000000000,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,", +"03000000100000008200000000000000,PS360+ v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,", +"03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,", +"03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,", +"03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,", +"03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,", +"03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", +"030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00008b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00008a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,", +"0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,", +"0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,", +"030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000006f0e00001e01000000000000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", +"03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", +"03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,", +"03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,x:b0,y:b1,platform:Windows,", +"03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", +"03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,", +"03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", +"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows,", +"03000000300f00001101000000000000,saitek rumble pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,", +"0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,", +"030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,", +"030000008f0e00000800000000000000,SpeedLink Strike FX Wireless,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", +"03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows,", +"03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", +"03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,", +"030000004f04000015b3000000000000,Thrustmaster Dual Analog 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,", +"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,", +"030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,", +"03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,", +"03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", +"03000000380700006652000000000000,UnKnown,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", +"03000000632500002305000000000000,USB Vibration Joystick (BM),a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", +"03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,", +"03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", +"03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", +"03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,", +"03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,", +"03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,", +"030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,", +"03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,", +"03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", +"030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000000d0f00005f00000000000000,HORI Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000000d0f00005e00000000000000,HORI Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000000d0f00004d00000000000000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000000d0f00006e00000000010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000000d0f00006600000000010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,", +"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,", +"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,", +"030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,", +"03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,", +"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,", +"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,", +"03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,", +"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,", +"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,", +"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,", +"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,", +"030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", +"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", +"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,", +"03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,", +"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,", +"030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000005e0400008e02000001000000,Steam Virtual GamePad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,", +"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,", +"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,", +"03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,", +"03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,", +"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,", +"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,", +"03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", +"03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", +"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,", +"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,", +"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,", +"030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,", +"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,", +"030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,", +"030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,", +"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,", +"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"03000000022000000090000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"03000000c82d00000190000011010000,8Bitdo NES30 Pro 8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,", +"05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,", +"05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,", +"05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,", +"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", +"05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,", +"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,", +"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", +"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,", +"03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,", +"03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,", +"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,", +"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,", +"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:a0,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:a3,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006f0e00001f01000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000280400000140000000010000,Gravis GamePad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", +"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,", +"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,", +"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,", +"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,", +"03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,", +"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", +"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,", +"030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,", +"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,", +"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,", +"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,", +"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,", +"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,", +"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,", +"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,platform:Linux,", +"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,", +"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,", +"03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"03000000380700008433000011010000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000380700008483000011010000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,", +"03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,", +"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,", +"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,", +"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,", +"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,", +"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,", +"05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,", +"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,", +"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,", +"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,", +"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,", +"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", +"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,", +"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", +"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", +"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", +"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", +"030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", +"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", +"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", +"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,", +"050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", +"050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", +"030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", +"050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", +"030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,", +"030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,", +"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,", +"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,", +"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,", +"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,", +"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,", +"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,", +"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,", +"03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,", +"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,", +"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,", +"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,", +"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,", +"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,", +"03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", +"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,", +"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,", +"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,", +"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,", +"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,", +"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,", +"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", +"03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,", +"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,", +"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,", +"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,", +"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,", +"05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,", +"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,", +"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,", +"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", +"03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,", +"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,", +"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,", +"61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,", +"35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,", +"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,", +"5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,", +"34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,", +"4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,", +"4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,", +"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,", + +"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", +null +]; \ No newline at end of file diff --git a/source/glfw3/monitor.d b/source/glfw3/monitor.d new file mode 100644 index 0000000..23fe33f --- /dev/null +++ b/source/glfw3/monitor.d @@ -0,0 +1,515 @@ +/// Translated from C to D +module glfw3.monitor; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +import glfw3.internal; + +import core.stdc.assert_; +import core.stdc.math; +import core.stdc.string; +import core.stdc.stdlib; +import core.stdc.limits; + +// Lexically compare video modes, used by qsort +// +private int compareVideoModes(const(void)* fp, const(void)* sp) { + auto fm = cast(const(GLFWvidmode)*) fp; + auto sm = cast(const(GLFWvidmode)*) sp; + const(int) fbpp = fm.redBits + fm.greenBits + fm.blueBits; + const(int) sbpp = sm.redBits + sm.greenBits + sm.blueBits; + const(int) farea = fm.width * fm.height; + const(int) sarea = sm.width * sm.height; + + // First sort on color bits per pixel + if (fbpp != sbpp) + return fbpp - sbpp; + + // Then sort on screen area + if (farea != sarea) + return farea - sarea; + + // Then sort on width + if (fm.width != sm.width) + return fm.width - sm.width; + + // Lastly sort on refresh rate + return fm.refreshRate - sm.refreshRate; +} + +// Retrieves the available modes for the specified monitor +// +private GLFWbool refreshVideoModes(_GLFWmonitor* monitor) { + int modeCount; + GLFWvidmode* modes; + + if (monitor.modes) + return GLFW_TRUE; + + modes = _glfwPlatformGetVideoModes(monitor, &modeCount); + if (!modes) + return GLFW_FALSE; + + qsort(modes, modeCount, GLFWvidmode.sizeof, &compareVideoModes); + + free(monitor.modes); + monitor.modes = modes; + monitor.modeCount = modeCount; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +// Notifies shared code of a monitor connection or disconnection +// +void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) { + if (action == GLFW_CONNECTED) + { + _glfw.monitorCount++; + _glfw.monitors = + cast(_GLFWmonitor**) realloc(_glfw.monitors, (_GLFWmonitor*).sizeof * _glfw.monitorCount); + + if (placement == _GLFW_INSERT_FIRST) + { + memmove(_glfw.monitors + 1, + _glfw.monitors, + (cast(size_t) _glfw.monitorCount - 1) * (_GLFWmonitor*).sizeof); + _glfw.monitors[0] = monitor; + } + else + _glfw.monitors[_glfw.monitorCount - 1] = monitor; + } + else if (action == GLFW_DISCONNECTED) + { + int i; + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window.next) + { + if (window.monitor == monitor) + { + int width;int height;int xoff;int yoff; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetWindowMonitor(window, null, 0, 0, width, height, 0); + _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, null, null); + _glfwPlatformSetWindowPos(window, xoff, yoff); + } + } + + for (i = 0; i < _glfw.monitorCount; i++) + { + if (_glfw.monitors[i] == monitor) + { + _glfw.monitorCount--; + memmove(_glfw.monitors + i, + _glfw.monitors + i + 1, + (cast(size_t) _glfw.monitorCount - i) * (_GLFWmonitor*).sizeof); + break; + } + } + } + + if (_glfw.callbacks.monitor) + _glfw.callbacks.monitor(cast(GLFWmonitor*) monitor, action); + + if (action == GLFW_DISCONNECTED) + _glfwFreeMonitor(monitor); +} + +// Notifies shared code that a full screen window has acquired or released +// a monitor +// +void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) { + monitor.window = window; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Allocates and returns a monitor object with the specified name and dimensions +// +_GLFWmonitor* _glfwAllocMonitor(const(char)* name, int widthMM, int heightMM) { + auto monitor = cast(_GLFWmonitor*) calloc(1, _GLFWmonitor.sizeof); + monitor.widthMM = widthMM; + monitor.heightMM = heightMM; + + if (name) + monitor.name = _glfw_strdup(name); + + return monitor; +} + +// Frees a monitor object and any data associated with it +// +void _glfwFreeMonitor(_GLFWmonitor* monitor) { + if (monitor == null) + return; + + _glfwPlatformFreeMonitor(monitor); + + _glfwFreeGammaArrays(&monitor.originalRamp); + _glfwFreeGammaArrays(&monitor.currentRamp); + + free(monitor.modes); + free(monitor.name); + free(monitor); +} + +// Allocates red, green and blue value arrays of the specified size +// +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, uint size) { + ramp.red = cast(ushort*) calloc(size, ushort.sizeof); + ramp.green = cast(ushort*) calloc(size, ushort.sizeof); + ramp.blue = cast(ushort*) calloc(size, ushort.sizeof); + ramp.size = size; +} + +// Frees the red, green and blue value arrays and clears the struct +// +void _glfwFreeGammaArrays(GLFWgammaramp* ramp) { + free(ramp.red); + free(ramp.green); + free(ramp.blue); + + memset(ramp, 0, GLFWgammaramp.sizeof); +} + +// Chooses the video mode most closely matching the desired one +// +const(GLFWvidmode)* _glfwChooseVideoMode(_GLFWmonitor* monitor, const(GLFWvidmode)* desired) { + int i; + uint sizeDiff;uint leastSizeDiff = UINT_MAX; + uint rateDiff;uint leastRateDiff = UINT_MAX; + uint colorDiff;uint leastColorDiff = UINT_MAX; + const(GLFWvidmode)* current; + const(GLFWvidmode)* closest = null; + + if (!refreshVideoModes(monitor)) + return null; + + for (i = 0; i < monitor.modeCount; i++) + { + current = monitor.modes + i; + + colorDiff = 0; + + if (desired.redBits != GLFW_DONT_CARE) + colorDiff += abs(current.redBits - desired.redBits); + if (desired.greenBits != GLFW_DONT_CARE) + colorDiff += abs(current.greenBits - desired.greenBits); + if (desired.blueBits != GLFW_DONT_CARE) + colorDiff += abs(current.blueBits - desired.blueBits); + + sizeDiff = abs((current.width - desired.width) * + (current.width - desired.width) + + (current.height - desired.height) * + (current.height - desired.height)); + + if (desired.refreshRate != GLFW_DONT_CARE) + rateDiff = abs(current.refreshRate - desired.refreshRate); + else + rateDiff = UINT_MAX - current.refreshRate; + + if ((colorDiff < leastColorDiff) || + (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) || + (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) + { + closest = current; + leastSizeDiff = sizeDiff; + leastRateDiff = rateDiff; + leastColorDiff = colorDiff; + } + } + + return closest; +} + +// Performs lexical comparison between two @ref GLFWvidmode structures +// +int _glfwCompareVideoModes(const(GLFWvidmode)* fm, const(GLFWvidmode)* sm) { + return compareVideoModes(fm, sm); +} + +// Splits a color depth into red, green and blue bit depths +// +void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) { + int delta; + + // We assume that by 32 the user really meant 24 + if (bpp == 32) + bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + + *red = *green = *blue = bpp / 3; + delta = bpp - (*red * 3); + if (delta >= 1) + *green = *green + 1; + + if (delta == 2) + *red = *red + 1; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWmonitor** glfwGetMonitors(int* count) { + assert(count != null); + + *count = 0; + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + *count = _glfw.monitorCount; + return cast(GLFWmonitor**) _glfw.monitors; +} + +GLFWmonitor* glfwGetPrimaryMonitor() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (!_glfw.monitorCount) + return null; + + return cast(GLFWmonitor*) _glfw.monitors[0]; +} + +void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + mixin(_GLFW_REQUIRE_INIT); + + _glfwPlatformGetMonitorPos(monitor, xpos, ypos); +} + +void glfwGetMonitorWorkarea(GLFWmonitor* handle, int* xpos, int* ypos, int* width, int* height) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + if (width) + *width = 0; + if (height) + *height = 0; + + mixin(_GLFW_REQUIRE_INIT); + + _glfwPlatformGetMonitorWorkarea(monitor, xpos, ypos, width, height); +} + +void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + if (widthMM) + *widthMM = 0; + if (heightMM) + *heightMM = 0; + + mixin(_GLFW_REQUIRE_INIT); + + if (widthMM) + *widthMM = monitor.widthMM; + if (heightMM) + *heightMM = monitor.heightMM; +} + +void glfwGetMonitorContentScale(GLFWmonitor* handle, float* xscale, float* yscale) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + if (xscale) + *xscale = 0.0f; + if (yscale) + *yscale = 0.0f; + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale); +} + +const(char)* glfwGetMonitorName(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return monitor.name; +} + +void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + mixin(_GLFW_REQUIRE_INIT); + monitor.userPointer = pointer; +} + +void* glfwGetMonitorUserPointer(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return monitor.userPointer; +} + +GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun); + return cbfun; +} + +const(GLFWvidmode)* glfwGetVideoModes(GLFWmonitor* handle, int* count) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + assert(count != null); + + *count = 0; + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (!refreshVideoModes(monitor)) + return null; + + *count = monitor.modeCount; + return monitor.modes; +} + +const(GLFWvidmode)* glfwGetVideoMode(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + _glfwPlatformGetVideoMode(monitor, &monitor.currentMode); + return &monitor.currentMode; +} + +void glfwSetGamma(GLFWmonitor* handle, float gamma) { + uint i; + ushort* values; + GLFWgammaramp ramp; + const(GLFWgammaramp)* original; + assert(handle != null); + assert(gamma > 0.0f); + assert(gamma <= float.max); + + mixin(_GLFW_REQUIRE_INIT); + + if (gamma != gamma || gamma <= 0.0f || gamma > float.max) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma); + return; + } + + original = glfwGetGammaRamp(handle); + if (!original) + return; + + values = cast(ushort*) calloc(original.size, ushort.sizeof); + + for (i = 0; i < original.size; i++) + { + float value; + + // Calculate intensity + value = i / cast(float) (original.size - 1); + // Apply gamma curve + value = powf(value, 1.0f / gamma) * 65535.0f + 0.5f; + // Clamp to value range + value = _glfw_fminf(value, 65535.0f); + + values[i] = cast(ushort) value; + } + + ramp.red = values; + ramp.green = values; + ramp.blue = values; + ramp.size = original.size; + + glfwSetGammaRamp(handle, &ramp); + free(values); +} + +const(GLFWgammaramp)* glfwGetGammaRamp(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + _glfwFreeGammaArrays(&monitor.currentRamp); + if (!_glfwPlatformGetGammaRamp(monitor, &monitor.currentRamp)) + return null; + + return &monitor.currentRamp; +} + +void glfwSetGammaRamp(GLFWmonitor* handle, const(GLFWgammaramp)* ramp) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + assert(monitor != null); + assert(ramp != null); + assert(ramp.size > 0); + assert(ramp.red != null); + assert(ramp.green != null); + assert(ramp.blue != null); + + if (ramp.size <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid gamma ramp size %i", + ramp.size); + return; + } + + mixin(_GLFW_REQUIRE_INIT); + + if (!monitor.originalRamp.size) + { + if (!_glfwPlatformGetGammaRamp(monitor, &monitor.originalRamp)) + return; + } + + _glfwPlatformSetGammaRamp(monitor, ramp); +} \ No newline at end of file diff --git a/source/glfw3/null_init.d b/source/glfw3/null_init.d new file mode 100644 index 0000000..3abb11a --- /dev/null +++ b/source/glfw3/null_init.d @@ -0,0 +1,51 @@ +/// Translated from C to D +module glfw3.null_init; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2016-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit() { + _glfwInitTimerPOSIX(); + return GLFW_TRUE; +} + +void _glfwPlatformTerminate() { + _glfwTerminateOSMesa(); +} + +const(char)* _glfwPlatformGetVersionString() { + return _GLFW_VERSION_NUMBER.stringof ~ " null OSMesa"; +} \ No newline at end of file diff --git a/source/glfw3/null_joystick.d b/source/glfw3/null_joystick.d new file mode 100644 index 0000000..706b65e --- /dev/null +++ b/source/glfw3/null_joystick.d @@ -0,0 +1,44 @@ +/// Translated from C to D +module glfw3.null_joystick; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { + return GLFW_FALSE; +} + +void _glfwPlatformUpdateGamepadGUID(char* guid) { +} \ No newline at end of file diff --git a/source/glfw3/null_monitor.d b/source/glfw3/null_monitor.d new file mode 100644 index 0000000..19efd0c --- /dev/null +++ b/source/glfw3/null_monitor.d @@ -0,0 +1,68 @@ +/// Translated from C to D +module glfw3.null_monitor; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2016-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { + if (xscale) + *xscale = 1.0f; + if (yscale) + *yscale = 1.0f; +} + +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { + return null; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { +} + +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { + return GLFW_FALSE; +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const(GLFWgammaramp)* ramp) { +} \ No newline at end of file diff --git a/source/glfw3/null_platform.d b/source/glfw3/null_platform.d new file mode 100644 index 0000000..6b8f7c4 --- /dev/null +++ b/source/glfw3/null_platform.d @@ -0,0 +1,64 @@ +/// Translated from C to D +module glfw3.null_platform; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2016-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +import core.sys.posix.dlfcn; + +mixin template _GLFW_PLATFORM_WINDOW_STATE() {GLFWwindowNull null_;} + +mixin template _GLFW_PLATFORM_CONTEXT_STATE() { int dummyContext; }; +mixin template _GLFW_PLATFORM_MONITOR_STATE() { int dummyMonitor; }; +mixin template _GLFW_PLATFORM_CURSOR_STATE() { int dummyCursor; }; +mixin template _GLFW_PLATFORM_LIBRARY_WINDOW_STATE() { int dummyLibraryWindow; }; +mixin template _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE() {int dummyLibraryContext; }; +mixin template _GLFW_EGL_CONTEXT_STATE() { int dummyEGLContext; }; +mixin template _GLFW_EGL_LIBRARY_CONTEXT_STATE() { int dummyEGLLibraryContext; }; + +public import glfw3.osmesa_context; +public import glfw3.posix_time; +public import glfw3.posix_thread; +public import glfw3.null_joystick; + +version (_GLFW_WIN32) { + auto _glfw_dlopen(const(char)* name) { return LoadLibraryA(name); } + auto _glfw_dlclose(void* handle) { return FreeLibrary(cast(HMODULE) handle); } + auto _glfw_dlsym(void* handle, const(char)* name) { return GetProcAddress(cast(HMODULE) handle, name);} +} else { + auto _glfw_dlopen(const(char)* name) {return dlopen(name, RTLD_LAZY | RTLD_LOCAL);} + auto _glfw_dlclose(void* handle) {return dlclose(handle);} + auto _glfw_dlsym(void* handle, const(char)* name) {return dlsym(handle, name);} +} + +// Null-specific per-window data +// +struct _GLFWwindowNull { + int width; + int height; +} \ No newline at end of file diff --git a/source/glfw3/null_window.d b/source/glfw3/null_window.d new file mode 100644 index 0000000..60069f0 --- /dev/null +++ b/source/glfw3/null_window.d @@ -0,0 +1,260 @@ +/// Translated from C to D +module glfw3.null_window; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2016-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + + +static int createNativeWindow(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig) { + window.null_.width = wndconfig.width; + window.null_.height = wndconfig.height; + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + if (!createNativeWindow(window, wndconfig)) + return GLFW_FALSE; + + if (ctxconfig.client != GLFW_NO_API) + { + if (ctxconfig.source == GLFW_NATIVE_CONTEXT_API || + ctxconfig.source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Null: EGL not available"); + return GLFW_FALSE; + } + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { + if (window.context.destroy) + window.context.destroy(window); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const(char)* title) { +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const(GLFWimage)* images) { +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { + if (width) + *width = window.null_.width; + if (height) + *height = window.null_.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { + window.null_.width = width; + window.null_.height = height; +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d) { +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { + if (width) + *width = window.null_.width; + if (height) + *height = window.null_.height; +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale) { + if (xscale) + *xscale = 1.0f; + if (yscale) + *yscale = 1.0f; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) { +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) { +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { + return GLFW_FALSE; +} + +int _glfwPlatformWindowHovered(_GLFWwindow* window) { + return GLFW_FALSE; +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { + return GLFW_FALSE; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { +} + +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { + return 1.0f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { +} + +void _glfwPlatformSetRawMouseMotion(_GLFWwindow* window, GLFWbool enabled) { +} + +GLFWbool _glfwPlatformRawMouseMotionSupported() { + return GLFW_FALSE; +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) { +} + + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { +} + +void _glfwPlatformUnhideWindow(_GLFWwindow* window) { +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) { +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) { +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) { + return GLFW_FALSE; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) { + return GLFW_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) { + return GLFW_FALSE; +} + +void _glfwPlatformPollEvents() { +} + +void _glfwPlatformWaitEvents() { +} + +void _glfwPlatformWaitEventsTimeout(double timeout) { +} + +void _glfwPlatformPostEmptyEvent() { +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const(GLFWimage)* image, int xhot, int yhot) { + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { +} + +void _glfwPlatformSetClipboardString(const(char)* string) { +} + +const(char)* _glfwPlatformGetClipboardString() { + return null; +} + +const(char)* _glfwPlatformGetScancodeName(int scancode) { + return ""; +} + +int _glfwPlatformGetKeyScancode(int key) { + return -1; +} + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint queuefamily) { + return GLFW_FALSE; +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const(VkAllocationCallbacks)* allocator, VkSurfaceKHR* surface) { + // This seems like the most appropriate error to return here + return VK_ERROR_INITIALIZATION_FAILED; +} \ No newline at end of file diff --git a/source/glfw3/osmesa_context.d b/source/glfw3/osmesa_context.d new file mode 100644 index 0000000..cb2794f --- /dev/null +++ b/source/glfw3/osmesa_context.d @@ -0,0 +1,404 @@ +/// Translated from C to D +module glfw3.osmesa_context; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 OSMesa - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016 Google Inc. +// Copyright (c) 2016-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +import core.stdc.stdlib; +import core.stdc.string; +import core.stdc.assert_; + +import glfw3.internal; + +enum OSMESA_RGBA = 0x1908; +enum OSMESA_FORMAT = 0x22; +enum OSMESA_DEPTH_BITS = 0x30; +enum OSMESA_STENCIL_BITS = 0x31; +enum OSMESA_ACCUM_BITS = 0x32; +enum OSMESA_PROFILE = 0x33; +enum OSMESA_CORE_PROFILE = 0x34; +enum OSMESA_COMPAT_PROFILE = 0x35; +enum OSMESA_CONTEXT_MAJOR_VERSION = 0x36; +enum OSMESA_CONTEXT_MINOR_VERSION = 0x37; + +alias void* OSMesaContext; +alias void function() OSMESAproc; + +alias OSMesaContext function(GLenum, GLint, GLint, GLint, OSMesaContext) PFN_OSMesaCreateContextExt; +alias OSMesaContext function(const(int)*, OSMesaContext) PFN_OSMesaCreateContextAttribs; +alias void function(OSMesaContext) PFN_OSMesaDestroyContext; +alias int function(OSMesaContext, void*, int, int, int) PFN_OSMesaMakeCurrent; +alias int function(OSMesaContext, int*, int*, int*, void**) PFN_OSMesaGetColorBuffer; +alias int function(OSMesaContext, int*, int*, int*, void**) PFN_OSMesaGetDepthBuffer; +alias GLFWglproc function(const(char)*) PFN_OSMesaGetProcAddress; +alias OSMesaCreateContextExt = _glfw.osmesa.CreateContextExt; +alias OSMesaCreateContextAttribs = _glfw.osmesa.CreateContextAttribs; +alias OSMesaDestroyContext = _glfw.osmesa.DestroyContext; +alias OSMesaMakeCurrent = _glfw.osmesa.MakeCurrent; +alias OSMesaGetColorBuffer = _glfw.osmesa.GetColorBuffer; +alias OSMesaGetDepthBuffer = _glfw.osmesa.GetDepthBuffer; +alias OSMesaGetProcAddress = _glfw.osmesa.GetProcAddress; + +mixin template _GLFW_OSMESA_CONTEXT_STATE() { _GLFWcontextOSMesa osmesa;} +mixin template _GLFW_OSMESA_LIBRARY_CONTEXT_STATE() { _GLFWlibraryOSMesa osmesa;} + +// OSMesa-specific per-context data +// +struct _GLFWcontextOSMesa { + OSMesaContext handle; + int width; + int height; + void* buffer; + +}/+alias _GLFWcontextOSMesa _GLFWcontextOSMesa;+/ + +// OSMesa-specific global data +// +struct _GLFWlibraryOSMesa { + void* handle; + + PFN_OSMesaCreateContextExt CreateContextExt; + PFN_OSMesaCreateContextAttribs CreateContextAttribs; + PFN_OSMesaDestroyContext DestroyContext; + PFN_OSMesaMakeCurrent MakeCurrent; + PFN_OSMesaGetColorBuffer GetColorBuffer; + PFN_OSMesaGetDepthBuffer GetDepthBuffer; + PFN_OSMesaGetProcAddress GetProcAddress; + +}/+alias _GLFWlibraryOSMesa _GLFWlibraryOSMesa;+/ + +GLFWbool _glfwInitOSMesa(); +void _glfwTerminateOSMesa(); +GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig); + +private void makeContextCurrentOSMesa(_GLFWwindow* window) { + if (window) + { + int width;int height; + _glfwPlatformGetFramebufferSize(window, &width, &height); + + // Check to see if we need to allocate a new buffer + if ((window.context.osmesa.buffer == null) || + (width != window.context.osmesa.width) || + (height != window.context.osmesa.height)) + { + free(window.context.osmesa.buffer); + + // Allocate the new buffer (width * height * 8-bit RGBA) + window.context.osmesa.buffer = calloc(4, cast(size_t) width * height); + window.context.osmesa.width = width; + window.context.osmesa.height = height; + } + + if (!_glfw.osmesa.MakeCurrent(window.context.osmesa.handle, + window.context.osmesa.buffer, + GL_UNSIGNED_BYTE, + width, height)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to make context current"); + return; + } + } + + _glfwPlatformSetTls(&_glfw.contextSlot, window); +} + +private GLFWglproc getProcAddressOSMesa(const(char)* procname) { + return cast(GLFWglproc) _glfw.osmesa.GetProcAddress(procname); +} + +private void destroyContextOSMesa(_GLFWwindow* window) { + if (window.context.osmesa.handle) + { + _glfw.osmesa.DestroyContext(window.context.osmesa.handle); + window.context.osmesa.handle = null; + } + + if (window.context.osmesa.buffer) + { + free(window.context.osmesa.buffer); + window.context.osmesa.width = 0; + window.context.osmesa.height = 0; + } +} + +static void swapBuffersOSMesa(_GLFWwindow* window) { + // No double buffering on OSMesa +} + +static void swapIntervalOSMesa(int interval) { + // No swap interval on OSMesa +} + +static int extensionSupportedOSMesa(const(char)* extension) { + // OSMesa does not have extensions + return GLFW_FALSE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwInitOSMesa() { + int i; + + version(Windows) { + static immutable char*[3] sonames = ["libOSMesa.dll", "OSMesa.dll", null]; + } else version(Cygwin) { + static immutable char*[2] sonames = ["libOSMesa.8.dylib", null]; + } else { + static immutable char*[3] sonames = ["libOSMesa.so.8", "libOSMesa.so.6", null]; + } + + if (_glfw.osmesa.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.osmesa.handle = _glfw_dlopen(sonames[i]); + if (_glfw.osmesa.handle) + break; + } + + if (!_glfw.osmesa.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found"); + return GLFW_FALSE; + } + + _glfw.osmesa.CreateContextExt = cast(PFN_OSMesaCreateContextExt) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt"); + _glfw.osmesa.CreateContextAttribs = cast(PFN_OSMesaCreateContextAttribs) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); + _glfw.osmesa.DestroyContext = cast(PFN_OSMesaDestroyContext) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext"); + _glfw.osmesa.MakeCurrent = cast(PFN_OSMesaMakeCurrent) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent"); + _glfw.osmesa.GetColorBuffer = cast(PFN_OSMesaGetColorBuffer) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); + _glfw.osmesa.GetDepthBuffer = cast(PFN_OSMesaGetDepthBuffer) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); + _glfw.osmesa.GetProcAddress = cast(PFN_OSMesaGetProcAddress) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress"); + + if (!_glfw.osmesa.CreateContextExt || + !_glfw.osmesa.DestroyContext || + !_glfw.osmesa.MakeCurrent || + !_glfw.osmesa.GetColorBuffer || + !_glfw.osmesa.GetDepthBuffer || + !_glfw.osmesa.GetProcAddress) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to load required entry points"); + + _glfwTerminateOSMesa(); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwTerminateOSMesa() { + if (_glfw.osmesa.handle) + { + _glfw_dlclose(_glfw.osmesa.handle); + _glfw.osmesa.handle = null; + } +} + +GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + OSMesaContext share = null; + const(int) accumBits = fbconfig.accumRedBits + + fbconfig.accumGreenBits + + fbconfig.accumBlueBits + + fbconfig.accumAlphaBits; + + if (ctxconfig.client == GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "OSMesa: OpenGL ES is not available on OSMesa"); + return GLFW_FALSE; + } + + if (ctxconfig.share) + share = cast(void*) ctxconfig.share.context.osmesa.handle; + + //if (OSMesaCreateContextAttribs) + if (_glfw.osmesa.CreateContextAttribs) + { + int index = 0;int[40] attribs; + void setAttrib(int a, int v) { + assert((cast(size_t) index + 1) < attribs.length); + attribs[index++] = a; + attribs[index++] = v; + } + + setAttrib(OSMESA_FORMAT, OSMESA_RGBA); + setAttrib(OSMESA_DEPTH_BITS, fbconfig.depthBits); + setAttrib(OSMESA_STENCIL_BITS, fbconfig.stencilBits); + setAttrib(OSMESA_ACCUM_BITS, accumBits); + + if (ctxconfig.profile == GLFW_OPENGL_CORE_PROFILE) + { + setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE); + } + else if (ctxconfig.profile == GLFW_OPENGL_COMPAT_PROFILE) + { + setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); + } + + if (ctxconfig.major != 1 || ctxconfig.minor != 0) + { + setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig.major); + setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig.minor); + } + + if (ctxconfig.forward) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "OSMesa: Forward-compatible contexts not supported"); + return GLFW_FALSE; + } + + setAttrib(0, 0); + + window.context.osmesa.handle = + _glfw.osmesa.CreateContextAttribs(attribs.ptr, share); + } + else + { + if (ctxconfig.profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "OSMesa: OpenGL profiles unavailable"); + return GLFW_FALSE; + } + + window.context.osmesa.handle = + _glfw.osmesa.CreateContextExt(OSMESA_RGBA, + fbconfig.depthBits, + fbconfig.stencilBits, + accumBits, + share); + } + + if (window.context.osmesa.handle == null) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "OSMesa: Failed to create context"); + return GLFW_FALSE; + } + + window.context.makeCurrent = &makeContextCurrentOSMesa; + window.context.swapBuffers = &swapBuffersOSMesa; + window.context.swapInterval = &swapIntervalOSMesa; + window.context.extensionSupported = &extensionSupportedOSMesa; + window.context.getProcAddress = &getProcAddressOSMesa; + window.context.destroy = &destroyContextOSMesa; + + return GLFW_TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width, int* height, int* format, void** buffer) { + void* mesaBuffer; + GLint mesaWidth;GLint mesaHeight;GLint mesaFormat; + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("GLFW_FALSE")); + + if (!_glfw.osmesa.GetColorBuffer(window.context.osmesa.handle, + &mesaWidth, &mesaHeight, + &mesaFormat, &mesaBuffer)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to retrieve color buffer"); + return GLFW_FALSE; + } + + if (width) + *width = mesaWidth; + if (height) + *height = mesaHeight; + if (format) + *format = mesaFormat; + if (buffer) + *buffer = mesaBuffer; + + return GLFW_TRUE; +} + +int glfwGetOSMesaDepthBuffer(GLFWwindow* handle, int* width, int* height, int* bytesPerValue, void** buffer) { + void* mesaBuffer; + GLint mesaWidth;GLint mesaHeight;GLint mesaBytes; + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("GLFW_FALSE")); + + if (!_glfw.osmesa.GetDepthBuffer(window.context.osmesa.handle, + &mesaWidth, &mesaHeight, + &mesaBytes, &mesaBuffer)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to retrieve depth buffer"); + return GLFW_FALSE; + } + + if (width) + *width = mesaWidth; + if (height) + *height = mesaHeight; + if (bytesPerValue) + *bytesPerValue = mesaBytes; + if (buffer) + *buffer = mesaBuffer; + + return GLFW_TRUE; +} + +OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("null")); + + if (window.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); + return null; + } + + return window.context.osmesa.handle; +} \ No newline at end of file diff --git a/source/glfw3/package.d b/source/glfw3/package.d new file mode 100644 index 0000000..a4a2089 --- /dev/null +++ b/source/glfw3/package.d @@ -0,0 +1,6 @@ +module glfw3; + +public { + import glfw3.api; + import glfw3.apinative; +} \ No newline at end of file diff --git a/source/glfw3/posix_thread.d b/source/glfw3/posix_thread.d new file mode 100644 index 0000000..70c19b6 --- /dev/null +++ b/source/glfw3/posix_thread.d @@ -0,0 +1,121 @@ +/// Translated from C to D +module glfw3.posix_thread; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +import core.stdc.assert_; +import core.stdc.string; +import core.sys.posix.pthread; + +// POSIX-specific thread local storage data +// +struct _GLFWtlsPOSIX +{ + GLFWbool allocated; + pthread_key_t key; +} + +// POSIX-specific mutex data +// +struct _GLFWmutexPOSIX +{ + import core.sys.posix.pthread: pthread_mutex_t; + GLFWbool allocated; + pthread_mutex_t handle; + +} + +mixin template _GLFW_PLATFORM_TLS_STATE() { _GLFWtlsPOSIX posix;} +mixin template _GLFW_PLATFORM_MUTEX_STATE() { _GLFWmutexPOSIX posix;} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) { + assert(tls.posix.allocated == GLFW_FALSE); + + if (pthread_key_create(&tls.posix.key, null) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "POSIX: Failed to create context TLS"); + return GLFW_FALSE; + } + + tls.posix.allocated = GLFW_TRUE; + return GLFW_TRUE; +} + +void _glfwPlatformDestroyTls(_GLFWtls* tls) { + if (tls.posix.allocated) + pthread_key_delete(tls.posix.key); + memset(tls, 0, _GLFWtls.sizeof); +} + +void* _glfwPlatformGetTls(_GLFWtls* tls) { + assert(tls.posix.allocated == GLFW_TRUE); + return pthread_getspecific(tls.posix.key); +} + +void _glfwPlatformSetTls(_GLFWtls* tls, void* value) { + assert(tls.posix.allocated == GLFW_TRUE); + pthread_setspecific(tls.posix.key, value); +} + +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) { + assert(mutex.posix.allocated == GLFW_FALSE); + + if (pthread_mutex_init(&mutex.posix.handle, null) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create mutex"); + return GLFW_FALSE; + } + + return mutex.posix.allocated = GLFW_TRUE; +} + +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) { + if (mutex.posix.allocated) + pthread_mutex_destroy(&mutex.posix.handle); + memset(mutex, 0, _GLFWmutex.sizeof); +} + +void _glfwPlatformLockMutex(_GLFWmutex* mutex) { + assert(mutex.posix.allocated == GLFW_TRUE); + pthread_mutex_lock(&mutex.posix.handle); +} + +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) { + assert(mutex.posix.allocated == GLFW_TRUE); + pthread_mutex_unlock(&mutex.posix.handle); +} \ No newline at end of file diff --git a/source/glfw3/posix_time.d b/source/glfw3/posix_time.d new file mode 100644 index 0000000..0d89d92 --- /dev/null +++ b/source/glfw3/posix_time.d @@ -0,0 +1,85 @@ +/// Translated from C to D +module glfw3.posix_time; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +import core.sys.posix.time; +import core.sys.posix.sys.time; + +import core.stdc.time; + +mixin template _GLFW_PLATFORM_LIBRARY_TIMER_STATE() {_GLFWtimerPOSIX posix;} + +// POSIX-specific global timer data +// +struct _GLFWtimerPOSIX +{ + GLFWbool monotonic; + ulong frequency; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerPOSIX() { + timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + _glfw.timer.posix.monotonic = GLFW_TRUE; + _glfw.timer.posix.frequency = 1000000000; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +ulong _glfwPlatformGetTimerValue() { + if (_glfw.timer.posix.monotonic) { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return cast(ulong) ts.tv_sec * cast(ulong) 1000000000 + cast(ulong) ts.tv_nsec; + } else { + timeval tv; + gettimeofday(&tv, null); + return cast(ulong) tv.tv_sec * cast(ulong) 1000000 + cast(ulong) tv.tv_usec; + } +} + +ulong _glfwPlatformGetTimerFrequency() { + return _glfw.timer.posix.frequency; +} \ No newline at end of file diff --git a/source/glfw3/vulkan.d b/source/glfw3/vulkan.d new file mode 100644 index 0000000..91ef9eb --- /dev/null +++ b/source/glfw3/vulkan.d @@ -0,0 +1,324 @@ +/// Translated from C to D +module vulkan; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2018 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +import glfw3.internal; + +import core.stdc.assert_; +import core.stdc.string; +import core.stdc.stdlib; + +enum _GLFW_FIND_LOADER = 1; +enum _GLFW_REQUIRE_LOADER = 2; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwInitVulkan(int mode) { + VkResult err; + VkExtensionProperties* ep; + uint i;uint count; + + if (_glfw.vk.available) + return GLFW_TRUE; + +version (_GLFW_VULKAN_STATIC) {} else { +version (_GLFW_VULKAN_LIBRARY) { + _glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY); +} else version (_GLFW_WIN32) { + _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); +} else version (_GLFW_COCOA) { + _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib"); + if (!_glfw.vk.handle) + _glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS(); +} else { + _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); +} + if (!_glfw.vk.handle) + { + if (mode == _GLFW_REQUIRE_LOADER) + _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); + + return GLFW_FALSE; + } + + _glfw.vk.GetInstanceProcAddr = cast(PFN_vkGetInstanceProcAddr) + _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr"); + if (!_glfw.vk.GetInstanceProcAddr) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Loader does not export vkGetInstanceProcAddr"); + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + _glfw.vk.EnumerateInstanceExtensionProperties = cast(PFN_vkEnumerateInstanceExtensionProperties) + _glfw.vk.GetInstanceProcAddr(null, "vkEnumerateInstanceExtensionProperties"); + if (!_glfw.vk.EnumerateInstanceExtensionProperties) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } +} // _GLFW_VULKAN_STATIC + + err = _glfw.vk.EnumerateInstanceExtensionProperties(null, &count, null); + if (err) + { + // NOTE: This happens on systems with a loader but without any Vulkan ICD + if (mode == _GLFW_REQUIRE_LOADER) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Failed to query instance extension count: %s", + _glfwGetVulkanResultString(err)); + } + + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + ep = cast(VkExtensionProperties*) calloc(count, VkExtensionProperties.sizeof); + + err = _glfw.vk.EnumerateInstanceExtensionProperties(null, &count, ep); + if (err) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Failed to query instance extensions: %s", + _glfwGetVulkanResultString(err)); + + free(ep); + _glfwTerminateVulkan(); + return GLFW_FALSE; + } + + for (i = 0; i < count; i++) + { + if (strcmp(ep[i].extensionName.ptr, "VK_KHR_surface") == 0) { + _glfw.vk.KHR_surface = GLFW_TRUE; + } else { + version (_GLFW_WIN32) { + if (strcmp(ep[i].extensionName.ptr, "VK_KHR_win32_surface") == 0) { + _glfw.vk.KHR_win32_surface = GLFW_TRUE; + } + } else version (_GLFW_COCOA) { + if (strcmp(ep[i].extensionName.ptr, "VK_MVK_macos_surface") == 0) + _glfw.vk.MVK_macos_surface = GLFW_TRUE; + else if (strcmp(ep[i].extensionName.ptr, "VK_EXT_metal_surface") == 0) + _glfw.vk.EXT_metal_surface = GLFW_TRUE; + } else version (_GLFW_X11) { + if (strcmp(ep[i].extensionName.ptr, "VK_KHR_xlib_surface") == 0) + _glfw.vk.KHR_xlib_surface = GLFW_TRUE; + else if (strcmp(ep[i].extensionName.ptr, "VK_KHR_xcb_surface") == 0) + _glfw.vk.KHR_xcb_surface = GLFW_TRUE; + } else version (_GLFW_WAYLAND) { + if (strcmp(ep[i].extensionName.ptr, "VK_KHR_wayland_surface") == 0) + _glfw.vk.KHR_wayland_surface = GLFW_TRUE; + } + } + } + + free(ep); + + _glfw.vk.available = GLFW_TRUE; + + _glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions.ptr); + + return GLFW_TRUE; +} + +void _glfwTerminateVulkan() { +version(_GLFW_VULKAN_STATIC) {} else { + if (_glfw.vk.handle) + _glfw_dlclose(_glfw.vk.handle); +} +} + +const(char)* _glfwGetVulkanResultString(VkResult result) { + switch (result) + { + case VkResult.VK_SUCCESS: + return "Success"; + case VkResult.VK_NOT_READY: + return "A fence or query has not yet completed"; + case VkResult.VK_TIMEOUT: + return "A wait operation has not completed in the specified time"; + case VkResult.VK_EVENT_SET: + return "An event is signaled"; + case VkResult.VK_EVENT_RESET: + return "An event is unsignaled"; + case VkResult.VK_INCOMPLETE: + return "A return array was too small for the result"; + case VkResult.VK_ERROR_OUT_OF_HOST_MEMORY: + return "A host memory allocation has failed"; + case VkResult.VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "A device memory allocation has failed"; + case VkResult.VK_ERROR_INITIALIZATION_FAILED: + return "Initialization of an object could not be completed for implementation-specific reasons"; + case VkResult.VK_ERROR_DEVICE_LOST: + return "The logical or physical device has been lost"; + case VkResult.VK_ERROR_MEMORY_MAP_FAILED: + return "Mapping of a memory object has failed"; + case VkResult.VK_ERROR_LAYER_NOT_PRESENT: + return "A requested layer is not present or could not be loaded"; + case VkResult.VK_ERROR_EXTENSION_NOT_PRESENT: + return "A requested extension is not supported"; + case VkResult.VK_ERROR_FEATURE_NOT_PRESENT: + return "A requested feature is not supported"; + case VkResult.VK_ERROR_INCOMPATIBLE_DRIVER: + return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible"; + case VkResult.VK_ERROR_TOO_MANY_OBJECTS: + return "Too many objects of the type have already been created"; + case VkResult.VK_ERROR_FORMAT_NOT_SUPPORTED: + return "A requested format is not supported on this device"; + case VkResult.VK_ERROR_SURFACE_LOST_KHR: + return "A surface is no longer available"; + case VkResult.VK_SUBOPTIMAL_KHR: + return "A swapchain no longer matches the surface properties exactly, but can still be used"; + case VkResult.VK_ERROR_OUT_OF_DATE_KHR: + return "A surface has changed in such a way that it is no longer compatible with the swapchain"; + case VkResult.VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "The display used by a swapchain does not use the same presentable image layout"; + case VkResult.VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API"; + case VkResult.VK_ERROR_VALIDATION_FAILED_EXT: + return "A validation layer found an error"; + default: + return "ERROR: UNKNOWN VULKAN ERROR"; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +int glfwVulkanSupported() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); + return _glfwInitVulkan(_GLFW_FIND_LOADER); +} + +const(char)** glfwGetRequiredInstanceExtensions(uint* count) { + assert(count != null); + + *count = 0; + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) + return null; + + if (!_glfw.vk.extensions[0]) + return null; + + *count = 2; + return cast(const(char)**) _glfw.vk.extensions; +} + +GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const(char)* procname) { + GLFWvkproc proc; + assert(procname != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) + return null; + + proc = cast(GLFWvkproc) _glfw.vk.GetInstanceProcAddr(instance, procname); +version (_GLFW_VULKAN_STATIC) { + if (!proc) + { + if (strcmp(procname, "vkGetInstanceProcAddr") == 0) + return cast(GLFWvkproc) vkGetInstanceProcAddr; + } +} else { + if (!proc) + proc = cast(GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname); +} + + return proc; +} + +int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint queuefamily) { + assert(instance != null); + assert(device != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); + + if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) + return GLFW_FALSE; + + if (!_glfw.vk.extensions[0]) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Window surface creation extensions not found"); + return GLFW_FALSE; + } + + return _glfwPlatformGetPhysicalDevicePresentationSupport(instance, + device, + queuefamily); +} + +VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* handle, const(VkAllocationCallbacks)* allocator, VkSurfaceKHR* surface) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(instance != null); + assert(window != null); + assert(surface != null); + + *surface = VK_NULL_HANDLE; + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"VkResult.VK_ERROR_INITIALIZATION_FAILED"); + + if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) + return VkResult.VK_ERROR_INITIALIZATION_FAILED; + + if (!_glfw.vk.extensions[0]) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Vulkan: Window surface creation extensions not found"); + return VkResult.VK_ERROR_EXTENSION_NOT_PRESENT; + } + + if (window.context.client != GLFW_NO_API) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API"); + return VkResult.VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; + } + + return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface); +} \ No newline at end of file diff --git a/source/glfw3/wayland.d b/source/glfw3/wayland.d new file mode 100644 index 0000000..d06415b --- /dev/null +++ b/source/glfw3/wayland.d @@ -0,0 +1,1231 @@ +module glfw3.wayland; + +extern(C): nothrow: @nogc: + +// extensions + +struct zxdg_toplevel_decoration_v1_listener { +extern(C): nothrow: @nogc: + void function(void* data, zxdg_toplevel_decoration_v1* decoration, uint mode) configure; +} + +struct xdg_toplevel_listener { +extern(C): nothrow: @nogc: + void function(void* data, xdg_toplevel* toplevel, int width, int height, wl_array* states) configure; + void function(void* data, xdg_toplevel* toplevel) close; +} + +struct xdg_surface_listener { +extern(C): nothrow: @nogc: + void function(void* data, xdg_surface* surface, uint serial) configure; +} + +struct zwp_relative_pointer_v1_listener { +extern(C): nothrow: @nogc: + void function(void* data, zwp_relative_pointer_v1* pointer, uint timeHi, uint timeLo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dxUnaccel, wl_fixed_t dyUnaccel) relativeMotion; +} + +struct zwp_locked_pointer_v1_listener { +extern(C): nothrow: @nogc: + void function(void* data, zwp_locked_pointer_v1* lockedPointer) locked; + void function(void* data, zwp_locked_pointer_v1* lockedPointer) unlocked; +} + +// +struct wl_buffer; +struct wl_callback; +struct wl_compositor; +struct wl_cursor_theme; +struct wl_data_device_manager; +struct wl_data_device; +struct wl_data_offer; +struct wl_data_source; +struct wl_display; +struct wl_egl_window; +struct wl_keyboard; +struct wl_output; +struct wl_pointer; +struct wl_region; +struct wl_registry; +struct wl_seat; +struct wl_shell_surface; +struct wl_shell; +struct wl_shm_pool; +struct wl_shm; +struct wl_subcompositor; +struct wl_subsurface; +struct wl_surface; +struct wl_touch; +struct wp_viewport; +struct wp_viewporter; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; +struct zwp_idle_inhibit_manager_v1; +struct zwp_idle_inhibitor_v1; +struct zwp_locked_pointer_v1; +struct zwp_pointer_constraints_v1; +struct zwp_relative_pointer_manager_v1; +struct zwp_relative_pointer_v1; +struct zxdg_decoration_manager_v1; +struct zxdg_toplevel_decoration_v1; + +alias wl_fixed_t = uint; + +pure @safe nothrow @nogc +pragma(inline, true) double wl_fixed_to_double(wl_fixed_t f) { + static union U { + double d; + ulong i; + } + U u; + u.i = ((1023L + 44L) << 52) + (1L << 51) + f; + return u.d - (3L << 43); +} + +struct wl_array { + size_t size; + size_t alloc; + void *data; +} + +enum wl_seat_capability { + WL_SEAT_CAPABILITY_POINTER = 1, + WL_SEAT_CAPABILITY_KEYBOARD = 2, + WL_SEAT_CAPABILITY_TOUCH = 4, +} +enum WL_SEAT_CAPABILITY_POINTER = wl_seat_capability.WL_SEAT_CAPABILITY_POINTER; +enum WL_SEAT_CAPABILITY_KEYBOARD = wl_seat_capability.WL_SEAT_CAPABILITY_KEYBOARD; +enum WL_SEAT_CAPABILITY_TOUCH = wl_seat_capability.WL_SEAT_CAPABILITY_TOUCH; + +enum wl_output_mode { + WL_OUTPUT_MODE_CURRENT = 0x1, + WL_OUTPUT_MODE_PREFERRED = 0x2, +} +enum WL_OUTPUT_MODE_CURRENT = wl_output_mode.WL_OUTPUT_MODE_CURRENT; +enum WL_OUTPUT_MODE_PREFERRED = wl_output_mode.WL_OUTPUT_MODE_PREFERRED; + +enum wl_pointer_button_state { + WL_POINTER_BUTTON_STATE_RELEASED = 0, + WL_POINTER_BUTTON_STATE_PRESSED = 1, +} +enum WL_POINTER_BUTTON_STATE_RELEASED = wl_pointer_button_state.WL_POINTER_BUTTON_STATE_RELEASED; +enum WL_POINTER_BUTTON_STATE_PRESSED = wl_pointer_button_state.WL_POINTER_BUTTON_STATE_PRESSED; + +enum wl_keyboard_key_state { + WL_KEYBOARD_KEY_STATE_RELEASED = 0, + WL_KEYBOARD_KEY_STATE_PRESSED = 1, +} +enum WL_KEYBOARD_KEY_STATE_RELEASED = wl_keyboard_key_state.WL_KEYBOARD_KEY_STATE_RELEASED; +enum WL_KEYBOARD_KEY_STATE_PRESSED = wl_keyboard_key_state.WL_KEYBOARD_KEY_STATE_PRESSED; + +enum wl_pointer_axis { + WL_POINTER_AXIS_VERTICAL_SCROLL = 0, + WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, +} +enum WL_POINTER_AXIS_VERTICAL_SCROLL = wl_pointer_axis.WL_POINTER_AXIS_VERTICAL_SCROLL; +enum WL_POINTER_AXIS_HORIZONTAL_SCROLL = wl_pointer_axis.WL_POINTER_AXIS_HORIZONTAL_SCROLL; + +enum wl_keyboard_keymap_format { + WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, +} +enum WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = wl_keyboard_keymap_format.WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; +enum WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = wl_keyboard_keymap_format.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1; + +struct wl_message { + const(char)* name; + const(char)* signature; + const(wl_interface)** types; +} + +struct wl_interface { + const char *name; + int version_; + int method_count; + const(wl_message)* methods; + int event_count; + const(wl_message)* events; +} + +/* +wl_array_for_each(pos, array) + for (pos = (array)->data; + (const char *) pos < ((const char *) (array)->data + (array)->size); + (pos)++) +*/ + +struct wl_pointer_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_pointer* wl_pointer, uint serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) enter; + void function(void* data, wl_pointer* wl_pointer, uint serial, wl_surface* surface) leave; + void function(void* data, wl_pointer* wl_pointer, uint time, wl_fixed_t surface_x, wl_fixed_t surface_y) motion; + void function(void* data, wl_pointer* wl_pointer, uint serial, uint time, uint button, uint state) button; + void function(void* data, wl_pointer* wl_pointer, uint time, uint axis, wl_fixed_t value) axis; + void function(void* data, wl_pointer* wl_pointer) frame; + void function(void* data, wl_pointer* wl_pointer, uint axis_source) axis_source; + void function(void* data, wl_pointer* wl_pointer, uint time, uint axis) axis_stop; + void function(void* data, wl_pointer* wl_pointer, uint axis, int discrete) axis_discrete; +} + +struct wl_keyboard_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_keyboard* wl_keyboard, uint format, int fd, uint size) keymap; + void function(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface, wl_array* keys) enter; + void function(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface) leave; + void function(void* data, wl_keyboard* wl_keyboard, uint serial, uint time, uint key, uint state) key; + void function(void* data, wl_keyboard* wl_keyboard, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group) modifiers; + void function(void* data, wl_keyboard* wl_keyboard, int rate, int delay) repeat_info; +} + +struct wl_seat_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_seat* wl_seat, uint capabilities) capabilities; + void function(void* data, wl_seat* wl_seat, const(char)* name) name; +} +struct wl_data_offer_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_data_offer* wl_data_offer, const(char)* mime_type) offer; + void function(void* data, wl_data_offer* wl_data_offer, uint source_actions) source_actions; + void function(void* data, wl_data_offer* wl_data_offer, uint dnd_action) action; +} + +struct wl_surface_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_surface* wl_surface, wl_output* output) enter; + void function(void* data, wl_surface* wl_surface, wl_output* output) leave; +} + +struct wl_data_device_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_data_device* wl_data_device, wl_data_offer* id) data_offer; + void function(void* data, wl_data_device* wl_data_device, uint serial, wl_surface* surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer* id) enter; + void function(void* data, wl_data_device* wl_data_device) leave; + void function(void* data, wl_data_device* wl_data_device, uint time, wl_fixed_t x, wl_fixed_t y) motion; + void function(void* data, wl_data_device* wl_data_device) drop; + void function(void* data, wl_data_device* wl_data_device, wl_data_offer* id) selection; +} + +struct wl_registry_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_registry* wl_registry, uint name, const(char)* interface_, uint version_) global; + void function(void* data, wl_registry* wl_registry, uint name) global_remove; +} + +struct wl_output_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_output* wl_output, int x, int y, int physical_width, int physical_height, int subpixel, const(char)* make, const(char)* model, int transform) geometry; + void function(void* data, wl_output* wl_output, uint flags, int width, int height, int refresh) mode; + void function(void* data, wl_output* wl_output) done; + void function(void* data, wl_output* wl_output, int factor) scale; +} +struct wl_data_source_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_data_source* wl_data_source, const(char)* mime_type) target; + void function(void* data, wl_data_source* wl_data_source, const(char)* mime_type, int fd) send; + void function(void* data, wl_data_source* wl_data_source) cancelled; + void function(void* data, wl_data_source* wl_data_source) dnd_drop_performed; + void function(void* data, wl_data_source* wl_data_source) dnd_finished; + void function(void* data, wl_data_source* wl_data_source, uint dnd_action) action; +} + +// note: I have no idea where this is defined in C headers, but this is how it's used in GLFW +struct xdg_wm_base_listener { + extern(C): @nogc: nothrow: + void function(void* data, xdg_wm_base* wmBase, uint serial) ping; +} + +struct wl_shell_surface_listener { + extern(C): @nogc: nothrow: + void function(void* data, wl_shell_surface* wl_shell_surface, uint serial) ping; + void function(void* data, wl_shell_surface* wl_shell_surface, uint edges, int width, int height) configure; + void function(void* data, wl_shell_surface* wl_shell_surface) popup_done; +} + +pragma(inline, true) static void* wl_registry_bind(wl_registry* wl_registry, uint name, const(wl_interface)* interface_, uint version_) { + wl_proxy* id; + id = wl_proxy_marshal_constructor_versioned(cast(wl_proxy*) wl_registry, + WL_REGISTRY_BIND, interface_, version_, name, interface_.name, version_, null); + + return cast(void*) id; +} + +pragma(inline, true) static int wl_output_add_listener(wl_output* wl_output, const(wl_output_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_output, + cast(void function()) listener, data); +} + +pragma(inline, true) static void wl_output_destroy(wl_output* wl_output) { + wl_proxy_destroy(cast(wl_proxy*) wl_output); +} + +extern const wl_interface wl_display_interface; +extern const wl_interface wl_registry_interface; +extern const wl_interface wl_callback_interface; +extern const wl_interface wl_compositor_interface; +extern const wl_interface wl_shm_pool_interface; +extern const wl_interface wl_shm_interface; +extern const wl_interface wl_buffer_interface; +extern const wl_interface wl_data_offer_interface; +extern const wl_interface wl_data_source_interface; +extern const wl_interface wl_data_device_interface; +extern const wl_interface wl_data_device_manager_interface; +extern const wl_interface wl_shell_interface; +extern const wl_interface wl_shell_surface_interface; +extern const wl_interface wl_surface_interface; +extern const wl_interface wl_seat_interface; +extern const wl_interface wl_pointer_interface; +extern const wl_interface wl_keyboard_interface; +extern const wl_interface wl_touch_interface; +extern const wl_interface wl_output_interface; +extern const wl_interface wl_region_interface; +extern const wl_interface wl_subcompositor_interface; +extern const wl_interface wl_subsurface_interface; + +enum /*wl_shell_surface_resize*/ { + WL_SHELL_SURFACE_RESIZE_NONE = 0, + WL_SHELL_SURFACE_RESIZE_TOP = 1, + WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, + WL_SHELL_SURFACE_RESIZE_LEFT = 4, + WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, + WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, + WL_SHELL_SURFACE_RESIZE_RIGHT = 8, + WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, + WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, +} + +// Bulk +enum wl_display_error { + WL_DISPLAY_ERROR_INVALID_OBJECT = 0, + WL_DISPLAY_ERROR_INVALID_METHOD = 1, + WL_DISPLAY_ERROR_NO_MEMORY = 2, +} +struct wl_display_listener { + void function(void* data, wl_display* wl_display, void* object_id, uint code, const(char)* message) error; + void function(void* data, wl_display* wl_display, uint id) delete_id; +} +pragma(inline, true) static int wl_display_add_listener(wl_display* wl_display, const(wl_display_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_display, + cast(void function()) listener, data); +} +enum WL_DISPLAY_SYNC = 0; +enum WL_DISPLAY_GET_REGISTRY = 1; +enum WL_DISPLAY_ERROR_SINCE_VERSION = 1; +enum WL_DISPLAY_DELETE_ID_SINCE_VERSION = 1; +enum WL_DISPLAY_SYNC_SINCE_VERSION = 1; +enum WL_DISPLAY_GET_REGISTRY_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_display_set_user_data(wl_display* wl_display, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_display, user_data); +} +pragma(inline, true) static void* wl_display_get_user_data(wl_display* wl_display) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_display); +} +pragma(inline, true) static uint wl_display_get_version(wl_display* wl_display) { + return wl_proxy_get_version(cast(wl_proxy*) wl_display); +} +pragma(inline, true) static wl_callback* wl_display_sync(wl_display* wl_display) { + wl_proxy* callback; + callback = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_display, + WL_DISPLAY_SYNC, &wl_callback_interface, null); + return cast(wl_callback*) callback; +} +pragma(inline, true) static wl_registry* wl_display_get_registry(wl_display* wl_display) { + wl_proxy* registry; + registry = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_display, + WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, null); + return cast(wl_registry*) registry; +} +pragma(inline, true) static int wl_registry_add_listener(wl_registry* wl_registry, const(wl_registry_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_registry, + cast(void function()) listener, data); +} +enum WL_REGISTRY_BIND = 0; +enum WL_REGISTRY_GLOBAL_SINCE_VERSION = 1; +enum WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION = 1; +enum WL_REGISTRY_BIND_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_registry_set_user_data(wl_registry* wl_registry, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_registry, user_data); +} +pragma(inline, true) static void* wl_registry_get_user_data(wl_registry* wl_registry) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_registry); +} +pragma(inline, true) static uint wl_registry_get_version(wl_registry* wl_registry) { + return wl_proxy_get_version(cast(wl_proxy*) wl_registry); +} + +pragma(inline, true) static void wl_registry_destroy(wl_registry* wl_registry) { + wl_proxy_destroy(cast(wl_proxy*) wl_registry); +} +struct wl_callback_listener { + void function(void* data, wl_callback* wl_callback, uint callback_data) done; +} +pragma(inline, true) static int wl_callback_add_listener(wl_callback* wl_callback, const(wl_callback_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_callback, + cast(void function()) listener, data); +} +enum WL_CALLBACK_DONE_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_callback_set_user_data(wl_callback* wl_callback, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_callback, user_data); +} +pragma(inline, true) static void* wl_callback_get_user_data(wl_callback* wl_callback) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_callback); +} +pragma(inline, true) static uint wl_callback_get_version(wl_callback* wl_callback) { + return wl_proxy_get_version(cast(wl_proxy*) wl_callback); +} +pragma(inline, true) static void wl_callback_destroy(wl_callback* wl_callback) { + wl_proxy_destroy(cast(wl_proxy*) wl_callback); +} +enum WL_COMPOSITOR_CREATE_SURFACE = 0; +enum WL_COMPOSITOR_CREATE_REGION = 1; +enum WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION = 1; +enum WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_compositor_set_user_data(wl_compositor* wl_compositor, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_compositor, user_data); +} +pragma(inline, true) static void* wl_compositor_get_user_data(wl_compositor* wl_compositor) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_compositor); +} +pragma(inline, true) static uint wl_compositor_get_version(wl_compositor* wl_compositor) { + return wl_proxy_get_version(cast(wl_proxy*) wl_compositor); +} +pragma(inline, true) static void wl_compositor_destroy(wl_compositor* wl_compositor) { + wl_proxy_destroy(cast(wl_proxy*) wl_compositor); +} +pragma(inline, true) static wl_surface* wl_compositor_create_surface(wl_compositor* wl_compositor) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_compositor, + WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, null); + return cast(wl_surface*) id; +} +pragma(inline, true) static wl_region* wl_compositor_create_region(wl_compositor* wl_compositor) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_compositor, + WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, null); + return cast(wl_region*) id; +} +enum WL_SHM_POOL_CREATE_BUFFER = 0; +enum WL_SHM_POOL_DESTROY = 1; +enum WL_SHM_POOL_RESIZE = 2; +enum WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION = 1; +enum WL_SHM_POOL_DESTROY_SINCE_VERSION = 1; +enum WL_SHM_POOL_RESIZE_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_shm_pool_set_user_data(wl_shm_pool* wl_shm_pool, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_shm_pool, user_data); +} +pragma(inline, true) static void* wl_shm_pool_get_user_data(wl_shm_pool* wl_shm_pool) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_shm_pool); +} +pragma(inline, true) static uint wl_shm_pool_get_version(wl_shm_pool* wl_shm_pool) { + return wl_proxy_get_version(cast(wl_proxy*) wl_shm_pool); +} +pragma(inline, true) static wl_buffer* wl_shm_pool_create_buffer(wl_shm_pool* wl_shm_pool, int offset, int width, int height, int stride, uint format) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_shm_pool, + WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, null, offset, width, height, stride, format); + return cast(wl_buffer*) id; +} +pragma(inline, true) static void wl_shm_pool_destroy(wl_shm_pool* wl_shm_pool) { + wl_proxy_marshal(cast(wl_proxy*) wl_shm_pool, + WL_SHM_POOL_DESTROY); + wl_proxy_destroy(cast(wl_proxy*) wl_shm_pool); +} +pragma(inline, true) static void wl_shm_pool_resize(wl_shm_pool* wl_shm_pool, int size) { + wl_proxy_marshal(cast(wl_proxy*) wl_shm_pool, WL_SHM_POOL_RESIZE, size); +} +enum wl_shm_error { + WL_SHM_ERROR_INVALID_FORMAT = 0, + WL_SHM_ERROR_INVALID_STRIDE = 1, + WL_SHM_ERROR_INVALID_FD = 2, +} +enum wl_shm_format { + WL_SHM_FORMAT_ARGB8888 = 0, + WL_SHM_FORMAT_XRGB8888 = 1, + WL_SHM_FORMAT_C8 = 0x20203843, + WL_SHM_FORMAT_RGB332 = 0x38424752, + WL_SHM_FORMAT_BGR233 = 0x38524742, + WL_SHM_FORMAT_XRGB4444 = 0x32315258, + WL_SHM_FORMAT_XBGR4444 = 0x32314258, + WL_SHM_FORMAT_RGBX4444 = 0x32315852, + WL_SHM_FORMAT_BGRX4444 = 0x32315842, + WL_SHM_FORMAT_ARGB4444 = 0x32315241, + WL_SHM_FORMAT_ABGR4444 = 0x32314241, + WL_SHM_FORMAT_RGBA4444 = 0x32314152, + WL_SHM_FORMAT_BGRA4444 = 0x32314142, + WL_SHM_FORMAT_XRGB1555 = 0x35315258, + WL_SHM_FORMAT_XBGR1555 = 0x35314258, + WL_SHM_FORMAT_RGBX5551 = 0x35315852, + WL_SHM_FORMAT_BGRX5551 = 0x35315842, + WL_SHM_FORMAT_ARGB1555 = 0x35315241, + WL_SHM_FORMAT_ABGR1555 = 0x35314241, + WL_SHM_FORMAT_RGBA5551 = 0x35314152, + WL_SHM_FORMAT_BGRA5551 = 0x35314142, + WL_SHM_FORMAT_RGB565 = 0x36314752, + WL_SHM_FORMAT_BGR565 = 0x36314742, + WL_SHM_FORMAT_RGB888 = 0x34324752, + WL_SHM_FORMAT_BGR888 = 0x34324742, + WL_SHM_FORMAT_XBGR8888 = 0x34324258, + WL_SHM_FORMAT_RGBX8888 = 0x34325852, + WL_SHM_FORMAT_BGRX8888 = 0x34325842, + WL_SHM_FORMAT_ABGR8888 = 0x34324241, + WL_SHM_FORMAT_RGBA8888 = 0x34324152, + WL_SHM_FORMAT_BGRA8888 = 0x34324142, + WL_SHM_FORMAT_XRGB2101010 = 0x30335258, + WL_SHM_FORMAT_XBGR2101010 = 0x30334258, + WL_SHM_FORMAT_RGBX1010102 = 0x30335852, + WL_SHM_FORMAT_BGRX1010102 = 0x30335842, + WL_SHM_FORMAT_ARGB2101010 = 0x30335241, + WL_SHM_FORMAT_ABGR2101010 = 0x30334241, + WL_SHM_FORMAT_RGBA1010102 = 0x30334152, + WL_SHM_FORMAT_BGRA1010102 = 0x30334142, + WL_SHM_FORMAT_YUYV = 0x56595559, + WL_SHM_FORMAT_YVYU = 0x55595659, + WL_SHM_FORMAT_UYVY = 0x59565955, + WL_SHM_FORMAT_VYUY = 0x59555956, + WL_SHM_FORMAT_AYUV = 0x56555941, + WL_SHM_FORMAT_NV12 = 0x3231564e, + WL_SHM_FORMAT_NV21 = 0x3132564e, + WL_SHM_FORMAT_NV16 = 0x3631564e, + WL_SHM_FORMAT_NV61 = 0x3136564e, + WL_SHM_FORMAT_YUV410 = 0x39565559, + WL_SHM_FORMAT_YVU410 = 0x39555659, + WL_SHM_FORMAT_YUV411 = 0x31315559, + WL_SHM_FORMAT_YVU411 = 0x31315659, + WL_SHM_FORMAT_YUV420 = 0x32315559, + WL_SHM_FORMAT_YVU420 = 0x32315659, + WL_SHM_FORMAT_YUV422 = 0x36315559, + WL_SHM_FORMAT_YVU422 = 0x36315659, + WL_SHM_FORMAT_YUV444 = 0x34325559, + WL_SHM_FORMAT_YVU444 = 0x34325659, +} +struct wl_shm_listener { + void function(void* data, wl_shm* wl_shm, uint format) format; +}; +pragma(inline, true) static int wl_shm_add_listener(wl_shm* wl_shm, const(wl_shm_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_shm, cast(void function()) listener, data); +} +enum WL_SHM_CREATE_POOL = 0; +enum WL_SHM_FORMAT_SINCE_VERSION = 1; +enum WL_SHM_CREATE_POOL_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_shm_set_user_data(wl_shm* wl_shm, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_shm, user_data); +} +pragma(inline, true) static void* wl_shm_get_user_data(wl_shm* wl_shm) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_shm); +} +pragma(inline, true) static uint wl_shm_get_version(wl_shm* wl_shm) { + return wl_proxy_get_version(cast(wl_proxy*) wl_shm); +} +pragma(inline, true) static void wl_shm_destroy(wl_shm* wl_shm) { + wl_proxy_destroy(cast(wl_proxy*) wl_shm); +} +pragma(inline, true) static wl_shm_pool* wl_shm_create_pool(wl_shm* wl_shm, int fd, int size) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_shm, + WL_SHM_CREATE_POOL, &wl_shm_pool_interface, null, fd, size); + return cast(wl_shm_pool*) id; +} +struct wl_buffer_listener { + void function(void* data, wl_buffer* wl_buffer) release; +}; +pragma(inline, true) static int wl_buffer_add_listener(wl_buffer* wl_buffer, const(wl_buffer_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_buffer, + cast(void function()) listener, data); +} +enum WL_BUFFER_DESTROY = 0; +enum WL_BUFFER_RELEASE_SINCE_VERSION = 1; +enum WL_BUFFER_DESTROY_SINCE_VERSION = 1; +pragma(inline, true) static void wl_buffer_set_user_data(wl_buffer* wl_buffer, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_buffer, user_data); +} +pragma(inline, true) static void* wl_buffer_get_user_data(wl_buffer* wl_buffer) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_buffer); +} +pragma(inline, true) static uint wl_buffer_get_version(wl_buffer* wl_buffer) { + return wl_proxy_get_version(cast(wl_proxy*) wl_buffer); +} +pragma(inline, true) static void wl_buffer_destroy(wl_buffer* wl_buffer) { + wl_proxy_marshal(cast(wl_proxy*) wl_buffer, + WL_BUFFER_DESTROY); + wl_proxy_destroy(cast(wl_proxy*) wl_buffer); +} +enum wl_data_offer_error { + WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, + WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, + WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, + WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, +} +pragma(inline, true) static int wl_data_offer_add_listener(wl_data_offer* wl_data_offer, const(wl_data_offer_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_data_offer, + cast(void function()) listener, data); +} +enum WL_DATA_OFFER_ACCEPT = 0; +enum WL_DATA_OFFER_RECEIVE = 1; +enum WL_DATA_OFFER_DESTROY = 2; +enum WL_DATA_OFFER_FINISH = 3; +enum WL_DATA_OFFER_SET_ACTIONS = 4; +enum WL_DATA_OFFER_OFFER_SINCE_VERSION = 1; +enum WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION = 3; +enum WL_DATA_OFFER_ACTION_SINCE_VERSION = 3; +enum WL_DATA_OFFER_ACCEPT_SINCE_VERSION = 1; +enum WL_DATA_OFFER_RECEIVE_SINCE_VERSION = 1; +enum WL_DATA_OFFER_DESTROY_SINCE_VERSION = 1; +enum WL_DATA_OFFER_FINISH_SINCE_VERSION = 3; +enum WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION = 3; +pragma(inline, true) static void wl_data_offer_set_user_data(wl_data_offer* wl_data_offer, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_data_offer, user_data); +} +pragma(inline, true) static void* wl_data_offer_get_user_data(wl_data_offer* wl_data_offer) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_data_offer); +} +pragma(inline, true) static uint wl_data_offer_get_version(wl_data_offer* wl_data_offer) { + return wl_proxy_get_version(cast(wl_proxy*) wl_data_offer); +} +pragma(inline, true) static void wl_data_offer_accept(wl_data_offer* wl_data_offer, uint serial, const(char)* mime_type) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_offer, + WL_DATA_OFFER_ACCEPT, serial, mime_type); +} +pragma(inline, true) static void wl_data_offer_receive(wl_data_offer* wl_data_offer, const(char)* mime_type, int fd) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_offer, + WL_DATA_OFFER_RECEIVE, mime_type, fd); +} +pragma(inline, true) static void wl_data_offer_destroy(wl_data_offer* wl_data_offer) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_offer, + WL_DATA_OFFER_DESTROY); + wl_proxy_destroy(cast(wl_proxy*) wl_data_offer); +} +pragma(inline, true) static void wl_data_offer_finish(wl_data_offer* wl_data_offer) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_offer, + WL_DATA_OFFER_FINISH); +} +pragma(inline, true) static void wl_data_offer_set_actions(wl_data_offer* wl_data_offer, uint dnd_actions, uint preferred_action) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_offer, + WL_DATA_OFFER_SET_ACTIONS, dnd_actions, preferred_action); +} +enum wl_data_source_error { + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, + WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, +} +pragma(inline, true) static int wl_data_source_add_listener(wl_data_source* wl_data_source, const(wl_data_source_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_data_source, + cast(void function()) listener, data); +} +enum WL_DATA_SOURCE_OFFER = 0; +enum WL_DATA_SOURCE_DESTROY = 1; +enum WL_DATA_SOURCE_SET_ACTIONS = 2; +enum WL_DATA_SOURCE_TARGET_SINCE_VERSION = 1; +enum WL_DATA_SOURCE_SEND_SINCE_VERSION = 1; +enum WL_DATA_SOURCE_CANCELLED_SINCE_VERSION = 1; +enum WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION = 3; +enum WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION = 3; +enum WL_DATA_SOURCE_ACTION_SINCE_VERSION = 3; +enum WL_DATA_SOURCE_OFFER_SINCE_VERSION = 1; +enum WL_DATA_SOURCE_DESTROY_SINCE_VERSION = 1; +enum WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION = 3; +pragma(inline, true) static void wl_data_source_set_user_data(wl_data_source* wl_data_source, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_data_source, user_data); +} +pragma(inline, true) static void* wl_data_source_get_user_data(wl_data_source* wl_data_source) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_data_source); +} +pragma(inline, true) static uint wl_data_source_get_version(wl_data_source* wl_data_source) { + return wl_proxy_get_version(cast(wl_proxy*) wl_data_source); +} +pragma(inline, true) static void wl_data_source_offer(wl_data_source* wl_data_source, const(char)* mime_type) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_source, + WL_DATA_SOURCE_OFFER, mime_type); +} +pragma(inline, true) static void wl_data_source_destroy(wl_data_source* wl_data_source) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_source, + WL_DATA_SOURCE_DESTROY); + wl_proxy_destroy(cast(wl_proxy*) wl_data_source); +} +pragma(inline, true) static void wl_data_source_set_actions(wl_data_source* wl_data_source, uint dnd_actions) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_source, + WL_DATA_SOURCE_SET_ACTIONS, dnd_actions); +} +enum wl_data_device_error { + WL_DATA_DEVICE_ERROR_ROLE = 0, +} +pragma(inline, true) static int wl_data_device_add_listener(wl_data_device* wl_data_device, const(wl_data_device_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_data_device, + cast(void function()) listener, data); +} +enum WL_DATA_DEVICE_START_DRAG = 0; +enum WL_DATA_DEVICE_SET_SELECTION = 1; +enum WL_DATA_DEVICE_RELEASE = 2; +enum WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_ENTER_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_LEAVE_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_MOTION_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_DROP_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_SELECTION_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_START_DRAG_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_RELEASE_SINCE_VERSION = 2; +pragma(inline, true) static void wl_data_device_set_user_data(wl_data_device* wl_data_device, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_data_device, user_data); +} +pragma(inline, true) static void* wl_data_device_get_user_data(wl_data_device* wl_data_device) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_data_device); +} +pragma(inline, true) static uint wl_data_device_get_version(wl_data_device* wl_data_device) { + return wl_proxy_get_version(cast(wl_proxy*) wl_data_device); +} +pragma(inline, true) static void wl_data_device_destroy(wl_data_device* wl_data_device) { + wl_proxy_destroy(cast(wl_proxy*) wl_data_device); +} +pragma(inline, true) static void wl_data_device_start_drag(wl_data_device* wl_data_device, wl_data_source* source, wl_surface* origin, wl_surface* icon, uint serial) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_device, + WL_DATA_DEVICE_START_DRAG, source, origin, icon, serial); +} +pragma(inline, true) static void wl_data_device_set_selection(wl_data_device* wl_data_device, wl_data_source* source, uint serial) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_device, + WL_DATA_DEVICE_SET_SELECTION, source, serial); +} +pragma(inline, true) static void wl_data_device_release(wl_data_device* wl_data_device) { + wl_proxy_marshal(cast(wl_proxy*) wl_data_device, + WL_DATA_DEVICE_RELEASE); + wl_proxy_destroy(cast(wl_proxy*) wl_data_device); +} +enum wl_data_device_manager_dnd_action { + WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, + WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, +} +enum WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE = 0; +enum WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE = 1; +enum WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION = 1; +enum WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION = 1; +pragma(inline, true) static void wl_data_device_manager_set_user_data(wl_data_device_manager* wl_data_device_manager, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_data_device_manager, user_data); +} +pragma(inline, true) static void* wl_data_device_manager_get_user_data(wl_data_device_manager* wl_data_device_manager) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_data_device_manager); +} +pragma(inline, true) static uint wl_data_device_manager_get_version(wl_data_device_manager* wl_data_device_manager) { + return wl_proxy_get_version(cast(wl_proxy*) wl_data_device_manager); +} +pragma(inline, true) static void wl_data_device_manager_destroy(wl_data_device_manager* wl_data_device_manager) { + wl_proxy_destroy(cast(wl_proxy*) wl_data_device_manager); +} +pragma(inline, true) static wl_data_source* wl_data_device_manager_create_data_source(wl_data_device_manager* wl_data_device_manager) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_data_device_manager, + WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, null); + return cast(wl_data_source*) id; +} +pragma(inline, true) static wl_data_device* wl_data_device_manager_get_data_device(wl_data_device_manager* wl_data_device_manager, wl_seat* seat) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_data_device_manager, + WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, null, seat); + return cast(wl_data_device*) id; +} +enum wl_shell_error { + WL_SHELL_ERROR_ROLE = 0, +} +enum WL_SHELL_GET_SHELL_SURFACE = 0; +enum WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION = 1; +pragma(inline, true) static void wl_shell_set_user_data(wl_shell* wl_shell, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_shell, user_data); +} +pragma(inline, true) static void* wl_shell_get_user_data(wl_shell* wl_shell) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_shell); +} +pragma(inline, true) static uint wl_shell_get_version(wl_shell* wl_shell) { + return wl_proxy_get_version(cast(wl_proxy*) wl_shell); +} +pragma(inline, true) static void wl_shell_destroy(wl_shell* wl_shell) { + wl_proxy_destroy(cast(wl_proxy*) wl_shell); +} +pragma(inline, true) static wl_shell_surface* wl_shell_get_shell_surface(wl_shell* wl_shell, wl_surface* surface) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_shell, + WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, null, surface); + return cast(wl_shell_surface*) id; +} +enum /*wl_shell_surface_transient*/ { + WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, +} +enum wl_shell_surface_fullscreen_method { + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, +} +pragma(inline, true) static int wl_shell_surface_add_listener(wl_shell_surface* wl_shell_surface, const(wl_shell_surface_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_shell_surface, cast(void function()) listener, data); +} +enum WL_SHELL_SURFACE_PONG = 0; +enum WL_SHELL_SURFACE_MOVE = 1; +enum WL_SHELL_SURFACE_RESIZE = 2; +enum WL_SHELL_SURFACE_SET_TOPLEVEL = 3; +enum WL_SHELL_SURFACE_SET_TRANSIENT = 4; +enum WL_SHELL_SURFACE_SET_FULLSCREEN = 5; +enum WL_SHELL_SURFACE_SET_POPUP = 6; +enum WL_SHELL_SURFACE_SET_MAXIMIZED = 7; +enum WL_SHELL_SURFACE_SET_TITLE = 8; +enum WL_SHELL_SURFACE_SET_CLASS = 9; +enum WL_SHELL_SURFACE_PING_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_PONG_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_MOVE_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_RESIZE_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION = 1; +enum WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_shell_surface_set_user_data(wl_shell_surface* wl_shell_surface, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_shell_surface, user_data); +} +pragma(inline, true) static void* wl_shell_surface_get_user_data(wl_shell_surface* wl_shell_surface) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_shell_surface); +} +pragma(inline, true) static uint wl_shell_surface_get_version(wl_shell_surface* wl_shell_surface) { + return wl_proxy_get_version(cast(wl_proxy*) wl_shell_surface); +} +pragma(inline, true) static void wl_shell_surface_destroy(wl_shell_surface* wl_shell_surface) { + wl_proxy_destroy(cast(wl_proxy*) wl_shell_surface); +} +pragma(inline, true) static void wl_shell_surface_pong(wl_shell_surface* wl_shell_surface, uint serial) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, + WL_SHELL_SURFACE_PONG, serial); +} +pragma(inline, true) static void wl_shell_surface_move(wl_shell_surface* wl_shell_surface, wl_seat* seat, uint serial) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, + WL_SHELL_SURFACE_MOVE, seat, serial); +} +pragma(inline, true) static void wl_shell_surface_resize(wl_shell_surface* wl_shell_surface, wl_seat* seat, uint serial, uint edges) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, + WL_SHELL_SURFACE_RESIZE, seat, serial, edges); +} +pragma(inline, true) static void wl_shell_surface_set_toplevel(wl_shell_surface* wl_shell_surface) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, WL_SHELL_SURFACE_SET_TOPLEVEL); +} +pragma(inline, true) static void wl_shell_surface_set_transient(wl_shell_surface* wl_shell_surface, wl_surface* parent, int x, int y, uint flags) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, + WL_SHELL_SURFACE_SET_TRANSIENT, parent, x, y, flags); +} +pragma(inline, true) static void wl_shell_surface_set_fullscreen(wl_shell_surface* wl_shell_surface, uint method, uint framerate, wl_output* output) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, + WL_SHELL_SURFACE_SET_FULLSCREEN, method, framerate, output); +} +pragma(inline, true) static void wl_shell_surface_set_popup(wl_shell_surface* wl_shell_surface, wl_seat* seat, uint serial, wl_surface* parent, int x, int y, uint flags) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, + WL_SHELL_SURFACE_SET_POPUP, seat, serial, parent, x, y, flags); +} +pragma(inline, true) static void wl_shell_surface_set_maximized(wl_shell_surface* wl_shell_surface, wl_output* output) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, WL_SHELL_SURFACE_SET_MAXIMIZED, output); +} +pragma(inline, true) static void wl_shell_surface_set_title(wl_shell_surface* wl_shell_surface, const(char)* title) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, WL_SHELL_SURFACE_SET_TITLE, title); +} +pragma(inline, true) static void wl_shell_surface_set_class(wl_shell_surface* wl_shell_surface, const(char)* class_) { + wl_proxy_marshal(cast(wl_proxy*) wl_shell_surface, + WL_SHELL_SURFACE_SET_CLASS, class_); +} +enum wl_surface_error { + WL_SURFACE_ERROR_INVALID_SCALE = 0, + WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, +} +pragma(inline, true) static int wl_surface_add_listener(wl_surface* wl_surface, const(wl_surface_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_surface, cast(void function()) listener, data); +} +enum WL_SURFACE_DESTROY = 0; +enum WL_SURFACE_ATTACH = 1; +enum WL_SURFACE_DAMAGE = 2; +enum WL_SURFACE_FRAME = 3; +enum WL_SURFACE_SET_OPAQUE_REGION = 4; +enum WL_SURFACE_SET_INPUT_REGION = 5; +enum WL_SURFACE_COMMIT = 6; +enum WL_SURFACE_SET_BUFFER_TRANSFORM = 7; +enum WL_SURFACE_SET_BUFFER_SCALE = 8; +enum WL_SURFACE_DAMAGE_BUFFER = 9; +enum WL_SURFACE_ENTER_SINCE_VERSION = 1; +enum WL_SURFACE_LEAVE_SINCE_VERSION = 1; +enum WL_SURFACE_DESTROY_SINCE_VERSION = 1; +enum WL_SURFACE_ATTACH_SINCE_VERSION = 1; +enum WL_SURFACE_DAMAGE_SINCE_VERSION = 1; +enum WL_SURFACE_FRAME_SINCE_VERSION = 1; +enum WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION = 1; +enum WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION = 1; +enum WL_SURFACE_COMMIT_SINCE_VERSION = 1; +enum WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION = 2; +enum WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION = 3; +enum WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION = 4; + +pragma(inline, true) static void wl_surface_set_user_data(wl_surface* wl_surface, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_surface, user_data); +} +pragma(inline, true) static void* wl_surface_get_user_data(wl_surface* wl_surface) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_surface); +} +pragma(inline, true) static uint wl_surface_get_version(wl_surface* wl_surface) { + return wl_proxy_get_version(cast(wl_proxy*) wl_surface); +} +pragma(inline, true) static void wl_surface_destroy(wl_surface* wl_surface) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_DESTROY); + wl_proxy_destroy(cast(wl_proxy*) wl_surface); +} +pragma(inline, true) static void wl_surface_attach(wl_surface* wl_surface, wl_buffer* buffer, int x, int y) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_ATTACH, buffer, x, y); +} +pragma(inline, true) static void wl_surface_damage(wl_surface* wl_surface, int x, int y, int width, int height) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_DAMAGE, x, y, width, height); +} +pragma(inline, true) static wl_callback* wl_surface_frame(wl_surface* wl_surface) { + wl_proxy* callback; + callback = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_surface, + WL_SURFACE_FRAME, &wl_callback_interface, null); + return cast(wl_callback*) callback; +} +pragma(inline, true) static void wl_surface_set_opaque_region(wl_surface* wl_surface, wl_region* region) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_SET_OPAQUE_REGION, region); +} +pragma(inline, true) static void wl_surface_set_input_region(wl_surface* wl_surface, wl_region* region) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_SET_INPUT_REGION, region); +} +pragma(inline, true) static void wl_surface_commit(wl_surface* wl_surface) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_COMMIT); +} +pragma(inline, true) static void wl_surface_set_buffer_transform(wl_surface* wl_surface, int transform) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_SET_BUFFER_TRANSFORM, transform); +} +pragma(inline, true) static void wl_surface_set_buffer_scale(wl_surface* wl_surface, int scale) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_SET_BUFFER_SCALE, scale); +} +pragma(inline, true) static void wl_surface_damage_buffer(wl_surface* wl_surface, int x, int y, int width, int height) { + wl_proxy_marshal(cast(wl_proxy*) wl_surface, + WL_SURFACE_DAMAGE_BUFFER, x, y, width, height); +} +pragma(inline, true) static int wl_seat_add_listener(wl_seat* wl_seat, const(wl_seat_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_seat, + cast(void function()) listener, data); +} +enum WL_SEAT_GET_POINTER = 0; +enum WL_SEAT_GET_KEYBOARD = 1; +enum WL_SEAT_GET_TOUCH = 2; +enum WL_SEAT_RELEASE = 3; +enum WL_SEAT_CAPABILITIES_SINCE_VERSION = 1; +enum WL_SEAT_NAME_SINCE_VERSION = 2; +enum WL_SEAT_GET_POINTER_SINCE_VERSION = 1; +enum WL_SEAT_GET_KEYBOARD_SINCE_VERSION = 1; +enum WL_SEAT_GET_TOUCH_SINCE_VERSION = 1; +enum WL_SEAT_RELEASE_SINCE_VERSION = 5; + +pragma(inline, true) static void wl_seat_set_user_data(wl_seat* wl_seat, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_seat, user_data); +} +pragma(inline, true) static void* wl_seat_get_user_data(wl_seat* wl_seat) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_seat); +} +pragma(inline, true) static uint wl_seat_get_version(wl_seat* wl_seat) { + return wl_proxy_get_version(cast(wl_proxy*) wl_seat); +} + +pragma(inline, true) static void wl_seat_destroy(wl_seat* wl_seat) { + wl_proxy_destroy(cast(wl_proxy*) wl_seat); +} +pragma(inline, true) static wl_pointer* wl_seat_get_pointer(wl_seat* wl_seat) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_seat, + WL_SEAT_GET_POINTER, &wl_pointer_interface, null); + return cast(wl_pointer*) id; +} +pragma(inline, true) static wl_keyboard* wl_seat_get_keyboard(wl_seat* wl_seat) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_seat, + WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, null); + return cast(wl_keyboard*) id; +} +pragma(inline, true) static wl_touch* wl_seat_get_touch(wl_seat* wl_seat) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_seat, WL_SEAT_GET_TOUCH, &wl_touch_interface, null); + return cast(wl_touch*) id; +} +pragma(inline, true) static void wl_seat_release(wl_seat* wl_seat) { + wl_proxy_marshal(cast(wl_proxy*) wl_seat, WL_SEAT_RELEASE); + wl_proxy_destroy(cast(wl_proxy*) wl_seat); +} +enum wl_pointer_error { + WL_POINTER_ERROR_ROLE = 0, +} +enum wl_pointer_axis_source { + WL_POINTER_AXIS_SOURCE_WHEEL = 0, + WL_POINTER_AXIS_SOURCE_FINGER = 1, + WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, +} +pragma(inline, true) static int wl_pointer_add_listener(wl_pointer* wl_pointer, const(wl_pointer_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_pointer, cast(void function()) listener, data); +} +enum WL_POINTER_SET_CURSOR = 0; +enum WL_POINTER_RELEASE = 1; +enum WL_POINTER_ENTER_SINCE_VERSION = 1; +enum WL_POINTER_LEAVE_SINCE_VERSION = 1; +enum WL_POINTER_MOTION_SINCE_VERSION = 1; +enum WL_POINTER_BUTTON_SINCE_VERSION = 1; +enum WL_POINTER_AXIS_SINCE_VERSION = 1; +enum WL_POINTER_FRAME_SINCE_VERSION = 5; +enum WL_POINTER_AXIS_SOURCE_SINCE_VERSION = 5; +enum WL_POINTER_AXIS_STOP_SINCE_VERSION = 5; +enum WL_POINTER_AXIS_DISCRETE_SINCE_VERSION = 5; +enum WL_POINTER_SET_CURSOR_SINCE_VERSION = 1; +enum WL_POINTER_RELEASE_SINCE_VERSION = 3; + +pragma(inline, true) static void wl_pointer_set_user_data(wl_pointer* wl_pointer, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_pointer, user_data); +} +pragma(inline, true) static void* wl_pointer_get_user_data(wl_pointer* wl_pointer) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_pointer); +} +pragma(inline, true) static uint wl_pointer_get_version(wl_pointer* wl_pointer) { + return wl_proxy_get_version(cast(wl_proxy*) wl_pointer); +} +pragma(inline, true) static void wl_pointer_destroy(wl_pointer* wl_pointer) { + wl_proxy_destroy(cast(wl_proxy*) wl_pointer); +} +pragma(inline, true) static void wl_pointer_set_cursor(wl_pointer* wl_pointer, uint serial, wl_surface* surface, int hotspot_x, int hotspot_y) { + wl_proxy_marshal(cast(wl_proxy*) wl_pointer, + WL_POINTER_SET_CURSOR, serial, surface, hotspot_x, hotspot_y); +} +pragma(inline, true) static void wl_pointer_release(wl_pointer* wl_pointer) { + wl_proxy_marshal(cast(wl_proxy*) wl_pointer, + WL_POINTER_RELEASE); + wl_proxy_destroy(cast(wl_proxy*) wl_pointer); +} +pragma(inline, true) static int wl_keyboard_add_listener(wl_keyboard* wl_keyboard, const(wl_keyboard_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_keyboard, + cast(void function()) listener, data); +} +enum WL_KEYBOARD_RELEASE = 0; +enum WL_KEYBOARD_KEYMAP_SINCE_VERSION = 1; +enum WL_KEYBOARD_ENTER_SINCE_VERSION = 1; +enum WL_KEYBOARD_LEAVE_SINCE_VERSION = 1; +enum WL_KEYBOARD_KEY_SINCE_VERSION = 1; +enum WL_KEYBOARD_MODIFIERS_SINCE_VERSION = 1; +enum WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION = 4; +enum WL_KEYBOARD_RELEASE_SINCE_VERSION = 3; + +pragma(inline, true) static void wl_keyboard_set_user_data(wl_keyboard* wl_keyboard, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_keyboard, user_data); +} + +pragma(inline, true) static void* wl_keyboard_get_user_data(wl_keyboard* wl_keyboard) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_keyboard); +} +pragma(inline, true) static uint wl_keyboard_get_version(wl_keyboard* wl_keyboard) { + return wl_proxy_get_version(cast(wl_proxy*) wl_keyboard); +} + +pragma(inline, true) static void wl_keyboard_destroy(wl_keyboard* wl_keyboard) { + wl_proxy_destroy(cast(wl_proxy*) wl_keyboard); +} +pragma(inline, true) static void wl_keyboard_release(wl_keyboard* wl_keyboard) { + wl_proxy_marshal(cast(wl_proxy*) wl_keyboard, + WL_KEYBOARD_RELEASE); + wl_proxy_destroy(cast(wl_proxy*) wl_keyboard); +} +struct wl_touch_listener { + void function(void* data, wl_touch* wl_touch, uint serial, uint time, wl_surface* surface, int id, wl_fixed_t x, wl_fixed_t y) down; + void function(void* data, wl_touch* wl_touch, uint serial, uint time, int id) up; + void function(void* data, wl_touch* wl_touch, uint time, int id, wl_fixed_t x, wl_fixed_t y) motion; + void function(void* data, wl_touch* wl_touch) frame; + void function(void* data, wl_touch* wl_touch) cancel; +}; +pragma(inline, true) static int wl_touch_add_listener(wl_touch* wl_touch, const(wl_touch_listener)* listener, void* data) { + return wl_proxy_add_listener(cast(wl_proxy*) wl_touch, cast(void function()) listener, data); +} +enum WL_TOUCH_RELEASE = 0; +enum WL_TOUCH_DOWN_SINCE_VERSION = 1; +enum WL_TOUCH_UP_SINCE_VERSION = 1; +enum WL_TOUCH_MOTION_SINCE_VERSION = 1; +enum WL_TOUCH_FRAME_SINCE_VERSION = 1; +enum WL_TOUCH_CANCEL_SINCE_VERSION = 1; +enum WL_TOUCH_RELEASE_SINCE_VERSION = 3; + +pragma(inline, true) static void wl_touch_set_user_data(wl_touch* wl_touch, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_touch, user_data); +} + +pragma(inline, true) static void* wl_touch_get_user_data(wl_touch* wl_touch) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_touch); +} +pragma(inline, true) static uint wl_touch_get_version(wl_touch* wl_touch) { + return wl_proxy_get_version(cast(wl_proxy*) wl_touch); +} + +pragma(inline, true) static void wl_touch_destroy(wl_touch* wl_touch) { + wl_proxy_destroy(cast(wl_proxy*) wl_touch); +} +pragma(inline, true) static void wl_touch_release(wl_touch* wl_touch) { + wl_proxy_marshal(cast(wl_proxy*) wl_touch, WL_TOUCH_RELEASE); + wl_proxy_destroy(cast(wl_proxy*) wl_touch); +} +enum wl_output_subpixel { + WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, + WL_OUTPUT_SUBPIXEL_NONE = 1, + WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, + WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, + WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, + WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, +} +enum wl_output_transform { + WL_OUTPUT_TRANSFORM_NORMAL = 0, + WL_OUTPUT_TRANSFORM_90 = 1, + WL_OUTPUT_TRANSFORM_180 = 2, + WL_OUTPUT_TRANSFORM_270 = 3, + WL_OUTPUT_TRANSFORM_FLIPPED = 4, + WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, + WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, + WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, +} +enum WL_OUTPUT_RELEASE = 0; +enum WL_OUTPUT_GEOMETRY_SINCE_VERSION = 1; +enum WL_OUTPUT_MODE_SINCE_VERSION = 1; +enum WL_OUTPUT_DONE_SINCE_VERSION = 2; +enum WL_OUTPUT_SCALE_SINCE_VERSION = 2; +enum WL_OUTPUT_RELEASE_SINCE_VERSION = 3; + +pragma(inline, true) static void wl_output_set_user_data(wl_output* wl_output, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_output, user_data); +} +pragma(inline, true) static void* wl_output_get_user_data(wl_output* wl_output) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_output); +} +pragma(inline, true) static uint wl_output_get_version(wl_output* wl_output) { + return wl_proxy_get_version(cast(wl_proxy*) wl_output); +} +pragma(inline, true) static void wl_output_release(wl_output* wl_output) { + wl_proxy_marshal(cast(wl_proxy*) wl_output, WL_OUTPUT_RELEASE); + wl_proxy_destroy(cast(wl_proxy*) wl_output); +} +enum WL_REGION_DESTROY = 0; +enum WL_REGION_ADD = 1; +enum WL_REGION_SUBTRACT = 2; +enum WL_REGION_DESTROY_SINCE_VERSION = 1; +enum WL_REGION_ADD_SINCE_VERSION = 1; +enum WL_REGION_SUBTRACT_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_region_set_user_data(wl_region* wl_region, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_region, user_data); +} + +pragma(inline, true) static void* wl_region_get_user_data(wl_region* wl_region) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_region); +} +pragma(inline, true) static uint wl_region_get_version(wl_region* wl_region) { + return wl_proxy_get_version(cast(wl_proxy*) wl_region); +} +pragma(inline, true) static void wl_region_destroy(wl_region* wl_region) { + wl_proxy_marshal(cast(wl_proxy*) wl_region, + WL_REGION_DESTROY); + wl_proxy_destroy(cast(wl_proxy*) wl_region); +} +pragma(inline, true) static void wl_region_add(wl_region* wl_region, int x, int y, int width, int height) { + wl_proxy_marshal(cast(wl_proxy*) wl_region, + WL_REGION_ADD, x, y, width, height); +} +pragma(inline, true) static void wl_region_subtract(wl_region* wl_region, int x, int y, int width, int height) { + wl_proxy_marshal(cast(wl_proxy*) wl_region, + WL_REGION_SUBTRACT, x, y, width, height); +} +enum wl_subcompositor_error { + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, +} +enum WL_SUBCOMPOSITOR_DESTROY = 0; +enum WL_SUBCOMPOSITOR_GET_SUBSURFACE = 1; +enum WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION = 1; +enum WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION = 1; + + +pragma(inline, true) static void wl_subcompositor_set_user_data(wl_subcompositor* wl_subcompositor, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_subcompositor, user_data); +} + + +pragma(inline, true) static void* wl_subcompositor_get_user_data(wl_subcompositor* wl_subcompositor) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_subcompositor); +} +pragma(inline, true) static uint wl_subcompositor_get_version(wl_subcompositor* wl_subcompositor) { + return wl_proxy_get_version(cast(wl_proxy*) wl_subcompositor); +} +pragma(inline, true) static void wl_subcompositor_destroy(wl_subcompositor* wl_subcompositor) { + wl_proxy_marshal(cast(wl_proxy*) wl_subcompositor, + WL_SUBCOMPOSITOR_DESTROY); + wl_proxy_destroy(cast(wl_proxy*) wl_subcompositor); +} +pragma(inline, true) static wl_subsurface* wl_subcompositor_get_subsurface(wl_subcompositor* wl_subcompositor, wl_surface* surface, wl_surface* parent) { + wl_proxy* id; + id = wl_proxy_marshal_constructor(cast(wl_proxy*) wl_subcompositor, + WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, null, surface, parent); + return cast(wl_subsurface*) id; +} +enum wl_subsurface_error { + WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, +} +enum WL_SUBSURFACE_DESTROY = 0; +enum WL_SUBSURFACE_SET_POSITION = 1; +enum WL_SUBSURFACE_PLACE_ABOVE = 2; +enum WL_SUBSURFACE_PLACE_BELOW = 3; +enum WL_SUBSURFACE_SET_SYNC = 4; +enum WL_SUBSURFACE_SET_DESYNC = 5; +enum WL_SUBSURFACE_DESTROY_SINCE_VERSION = 1; +enum WL_SUBSURFACE_SET_POSITION_SINCE_VERSION = 1; +enum WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION = 1; +enum WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION = 1; +enum WL_SUBSURFACE_SET_SYNC_SINCE_VERSION = 1; +enum WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION = 1; + +pragma(inline, true) static void wl_subsurface_set_user_data(wl_subsurface* wl_subsurface, void* user_data) { + wl_proxy_set_user_data(cast(wl_proxy*) wl_subsurface, user_data); +} +pragma(inline, true) static void* wl_subsurface_get_user_data(wl_subsurface* wl_subsurface) { + return wl_proxy_get_user_data(cast(wl_proxy*) wl_subsurface); +} +pragma(inline, true) static uint wl_subsurface_get_version(wl_subsurface* wl_subsurface) { + return wl_proxy_get_version(cast(wl_proxy*) wl_subsurface); +} +pragma(inline, true) static void wl_subsurface_destroy(wl_subsurface* wl_subsurface) { + wl_proxy_marshal(cast(wl_proxy*) wl_subsurface, WL_SUBSURFACE_DESTROY); + wl_proxy_destroy(cast(wl_proxy*) wl_subsurface); +} +pragma(inline, true) static void wl_subsurface_set_position(wl_subsurface* wl_subsurface, int x, int y) { + wl_proxy_marshal(cast(wl_proxy*) wl_subsurface, + WL_SUBSURFACE_SET_POSITION, x, y); +} +pragma(inline, true) static void wl_subsurface_place_above(wl_subsurface* wl_subsurface, wl_surface* sibling) { + wl_proxy_marshal(cast(wl_proxy*) wl_subsurface, + WL_SUBSURFACE_PLACE_ABOVE, sibling); +} +pragma(inline, true) static void wl_subsurface_place_below(wl_subsurface* wl_subsurface, wl_surface* sibling) { + wl_proxy_marshal(cast(wl_proxy*) wl_subsurface, + WL_SUBSURFACE_PLACE_BELOW, sibling); +} +pragma(inline, true) static void wl_subsurface_set_sync(wl_subsurface* wl_subsurface) { + wl_proxy_marshal(cast(wl_proxy*) wl_subsurface, + WL_SUBSURFACE_SET_SYNC); +} +pragma(inline, true) static void wl_subsurface_set_desync(wl_subsurface* wl_subsurface) { + wl_proxy_marshal(cast(wl_proxy*) wl_subsurface, + WL_SUBSURFACE_SET_DESYNC); +} diff --git a/source/glfw3/wgl_context.d b/source/glfw3/wgl_context.d new file mode 100644 index 0000000..e9f4a75 --- /dev/null +++ b/source/glfw3/wgl_context.d @@ -0,0 +1,910 @@ +/// Translated from C to D +module glfw3.wgl_context; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 WGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +public import glfw3.internal; +import core.stdc.string: memset; + +// header +enum WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000; +enum WGL_SUPPORT_OPENGL_ARB = 0x2010; +enum WGL_DRAW_TO_WINDOW_ARB = 0x2001; +enum WGL_PIXEL_TYPE_ARB = 0x2013; +enum WGL_TYPE_RGBA_ARB = 0x202b; +enum WGL_ACCELERATION_ARB = 0x2003; +enum WGL_NO_ACCELERATION_ARB = 0x2025; +enum WGL_RED_BITS_ARB = 0x2015; +enum WGL_RED_SHIFT_ARB = 0x2016; +enum WGL_GREEN_BITS_ARB = 0x2017; +enum WGL_GREEN_SHIFT_ARB = 0x2018; +enum WGL_BLUE_BITS_ARB = 0x2019; +enum WGL_BLUE_SHIFT_ARB = 0x201a; +enum WGL_ALPHA_BITS_ARB = 0x201b; +enum WGL_ALPHA_SHIFT_ARB = 0x201c; +enum WGL_ACCUM_BITS_ARB = 0x201d; +enum WGL_ACCUM_RED_BITS_ARB = 0x201e; +enum WGL_ACCUM_GREEN_BITS_ARB = 0x201f; +enum WGL_ACCUM_BLUE_BITS_ARB = 0x2020; +enum WGL_ACCUM_ALPHA_BITS_ARB = 0x2021; +enum WGL_DEPTH_BITS_ARB = 0x2022; +enum WGL_STENCIL_BITS_ARB = 0x2023; +enum WGL_AUX_BUFFERS_ARB = 0x2024; +enum WGL_STEREO_ARB = 0x2012; +enum WGL_DOUBLE_BUFFER_ARB = 0x2011; +enum WGL_SAMPLES_ARB = 0x2042; +enum WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB = 0x20a9; +enum WGL_CONTEXT_DEBUG_BIT_ARB = 0x00000001; +enum WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x00000002; +enum WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126; +enum WGL_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001; +enum WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002; +enum WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091; +enum WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092; +enum WGL_CONTEXT_FLAGS_ARB = 0x2094; +enum WGL_CONTEXT_ES2_PROFILE_BIT_EXT = 0x00000004; +enum WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB = 0x00000004; +enum WGL_LOSE_CONTEXT_ON_RESET_ARB = 0x8252; +enum WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB = 0x8256; +enum WGL_NO_RESET_NOTIFICATION_ARB = 0x8261; +enum WGL_CONTEXT_RELEASE_BEHAVIOR_ARB = 0x2097; +enum WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB = 0; +enum WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB = 0x2098; +enum WGL_CONTEXT_OPENGL_NO_ERROR_ARB = 0x31b3; +enum WGL_COLORSPACE_EXT = 0x309d; +enum WGL_COLORSPACE_SRGB_EXT = 0x3089; + +enum ERROR_INVALID_VERSION_ARB = 0x2095; +enum ERROR_INVALID_PROFILE_ARB = 0x2096; +enum ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB = 0x2054; + +// WGL extension pointer typedefs +extern(Windows) { + alias BOOL function(int) PFNWGLSWAPINTERVALEXTPROC; + alias BOOL function(HDC, int, int, UINT, const(int)*, int*) PFNWGLGETPIXELFORMATATTRIBIVARBPROC; + alias const(char)* function() PFNWGLGETEXTENSIONSSTRINGEXTPROC; + alias const(char)* function(HDC) PFNWGLGETEXTENSIONSSTRINGARBPROC; + alias HGLRC function(HDC, HGLRC, const(int)*) PFNWGLCREATECONTEXTATTRIBSARBPROC; + alias wglSwapIntervalEXT = _glfw.wgl.SwapIntervalEXT; + alias wglGetPixelFormatAttribivARB = _glfw.wgl.GetPixelFormatAttribivARB; + alias wglGetExtensionsStringEXT = _glfw.wgl.GetExtensionsStringEXT; + alias wglGetExtensionsStringARB = _glfw.wgl.GetExtensionsStringARB; + alias wglCreateContextAttribsARB = _glfw.wgl.CreateContextAttribsARB; + + // opengl32.dll function pointer typedefs + alias HGLRC function(HDC) PFN_wglCreateContext; + alias BOOL function(HGLRC) PFN_wglDeleteContext; + alias PROC function(LPCSTR) PFN_wglGetProcAddress; + alias HDC function() PFN_wglGetCurrentDC; + alias HGLRC function() PFN_wglGetCurrentContext; + alias BOOL function(HDC, HGLRC) PFN_wglMakeCurrent; + alias BOOL function(HGLRC, HGLRC) PFN_wglShareLists; + alias wglCreateContext = _glfw.wgl.CreateContext; + alias wglDeleteContext = _glfw.wgl.DeleteContext; + alias wglGetProcAddress = _glfw.wgl.GetProcAddress; + alias wglGetCurrentDC = _glfw.wgl.GetCurrentDC; + alias wglGetCurrentContext = _glfw.wgl.GetCurrentContext; + alias wglMakeCurrent = _glfw.wgl.MakeCurrent; + alias wglShareLists = _glfw.wgl.ShareLists; +} + +enum _GLFW_RECREATION_NOT_NEEDED = 0; +enum _GLFW_RECREATION_REQUIRED = 1; +enum _GLFW_RECREATION_IMPOSSIBLE = 2; + +mixin template _GLFW_PLATFORM_CONTEXT_STATE() { _GLFWcontextWGL wgl;} +mixin template _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE() {_GLFWlibraryWGL wgl;} + +// WGL-specific per-context data +// +struct _GLFWcontextWGL { + HDC dc; + HGLRC handle; + int interval; + +} + +// WGL-specific global data +// +struct _GLFWlibraryWGL { + HINSTANCE instance; + PFN_wglCreateContext CreateContext; + PFN_wglDeleteContext DeleteContext; + PFN_wglGetProcAddress GetProcAddress; + PFN_wglGetCurrentDC GetCurrentDC; + PFN_wglGetCurrentContext GetCurrentContext; + PFN_wglMakeCurrent MakeCurrent; + PFN_wglShareLists ShareLists; + + PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; + PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; + PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; + PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLFWbool EXT_swap_control; + GLFWbool EXT_colorspace; + GLFWbool ARB_multisample; + GLFWbool ARB_framebuffer_sRGB; + GLFWbool EXT_framebuffer_sRGB; + GLFWbool ARB_pixel_format; + GLFWbool ARB_create_context; + GLFWbool ARB_create_context_profile; + GLFWbool EXT_create_context_es2_profile; + GLFWbool ARB_create_context_robustness; + GLFWbool ARB_create_context_no_error; + GLFWbool ARB_context_flush_control; + +} + +GLFWbool _glfwInitWGL(); +void _glfwTerminateWGL(); +GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig); +// + +import core.stdc.stdlib; +import core.stdc.assert_; + +// Return the value corresponding to the specified attribute +// +static int findPixelFormatAttribValue(const(int)* attribs, int attribCount, const(int)* values, int attrib) { + int i; + + for (i = 0; i < attribCount; i++) + { + if (attribs[i] == attrib) + return values[i]; + } + + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Unknown pixel format attribute requested"); + return 0; +} + + +// Return a list of available and usable framebuffer configs +// +static int choosePixelFormat(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + _GLFWfbconfig* usableConfigs; + const(_GLFWfbconfig)* closest; + int i;int pixelFormat;int nativeCount;int usableCount = 0;int attribCount = 0; + int[40] attribs; + int[attribs.sizeof / typeof((attribs[0])).sizeof] values; + + void addAttrib(int a) { + assert(cast(size_t) attribCount < attribs.length); + attribs[attribCount++] = a; + } + + auto findAttribValue(int a) { + return findPixelFormatAttribValue(attribs.ptr, attribCount, values.ptr, a); + } + + if (_glfw.wgl.ARB_pixel_format) + { + const(int) attrib = WGL_NUMBER_PIXEL_FORMATS_ARB; + + if (!_glfw.wgl.GetPixelFormatAttribivARB(window.context.wgl.dc, + 1, 0, 1, &attrib, &nativeCount)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve pixel format attribute"); + return 0; + } + + addAttrib(WGL_SUPPORT_OPENGL_ARB); + addAttrib(WGL_DRAW_TO_WINDOW_ARB); + addAttrib(WGL_PIXEL_TYPE_ARB); + addAttrib(WGL_ACCELERATION_ARB); + addAttrib(WGL_RED_BITS_ARB); + addAttrib(WGL_RED_SHIFT_ARB); + addAttrib(WGL_GREEN_BITS_ARB); + addAttrib(WGL_GREEN_SHIFT_ARB); + addAttrib(WGL_BLUE_BITS_ARB); + addAttrib(WGL_BLUE_SHIFT_ARB); + addAttrib(WGL_ALPHA_BITS_ARB); + addAttrib(WGL_ALPHA_SHIFT_ARB); + addAttrib(WGL_DEPTH_BITS_ARB); + addAttrib(WGL_STENCIL_BITS_ARB); + addAttrib(WGL_ACCUM_BITS_ARB); + addAttrib(WGL_ACCUM_RED_BITS_ARB); + addAttrib(WGL_ACCUM_GREEN_BITS_ARB); + addAttrib(WGL_ACCUM_BLUE_BITS_ARB); + addAttrib(WGL_ACCUM_ALPHA_BITS_ARB); + addAttrib(WGL_AUX_BUFFERS_ARB); + addAttrib(WGL_STEREO_ARB); + addAttrib(WGL_DOUBLE_BUFFER_ARB); + + if (_glfw.wgl.ARB_multisample) + addAttrib(WGL_SAMPLES_ARB); + + if (ctxconfig.client == GLFW_OPENGL_API) + { + if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) + addAttrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); + } + else + { + if (_glfw.wgl.EXT_colorspace) + addAttrib(WGL_COLORSPACE_EXT); + } + } + else + { + nativeCount = DescribePixelFormat(window.context.wgl.dc, + 1, + PIXELFORMATDESCRIPTOR.sizeof, + null); + } + + usableConfigs = cast(_GLFWfbconfig*) calloc(nativeCount, _GLFWfbconfig.sizeof); + + for (i = 0; i < nativeCount; i++) + { + _GLFWfbconfig* u = usableConfigs + usableCount; + pixelFormat = i + 1; + + if (_glfw.wgl.ARB_pixel_format) + { + // Get pixel format attributes through "modern" extension + + if (!_glfw.wgl.GetPixelFormatAttribivARB(window.context.wgl.dc, + pixelFormat, 0, + attribCount, + attribs.ptr, values.ptr)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve pixel format attributes"); + + free(usableConfigs); + return 0; + } + + if (!findAttribValue(WGL_SUPPORT_OPENGL_ARB) || + !findAttribValue(WGL_DRAW_TO_WINDOW_ARB)) + { + continue; + } + + if (findAttribValue(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) + continue; + + if (findAttribValue(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) + continue; + + u.redBits = findAttribValue(WGL_RED_BITS_ARB); + u.greenBits = findAttribValue(WGL_GREEN_BITS_ARB); + u.blueBits = findAttribValue(WGL_BLUE_BITS_ARB); + u.alphaBits = findAttribValue(WGL_ALPHA_BITS_ARB); + + u.depthBits = findAttribValue(WGL_DEPTH_BITS_ARB); + u.stencilBits = findAttribValue(WGL_STENCIL_BITS_ARB); + + u.accumRedBits = findAttribValue(WGL_ACCUM_RED_BITS_ARB); + u.accumGreenBits = findAttribValue(WGL_ACCUM_GREEN_BITS_ARB); + u.accumBlueBits = findAttribValue(WGL_ACCUM_BLUE_BITS_ARB); + u.accumAlphaBits = findAttribValue(WGL_ACCUM_ALPHA_BITS_ARB); + + u.auxBuffers = findAttribValue(WGL_AUX_BUFFERS_ARB); + + if (findAttribValue(WGL_STEREO_ARB)) + u.stereo = GLFW_TRUE; + if (findAttribValue(WGL_DOUBLE_BUFFER_ARB)) + u.doublebuffer = GLFW_TRUE; + + if (_glfw.wgl.ARB_multisample) + u.samples = findAttribValue(WGL_SAMPLES_ARB); + + if (ctxconfig.client == GLFW_OPENGL_API) + { + if (_glfw.wgl.ARB_framebuffer_sRGB || + _glfw.wgl.EXT_framebuffer_sRGB) + { + if (findAttribValue(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) + u.sRGB = GLFW_TRUE; + } + } + else + { + if (_glfw.wgl.EXT_colorspace) + { + if (findAttribValue(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT) + u.sRGB = GLFW_TRUE; + } + } + } + else + { + // Get pixel format attributes through legacy PFDs + + PIXELFORMATDESCRIPTOR pfd; + + if (!DescribePixelFormat(window.context.wgl.dc, + pixelFormat, + PIXELFORMATDESCRIPTOR.sizeof, + &pfd)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to describe pixel format"); + + free(usableConfigs); + return 0; + } + + if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || + !(pfd.dwFlags & PFD_SUPPORT_OPENGL)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && + (pfd.dwFlags & PFD_GENERIC_FORMAT)) + { + continue; + } + + if (pfd.iPixelType != PFD_TYPE_RGBA) + continue; + + u.redBits = pfd.cRedBits; + u.greenBits = pfd.cGreenBits; + u.blueBits = pfd.cBlueBits; + u.alphaBits = pfd.cAlphaBits; + + u.depthBits = pfd.cDepthBits; + u.stencilBits = pfd.cStencilBits; + + u.accumRedBits = pfd.cAccumRedBits; + u.accumGreenBits = pfd.cAccumGreenBits; + u.accumBlueBits = pfd.cAccumBlueBits; + u.accumAlphaBits = pfd.cAccumAlphaBits; + + u.auxBuffers = pfd.cAuxBuffers; + + if (pfd.dwFlags & PFD_STEREO) + u.stereo = GLFW_TRUE; + if (pfd.dwFlags & PFD_DOUBLEBUFFER) + u.doublebuffer = GLFW_TRUE; + } + + u.handle = pixelFormat; + usableCount++; + } + + if (!usableCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "WGL: The driver does not appear to support OpenGL"); + + free(usableConfigs); + return 0; + } + + closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount); + if (!closest) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "WGL: Failed to find a suitable pixel format"); + + free(usableConfigs); + return 0; + } + + pixelFormat = cast(int) closest.handle; + free(usableConfigs); + + return pixelFormat; +} + +static void makeContextCurrentWGL(_GLFWwindow* window) { + if (window) + { + if (_glfw.wgl.MakeCurrent(window.context.wgl.dc, window.context.wgl.handle)) + _glfwPlatformSetTls(&_glfw.contextSlot, window); + else + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to make context current"); + _glfwPlatformSetTls(&_glfw.contextSlot, null); + } + } + else + { + if (!_glfw.wgl.MakeCurrent(null, null)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to clear current context"); + } + + _glfwPlatformSetTls(&_glfw.contextSlot, null); + } +} + +static void swapBuffersWGL(_GLFWwindow* window) { + if (!window.monitor) + { + if (IsWindowsVistaOrGreater()) + { + // DWM Composition is always enabled on Win8+ + BOOL enabled = IsWindows8OrGreater(); + + // HACK: Use DwmFlush when desktop composition is enabled + if (enabled || + (SUCCEEDED(_glfw.win32.dwmapi.IsCompositionEnabled(&enabled)) && enabled)) + { + int count = abs(window.context.wgl.interval); + while (count--) + _glfw.win32.dwmapi.Flush(); + } + } + } + + SwapBuffers(window.context.wgl.dc); +} + +static void swapIntervalWGL(int interval) { + auto window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); + + window.context.wgl.interval = interval; + + if (!window.monitor) + { + if (IsWindowsVistaOrGreater()) + { + // DWM Composition is always enabled on Win8+ + BOOL enabled = IsWindows8OrGreater(); + + // HACK: Disable WGL swap interval when desktop composition is enabled to + // avoid interfering with DWM vsync + if (enabled || + (SUCCEEDED(_glfw.win32.dwmapi.IsCompositionEnabled(&enabled)) && enabled)) + interval = 0; + } + } + + if (_glfw.wgl.EXT_swap_control) + _glfw.wgl.SwapIntervalEXT(interval); +} + +static int extensionSupportedWGL(const(char)* extension) { + const(char)* extensions = null; + + if (_glfw.wgl.GetExtensionsStringARB) + extensions = _glfw.wgl.GetExtensionsStringARB(_glfw.wgl.GetCurrentDC()); + else if (_glfw.wgl.GetExtensionsStringEXT) + extensions = _glfw.wgl.GetExtensionsStringEXT(); + + if (!extensions) + return GLFW_FALSE; + + return _glfwStringInExtensionString(extension, extensions); +} + +static GLFWglproc getProcAddressWGL(const(char)* procname) { + const(GLFWglproc) proc = cast(GLFWglproc) _glfw.wgl.GetProcAddress(procname); + if (proc) + return proc; + + return cast(GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); +} + +static void destroyContextWGL(_GLFWwindow* window) { + if (window.context.wgl.handle) + { + _glfw.wgl.DeleteContext(window.context.wgl.handle); + window.context.wgl.handle = null; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize WGL +// +GLFWbool _glfwInitWGL() { + PIXELFORMATDESCRIPTOR pfd; + HGLRC prc;HGLRC rc; + HDC pdc;HDC dc; + + if (_glfw.wgl.instance) + return GLFW_TRUE; + + _glfw.wgl.instance = LoadLibraryA("opengl32.dll"); + if (!_glfw.wgl.instance) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to load opengl32.dll"); + return GLFW_FALSE; + } + + _glfw.wgl.CreateContext = cast(PFN_wglCreateContext) + GetProcAddress(_glfw.wgl.instance, "wglCreateContext"); + _glfw.wgl.DeleteContext = cast(PFN_wglDeleteContext) + GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); + _glfw.wgl.GetProcAddress = cast(PFN_wglGetProcAddress) + GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); + _glfw.wgl.GetCurrentDC = cast(PFN_wglGetCurrentDC) + GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC"); + _glfw.wgl.GetCurrentContext = cast(PFN_wglGetCurrentContext) + GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext"); + _glfw.wgl.MakeCurrent = cast(PFN_wglMakeCurrent) + GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); + _glfw.wgl.ShareLists = cast(PFN_wglShareLists) + GetProcAddress(_glfw.wgl.instance, "wglShareLists"); + + // NOTE: A dummy context has to be created for opengl32.dll to load the + // OpenGL ICD, from which we can then query WGL extensions + // NOTE: This code will accept the Microsoft GDI ICD; accelerated context + // creation failure occurs during manual pixel format enumeration + + dc = GetDC(_glfw.win32.helperWindowHandle); + + memset(&pfd, 0, typeof(pfd).sizeof); + pfd.nSize = typeof(pfd).sizeof; + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + + if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to set pixel format for dummy context"); + return GLFW_FALSE; + } + + rc = _glfw.wgl.CreateContext(dc); + if (!rc) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to create dummy context"); + return GLFW_FALSE; + } + + pdc = _glfw.wgl.GetCurrentDC(); + prc = _glfw.wgl.GetCurrentContext(); + + if (!_glfw.wgl.MakeCurrent(dc, rc)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to make dummy context current"); + _glfw.wgl.MakeCurrent(pdc, prc); + _glfw.wgl.DeleteContext(rc); + return GLFW_FALSE; + } + + // NOTE: Functions must be loaded first as they're needed to retrieve the + // extension string that tells us whether the functions are supported + _glfw.wgl.GetExtensionsStringEXT = cast(PFNWGLGETEXTENSIONSSTRINGEXTPROC) + _glfw.wgl.GetProcAddress("wglGetExtensionsStringEXT"); + _glfw.wgl.GetExtensionsStringARB = cast(PFNWGLGETEXTENSIONSSTRINGARBPROC) + _glfw.wgl.GetProcAddress("wglGetExtensionsStringARB"); + _glfw.wgl.CreateContextAttribsARB = cast(PFNWGLCREATECONTEXTATTRIBSARBPROC) + _glfw.wgl.GetProcAddress("wglCreateContextAttribsARB"); + _glfw.wgl.SwapIntervalEXT = cast(PFNWGLSWAPINTERVALEXTPROC) + _glfw.wgl.GetProcAddress("wglSwapIntervalEXT"); + _glfw.wgl.GetPixelFormatAttribivARB = cast(PFNWGLGETPIXELFORMATATTRIBIVARBPROC) + _glfw.wgl.GetProcAddress("wglGetPixelFormatAttribivARB"); + + // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not + // checked below as we are already using them + _glfw.wgl.ARB_multisample = + extensionSupportedWGL("WGL_ARB_multisample"); + _glfw.wgl.ARB_framebuffer_sRGB = + extensionSupportedWGL("WGL_ARB_framebuffer_sRGB"); + _glfw.wgl.EXT_framebuffer_sRGB = + extensionSupportedWGL("WGL_EXT_framebuffer_sRGB"); + _glfw.wgl.ARB_create_context = + extensionSupportedWGL("WGL_ARB_create_context"); + _glfw.wgl.ARB_create_context_profile = + extensionSupportedWGL("WGL_ARB_create_context_profile"); + _glfw.wgl.EXT_create_context_es2_profile = + extensionSupportedWGL("WGL_EXT_create_context_es2_profile"); + _glfw.wgl.ARB_create_context_robustness = + extensionSupportedWGL("WGL_ARB_create_context_robustness"); + _glfw.wgl.ARB_create_context_no_error = + extensionSupportedWGL("WGL_ARB_create_context_no_error"); + _glfw.wgl.EXT_swap_control = + extensionSupportedWGL("WGL_EXT_swap_control"); + _glfw.wgl.EXT_colorspace = + extensionSupportedWGL("WGL_EXT_colorspace"); + _glfw.wgl.ARB_pixel_format = + extensionSupportedWGL("WGL_ARB_pixel_format"); + _glfw.wgl.ARB_context_flush_control = + extensionSupportedWGL("WGL_ARB_context_flush_control"); + + _glfw.wgl.MakeCurrent(pdc, prc); + _glfw.wgl.DeleteContext(rc); + return GLFW_TRUE; +} + +// Terminate WGL +// +void _glfwTerminateWGL() { + if (_glfw.wgl.instance) + FreeLibrary(_glfw.wgl.instance); +} + +// Create the OpenGL or OpenGL ES context +// +GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + int[40] attribs; + int pixelFormat; + PIXELFORMATDESCRIPTOR pfd; + HGLRC share = null; + + if (ctxconfig.share) + share = cast(void*) ctxconfig.share.context.wgl.handle; + + window.context.wgl.dc = GetDC(window.win32.handle); + if (!window.context.wgl.dc) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve DC for window"); + return GLFW_FALSE; + } + + pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig); + if (!pixelFormat) + return GLFW_FALSE; + + if (!DescribePixelFormat(window.context.wgl.dc, + pixelFormat, typeof(pfd).sizeof, &pfd)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve PFD for selected pixel format"); + return GLFW_FALSE; + } + + if (!SetPixelFormat(window.context.wgl.dc, pixelFormat, &pfd)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to set selected pixel format"); + return GLFW_FALSE; + } + + if (ctxconfig.client == GLFW_OPENGL_API) + { + if (ctxconfig.forward) + { + if (!_glfw.wgl.ARB_create_context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable"); + return GLFW_FALSE; + } + } + + if (ctxconfig.profile) + { + if (!_glfw.wgl.ARB_create_context_profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable"); + return GLFW_FALSE; + } + } + } + else + { + if (!_glfw.wgl.ARB_create_context || + !_glfw.wgl.ARB_create_context_profile || + !_glfw.wgl.EXT_create_context_es2_profile) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable"); + return GLFW_FALSE; + } + } + + if (_glfw.wgl.ARB_create_context) + { + int index = 0;int mask = 0;int flags = 0; + + void setAttrib(int a, int v) { + assert((cast(size_t) index + 1) < attribs.length); + attribs[index++] = a; + attribs[index++] = v; + } + + if (ctxconfig.client == GLFW_OPENGL_API) + { + if (ctxconfig.forward) + flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (ctxconfig.profile == GLFW_OPENGL_CORE_PROFILE) + mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (ctxconfig.profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + else + mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (ctxconfig.debug_) + flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + + if (ctxconfig.robustness) + { + if (_glfw.wgl.ARB_create_context_robustness) + { + if (ctxconfig.robustness == GLFW_NO_RESET_NOTIFICATION) + { + setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_NO_RESET_NOTIFICATION_ARB); + } + else if (ctxconfig.robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_LOSE_CONTEXT_ON_RESET_ARB); + } + + flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (ctxconfig.release) + { + if (_glfw.wgl.ARB_context_flush_control) + { + if (ctxconfig.release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig.release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + if (ctxconfig.noerror) + { + if (_glfw.wgl.ARB_create_context_no_error) + setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + } + + // NOTE: Only request an explicitly versioned context when necessary, as + // explicitly requesting version 1.0 does not always return the + // highest version supported by the driver + if (ctxconfig.major != 1 || ctxconfig.minor != 0) + { + setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig.major); + setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig.minor); + } + + if (flags) + setAttrib(WGL_CONTEXT_FLAGS_ARB, flags); + + if (mask) + setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); + + setAttrib(0, 0); + + window.context.wgl.handle = + _glfw.wgl.CreateContextAttribsARB(window.context.wgl.dc, share, attribs.ptr); + if (!window.context.wgl.handle) + { + const(DWORD) error = GetLastError(); + + if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) + { + if (ctxconfig.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support OpenGL version %i.%i", + ctxconfig.major, + ctxconfig.minor); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support OpenGL ES version %i.%i", + ctxconfig.major, + ctxconfig.minor); + } + } + else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Driver does not support the requested OpenGL profile"); + } + else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "WGL: The share context is not compatible with the requested context"); + } + else + { + if (ctxconfig.client == GLFW_OPENGL_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL context"); + } + else + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL ES context"); + } + } + + return GLFW_FALSE; + } + } + else + { + window.context.wgl.handle = _glfw.wgl.CreateContext(window.context.wgl.dc); + if (!window.context.wgl.handle) + { + _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL context"); + return GLFW_FALSE; + } + + if (share) + { + if (!_glfw.wgl.ShareLists(share, window.context.wgl.handle)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to enable sharing with specified OpenGL context"); + return GLFW_FALSE; + } + } + } + + window.context.makeCurrent = &makeContextCurrentWGL; + window.context.swapBuffers = &swapBuffersWGL; + window.context.swapInterval = &swapIntervalWGL; + window.context.extensionSupported = &extensionSupportedWGL; + window.context.getProcAddress = &getProcAddressWGL; + window.context.destroy = &destroyContextWGL; + + return GLFW_TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +export HGLRC glfwGetWGLContext(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (window.context.client == GLFW_NO_API) + { + _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); + return null; + } + + return window.context.wgl.handle; +} \ No newline at end of file diff --git a/source/glfw3/win32_init.d b/source/glfw3/win32_init.d new file mode 100644 index 0000000..e4aff48 --- /dev/null +++ b/source/glfw3/win32_init.d @@ -0,0 +1,631 @@ +/// Translated from C to D +module glfw3.win32_init; + +extern(C): @nogc: nothrow: __gshared: + +private template HasVersion(string versionId) { + mixin("version("~versionId~") {enum HasVersion = true;} else {enum HasVersion = false;}"); +} +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +public import glfw3.internal; + +import core.stdc.stdlib; +import core.stdc.string; + +static const(GUID) _glfw_GUID_DEVINTERFACE_HID = GUID(0x4d1e55b2,0xf16f,0x11cf,[0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30]); + +enum GUID_DEVINTERFACE_HID = _glfw_GUID_DEVINTERFACE_HID; + +static if (HasVersion!"_GLFW_USE_HYBRID_HPG" || HasVersion!"_GLFW_USE_OPTIMUS_HPG") { + +// Executables (but not DLLs) exporting this symbol with this value will be +// automatically directed to the high-performance GPU on Nvidia Optimus systems +// with up-to-date drivers +// +DWORD NvOptimusEnablement = 1; + +// Executables (but not DLLs) exporting this symbol with this value will be +// automatically directed to the high-performance GPU on AMD PowerXpress systems +// with up-to-date drivers +// +int AmdPowerXpressRequestHighPerformance = 1; + +} // _GLFW_USE_HYBRID_HPG + +version (_GLFW_BUILD_DLL) { + +// GLFW DLL entry point +// +extern(Windows) BOOL DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { + return TRUE; +} + +} // _GLFW_BUILD_DLL + +// Load necessary libraries (DLLs) +// +static GLFWbool loadLibraries() { + _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll"); + if (!_glfw.win32.winmm.instance) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to load winmm.dll"); + return GLFW_FALSE; + } + + _glfw.win32.winmm.GetTime = cast(PFN_timeGetTime) + GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime"); + + _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); + if (!_glfw.win32.user32.instance) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to load user32.dll"); + return GLFW_FALSE; + } + + _glfw.win32.user32.SetProcessDPIAware_ = cast(PFN_SetProcessDPIAware) + GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); + _glfw.win32.user32.ChangeWindowMessageFilterEx_ = cast(PFN_ChangeWindowMessageFilterEx) + GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); + _glfw.win32.user32.EnableNonClientDpiScaling_ = cast(PFN_EnableNonClientDpiScaling) + GetProcAddress(_glfw.win32.user32.instance, "EnableNonClientDpiScaling"); + _glfw.win32.user32.SetProcessDpiAwarenessContext_ = cast(PFN_SetProcessDpiAwarenessContext) + GetProcAddress(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext"); + _glfw.win32.user32.GetDpiForWindow_ = cast(PFN_GetDpiForWindow) + GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow"); + _glfw.win32.user32.AdjustWindowRectExForDpi_ = cast(PFN_AdjustWindowRectExForDpi) + GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi"); + + _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); + if (_glfw.win32.dinput8.instance) + { + _glfw.win32.dinput8.Create = cast(PFN_DirectInput8Create) + GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create"); + } + + { + int i; + const(char)*[6] names = [ + "xinput1_4.dll".ptr, + "xinput1_3.dll".ptr, + "xinput9_1_0.dll".ptr, + "xinput1_2.dll".ptr, + "xinput1_1.dll".ptr, + null + ]; + + for (i = 0; names[i]; i++) + { + _glfw.win32.xinput.instance = LoadLibraryA(names[i]); + if (_glfw.win32.xinput.instance) + { + _glfw.win32.xinput.GetCapabilities = cast(PFN_XInputGetCapabilities) + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities"); + _glfw.win32.xinput.GetState = cast(PFN_XInputGetState) + GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState"); + + break; + } + } + } + + _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); + if (_glfw.win32.dwmapi.instance) + { + _glfw.win32.dwmapi.IsCompositionEnabled = cast(PFN_DwmIsCompositionEnabled) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); + _glfw.win32.dwmapi.Flush = cast(PFN_DwmFlush) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); + _glfw.win32.dwmapi.EnableBlurBehindWindow = cast(PFN_DwmEnableBlurBehindWindow) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); + } + + _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); + if (_glfw.win32.shcore.instance) + { + _glfw.win32.shcore.SetProcessDpiAwareness_ = cast(PFN_SetProcessDpiAwareness) + GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); + _glfw.win32.shcore.GetDpiForMonitor_ = cast(PFN_GetDpiForMonitor) + GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor"); + } + + _glfw.win32.ntdll.instance = LoadLibraryA("ntdll.dll"); + if (_glfw.win32.ntdll.instance) + { + _glfw.win32.ntdll.RtlVerifyVersionInfo_ = cast(PFN_RtlVerifyVersionInfo) + GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo"); + } + + return GLFW_TRUE; +} + +// Unload used libraries (DLLs) +// +static void freeLibraries() { + if (_glfw.win32.xinput.instance) + FreeLibrary(_glfw.win32.xinput.instance); + + if (_glfw.win32.dinput8.instance) + FreeLibrary(_glfw.win32.dinput8.instance); + + if (_glfw.win32.winmm.instance) + FreeLibrary(_glfw.win32.winmm.instance); + + if (_glfw.win32.user32.instance) + FreeLibrary(_glfw.win32.user32.instance); + + if (_glfw.win32.dwmapi.instance) + FreeLibrary(_glfw.win32.dwmapi.instance); + + if (_glfw.win32.shcore.instance) + FreeLibrary(_glfw.win32.shcore.instance); + + if (_glfw.win32.ntdll.instance) + FreeLibrary(_glfw.win32.ntdll.instance); +} + +// Create key code translation tables +// +static void createKeyTables() { + int scancode; + + memset(_glfw.win32.keycodes.ptr, -1, typeof((_glfw.win32.keycodes)).sizeof); + memset(_glfw.win32.scancodes.ptr, -1, typeof((_glfw.win32.scancodes)).sizeof); + + _glfw.win32.keycodes[0x00B] = GLFW_KEY_0; + _glfw.win32.keycodes[0x002] = GLFW_KEY_1; + _glfw.win32.keycodes[0x003] = GLFW_KEY_2; + _glfw.win32.keycodes[0x004] = GLFW_KEY_3; + _glfw.win32.keycodes[0x005] = GLFW_KEY_4; + _glfw.win32.keycodes[0x006] = GLFW_KEY_5; + _glfw.win32.keycodes[0x007] = GLFW_KEY_6; + _glfw.win32.keycodes[0x008] = GLFW_KEY_7; + _glfw.win32.keycodes[0x009] = GLFW_KEY_8; + _glfw.win32.keycodes[0x00A] = GLFW_KEY_9; + _glfw.win32.keycodes[0x01E] = GLFW_KEY_A; + _glfw.win32.keycodes[0x030] = GLFW_KEY_B; + _glfw.win32.keycodes[0x02E] = GLFW_KEY_C; + _glfw.win32.keycodes[0x020] = GLFW_KEY_D; + _glfw.win32.keycodes[0x012] = GLFW_KEY_E; + _glfw.win32.keycodes[0x021] = GLFW_KEY_F; + _glfw.win32.keycodes[0x022] = GLFW_KEY_G; + _glfw.win32.keycodes[0x023] = GLFW_KEY_H; + _glfw.win32.keycodes[0x017] = GLFW_KEY_I; + _glfw.win32.keycodes[0x024] = GLFW_KEY_J; + _glfw.win32.keycodes[0x025] = GLFW_KEY_K; + _glfw.win32.keycodes[0x026] = GLFW_KEY_L; + _glfw.win32.keycodes[0x032] = GLFW_KEY_M; + _glfw.win32.keycodes[0x031] = GLFW_KEY_N; + _glfw.win32.keycodes[0x018] = GLFW_KEY_O; + _glfw.win32.keycodes[0x019] = GLFW_KEY_P; + _glfw.win32.keycodes[0x010] = GLFW_KEY_Q; + _glfw.win32.keycodes[0x013] = GLFW_KEY_R; + _glfw.win32.keycodes[0x01F] = GLFW_KEY_S; + _glfw.win32.keycodes[0x014] = GLFW_KEY_T; + _glfw.win32.keycodes[0x016] = GLFW_KEY_U; + _glfw.win32.keycodes[0x02F] = GLFW_KEY_V; + _glfw.win32.keycodes[0x011] = GLFW_KEY_W; + _glfw.win32.keycodes[0x02D] = GLFW_KEY_X; + _glfw.win32.keycodes[0x015] = GLFW_KEY_Y; + _glfw.win32.keycodes[0x02C] = GLFW_KEY_Z; + + _glfw.win32.keycodes[0x028] = GLFW_KEY_APOSTROPHE; + _glfw.win32.keycodes[0x02B] = GLFW_KEY_BACKSLASH; + _glfw.win32.keycodes[0x033] = GLFW_KEY_COMMA; + _glfw.win32.keycodes[0x00D] = GLFW_KEY_EQUAL; + _glfw.win32.keycodes[0x029] = GLFW_KEY_GRAVE_ACCENT; + _glfw.win32.keycodes[0x01A] = GLFW_KEY_LEFT_BRACKET; + _glfw.win32.keycodes[0x00C] = GLFW_KEY_MINUS; + _glfw.win32.keycodes[0x034] = GLFW_KEY_PERIOD; + _glfw.win32.keycodes[0x01B] = GLFW_KEY_RIGHT_BRACKET; + _glfw.win32.keycodes[0x027] = GLFW_KEY_SEMICOLON; + _glfw.win32.keycodes[0x035] = GLFW_KEY_SLASH; + _glfw.win32.keycodes[0x056] = GLFW_KEY_WORLD_2; + + _glfw.win32.keycodes[0x00E] = GLFW_KEY_BACKSPACE; + _glfw.win32.keycodes[0x153] = GLFW_KEY_DELETE; + _glfw.win32.keycodes[0x14F] = GLFW_KEY_END; + _glfw.win32.keycodes[0x01C] = GLFW_KEY_ENTER; + _glfw.win32.keycodes[0x001] = GLFW_KEY_ESCAPE; + _glfw.win32.keycodes[0x147] = GLFW_KEY_HOME; + _glfw.win32.keycodes[0x152] = GLFW_KEY_INSERT; + _glfw.win32.keycodes[0x15D] = GLFW_KEY_MENU; + _glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN; + _glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP; + _glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE; + _glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE; + _glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE; + _glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB; + _glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK; + _glfw.win32.keycodes[0x145] = GLFW_KEY_NUM_LOCK; + _glfw.win32.keycodes[0x046] = GLFW_KEY_SCROLL_LOCK; + _glfw.win32.keycodes[0x03B] = GLFW_KEY_F1; + _glfw.win32.keycodes[0x03C] = GLFW_KEY_F2; + _glfw.win32.keycodes[0x03D] = GLFW_KEY_F3; + _glfw.win32.keycodes[0x03E] = GLFW_KEY_F4; + _glfw.win32.keycodes[0x03F] = GLFW_KEY_F5; + _glfw.win32.keycodes[0x040] = GLFW_KEY_F6; + _glfw.win32.keycodes[0x041] = GLFW_KEY_F7; + _glfw.win32.keycodes[0x042] = GLFW_KEY_F8; + _glfw.win32.keycodes[0x043] = GLFW_KEY_F9; + _glfw.win32.keycodes[0x044] = GLFW_KEY_F10; + _glfw.win32.keycodes[0x057] = GLFW_KEY_F11; + _glfw.win32.keycodes[0x058] = GLFW_KEY_F12; + _glfw.win32.keycodes[0x064] = GLFW_KEY_F13; + _glfw.win32.keycodes[0x065] = GLFW_KEY_F14; + _glfw.win32.keycodes[0x066] = GLFW_KEY_F15; + _glfw.win32.keycodes[0x067] = GLFW_KEY_F16; + _glfw.win32.keycodes[0x068] = GLFW_KEY_F17; + _glfw.win32.keycodes[0x069] = GLFW_KEY_F18; + _glfw.win32.keycodes[0x06A] = GLFW_KEY_F19; + _glfw.win32.keycodes[0x06B] = GLFW_KEY_F20; + _glfw.win32.keycodes[0x06C] = GLFW_KEY_F21; + _glfw.win32.keycodes[0x06D] = GLFW_KEY_F22; + _glfw.win32.keycodes[0x06E] = GLFW_KEY_F23; + _glfw.win32.keycodes[0x076] = GLFW_KEY_F24; + _glfw.win32.keycodes[0x038] = GLFW_KEY_LEFT_ALT; + _glfw.win32.keycodes[0x01D] = GLFW_KEY_LEFT_CONTROL; + _glfw.win32.keycodes[0x02A] = GLFW_KEY_LEFT_SHIFT; + _glfw.win32.keycodes[0x15B] = GLFW_KEY_LEFT_SUPER; + _glfw.win32.keycodes[0x137] = GLFW_KEY_PRINT_SCREEN; + _glfw.win32.keycodes[0x138] = GLFW_KEY_RIGHT_ALT; + _glfw.win32.keycodes[0x11D] = GLFW_KEY_RIGHT_CONTROL; + _glfw.win32.keycodes[0x036] = GLFW_KEY_RIGHT_SHIFT; + _glfw.win32.keycodes[0x15C] = GLFW_KEY_RIGHT_SUPER; + _glfw.win32.keycodes[0x150] = GLFW_KEY_DOWN; + _glfw.win32.keycodes[0x14B] = GLFW_KEY_LEFT; + _glfw.win32.keycodes[0x14D] = GLFW_KEY_RIGHT; + _glfw.win32.keycodes[0x148] = GLFW_KEY_UP; + + _glfw.win32.keycodes[0x052] = GLFW_KEY_KP_0; + _glfw.win32.keycodes[0x04F] = GLFW_KEY_KP_1; + _glfw.win32.keycodes[0x050] = GLFW_KEY_KP_2; + _glfw.win32.keycodes[0x051] = GLFW_KEY_KP_3; + _glfw.win32.keycodes[0x04B] = GLFW_KEY_KP_4; + _glfw.win32.keycodes[0x04C] = GLFW_KEY_KP_5; + _glfw.win32.keycodes[0x04D] = GLFW_KEY_KP_6; + _glfw.win32.keycodes[0x047] = GLFW_KEY_KP_7; + _glfw.win32.keycodes[0x048] = GLFW_KEY_KP_8; + _glfw.win32.keycodes[0x049] = GLFW_KEY_KP_9; + _glfw.win32.keycodes[0x04E] = GLFW_KEY_KP_ADD; + _glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL; + _glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE; + _glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER; + _glfw.win32.keycodes[0x059] = GLFW_KEY_KP_EQUAL; + _glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY; + _glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT; + + for (scancode = 0; scancode < 512; scancode++) + { + if (_glfw.win32.keycodes[scancode] > 0) + _glfw.win32.scancodes[_glfw.win32.keycodes[scancode]] = scancode; + } +} + +// Creates a dummy window for behind-the-scenes work +// +static GLFWbool createHelperWindow() { + MSG msg; + + _glfw.win32.helperWindowHandle = + CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, + _GLFW_WNDCLASSNAME.ptr, + "GLFW message window"w.ptr, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, 0, 1, 1, + null, null, + GetModuleHandleW(null), + null); + + if (!_glfw.win32.helperWindowHandle) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create helper window"); + return GLFW_FALSE; + } + + // HACK: The command to the first ShowWindow call is ignored if the parent + // process passed along a STARTUPINFO, so clear that with a no-op call + ShowWindow(_glfw.win32.helperWindowHandle, SW_HIDE); + + // Register for HID device notifications + { + DEV_BROADCAST_DEVICEINTERFACE_W dbi; + memset(&dbi, 0, typeof(dbi).sizeof); //ZeroMemory(&dbi, typeof(dbi).sizeof); + dbi.dbcc_size = typeof(dbi).sizeof; + dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; + + _glfw.win32.deviceNotificationHandle = + RegisterDeviceNotificationW(_glfw.win32.helperWindowHandle, + cast(DEV_BROADCAST_HDR*) &dbi, + DEVICE_NOTIFY_WINDOW_HANDLE); + } + + while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Returns a wide string version of the specified UTF-8 string +// +WCHAR* _glfwCreateWideStringFromUTF8Win32(const(char)* source) { + WCHAR* target; + int count; + + count = MultiByteToWideChar(CP_UTF8, 0, source, -1, null, 0); + if (!count) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string from UTF-8"); + return null; + } + + target = cast(WCHAR*) calloc(count, WCHAR.sizeof); + + if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string from UTF-8"); + free(target); + return null; + } + + return target; +} + +// Returns a UTF-8 string version of the specified wide string +// +char* _glfwCreateUTF8FromWideStringWin32(const(WCHAR)* source) { + char* target; + int size; + + size = WideCharToMultiByte(CP_UTF8, 0, source, -1, null, 0, null, null); + if (!size) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string to UTF-8"); + return null; + } + + target = cast(char*) calloc(size, 1); + + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, null, null)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string to UTF-8"); + free(target); + return null; + } + + return target; +} + +// Reports the specified error, appending information about the last Win32 error +// +void _glfwInputErrorWin32(int error, const(char)* description) { + WCHAR[_GLFW_MESSAGE_SIZE] buffer = ""w; + char[_GLFW_MESSAGE_SIZE] message = ""; + + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + null, + GetLastError() & 0xffff, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buffer.ptr, + buffer.sizeof / WCHAR.sizeof, + null); + WideCharToMultiByte(CP_UTF8, 0, buffer.ptr, -1, message.ptr, typeof(message).sizeof, null, null); + + _glfwInputError(error, "%s: %s", description, message.ptr); +} + +// Updates key names according to the current keyboard layout +// +void _glfwUpdateKeyNamesWin32() { + int key; + BYTE[256] state = 0; + + memset(_glfw.win32.keynames.ptr, 0, typeof(_glfw.win32.keynames).sizeof); + + for (key = GLFW_KEY_SPACE; key <= GLFW_KEY_LAST; key++) + { + UINT vk; + int scancode;int length; + WCHAR[16] chars; + + scancode = _glfw.win32.scancodes[key]; + if (scancode == -1) + continue; + + if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) + { + const(UINT)[15] vks = [ + VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, + VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, + VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE, + VK_MULTIPLY, VK_SUBTRACT, VK_ADD + ]; + + vk = vks[key - GLFW_KEY_KP_0]; + } + else + vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK); + + length = ToUnicode(vk, scancode, state.ptr, + chars.ptr, chars.sizeof / WCHAR.sizeof, + 0); + + if (length == -1) + { + length = ToUnicode(vk, scancode, state.ptr, + chars.ptr, chars.sizeof / WCHAR.sizeof, + 0); + } + + if (length < 1) + continue; + + WideCharToMultiByte(CP_UTF8, 0, chars.ptr, 1, + _glfw.win32.keynames[key].ptr, + typeof(_glfw.win32.keynames[key]).sizeof, + null, null); + } +} + +// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h +// +BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp) { + OSVERSIONINFOEXW osvi = OSVERSIONINFOEXW(OSVERSIONINFOEXW.sizeof, major, minor, 0, 0, (wchar[128]).init, sp); + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; + ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the + // latter lies unless the user knew to embed a non-default manifest + // announcing support for Windows 10 via supportedOS GUID + return _glfw.win32.ntdll.RtlVerifyVersionInfo_(&osvi, mask, cond) == 0; +} + +// Checks whether we are on at least the specified build of Windows 10 +// +BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build) { + OSVERSIONINFOEXW osvi = OSVERSIONINFOEXW(OSVERSIONINFOEXW.sizeof, 10, 0, build); + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER; + ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL); + // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the + // latter lies unless the user knew to embed a non-default manifest + // announcing support for Windows 10 via supportedOS GUID + return _glfw.win32.ntdll.RtlVerifyVersionInfo_(&osvi, mask, cond) == 0; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit() { + // To make SetForegroundWindow work as we want, we need to fiddle + // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early + // as possible in the hope of still being the foreground process) + SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, + &_glfw.win32.foregroundLockTimeout, 0); + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, null /*UIntToPtr(0)*/, + SPIF_SENDCHANGE); + + if (!loadLibraries()) + return GLFW_FALSE; + + createKeyTables(); + _glfwUpdateKeyNamesWin32(); + + if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) + _glfw.win32.user32.SetProcessDpiAwarenessContext_(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + else if (IsWindows8Point1OrGreater()) + _glfw.win32.shcore.SetProcessDpiAwareness_(PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE); + else if (IsWindowsVistaOrGreater()) + _glfw.win32.user32.SetProcessDPIAware_(); + + if (!_glfwRegisterWindowClassWin32()) + return GLFW_FALSE; + + if (!createHelperWindow()) + return GLFW_FALSE; + + _glfwInitTimerWin32(); + _glfwInitJoysticksWin32(); + + _glfwPollMonitorsWin32(); + return GLFW_TRUE; +} + +void _glfwPlatformTerminate() { + if (_glfw.win32.deviceNotificationHandle) + UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle); + + if (_glfw.win32.helperWindowHandle) + DestroyWindow(_glfw.win32.helperWindowHandle); + + _glfwUnregisterWindowClassWin32(); + + // Restore previous foreground lock timeout system setting + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, + cast(void*) cast(UINT_PTR) _glfw.win32.foregroundLockTimeout, + SPIF_SENDCHANGE); + + free(_glfw.win32.clipboardString); + free(_glfw.win32.rawInput); + + _glfwTerminateWGL(); + _glfwTerminateEGL(); + + _glfwTerminateJoysticksWin32(); + + freeLibraries(); +} + +const(char)* _glfwPlatformGetVersionString() { + version (MinGW) { + enum clibPart = " MinGW"; + } else version (CRuntime_Microsoft) { + enum clibPart = " VisualC"; + } else { + enum clibPart = ""; + } + + version(_GLFW_USE_HYBRID_HPG) { + enum optimusPart = " hybrid-GPU"; + } else version(_GLFW_USE_OPTIMUS_HPG) { + enum optimusPart = " hybrid-GPU"; + } else { + enum optimusPart = ""; + } + version (_GLFW_BUILD_DLL) { + enum dllPart = " DLL"; + } else { + enum dllPart = ""; + } + + return _GLFW_VERSION_NUMBER ~ " Win32 WGL EGL OSMesa" ~ clibPart ~ optimusPart ~ dllPart; +} \ No newline at end of file diff --git a/source/glfw3/win32_joystick.d b/source/glfw3/win32_joystick.d new file mode 100644 index 0000000..4fe0fc8 --- /dev/null +++ b/source/glfw3/win32_joystick.d @@ -0,0 +1,756 @@ +/// Translated from C to D +module glfw3.win32_joystick; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +public import glfw3.internal; +import core.stdc.stdlib; // free +import core.stdc.string; // memset + +// header +mixin template _GLFW_PLATFORM_JOYSTICK_STATE() {_GLFWjoystickWin32 win32;} +mixin template _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE() {int dummyLibraryJoystick;} + +enum _GLFW_PLATFORM_MAPPING_NAME = "Windows"; + +// Joystick element (axis, button or slider) +// +struct _GLFWjoyobjectWin32 { + int offset; + int type; +} + +// Win32-specific per-joystick data +// +struct _GLFWjoystickWin32 { + _GLFWjoyobjectWin32* objects; + int objectCount; + IDirectInputDevice8W* device; + DWORD index; + GUID guid; +} + +import core.stdc.stdio; +import core.stdc.math; + +enum _GLFW_TYPE_AXIS = 0; +enum _GLFW_TYPE_SLIDER = 1; +enum _GLFW_TYPE_BUTTON = 2; +enum _GLFW_TYPE_POV = 3; + +// Data produced with DirectInput device object enumeration +// +struct _GLFWobjenumWin32 { + IDirectInputDevice8W* device; + _GLFWjoyobjectWin32* objects; + int objectCount; + int axisCount; + int sliderCount; + int buttonCount; + int povCount; +} + +// Define local copies of the necessary GUIDs +// +static immutable GUID _glfw_IID_IDirectInput8W = GUID(0xbf798031,0x483a,0x4da2,[0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00]); +static immutable GUID _glfw_GUID_XAxis = GUID(0xa36d02e0,0xc9f3,0x11cf,[0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00]); +static immutable GUID _glfw_GUID_YAxis = GUID(0xa36d02e1,0xc9f3,0x11cf,[0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00]); +static immutable GUID _glfw_GUID_ZAxis = GUID(0xa36d02e2,0xc9f3,0x11cf,[0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00]); +static immutable GUID _glfw_GUID_RxAxis = GUID(0xa36d02f4,0xc9f3,0x11cf,[0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00]); +static immutable GUID _glfw_GUID_RyAxis = GUID(0xa36d02f5,0xc9f3,0x11cf,[0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00]); +static immutable GUID _glfw_GUID_RzAxis = GUID(0xa36d02e3,0xc9f3,0x11cf,[0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00]); +static immutable GUID _glfw_GUID_Slider = GUID(0xa36d02e4,0xc9f3,0x11cf,[0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00]); +static immutable GUID _glfw_GUID_POV = GUID(0xa36d02f2,0xc9f3,0x11cf,[0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00]); + +alias IID_IDirectInput8W = _glfw_IID_IDirectInput8W; +alias GUID_XAxis = _glfw_GUID_XAxis; +alias GUID_YAxis = _glfw_GUID_YAxis; +alias GUID_ZAxis = _glfw_GUID_ZAxis; +alias GUID_RxAxis = _glfw_GUID_RxAxis; +alias GUID_RyAxis = _glfw_GUID_RyAxis; +alias GUID_RzAxis = _glfw_GUID_RzAxis; +alias GUID_Slider = _glfw_GUID_Slider; +alias GUID_POV = _glfw_GUID_POV; + +// Object data array for our clone of c_dfDIJoystick +// Generated with https://github.com/elmindreda/c_dfDIJoystick2 +// +static DIOBJECTDATAFORMAT[44] _glfwObjectDataFormats = [ + DIOBJECTDATAFORMAT(&GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION), + DIOBJECTDATAFORMAT(&GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION), + DIOBJECTDATAFORMAT(&GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION), + DIOBJECTDATAFORMAT(&GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION), + DIOBJECTDATAFORMAT(&GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION), + DIOBJECTDATAFORMAT(&GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION), + DIOBJECTDATAFORMAT(&GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION), + DIOBJECTDATAFORMAT(&GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION), + DIOBJECTDATAFORMAT(&GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(&GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(&GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(&GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), + DIOBJECTDATAFORMAT(null,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0), +]; + +// Our clone of c_dfDIJoystick +// +static const DIDATAFORMAT _glfwDataFormat = DIDATAFORMAT( + DIDATAFORMAT.sizeof, + DIOBJECTDATAFORMAT.sizeof, + DIDFT_ABSAXIS, + DIJOYSTATE.sizeof, + _glfwObjectDataFormats.length, //_glfwObjectDataFormats.sizeof / DIOBJECTDATAFORMAT.sizeof, + _glfwObjectDataFormats.ptr +); + +// Returns a description fitting the specified XInput capabilities +// +static const(char)* getDeviceDescription(const(XINPUT_CAPABILITIES)* xic) { + switch (xic.SubType) + { + case XINPUT_DEVSUBTYPE_WHEEL: + return "XInput Wheel"; + case XINPUT_DEVSUBTYPE_ARCADE_STICK: + return "XInput Arcade Stick"; + case XINPUT_DEVSUBTYPE_FLIGHT_STICK: + return "XInput Flight Stick"; + case XINPUT_DEVSUBTYPE_DANCE_PAD: + return "XInput Dance Pad"; + case XINPUT_DEVSUBTYPE_GUITAR: + return "XInput Guitar"; + case XINPUT_DEVSUBTYPE_DRUM_KIT: + return "XInput Drum Kit"; + case XINPUT_DEVSUBTYPE_GAMEPAD: + { + if (xic.Flags & XINPUT_CAPS_WIRELESS) + return "Wireless Xbox Controller"; + else + return "Xbox Controller"; + } + default: break; + } + + return "Unknown XInput Device"; +} + +// Lexically compare device objects +// +static int compareJoystickObjects(const(void)* first, const(void)* second) { + auto fo = cast(const(_GLFWjoyobjectWin32)*) first; + auto so = cast(const(_GLFWjoyobjectWin32)*) second; + + if (fo.type != so.type) + return fo.type - so.type; + + return fo.offset - so.offset; +} + +// Checks whether the specified device supports XInput +// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom +// +static GLFWbool supportsXInput(const(GUID)* guid) { + UINT i;UINT count = 0; + RAWINPUTDEVICELIST* ridl; + GLFWbool result = GLFW_FALSE; + + if (GetRawInputDeviceList(null, &count, RAWINPUTDEVICELIST.sizeof) != 0) + return GLFW_FALSE; + + ridl = cast(RAWINPUTDEVICELIST*) calloc(count, RAWINPUTDEVICELIST.sizeof); + + if (GetRawInputDeviceList(ridl, &count, RAWINPUTDEVICELIST.sizeof) == cast(UINT) -1) + { + free(ridl); + return GLFW_FALSE; + } + + for (i = 0; i < count; i++) + { + RID_DEVICE_INFO rdi; + char[256] name; + UINT size; + + if (ridl[i].dwType != RIM_TYPEHID) + continue; + + memset(&rdi, 0, typeof(rdi).sizeof); //ZeroMemory(&rdi, typeof(rdi).sizeof); + rdi.cbSize = typeof(rdi).sizeof; + size = typeof(rdi).sizeof; + + if (cast(INT) GetRawInputDeviceInfoA(ridl[i].hDevice, + RIDI_DEVICEINFO, + &rdi, &size) == -1) + { + continue; + } + + if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != cast(LONG) guid.Data1) + continue; + + memset(name.ptr, 0, typeof(name).sizeof); + size = typeof(name).sizeof; + + if (cast(INT) GetRawInputDeviceInfoA(ridl[i].hDevice, + RIDI_DEVICENAME, + name.ptr, &size) == -1) + { + break; + } + + name[name.length - 1] = '\0'; + if (strstr(name.ptr, "IG_")) + { + result = GLFW_TRUE; + break; + } + } + + free(ridl); + return result; +} + +// Frees all resources associated with the specified joystick +// +static void closeJoystick(_GLFWjoystick* js) { + if (js.win32.device) + { + IDirectInputDevice8_Unacquire(js.win32.device); + IDirectInputDevice8_Release(js.win32.device); + } + + free(js.win32.objects); + + _glfwFreeJoystick(js); + _glfwInputJoystick(js, GLFW_DISCONNECTED); +} + +// DirectInput device object enumeration callback +// Insights gleaned from SDL +// +extern(Windows) BOOL deviceObjectCallback(const(DIDEVICEOBJECTINSTANCEW)* doi, void* user) { + auto data = cast(_GLFWobjenumWin32*) user; + _GLFWjoyobjectWin32* object = data.objects + data.objectCount; + + if (DIDFT_GETTYPE(doi.dwType) & DIDFT_AXIS) + { + DIPROPRANGE dipr; + + if (memcmp(&doi.guidType, &GUID_Slider, GUID.sizeof) == 0) + object.offset = DIJOFS_SLIDER(data.sliderCount); + else if (memcmp(&doi.guidType, &GUID_XAxis, GUID.sizeof) == 0) + object.offset = DIJOFS_X; + else if (memcmp(&doi.guidType, &GUID_YAxis, GUID.sizeof) == 0) + object.offset = DIJOFS_Y; + else if (memcmp(&doi.guidType, &GUID_ZAxis, GUID.sizeof) == 0) + object.offset = DIJOFS_Z; + else if (memcmp(&doi.guidType, &GUID_RxAxis, GUID.sizeof) == 0) + object.offset = DIJOFS_RX; + else if (memcmp(&doi.guidType, &GUID_RyAxis, GUID.sizeof) == 0) + object.offset = DIJOFS_RY; + else if (memcmp(&doi.guidType, &GUID_RzAxis, GUID.sizeof) == 0) + object.offset = DIJOFS_RZ; + else + return DIENUM_CONTINUE; + + memset(&dipr, 0, typeof(dipr).sizeof); + dipr.diph.dwSize = typeof(dipr).sizeof; + dipr.diph.dwHeaderSize = typeof((dipr.diph)).sizeof; + dipr.diph.dwObj = doi.dwType; + dipr.diph.dwHow = DIPH_BYID; + dipr.lMin = -32768; + dipr.lMax = 32767; + + if (FAILED(IDirectInputDevice8_SetProperty(data.device, + DIPROP_RANGE, + &dipr.diph))) + { + return DIENUM_CONTINUE; + } + + if (memcmp(&doi.guidType, &GUID_Slider, GUID.sizeof) == 0) + { + object.type = _GLFW_TYPE_SLIDER; + data.sliderCount++; + } + else + { + object.type = _GLFW_TYPE_AXIS; + data.axisCount++; + } + } + else if (DIDFT_GETTYPE(doi.dwType) & DIDFT_BUTTON) + { + object.offset = DIJOFS_BUTTON(data.buttonCount); + object.type = _GLFW_TYPE_BUTTON; + data.buttonCount++; + } + else if (DIDFT_GETTYPE(doi.dwType) & DIDFT_POV) + { + object.offset = DIJOFS_POV(data.povCount); + object.type = _GLFW_TYPE_POV; + data.povCount++; + } + + data.objectCount++; + return DIENUM_CONTINUE; +} + +// DirectInput device enumeration callback +// +private extern(Windows) BOOL deviceCallback(const(DIDEVICEINSTANCE)* di, void* user) { + int jid = 0; + DIDEVCAPS dc; + DIPROPDWORD dipd; + IDirectInputDevice8* device; + _GLFWobjenumWin32 data; + //_GLFWjoystick* js; moved down to avoid shadowing + char[33] guid; + char[256] name; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks.ptr + jid; + if (js.present) + { + if (memcmp(&js.win32.guid, &di.guidInstance, GUID.sizeof) == 0) + return DIENUM_CONTINUE; + } + } + + if (supportsXInput(&di.guidProduct)) + return DIENUM_CONTINUE; + + if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api, + &di.guidInstance, + &device, + null))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device"); + return DIENUM_CONTINUE; + } + + if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to set device data format"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + memset(&dc, 0, typeof(dc).sizeof); + dc.dwSize = typeof(dc).sizeof; + + if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to query device capabilities"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + memset(&dipd, 0, typeof(dipd).sizeof); + dipd.diph.dwSize = typeof(dipd).sizeof; + dipd.diph.dwHeaderSize = typeof((dipd.diph)).sizeof; + dipd.diph.dwHow = DIPH_DEVICE; + dipd.dwData = DIPROPAXISMODE_ABS; + + if (FAILED(IDirectInputDevice8_SetProperty(device, + DIPROP_AXISMODE, + &dipd.diph))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to set device axis mode"); + + IDirectInputDevice8_Release(device); + return DIENUM_CONTINUE; + } + + memset(&data, 0, typeof(data).sizeof); + data.device = device; + data.objects = cast(_GLFWjoyobjectWin32*) calloc(dc.dwAxes + cast(size_t) dc.dwButtons + dc.dwPOVs, + _GLFWjoyobjectWin32.sizeof); + + if (FAILED(IDirectInputDevice8_EnumObjects(device, + &deviceObjectCallback, + &data, + DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to enumerate device objects"); + + IDirectInputDevice8_Release(device); + free(data.objects); + return DIENUM_CONTINUE; + } + + qsort(data.objects, data.objectCount, + _GLFWjoyobjectWin32.sizeof, + &compareJoystickObjects); + + if (!WideCharToMultiByte(CP_UTF8, 0, + di.tszInstanceName.ptr, -1, + name.ptr, typeof(name).sizeof, + null, null)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert joystick name to UTF-8"); + + IDirectInputDevice8_Release(device); + free(data.objects); + return DIENUM_STOP; + } + + // Generate a joystick GUID that matches the SDL 2.0.5+ one + if (memcmp(&di.guidProduct.Data4[2], "PIDVID".ptr, 6) == 0) + { + sprintf(guid.ptr, "03000000%02x%02x0000%02x%02x000000000000", + cast(ubyte) di.guidProduct.Data1, + cast(ubyte) (di.guidProduct.Data1 >> 8), + cast(ubyte) (di.guidProduct.Data1 >> 16), + cast(ubyte) (di.guidProduct.Data1 >> 24)); + } + else + { + sprintf(guid.ptr, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00", + name[0], name[1], name[2], name[3], + name[4], name[5], name[6], name[7], + name[8], name[9], name[10]); + } + + _GLFWjoystick* js = _glfwAllocJoystick(name.ptr, guid.ptr, + data.axisCount + data.sliderCount, + data.buttonCount, + data.povCount); + if (!js) + { + IDirectInputDevice8_Release(device); + free(data.objects); + return DIENUM_STOP; + } + + js.win32.device = device; + js.win32.guid = di.guidInstance; + js.win32.objects = data.objects; + js.win32.objectCount = data.objectCount; + + _glfwInputJoystick(js, GLFW_CONNECTED); + return DIENUM_CONTINUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +void _glfwInitJoysticksWin32() { + if (_glfw.win32.dinput8.instance) + { + if (FAILED(mixin(DirectInput8Create)(GetModuleHandle(null), + DIRECTINPUT_VERSION, + &IID_IDirectInput8W, + cast(void**) &_glfw.win32.dinput8.api, + null))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create interface"); + } + } + _glfwDetectJoystickConnectionWin32(); +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticksWin32() { + int jid; + + for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) + closeJoystick(_glfw.joysticks.ptr + jid); + + if (_glfw.win32.dinput8.api) + IDirectInput8_Release(_glfw.win32.dinput8.api); +} + +// Checks for new joysticks after DBT_DEVICEARRIVAL +// +void _glfwDetectJoystickConnectionWin32() { + if (_glfw.win32.xinput.instance) + { + DWORD index; + + for (index = 0; index < XUSER_MAX_COUNT; index++) + { + int jid; + char[33] guid; + XINPUT_CAPABILITIES xic; + _GLFWjoystick* js; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (_glfw.joysticks[jid].present && + _glfw.joysticks[jid].win32.device == null && + _glfw.joysticks[jid].win32.index == index) + { + break; + } + } + + if (jid <= GLFW_JOYSTICK_LAST) + continue; + + if (mixin(XInputGetCapabilities)(index, 0, &xic) != ERROR_SUCCESS) + continue; + + // Generate a joystick GUID that matches the SDL 2.0.5+ one + sprintf(guid.ptr, "78696e707574%02x000000000000000000", + xic.SubType & 0xff); + + js = _glfwAllocJoystick(getDeviceDescription(&xic), guid.ptr, 6, 10, 1); + if (!js) + continue; + + js.win32.index = index; + + _glfwInputJoystick(js, GLFW_CONNECTED); + } + } + if (_glfw.win32.dinput8.api) + { + if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api, + DI8DEVCLASS_GAMECTRL, + &deviceCallback, + null, + DIEDFL_ALLDEVICES))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to enumerate DirectInput8 devices"); + return; + } + } +} + +// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE +// +void _glfwDetectJoystickDisconnectionWin32() { + int jid; + + for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + _GLFWjoystick* js = _glfw.joysticks.ptr + jid; + if (js.present) + _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) { + if (js.win32.device) + { + int i;int ai = 0;int bi = 0;int pi = 0; + HRESULT result; + DIJOYSTATE state; + + IDirectInputDevice8_Poll(js.win32.device); + result = IDirectInputDevice8_GetDeviceState(js.win32.device, + typeof(state).sizeof, + &state); + if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST) + { + IDirectInputDevice8_Acquire(js.win32.device); + IDirectInputDevice8_Poll(js.win32.device); + result = IDirectInputDevice8_GetDeviceState(js.win32.device, + typeof(state).sizeof, + &state); + } + + if (FAILED(result)) + { + closeJoystick(js); + return GLFW_FALSE; + } + + if (mode == _GLFW_POLL_PRESENCE) + return GLFW_TRUE; + + for (i = 0; i < js.win32.objectCount; i++) + { + const(void)* data = cast(char*) &state + js.win32.objects[i].offset; + + switch (js.win32.objects[i].type) + { + case _GLFW_TYPE_AXIS: + case _GLFW_TYPE_SLIDER: + { + const(float) value = (*(cast(LONG*) data) + 0.5f) / 32767.5f; + _glfwInputJoystickAxis(js, ai, value); + ai++; + break; + } + + case _GLFW_TYPE_BUTTON: + { + const(char) value = (*(cast(BYTE*) data) & 0x80) != 0; + _glfwInputJoystickButton(js, bi, value); + bi++; + break; + } + + case _GLFW_TYPE_POV: + { + const(int)[9] states = [ + GLFW_HAT_UP, + GLFW_HAT_RIGHT_UP, + GLFW_HAT_RIGHT, + GLFW_HAT_RIGHT_DOWN, + GLFW_HAT_DOWN, + GLFW_HAT_LEFT_DOWN, + GLFW_HAT_LEFT, + GLFW_HAT_LEFT_UP, + GLFW_HAT_CENTERED + ]; + + // Screams of horror are appropriate at this point + int state1 = LOWORD(*cast(DWORD*) data) / (45 * DI_DEGREES); + if (state1 < 0 || state1 > 8) + state1 = 8; + + _glfwInputJoystickHat(js, pi, cast(char) states[state1]); + pi++; + break; + } + default: break; + } + } + } + else + { + int i;int dpad = 0; + DWORD result; + XINPUT_STATE xis; + const(WORD)[10] buttons = [ + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_BACK, + XINPUT_GAMEPAD_START, + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB + ]; + + result = mixin(XInputGetState)(js.win32.index, &xis); + if (result != ERROR_SUCCESS) + { + if (result == ERROR_DEVICE_NOT_CONNECTED) + closeJoystick(js); + + return GLFW_FALSE; + } + + if (mode == _GLFW_POLL_PRESENCE) + return GLFW_TRUE; + + _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.0f); + _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.0f); + + for (i = 0; i < 10; i++) + { + const(char) value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0; + _glfwInputJoystickButton(js, i, value); + } + + if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) + dpad |= GLFW_HAT_UP; + if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) + dpad |= GLFW_HAT_RIGHT; + if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) + dpad |= GLFW_HAT_DOWN; + if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) + dpad |= GLFW_HAT_LEFT; + + _glfwInputJoystickHat(js, 0, cast(char) dpad); + } + + return GLFW_TRUE; +} + +void _glfwPlatformUpdateGamepadGUID(char* guid) { + if (strcmp(guid + 20, "504944564944") == 0) + { + char[33] original; + strncpy(original.ptr, guid, original.length - 1); + sprintf(guid, "03000000%.4s0000%.4s000000000000", + original.ptr, original.ptr + 4); + } +} \ No newline at end of file diff --git a/source/glfw3/win32_monitor.d b/source/glfw3/win32_monitor.d new file mode 100644 index 0000000..fd55e66 --- /dev/null +++ b/source/glfw3/win32_monitor.d @@ -0,0 +1,513 @@ +/// Translated from C to D +module glfw3.win32_monitor; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +public import glfw3.internal; + +import core.stdc.stdlib; +import core.stdc.string; +import core.stdc.limits; +import core.stdc.wchar_; + +// Callback for EnumDisplayMonitors in createMonitor +// +extern(Windows) static BOOL monitorCallback(HMONITOR handle, HDC dc, RECT* rect, LPARAM data) { + MONITORINFOEXW mi; + memset(&mi, 0, typeof(mi).sizeof); + mi.cbSize = typeof(mi).sizeof; + + if (GetMonitorInfoW(handle, cast(MONITORINFO*) &mi)) + { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) data; + if (wcscmp(mi.szDevice.ptr, monitor.win32.adapterName.ptr) == 0) + monitor.win32.handle = handle; + } + + return TRUE; +} + +// Create monitor from an adapter and (optionally) a display +// +static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* display) { + _GLFWmonitor* monitor; + int widthMM;int heightMM; + char* name; + HDC dc; + DEVMODEW dm; + RECT rect; + + if (display) + name = _glfwCreateUTF8FromWideStringWin32(display.DeviceString.ptr); + else + name = _glfwCreateUTF8FromWideStringWin32(adapter.DeviceString.ptr); + if (!name) + return null; + + memset(&dm, 0, typeof(dm).sizeof); + dm.dmSize = typeof(dm).sizeof; + EnumDisplaySettingsW(adapter.DeviceName.ptr, ENUM_CURRENT_SETTINGS, &dm); + + dc = CreateDCW("DISPLAY"w.ptr, adapter.DeviceName.ptr, null, null); + + if (IsWindows8Point1OrGreater()) + { + widthMM = GetDeviceCaps(dc, HORZSIZE); + heightMM = GetDeviceCaps(dc, VERTSIZE); + } + else + { + widthMM = cast(int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX)); + heightMM = cast(int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY)); + } + + DeleteDC(dc); + + monitor = _glfwAllocMonitor(name, widthMM, heightMM); + free(name); + + if (adapter.StateFlags & DISPLAY_DEVICE_MODESPRUNED) + monitor.win32.modesPruned = GLFW_TRUE; + + wcscpy(monitor.win32.adapterName.ptr, adapter.DeviceName.ptr); + WideCharToMultiByte(CP_UTF8, 0, + adapter.DeviceName.ptr, -1, + monitor.win32.publicAdapterName.ptr, + typeof(monitor.win32.publicAdapterName).sizeof, + null, null); + + if (display) + { + wcscpy(monitor.win32.displayName.ptr, display.DeviceName.ptr); + WideCharToMultiByte(CP_UTF8, 0, + display.DeviceName.ptr, -1, + monitor.win32.publicDisplayName.ptr, + typeof(monitor.win32.publicDisplayName).sizeof, + null, null); + } + + rect.left = dm.dmPosition.x; + rect.top = dm.dmPosition.y; + rect.right = dm.dmPosition.x + dm.dmPelsWidth; + rect.bottom = dm.dmPosition.y + dm.dmPelsHeight; + + EnumDisplayMonitors(null, &rect, &monitorCallback, cast(LPARAM) monitor); + return monitor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Poll for changes in the set of connected monitors +// +void _glfwPollMonitorsWin32() { + int i;int disconnectedCount; + _GLFWmonitor** disconnected = null; + DWORD adapterIndex;DWORD displayIndex; + DISPLAY_DEVICEW adapter;DISPLAY_DEVICEW display; + _GLFWmonitor* monitor; + + disconnectedCount = _glfw.monitorCount; + if (disconnectedCount) + { + disconnected = cast(_GLFWmonitor**) calloc(_glfw.monitorCount, (_GLFWmonitor*).sizeof); + memcpy(disconnected, + _glfw.monitors, + _glfw.monitorCount * (_GLFWmonitor*).sizeof); + } + + for (adapterIndex = 0; ; adapterIndex++) + { + int type = _GLFW_INSERT_LAST; + + memset(&adapter, 0, typeof(adapter).sizeof); + adapter.cb = typeof(adapter).sizeof; + + if (!EnumDisplayDevicesW(null, adapterIndex, &adapter, 0)) + break; + + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + type = _GLFW_INSERT_FIRST; + + for (displayIndex = 0; ; displayIndex++) + { + memset(&display, 0, typeof(display).sizeof); + display.cb = typeof(display).sizeof; + + if (!EnumDisplayDevicesW(adapter.DeviceName.ptr, displayIndex, &display, 0)) + break; + + if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i] && + wcscmp(disconnected[i].win32.displayName.ptr, + display.DeviceName.ptr) == 0) + { + disconnected[i] = null; + break; + } + } + + if (i < disconnectedCount) + continue; + + monitor = createMonitor(&adapter, &display); + if (!monitor) + { + free(disconnected); + return; + } + + _glfwInputMonitor(monitor, GLFW_CONNECTED, type); + + type = _GLFW_INSERT_LAST; + } + + // HACK: If an active adapter does not have any display devices + // (as sometimes happens), add it directly as a monitor + if (displayIndex == 0) + { + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i] && + wcscmp(disconnected[i].win32.adapterName.ptr, + adapter.DeviceName.ptr) == 0) + { + disconnected[i] = null; + break; + } + } + + if (i < disconnectedCount) + continue; + + monitor = createMonitor(&adapter, null); + if (!monitor) + { + free(disconnected); + return; + } + + _glfwInputMonitor(monitor, GLFW_CONNECTED, type); + } + } + + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i]) + _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); + } + + free(disconnected); +} + +// Change the current video mode +// +void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const(GLFWvidmode)* desired) { + GLFWvidmode current; + const(GLFWvidmode)* best; + DEVMODEW dm; + LONG result; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return; + + memset(&dm, 0, typeof(dm).sizeof); + dm.dmSize = typeof(dm).sizeof; + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | + DM_DISPLAYFREQUENCY; + dm.dmPelsWidth = best.width; + dm.dmPelsHeight = best.height; + dm.dmBitsPerPel = best.redBits + best.greenBits + best.blueBits; + dm.dmDisplayFrequency = best.refreshRate; + + if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) + dm.dmBitsPerPel = 32; + + result = ChangeDisplaySettingsExW(monitor.win32.adapterName.ptr, + &dm, + null, + CDS_FULLSCREEN, + null); + if (result == DISP_CHANGE_SUCCESSFUL) + monitor.win32.modeChanged = GLFW_TRUE; + else + { + const(char)* description = "Unknown error"; + + if (result == DISP_CHANGE_BADDUALVIEW) + description = "The system uses DualView"; + else if (result == DISP_CHANGE_BADFLAGS) + description = "Invalid flags"; + else if (result == DISP_CHANGE_BADMODE) + description = "Graphics mode not supported"; + else if (result == DISP_CHANGE_BADPARAM) + description = "Invalid parameter"; + else if (result == DISP_CHANGE_FAILED) + description = "Graphics mode failed"; + else if (result == DISP_CHANGE_NOTUPDATED) + description = "Failed to write to registry"; + else if (result == DISP_CHANGE_RESTART) + description = "Computer restart required"; + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to set video mode: %s", + description); + } +} + +// Restore the previously saved (original) video mode +// +void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) { + if (monitor.win32.modeChanged) + { + ChangeDisplaySettingsExW(monitor.win32.adapterName.ptr, + null, null, CDS_FULLSCREEN, null); + monitor.win32.modeChanged = GLFW_FALSE; + } +} + +void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) { + UINT xdpi;UINT ydpi; + + if (IsWindows8Point1OrGreater()) + mixin(GetDpiForMonitor)(handle, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + else + { + HDC dc = GetDC(null); + xdpi = GetDeviceCaps(dc, LOGPIXELSX); + ydpi = GetDeviceCaps(dc, LOGPIXELSY); + ReleaseDC(null, dc); + } + + if (xscale) + *xscale = xdpi / cast(float) USER_DEFAULT_SCREEN_DPI; + if (yscale) + *yscale = ydpi / cast(float) USER_DEFAULT_SCREEN_DPI; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { + DEVMODEW dm; + memset(&dm, 0, typeof(dm).sizeof); + dm.dmSize = typeof(dm).sizeof; + + EnumDisplaySettingsExW(monitor.win32.adapterName.ptr, + ENUM_CURRENT_SETTINGS, + &dm, + EDS_ROTATEDMODE); + + if (xpos) + *xpos = dm.dmPosition.x; + if (ypos) + *ypos = dm.dmPosition.y; +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { + _glfwGetMonitorContentScaleWin32(monitor.win32.handle, xscale, yscale); +} + +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { + MONITORINFO mi = MONITORINFO(MONITORINFO.sizeof); + GetMonitorInfo(monitor.win32.handle, &mi); + + if (xpos) + *xpos = mi.rcWork.left; + if (ypos) + *ypos = mi.rcWork.top; + if (width) + *width = mi.rcWork.right - mi.rcWork.left; + if (height) + *height = mi.rcWork.bottom - mi.rcWork.top; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { + int modeIndex = 0;int size = 0; + GLFWvidmode* result = null; + + *count = 0; + + for (;;) + { + int i; + GLFWvidmode mode; + DEVMODEW dm; + + memset(&dm, 0, typeof(dm).sizeof); + dm.dmSize = typeof(dm).sizeof; + + if (!EnumDisplaySettingsW(monitor.win32.adapterName.ptr, modeIndex, &dm)) + break; + + modeIndex++; + + // Skip modes with less than 15 BPP + if (dm.dmBitsPerPel < 15) + continue; + + mode.width = dm.dmPelsWidth; + mode.height = dm.dmPelsHeight; + mode.refreshRate = dm.dmDisplayFrequency; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode.redBits, + &mode.greenBits, + &mode.blueBits); + + for (i = 0; i < *count; i++) + { + if (_glfwCompareVideoModes(result + i, &mode) == 0) + break; + } + + // Skip duplicate modes + if (i < *count) + continue; + + if (monitor.win32.modesPruned) + { + // Skip modes not supported by the connected displays + if (ChangeDisplaySettingsExW(monitor.win32.adapterName.ptr, + &dm, + null, + CDS_TEST, + null) != DISP_CHANGE_SUCCESSFUL) + { + continue; + } + } + + if (*count == size) + { + size += 128; + result = cast(GLFWvidmode*) realloc(result, size * GLFWvidmode.sizeof); + } + + (*count)++; + result[*count - 1] = mode; + } + + if (!*count) + { + // HACK: Report the current mode if no valid modes were found + result = cast(GLFWvidmode*) calloc(1, GLFWvidmode.sizeof); + _glfwPlatformGetVideoMode(monitor, result); + *count = 1; + } + + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { + DEVMODEW dm; + memset(&dm, 0, typeof(dm).sizeof); + dm.dmSize = typeof(dm).sizeof; + + EnumDisplaySettingsW(monitor.win32.adapterName.ptr, ENUM_CURRENT_SETTINGS, &dm); + + mode.width = dm.dmPelsWidth; + mode.height = dm.dmPelsHeight; + mode.refreshRate = dm.dmDisplayFrequency; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode.redBits, + &mode.greenBits, + &mode.blueBits); +} + +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { + HDC dc; + WORD[256][3] values; + + dc = CreateDCW("DISPLAY"w.ptr, monitor.win32.adapterName.ptr, null, null); + GetDeviceGammaRamp(dc, values.ptr); + DeleteDC(dc); + + _glfwAllocGammaArrays(ramp, 256); + + memcpy(ramp.red, values[0].ptr, typeof(values[0]).sizeof); + memcpy(ramp.green, values[1].ptr, typeof(values[1]).sizeof); + memcpy(ramp.blue, values[2].ptr, typeof(values[2]).sizeof); + + return GLFW_TRUE; +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const(GLFWgammaramp)* ramp) { + HDC dc; + WORD[256][3] values; + + if (ramp.size != 256) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Gamma ramp size must be 256"); + return; + } + + memcpy(values[0].ptr, ramp.red, typeof((values[0])).sizeof); + memcpy(values[1].ptr, ramp.green, typeof((values[1])).sizeof); + memcpy(values[2].ptr, ramp.blue, typeof((values[2])).sizeof); + + dc = CreateDCW("DISPLAY"w.ptr, monitor.win32.adapterName.ptr, null, null); + SetDeviceGammaRamp(dc, values.ptr); + DeleteDC(dc); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +const(char)* glfwGetWin32Adapter(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return monitor.win32.publicAdapterName.ptr; +} + +const(char)* glfwGetWin32Monitor(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return monitor.win32.publicDisplayName.ptr; +} \ No newline at end of file diff --git a/source/glfw3/win32_platform.d b/source/glfw3/win32_platform.d new file mode 100644 index 0000000..ea3a428 --- /dev/null +++ b/source/glfw3/win32_platform.d @@ -0,0 +1,392 @@ +/// Translated from C to D +module glfw3.win32_platform; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +// GLFW uses DirectInput8 interfaces +enum DIRECTINPUT_VERSION = 0x0800; + +public import core.stdc.wctype; +public import core.sys.windows.windows; +public import core.sys.windows.winuser; +public import glfw3.directinput8; +public import glfw3.xinput; +public import core.sys.windows.objbase; // GUID +public import core.sys.windows.dbt; + +// TODO: make this @nogc nothrow upstream +@nogc nothrow extern (Windows) ULONGLONG VerSetConditionMask(ULONGLONG, DWORD, BYTE); + +// HACK: Define macros that some windows.h variants don't +enum WM_MOUSEHWHEEL = 0x020E; +enum WM_DWMCOMPOSITIONCHANGED = 0x031E; +enum WM_COPYGLOBALDATA = 0x0049; +//enum UNICODE_NOCHAR = 0xFFFF; +enum WM_DPICHANGED = 0x02E0; +int GET_XBUTTON_WPARAM(ulong w) {return HIWORD(w);} +enum EDS_ROTATEDMODE = 0x00000004; +enum DISPLAY_DEVICE_ACTIVE = 0x00000001; +enum _WIN32_WINNT_WINBLUE = 0x0602; +enum _WIN32_WINNT_WIN8 = 0x0602; +enum WM_GETDPISCALEDSIZE = 0x02e4; +enum USER_DEFAULT_SCREEN_DPI = 96; +enum OCR_HAND = 32649; + +// WINVER < 0x0601 +version(all) { + struct _CHANGEFILTERSTRUCT { + DWORD cbSize; + DWORD ExtStatus; + } + alias _CHANGEFILTERSTRUCT CHANGEFILTERSTRUCT; + + enum MSGFLT_ALLOW = 1; +} /*Windows 7*/ + +// WINVER < 0x0600 +version(all) { + enum DWM_BB_ENABLE = 0x00000001; + enum DWM_BB_BLURREGION = 0x00000002; + struct _DWM_BLURBEHIND { + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; + } + alias _DWM_BLURBEHIND DWM_BLURBEHIND; +} else { + //public import dwmapi; +} + +version (all) { + enum PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 + } + enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI + } + + enum DISP_CHANGE_BADDUALVIEW = -6; +} + +enum DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = cast(HANDLE) -4; + +// HACK: Define versionhelpers.h functions manually as MinGW lacks the header +static { + import core.sys.windows.sdkddkver: _WIN32_WINNT_WINXP, _WIN32_WINNT_VISTA, _WIN32_WINNT_WIN7; + // note: already in core.sys.windows.winver, but not @nogc + bool IsWindowsXPOrGreater() { + return cast(bool) _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINXP), + LOBYTE(_WIN32_WINNT_WINXP), 0); + } + bool IsWindowsVistaOrGreater() { + return cast(bool) _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), + LOBYTE(_WIN32_WINNT_VISTA), 0); + } + bool IsWindows7OrGreater() { + return cast(bool) _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN7), + LOBYTE(_WIN32_WINNT_WIN7), 0); + } + bool IsWindows8OrGreater() { + return cast(bool) _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN8), + LOBYTE(_WIN32_WINNT_WIN8), 0); + } + bool IsWindows8Point1OrGreater() { + return cast(bool) _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), + LOBYTE(_WIN32_WINNT_WINBLUE), 0); + } + + bool _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() { + return cast(bool) _glfwIsWindows10BuildOrGreaterWin32(14393); + } + bool _glfwIsWindows10CreatorsUpdateOrGreaterWin32() { + return cast(bool) _glfwIsWindows10BuildOrGreaterWin32(15063); + } + + auto GET_X_LPARAM(T)(T lp) { + import core.sys.windows.windef : LOWORD; + return (cast(int)cast(short)LOWORD(lp)); + } + auto GET_Y_LPARAM(T)(T lp) { + import core.sys.windows.windef : HIWORD; + return (cast(int)cast(short)HIWORD(lp)); + } +} + +// HACK: Define macros that some xinput.h variants don't +enum XINPUT_CAPS_WIRELESS = 0x0002; +enum XINPUT_DEVSUBTYPE_WHEEL = 0x02; +enum XINPUT_DEVSUBTYPE_ARCADE_STICK = 0x03; +enum XINPUT_DEVSUBTYPE_FLIGHT_STICK = 0x04; +enum XINPUT_DEVSUBTYPE_DANCE_PAD = 0x05; +enum XINPUT_DEVSUBTYPE_GUITAR = 0x06; +enum XINPUT_DEVSUBTYPE_DRUM_KIT = 0x08; +enum XINPUT_DEVSUBTYPE_ARCADE_PAD = 0x13; +enum XUSER_MAX_COUNT = 4; + +// HACK: Define macros that some dinput.h variants don't +enum DIDFT_OPTIONAL = 0x80000000; + +extern(Windows) { + // winmm.dll function pointer typedefs + alias PFN_timeGetTime = DWORD function(); + enum timeGetTime = "_glfw.win32.winmm.GetTime"; + + // xinput.dll function pointer typedefs + alias PFN_XInputGetCapabilities = DWORD function(DWORD,DWORD,XINPUT_CAPABILITIES*); + alias PFN_XInputGetState = DWORD function(DWORD,XINPUT_STATE*); + enum XInputGetCapabilities = "_glfw.win32.xinput.GetCapabilities"; + enum XInputGetState = "_glfw.win32.xinput.GetState"; + + // dinput8.dll function pointer typedefs + alias PFN_DirectInput8Create = HRESULT function(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN); + enum DirectInput8Create = "_glfw.win32.dinput8.Create"; + + // user32.dll function pointer typedefs + alias PFN_SetProcessDPIAware = BOOL function(); + alias PFN_ChangeWindowMessageFilterEx = BOOL function(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*); + alias PFN_EnableNonClientDpiScaling = BOOL function(HWND); + alias PFN_SetProcessDpiAwarenessContext = BOOL function(HANDLE); + alias PFN_GetDpiForWindow = UINT function(HWND); + alias PFN_AdjustWindowRectExForDpi = BOOL function(LPRECT,DWORD,BOOL,DWORD,UINT); + enum SetProcessDPIAware = "_glfw.win32.user32.SetProcessDPIAware_"; + enum ChangeWindowMessageFilterEx = "_glfw.win32.user32.ChangeWindowMessageFilterEx_"; + enum EnableNonClientDpiScaling = "_glfw.win32.user32.EnableNonClientDpiScaling_"; + enum SetProcessDpiAwarenessContext = "_glfw.win32.user32.SetProcessDpiAwarenessContext_"; + enum GetDpiForWindow = "_glfw.win32.user32.GetDpiForWindow_"; + enum AdjustWindowRectExForDpi = "_glfw.win32.user32.AdjustWindowRectExForDpi_"; + + // dwmapi.dll function pointer typedefs + alias PFN_DwmIsCompositionEnabled = HRESULT function(BOOL*); + alias PFN_DwmFlush = HRESULT function(); + alias PFN_DwmEnableBlurBehindWindow = HRESULT function(HWND, const(DWM_BLURBEHIND)*); + enum DwmIsCompositionEnabled = "_glfw.win32.dwmapi.IsCompositionEnabled"; + enum DwmFlush = "_glfw.win32.dwmapi.Flush"; + enum DwmEnableBlurBehindWindow = "_glfw.win32.dwmapi.EnableBlurBehindWindow"; + + // shcore.dll function pointer typedefs + alias PFN_SetProcessDpiAwareness = HRESULT function(PROCESS_DPI_AWARENESS); + alias PFN_GetDpiForMonitor = HRESULT function(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); + enum SetProcessDpiAwareness = "_glfw.win32.shcore.SetProcessDpiAwareness_"; + enum GetDpiForMonitor = "_glfw.win32.shcore.GetDpiForMonitor_"; + + // ntdll.dll function pointer typedefs + alias PFN_RtlVerifyVersionInfo = LONG function(OSVERSIONINFOEXW*,ULONG,ULONGLONG); + alias RtlVerifyVersionInfo = _glfw.win32.ntdll.RtlVerifyVersionInfo_; +} + +alias VkFlags VkWin32SurfaceCreateFlagsKHR; + +struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const(void)* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} + +alias PFN_vkCreateWin32SurfaceKHR = VkResult function(VkInstance, const(VkWin32SurfaceCreateInfoKHR)*, const(VkAllocationCallbacks)*, VkSurfaceKHR*); +alias PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR = VkBool32 function(VkPhysicalDevice, uint32_t); + +public import glfw3.win32_joystick; +public import glfw3.wgl_context; +public import glfw3.egl_context; +public import glfw3.osmesa_context; + +enum _GLFW_WNDCLASSNAME = "GLFW30"w; + +auto _glfw_dlopen(const(char)* name) { return LoadLibraryA(name); } +auto _glfw_dlclose(void* handle) { return FreeLibrary(cast(HMODULE) handle); } +auto _glfw_dlsym(void* handle, const(char)* name) { return GetProcAddress(cast(HMODULE) handle, name);} + +enum _GLFW_EGL_NATIVE_WINDOW = "cast(EGLNativeWindowType) window.win32.handle"; +enum _GLFW_EGL_NATIVE_DISPLAY = EGL_DEFAULT_DISPLAY; + +mixin template _GLFW_PLATFORM_WINDOW_STATE() { _GLFWwindowWin32 win32;} +mixin template _GLFW_PLATFORM_LIBRARY_WINDOW_STATE() {_GLFWlibraryWin32 win32;} +mixin template _GLFW_PLATFORM_LIBRARY_TIMER_STATE() { _GLFWtimerWin32 win32;} +mixin template _GLFW_PLATFORM_MONITOR_STATE() { _GLFWmonitorWin32 win32;} +mixin template _GLFW_PLATFORM_CURSOR_STATE() { _GLFWcursorWin32 win32;} +mixin template _GLFW_PLATFORM_TLS_STATE() { _GLFWtlsWin32 win32;} +mixin template _GLFW_PLATFORM_MUTEX_STATE() { _GLFWmutexWin32 win32;} + +// Win32-specific per-window data +// +struct _GLFWwindowWin32 { + HWND handle; + HICON bigIcon; + HICON smallIcon; + + GLFWbool cursorTracked; + GLFWbool frameAction; + GLFWbool iconified; + GLFWbool maximized; + // Whether to enable framebuffer transparency on DWM + GLFWbool transparent; + GLFWbool scaleToMonitor; + + // The last received cursor position, regardless of source + int lastCursorPosX;int lastCursorPosY; + +}/+alias _GLFWwindowWin32 _GLFWwindowWin32;+/ + +// Win32-specific global data +// +struct _GLFWlibraryWin32 { + import core.sys.windows.winuser: HDEVNOTIFY; + HWND helperWindowHandle; + HDEVNOTIFY deviceNotificationHandle; + DWORD foregroundLockTimeout; + int acquiredMonitorCount; + char* clipboardString; + int[512] keycodes; + int[GLFW_KEY_LAST + 1] scancodes; + char[5][GLFW_KEY_LAST + 1] keynames; + // Where to place the cursor when re-enabled + double restoreCursorPosX;double restoreCursorPosY; + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + RAWINPUT* rawInput; + int rawInputSize; + UINT mouseTrailSize; + + struct _Winmm { + HINSTANCE instance; + PFN_timeGetTime GetTime; + }_Winmm winmm; + + struct _Dinput8 { + HINSTANCE instance; + PFN_DirectInput8Create Create; + IDirectInput8W* api; + }_Dinput8 dinput8; + + struct _Xinput { + HINSTANCE instance; + PFN_XInputGetCapabilities GetCapabilities; + PFN_XInputGetState GetState; + }_Xinput xinput; + + struct _User32 { + HINSTANCE instance; + PFN_SetProcessDPIAware SetProcessDPIAware_; + PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_; + PFN_EnableNonClientDpiScaling EnableNonClientDpiScaling_; + PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_; + PFN_GetDpiForWindow GetDpiForWindow_; + PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_; + }_User32 user32; + + struct _Dwmapi { + HINSTANCE instance; + PFN_DwmIsCompositionEnabled IsCompositionEnabled; + PFN_DwmFlush Flush; + PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; + }_Dwmapi dwmapi; + + struct _Shcore { + HINSTANCE instance; + PFN_SetProcessDpiAwareness SetProcessDpiAwareness_; + PFN_GetDpiForMonitor GetDpiForMonitor_; + }_Shcore shcore; + + struct _Ntdll { + HINSTANCE instance; + PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; + }_Ntdll ntdll; + +}/+alias _GLFWlibraryWin32 _GLFWlibraryWin32;+/ + +// Win32-specific per-monitor data +// +struct _GLFWmonitorWin32 { + HMONITOR handle; + // This size matches the static size of DISPLAY_DEVICE.DeviceName + WCHAR[32] adapterName; + WCHAR[32] displayName; + char[32] publicAdapterName; + char[32] publicDisplayName; + GLFWbool modesPruned; + GLFWbool modeChanged; + +}/+alias _GLFWmonitorWin32 _GLFWmonitorWin32;+/ + +// Win32-specific per-cursor data +// +struct _GLFWcursorWin32 { + HCURSOR handle; + +}/+alias _GLFWcursorWin32 _GLFWcursorWin32;+/ + +// Win32-specific global timer data +// +struct _GLFWtimerWin32 { + GLFWbool hasPC; + ulong frequency; + +}/+alias _GLFWtimerWin32 _GLFWtimerWin32;+/ + +// Win32-specific thread local storage data +// +struct _GLFWtlsWin32 { + GLFWbool allocated; + DWORD index; + +}/+alias _GLFWtlsWin32 _GLFWtlsWin32;+/ + +// Win32-specific mutex data +// +struct _GLFWmutexWin32 { + GLFWbool allocated; + CRITICAL_SECTION section; + +}/+alias _GLFWmutexWin32 _GLFWmutexWin32;+/ + + +GLFWbool _glfwRegisterWindowClassWin32(); +void _glfwUnregisterWindowClassWin32(); + +wchar* _glfwCreateWideStringFromUTF8Win32(const(char)* source); +char* _glfwCreateUTF8FromWideStringWin32(const(wchar)* source); +BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp); +BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build); +void _glfwInputErrorWin32(int error, const(char)* description); +void _glfwUpdateKeyNamesWin32(); + +void _glfwInitTimerWin32(); + +void _glfwPollMonitorsWin32(); +void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const(GLFWvidmode)* desired); +void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor); +void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale); \ No newline at end of file diff --git a/source/glfw3/win32_thread.d b/source/glfw3/win32_thread.d new file mode 100644 index 0000000..764e52e --- /dev/null +++ b/source/glfw3/win32_thread.d @@ -0,0 +1,94 @@ +/// Translated from C to D +module glfw3.win32_thread; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +public import glfw3.internal; + +import core.stdc.assert_; +import core.stdc.string: memset; + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) { + assert(tls.win32.allocated == GLFW_FALSE); + + tls.win32.index = TlsAlloc(); + if (tls.win32.index == TLS_OUT_OF_INDEXES) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate TLS index"); + return GLFW_FALSE; + } + + tls.win32.allocated = GLFW_TRUE; + return GLFW_TRUE; +} + +void _glfwPlatformDestroyTls(_GLFWtls* tls) { + if (tls.win32.allocated) + TlsFree(tls.win32.index); + memset(tls, 0, _GLFWtls.sizeof); +} + +void* _glfwPlatformGetTls(_GLFWtls* tls) { + assert(tls.win32.allocated == GLFW_TRUE); + return TlsGetValue(tls.win32.index); +} + +void _glfwPlatformSetTls(_GLFWtls* tls, void* value) { + assert(tls.win32.allocated == GLFW_TRUE); + TlsSetValue(tls.win32.index, value); +} + +GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex) { + assert(mutex.win32.allocated == GLFW_FALSE); + InitializeCriticalSection(&mutex.win32.section); + return mutex.win32.allocated = GLFW_TRUE; +} + +void _glfwPlatformDestroyMutex(_GLFWmutex* mutex) { + if (mutex.win32.allocated) + DeleteCriticalSection(&mutex.win32.section); + memset(mutex, 0, _GLFWmutex.sizeof); +} + +void _glfwPlatformLockMutex(_GLFWmutex* mutex) { + assert(mutex.win32.allocated == GLFW_TRUE); + EnterCriticalSection(&mutex.win32.section); +} + +void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) { + assert(mutex.win32.allocated == GLFW_TRUE); + LeaveCriticalSection(&mutex.win32.section); +} \ No newline at end of file diff --git a/source/glfw3/win32_time.d b/source/glfw3/win32_time.d new file mode 100644 index 0000000..fd5c5ca --- /dev/null +++ b/source/glfw3/win32_time.d @@ -0,0 +1,76 @@ +/// Translated from C to D +module glfw3.win32_time; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +public import glfw3.internal; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimerWin32() { + ulong frequency; + + if (QueryPerformanceFrequency(cast(LARGE_INTEGER*) &frequency)) + { + _glfw.timer.win32.hasPC = GLFW_TRUE; + _glfw.timer.win32.frequency = frequency; + } + else + { + _glfw.timer.win32.hasPC = GLFW_FALSE; + _glfw.timer.win32.frequency = 1000; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +ulong _glfwPlatformGetTimerValue() { + if (_glfw.timer.win32.hasPC) + { + ulong value; + QueryPerformanceCounter(cast(LARGE_INTEGER*) &value); + return value; + } + else + return cast(ulong) _glfw.win32.winmm.GetTime(); +} + +ulong _glfwPlatformGetTimerFrequency() { + return _glfw.timer.win32.frequency; +} \ No newline at end of file diff --git a/source/glfw3/win32_window.d b/source/glfw3/win32_window.d new file mode 100644 index 0000000..eaebc8b --- /dev/null +++ b/source/glfw3/win32_window.d @@ -0,0 +1,2146 @@ +/// Translated from C to D +module glfw3.win32_window; + +extern(C): __gshared: +// @nogc: nothrow: + +//======================================================================== +// GLFW 3.3 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +public import glfw3.internal; + +public import glfw3.win32_platform: IsWindowsVistaOrGreater, IsWindowsXPOrGreater, IsWindows7OrGreater; + +import core.stdc.limits; +import core.stdc.stdlib; +import core.stdc.string; +import core.sys.windows.windows; +//public import windowsx; +//public import shellapi; + +// Returns the window style for the specified window +// +static DWORD getWindowStyle(const(_GLFWwindow)* window) { + DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + + if (window.monitor) + style |= WS_POPUP; + else + { + style |= WS_SYSMENU | WS_MINIMIZEBOX; + + if (window.decorated) + { + style |= WS_CAPTION; + + if (window.resizable) + style |= WS_MAXIMIZEBOX | WS_THICKFRAME; + } + else + style |= WS_POPUP; + } + + return style; +} + +// Returns the extended window style for the specified window +// +static DWORD getWindowExStyle(const(_GLFWwindow)* window) { + DWORD style = WS_EX_APPWINDOW; + + if (window.monitor || window.floating) + style |= WS_EX_TOPMOST; + + return style; +} + +// Returns the image whose area most closely matches the desired one +// +static const(GLFWimage)* chooseImage(int count, const(GLFWimage)* images, int width, int height) { + int i;int leastDiff = INT_MAX; + const(GLFWimage)* closest = null; + + for (i = 0; i < count; i++) + { + const(int) currDiff = abs(images[i].width * images[i].height - + width * height); + if (currDiff < leastDiff) + { + closest = images + i; + leastDiff = currDiff; + } + } + + return closest; +} + +// Creates an RGBA icon or cursor +// +static HICON createIcon(const(GLFWimage)* image, int xhot, int yhot, GLFWbool icon) { + int i; + HDC dc; + HICON handle; + HBITMAP color;HBITMAP mask; + BITMAPV5HEADER bi; + ICONINFO ii; + ubyte* target = null; + const(ubyte)* source = image.pixels; + + memset(&bi, 0, typeof(bi).sizeof); + bi.bV5Size = typeof(bi).sizeof; + bi.bV5Width = image.width; + bi.bV5Height = -image.height; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00ff0000; + bi.bV5GreenMask = 0x0000ff00; + bi.bV5BlueMask = 0x000000ff; + bi.bV5AlphaMask = 0xff000000; + + dc = GetDC(null); + color = CreateDIBSection(dc, + cast(BITMAPINFO*) &bi, + DIB_RGB_COLORS, + cast(void**) &target, + null, + cast(DWORD) 0); + ReleaseDC(null, dc); + + if (!color) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create RGBA bitmap"); + return null; + } + + mask = CreateBitmap(image.width, image.height, 1, 1, null); + if (!mask) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create mask bitmap"); + DeleteObject(color); + return null; + } + + for (i = 0; i < image.width * image.height; i++) + { + target[0] = source[2]; + target[1] = source[1]; + target[2] = source[0]; + target[3] = source[3]; + target += 4; + source += 4; + } + + memset(&ii, 0, typeof(ii).sizeof); + ii.fIcon = icon; + ii.xHotspot = xhot; + ii.yHotspot = yhot; + ii.hbmMask = mask; + ii.hbmColor = color; + + handle = CreateIconIndirect(&ii); + + DeleteObject(color); + DeleteObject(mask); + + if (!handle) + { + if (icon) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create icon"); + } + else + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create cursor"); + } + } + + return handle; +} + +// Translate content area size to full window size according to styles and DPI +// +static void getFullWindowSize(DWORD style, DWORD exStyle, int contentWidth, int contentHeight, int* fullWidth, int* fullHeight, UINT dpi) { + RECT rect = RECT(0, 0, contentWidth, contentHeight); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + mixin(AdjustWindowRectExForDpi)(&rect, style, FALSE, exStyle, dpi); + else + /*DynCall*/AdjustWindowRectEx(&rect, style, FALSE, exStyle); + + *fullWidth = rect.right - rect.left; + *fullHeight = rect.bottom - rect.top; +} +// Enforce the content area aspect ratio based on which edge is being dragged +// +static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) { + int xoff;int yoff; + UINT dpi = USER_DEFAULT_SCREEN_DPI; + const(float) ratio = cast(float) window.numer / cast(float) window.denom; + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + dpi = mixin(GetDpiForWindow)(window.win32.handle); + + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + 0, 0, &xoff, &yoff, dpi); + + if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || + edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) + { + area.bottom = area.top + yoff + + cast(int) ((area.right - area.left - xoff) / ratio); + } + else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) + { + area.top = area.bottom - yoff - + cast(int) ((area.right - area.left - xoff) / ratio); + } + else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) + { + area.right = area.left + xoff + + cast(int) ((area.bottom - area.top - yoff) * ratio); + } +} + +// Updates the cursor image according to its cursor mode +// +static void updateCursorImage(_GLFWwindow* window) { + if (window.cursorMode == GLFW_CURSOR_NORMAL) + { + if (window.cursor) + SetCursor(window.cursor.win32.handle); + else + SetCursor(LoadCursorW(null, IDC_ARROW)); + } + else + SetCursor(null); +} + +// Updates the cursor clip rect +// +static void updateClipRect(_GLFWwindow* window) { + if (window) + { + RECT clipRect; + GetClientRect(cast(void*) window.win32.handle, &clipRect); + ClientToScreen(cast(void*) window.win32.handle, cast(POINT*) &clipRect.left); + ClientToScreen(cast(void*) window.win32.handle, cast(POINT*) &clipRect.right); + ClipCursor(&clipRect); + } + else + ClipCursor(null); +} + +// Enables WM_INPUT messages for the mouse for the specified window +// +static void enableRawMouseMotion(_GLFWwindow* window) { + const(RAWINPUTDEVICE) rid = RAWINPUTDEVICE( 0x01, 0x02, 0, cast(void*) window.win32.handle ); + + if (!RegisterRawInputDevices(&rid, 1, typeof(rid).sizeof)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register raw input device"); + } +} + +// Disables WM_INPUT messages for the mouse +// +static void disableRawMouseMotion(_GLFWwindow* window) { + const RAWINPUTDEVICE rid = RAWINPUTDEVICE(0x01, 0x02, RIDEV_REMOVE, null); + + if (!RegisterRawInputDevices(&rid, 1, typeof(rid).sizeof)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to remove raw input device"); + } +} + +// Apply disabled cursor mode to a focused window +// +static void disableCursor(_GLFWwindow* window) { + _glfw.win32.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); + updateCursorImage(window); + _glfwCenterCursorInContentArea(window); + updateClipRect(window); + + if (window.rawMouseMotion) + enableRawMouseMotion(window); +} + +// Exit disabled cursor mode for the specified window +// +static void enableCursor(_GLFWwindow* window) { + if (window.rawMouseMotion) + disableRawMouseMotion(window); + + _glfw.win32.disabledCursorWindow = null; + updateClipRect(null); + _glfwPlatformSetCursorPos(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); + updateCursorImage(window); +} + +// Returns whether the cursor is in the content area of the specified window +// +static GLFWbool cursorInContentArea(_GLFWwindow* window) { + RECT area; + POINT pos; + + if (!GetCursorPos(&pos)) + return GLFW_FALSE; + + if (WindowFromPoint(pos) != window.win32.handle) + return GLFW_FALSE; + + GetClientRect(cast(void*) window.win32.handle, &area); + ClientToScreen(cast(void*) window.win32.handle, cast(POINT*) &area.left); + ClientToScreen(cast(void*) window.win32.handle, cast(POINT*) &area.right); + + return PtInRect(&area, pos); +} + +// Update native window styles to match attributes +// +static void updateWindowStyles(const(_GLFWwindow)* window) { + RECT rect; + DWORD style = GetWindowLongW(cast(void*) window.win32.handle, GWL_STYLE); + style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP); + style |= getWindowStyle(window); + + GetClientRect(cast(void*) window.win32.handle, &rect); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + mixin(AdjustWindowRectExForDpi)(&rect, style, FALSE, + getWindowExStyle(window), + mixin(GetDpiForWindow)(cast(void*) window.win32.handle)); + } + else + AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window)); + + ClientToScreen(cast(void*) window.win32.handle, cast(POINT*) &rect.left); + ClientToScreen(cast(void*) window.win32.handle, cast(POINT*) &rect.right); + SetWindowLongW(cast(void*) window.win32.handle, GWL_STYLE, style); + SetWindowPos(cast(void*) window.win32.handle, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER); +} + +// Update window framebuffer transparency +// +static void updateFramebufferTransparency(const(_GLFWwindow)* window) { + BOOL enabled; + + if (!IsWindowsVistaOrGreater()) + return; + + if (SUCCEEDED(_glfw.win32.dwmapi.IsCompositionEnabled(&enabled)) && enabled) + { + HRGN region = CreateRectRgn(0, 0, -1, -1); + DWM_BLURBEHIND bb = DWM_BLURBEHIND(0); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = region; + bb.fEnable = TRUE; + + if (SUCCEEDED(_glfw.win32.dwmapi.EnableBlurBehindWindow(cast(void*) window.win32.handle, &bb))) + { + // Decorated windows don't repaint the transparent background + // leaving a trail behind animations + // HACK: Making the window layered with a transparency color key + // seems to fix this. Normally, when specifying + // a transparency color key to be used when composing the + // layered window, all pixels painted by the window in this + // color will be transparent. That doesn't seem to be the + // case anymore, at least when used with blur behind window + // plus negative region. + LONG exStyle = GetWindowLongW(cast(void*) window.win32.handle, GWL_EXSTYLE); + exStyle |= WS_EX_LAYERED; + SetWindowLongW(cast(void*) window.win32.handle, GWL_EXSTYLE, exStyle); + + // Using a color key not equal to black to fix the trailing + // issue. When set to black, something is making the hit test + // not resize with the window frame. + SetLayeredWindowAttributes(cast(void*) window.win32.handle, + RGB(255, 0, 255), 255, LWA_COLORKEY); + } + + DeleteObject(region); + } + else + { + LONG exStyle = GetWindowLongW(cast(void*) window.win32.handle, GWL_EXSTYLE); + exStyle &= ~WS_EX_LAYERED; + SetWindowLongW(cast(void*) window.win32.handle, GWL_EXSTYLE, exStyle); + RedrawWindow(cast(void*) window.win32.handle, null, null, + RDW_ERASE | RDW_INVALIDATE | RDW_FRAME); + } +} + +// Retrieves and translates modifier keys +// +static int getKeyMods() { + int mods = 0; + + if (GetKeyState(VK_SHIFT) & 0x8000) + mods |= GLFW_MOD_SHIFT; + if (GetKeyState(VK_CONTROL) & 0x8000) + mods |= GLFW_MOD_CONTROL; + if (GetKeyState(VK_MENU) & 0x8000) + mods |= GLFW_MOD_ALT; + if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) + mods |= GLFW_MOD_SUPER; + if (GetKeyState(VK_CAPITAL) & 1) + mods |= GLFW_MOD_CAPS_LOCK; + if (GetKeyState(VK_NUMLOCK) & 1) + mods |= GLFW_MOD_NUM_LOCK; + + return mods; +} + +static void fitToMonitor(_GLFWwindow* window) { + MONITORINFO mi = MONITORINFO(MONITORINFO.sizeof); + GetMonitorInfo(window.monitor.win32.handle, &mi); + SetWindowPos(cast(void*) window.win32.handle, HWND_TOPMOST, + mi.rcMonitor.left, + mi.rcMonitor.top, + mi.rcMonitor.right - mi.rcMonitor.left, + mi.rcMonitor.bottom - mi.rcMonitor.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS); +} + +// Make the specified window and its video mode active on its monitor +// +static void acquireMonitor(_GLFWwindow* window) { + if (!_glfw.win32.acquiredMonitorCount) + { + SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); + + // HACK: When mouse trails are enabled the cursor becomes invisible when + // the OpenGL ICD switches to page flipping + if (IsWindowsXPOrGreater()) + { + SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0); + SystemParametersInfo(SPI_SETMOUSETRAILS, 0, null, 0); + } + } + + if (!window.monitor.window) + _glfw.win32.acquiredMonitorCount++; + + _glfwSetVideoModeWin32(window.monitor, &window.videoMode); + _glfwInputMonitorWindow(window.monitor, window); +} + +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) { + if (window.monitor.window != window) + return; + + _glfw.win32.acquiredMonitorCount--; + if (!_glfw.win32.acquiredMonitorCount) + { + SetThreadExecutionState(ES_CONTINUOUS); + + // HACK: Restore mouse trail length saved in acquireMonitor + if (IsWindowsXPOrGreater()) + SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, null, 0); + } + + _glfwInputMonitorWindow(window.monitor, null); + _glfwRestoreVideoModeWin32(window.monitor); +} + +// Window callback function (handles window messages) +// +static LRESULT windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + auto window = cast(_GLFWwindow*) GetPropW(hWnd, "GLFW"w.ptr); + if (!window) + { + // This is the message handling for the hidden helper window + // and for a regular window during its initial creation + + switch (uMsg) + { + case WM_NCCREATE: + { + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + mixin(EnableNonClientDpiScaling)(hWnd); + + break; + } + + case WM_DISPLAYCHANGE: + _glfwPollMonitorsWin32(); + break; + + case WM_DEVICECHANGE: + { + if (wParam == DBT_DEVICEARRIVAL) + { + DEV_BROADCAST_HDR* dbh = cast(DEV_BROADCAST_HDR*) lParam; + if (dbh && dbh.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickConnectionWin32(); + } + else if (wParam == DBT_DEVICEREMOVECOMPLETE) + { + DEV_BROADCAST_HDR* dbh = cast(DEV_BROADCAST_HDR*) lParam; + if (dbh && dbh.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + _glfwDetectJoystickDisconnectionWin32(); + } + + break; + } + default: break; + } + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + + switch (uMsg) + { + case WM_MOUSEACTIVATE: + { + // HACK: Postpone cursor disabling when the window was activated by + // clicking a caption button + if (HIWORD(lParam) == WM_LBUTTONDOWN) + { + if (LOWORD(lParam) != HTCLIENT) + window.win32.frameAction = GLFW_TRUE; + } + + break; + } + + case WM_CAPTURECHANGED: + { + // HACK: Disable the cursor once the caption button action has been + // completed or cancelled + if (lParam == 0 && window.win32.frameAction) + { + if (window.cursorMode == GLFW_CURSOR_DISABLED) + disableCursor(window); + + window.win32.frameAction = GLFW_FALSE; + } + + break; + } + + case WM_SETFOCUS: + { + _glfwInputWindowFocus(window, GLFW_TRUE); + + // HACK: Do not disable cursor while the user is interacting with + // a caption button + if (window.win32.frameAction) + break; + + if (window.cursorMode == GLFW_CURSOR_DISABLED) + disableCursor(window); + + return 0; + } + + case WM_KILLFOCUS: + { + if (window.cursorMode == GLFW_CURSOR_DISABLED) + enableCursor(window); + + if (window.monitor && window.autoIconify) + _glfwPlatformIconifyWindow(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); + return 0; + } + + case WM_SYSCOMMAND: + { + switch (wParam & 0xfff0) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + { + if (window.monitor) + { + // We are running in full screen mode, so disallow + // screen saver and screen blanking + return 0; + } + else + break; + } + + // User trying to access application menu using ALT? + case SC_KEYMENU: + return 0; + default: break; + } + break; + } + + case WM_CLOSE: + { + _glfwInputWindowCloseRequest(window); + return 0; + } + + case WM_INPUTLANGCHANGE: + { + _glfwUpdateKeyNamesWin32(); + break; + } + + case WM_CHAR: + case WM_SYSCHAR: + case WM_UNICHAR: + { + const(GLFWbool) plain = (uMsg != WM_SYSCHAR); + + if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR) + { + // WM_UNICHAR is not sent by Windows, but is sent by some + // third-party input method engine + // Returning TRUE here announces support for this message + return TRUE; + } + + _glfwInputChar(window, cast(uint) wParam, getKeyMods(), plain); + return 0; + } + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + { + int key;int scancode; + const(int) action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS; + const(int) mods = getKeyMods(); + + scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); + if (!scancode) + { + // NOTE: Some synthetic key messages have a scancode of zero + // HACK: Map the virtual key back to a usable scancode + scancode = MapVirtualKeyW(cast(UINT) wParam, MAPVK_VK_TO_VSC); + } + + key = _glfw.win32.keycodes[scancode]; + + // The Ctrl keys require special handling + if (wParam == VK_CONTROL) + { + if (HIWORD(lParam) & KF_EXTENDED) + { + // Right side keys have the extended key bit set + key = GLFW_KEY_RIGHT_CONTROL; + } + else + { + // NOTE: Alt Gr sends Left Ctrl followed by Right Alt + // HACK: We only want one event for Alt Gr, so if we detect + // this sequence we discard this Left Ctrl message now + // and later report Right Alt normally + MSG next; + const(DWORD) time = GetMessageTime(); + + if (PeekMessageW(&next, null, 0, 0, PM_NOREMOVE)) + { + if (next.message == WM_KEYDOWN || + next.message == WM_SYSKEYDOWN || + next.message == WM_KEYUP || + next.message == WM_SYSKEYUP) + { + if (next.wParam == VK_MENU && + (HIWORD(next.lParam) & KF_EXTENDED) && + next.time == time) + { + // Next message is Right Alt down so discard this + break; + } + } + } + + // This is a regular Left Ctrl message + key = GLFW_KEY_LEFT_CONTROL; + } + } + else if (wParam == VK_PROCESSKEY) + { + // IME notifies that keys have been filtered by setting the + // virtual key-code to VK_PROCESSKEY + break; + } + + if (action == GLFW_RELEASE && wParam == VK_SHIFT) + { + // HACK: Release both Shift keys on Shift up event, as when both + // are pressed the first release does not emit any event + // NOTE: The other half of this is in _glfwPlatformPollEvents + _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods); + _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods); + } + else if (wParam == VK_SNAPSHOT) + { + // HACK: Key down is not reported for the Print Screen key + _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); + _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); + } + else + _glfwInputKey(window, key, scancode, action, mods); + + break; + } + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + int i;int button;int action; + + if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP) + button = GLFW_MOUSE_BUTTON_LEFT; + else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP) + button = GLFW_MOUSE_BUTTON_RIGHT; + else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP) + button = GLFW_MOUSE_BUTTON_MIDDLE; + else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) + button = GLFW_MOUSE_BUTTON_4; + else + button = GLFW_MOUSE_BUTTON_5; + + if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || + uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN) + { + action = GLFW_PRESS; + } + else + action = GLFW_RELEASE; + + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window.mouseButtons[i] == GLFW_PRESS) + break; + } + + if (i > GLFW_MOUSE_BUTTON_LAST) + SetCapture(hWnd); + + _glfwInputMouseClick(window, button, action, getKeyMods()); + + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window.mouseButtons[i] == GLFW_PRESS) + break; + } + + if (i > GLFW_MOUSE_BUTTON_LAST) + ReleaseCapture(); + + if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) + return TRUE; + + return 0; + } + + case WM_MOUSEMOVE: + { + const(int) x = GET_X_LPARAM(lParam); + const(int) y = GET_Y_LPARAM(lParam); + + if (!window.win32.cursorTracked) + { + TRACKMOUSEEVENT tme; + memset(&tme, 0, typeof(tme).sizeof); + tme.cbSize = typeof(tme).sizeof; + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = window.win32.handle; + TrackMouseEvent(&tme); + + window.win32.cursorTracked = GLFW_TRUE; + _glfwInputCursorEnter(window, GLFW_TRUE); + } + + if (window.cursorMode == GLFW_CURSOR_DISABLED) + { + const(int) dx = x - window.win32.lastCursorPosX; + const(int) dy = y - window.win32.lastCursorPosY; + + if (_glfw.win32.disabledCursorWindow != window) + break; + if (window.rawMouseMotion) + break; + + _glfwInputCursorPos(window, + window.virtualCursorPosX + dx, + window.virtualCursorPosY + dy); + } + else + _glfwInputCursorPos(window, x, y); + + window.win32.lastCursorPosX = x; + window.win32.lastCursorPosY = y; + + return 0; + } + + case WM_INPUT: + { + UINT size = 0; + HRAWINPUT ri = cast(HRAWINPUT) lParam; + RAWINPUT* data = null; + int dx;int dy; + + if (_glfw.win32.disabledCursorWindow != window) + break; + if (!window.rawMouseMotion) + break; + + GetRawInputData(ri, RID_INPUT, null, &size, RAWINPUTHEADER.sizeof); + if (size > cast(UINT) _glfw.win32.rawInputSize) + { + free(_glfw.win32.rawInput); + _glfw.win32.rawInput = cast(RAWINPUT*) calloc(size, 1); + _glfw.win32.rawInputSize = size; + } + + size = _glfw.win32.rawInputSize; + if (GetRawInputData(ri, RID_INPUT, + _glfw.win32.rawInput, &size, + RAWINPUTHEADER.sizeof) == cast(UINT) -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve raw input data"); + break; + } + + data = _glfw.win32.rawInput; + if (data.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) + { + dx = data.data.mouse.lLastX - window.win32.lastCursorPosX; + dy = data.data.mouse.lLastY - window.win32.lastCursorPosY; + } + else + { + dx = data.data.mouse.lLastX; + dy = data.data.mouse.lLastY; + } + + _glfwInputCursorPos(window, + window.virtualCursorPosX + dx, + window.virtualCursorPosY + dy); + + window.win32.lastCursorPosX += dx; + window.win32.lastCursorPosY += dy; + break; + } + + case WM_MOUSELEAVE: + { + window.win32.cursorTracked = GLFW_FALSE; + _glfwInputCursorEnter(window, GLFW_FALSE); + return 0; + } + + case WM_MOUSEWHEEL: + { + _glfwInputScroll(window, 0.0, cast(SHORT) HIWORD(wParam) / cast(double) WHEEL_DELTA); + return 0; + } + + case WM_MOUSEHWHEEL: + { + // This message is only sent on Windows Vista and later + // NOTE: The X-axis is inverted for consistency with macOS and X11 + _glfwInputScroll(window, -(cast(SHORT) HIWORD(wParam) / cast(double) WHEEL_DELTA), 0.0); + return 0; + } + + case WM_ENTERSIZEMOVE: + case WM_ENTERMENULOOP: + { + if (window.win32.frameAction) + break; + + // HACK: Enable the cursor while the user is moving or + // resizing the window or using the window menu + if (window.cursorMode == GLFW_CURSOR_DISABLED) + enableCursor(window); + + break; + } + + case WM_EXITSIZEMOVE: + case WM_EXITMENULOOP: + { + if (window.win32.frameAction) + break; + + // HACK: Disable the cursor once the user is done moving or + // resizing the window or using the menu + if (window.cursorMode == GLFW_CURSOR_DISABLED) + disableCursor(window); + + break; + } + + case WM_SIZE: + { + const(GLFWbool) iconified = wParam == SIZE_MINIMIZED; + const(GLFWbool) maximized = wParam == SIZE_MAXIMIZED || + (window.win32.maximized && + wParam != SIZE_RESTORED); + + if (_glfw.win32.disabledCursorWindow == window) + updateClipRect(window); + + if (window.win32.iconified != iconified) + _glfwInputWindowIconify(window, iconified); + + if (window.win32.maximized != maximized) + _glfwInputWindowMaximize(window, maximized); + + _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); + _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); + + if (window.monitor && window.win32.iconified != iconified) + { + if (iconified) + releaseMonitor(window); + else + { + acquireMonitor(window); + fitToMonitor(window); + } + } + + window.win32.iconified = iconified; + window.win32.maximized = maximized; + return 0; + } + + case WM_MOVE: + { + if (_glfw.win32.disabledCursorWindow == window) + updateClipRect(window); + + // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as + // those macros do not handle negative window positions correctly + _glfwInputWindowPos(window, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam)); + return 0; + } + + case WM_SIZING: + { + if (window.numer == GLFW_DONT_CARE || + window.denom == GLFW_DONT_CARE) + { + break; + } + + applyAspectRatio(window, cast(int) wParam, cast(RECT*) lParam); + return TRUE; + } + + case WM_GETMINMAXINFO: + { + int xoff;int yoff; + UINT dpi = USER_DEFAULT_SCREEN_DPI; + MINMAXINFO* mmi = cast(MINMAXINFO*) lParam; + + if (window.monitor) + break; + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + dpi = mixin(GetDpiForWindow)(cast(void*) window.win32.handle); + + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), + 0, 0, &xoff, &yoff, dpi); + + if (window.minwidth != GLFW_DONT_CARE && + window.minheight != GLFW_DONT_CARE) + { + mmi.ptMinTrackSize.x = window.minwidth + xoff; + mmi.ptMinTrackSize.y = window.minheight + yoff; + } + + if (window.maxwidth != GLFW_DONT_CARE && + window.maxheight != GLFW_DONT_CARE) + { + mmi.ptMaxTrackSize.x = window.maxwidth + xoff; + mmi.ptMaxTrackSize.y = window.maxheight + yoff; + } + + if (!window.decorated) + { + MONITORINFO mi; + HMONITOR mh = MonitorFromWindow(cast(void*) window.win32.handle, + MONITOR_DEFAULTTONEAREST); + + memset(&mi, 0, typeof(mi).sizeof); + mi.cbSize = typeof(mi).sizeof; + GetMonitorInfo(mh, &mi); + + mmi.ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; + mmi.ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; + mmi.ptMaxSize.x = mi.rcWork.right - mi.rcWork.left; + mmi.ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top; + } + + return 0; + } + + case WM_PAINT: + { + _glfwInputWindowDamage(window); + break; + } + + case WM_ERASEBKGND: + { + return TRUE; + } + + case WM_NCACTIVATE: + case WM_NCPAINT: + { + // Prevent title bar from being drawn after restoring a minimized + // undecorated window + if (!window.decorated) + return TRUE; + + break; + } + + case WM_DWMCOMPOSITIONCHANGED: + { + if (window.win32.transparent) + updateFramebufferTransparency(window); + return 0; + } + + case WM_GETDPISCALEDSIZE: + { + if (window.win32.scaleToMonitor) + break; + + // Adjust the window size to keep the content area size constant + if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) + { + RECT source = RECT(0);RECT target = RECT(0); + SIZE* size = cast(SIZE*) lParam; + + mixin(AdjustWindowRectExForDpi)(&source, getWindowStyle(window), + FALSE, getWindowExStyle(window), + mixin(GetDpiForWindow)(cast(void*) window.win32.handle)); + mixin(AdjustWindowRectExForDpi)(&target, getWindowStyle(window), + FALSE, getWindowExStyle(window), + LOWORD(wParam)); + + size.cx += (target.right - target.left) - + (source.right - source.left); + size.cy += (target.bottom - target.top) - + (source.bottom - source.top); + return TRUE; + } + + break; + } + + case WM_DPICHANGED: + { + const(float) xscale = HIWORD(wParam) / cast(float) USER_DEFAULT_SCREEN_DPI; + const(float) yscale = LOWORD(wParam) / cast(float) USER_DEFAULT_SCREEN_DPI; + + // Only apply the suggested size if the OS is new enough to have + // sent a WM_GETDPISCALEDSIZE before this + if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) + { + RECT* suggested = cast(RECT*) lParam; + SetWindowPos(cast(void*) window.win32.handle, HWND_TOP, + suggested.left, + suggested.top, + suggested.right - suggested.left, + suggested.bottom - suggested.top, + SWP_NOACTIVATE | SWP_NOZORDER); + } + + _glfwInputWindowContentScale(window, xscale, yscale); + break; + } + + case WM_SETCURSOR: + { + if (LOWORD(lParam) == HTCLIENT) + { + updateCursorImage(window); + return TRUE; + } + + break; + } + + case WM_DROPFILES: + { + HDROP drop = cast(HDROP) wParam; + POINT pt; + int i; + + const(int) count = DragQueryFileW(drop, 0xffffffff, null, 0); + auto paths = cast(char**) calloc(count, (char*).sizeof); + + // Move the mouse to the position of the drop + DragQueryPoint(drop, &pt); + _glfwInputCursorPos(window, pt.x, pt.y); + + for (i = 0; i < count; i++) + { + const(UINT) length = DragQueryFileW(drop, i, null, 0); + WCHAR* buffer = cast(WCHAR*) calloc(cast(size_t) length + 1, WCHAR.sizeof); + + DragQueryFileW(drop, i, buffer, length + 1); + paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); + + free(buffer); + } + + _glfwInputDrop(window, count, cast(const(char)**) paths); + + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); + + DragFinish(drop); + return 0; + } + default: break; + } + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); +} + +// Creates the GLFW window +// +static int createNativeWindow(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig, const(_GLFWfbconfig)* fbconfig) { + int xpos;int ypos;int fullWidth;int fullHeight; + WCHAR* wideTitle; + DWORD style = getWindowStyle(window); + DWORD exStyle = getWindowExStyle(window); + + if (window.monitor) + { + GLFWvidmode mode; + + // NOTE: This window placement is temporary and approximate, as the + // correct position and size cannot be known until the monitor + // video mode has been picked in _glfwSetVideoModeWin32 + _glfwPlatformGetMonitorPos(window.monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window.monitor, &mode); + fullWidth = mode.width; + fullHeight = mode.height; + } + else + { + xpos = CW_USEDEFAULT; + ypos = CW_USEDEFAULT; + + window.win32.maximized = wndconfig.maximized; + if (wndconfig.maximized) + style |= WS_MAXIMIZE; + + getFullWindowSize(style, exStyle, + wndconfig.width, wndconfig.height, + &fullWidth, &fullHeight, + USER_DEFAULT_SCREEN_DPI); + } + + wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig.title); + if (!wideTitle) + return GLFW_FALSE; + + window.win32.handle = CreateWindowExW(exStyle, + _GLFW_WNDCLASSNAME.ptr, + wideTitle, + style, + xpos, ypos, + fullWidth, fullHeight, + null, // No parent window + null, // No window menu + GetModuleHandleW(null), + null); + + free(wideTitle); + + if (!window.win32.handle) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create window"); + return GLFW_FALSE; + } + + SetPropW(window.win32.handle, "GLFW"w.ptr, window); + + if (IsWindows7OrGreater()) + { + mixin(ChangeWindowMessageFilterEx)(window.win32.handle, + WM_DROPFILES, MSGFLT_ALLOW, null); + mixin(ChangeWindowMessageFilterEx)(window.win32.handle, + WM_COPYDATA, MSGFLT_ALLOW, null); + mixin(ChangeWindowMessageFilterEx)(window.win32.handle, + WM_COPYGLOBALDATA, MSGFLT_ALLOW, null); + } + + window.win32.scaleToMonitor = wndconfig.scaleToMonitor; + + // Adjust window rect to account for DPI scaling of the window frame and + // (if enabled) DPI scaling of the content area + // This cannot be done until we know what monitor the window was placed on + if (!window.monitor) + { + RECT rect = RECT( 0, 0, wndconfig.width, wndconfig.height ); + WINDOWPLACEMENT wp = WINDOWPLACEMENT( WINDOWPLACEMENT.sizeof ); + + if (wndconfig.scaleToMonitor) + { + float xscale;float yscale; + _glfwPlatformGetWindowContentScale(window, &xscale, &yscale); + rect.right = cast(int) (rect.right * xscale); + rect.bottom = cast(int) (rect.bottom * yscale); + } + + ClientToScreen(window.win32.handle, cast(POINT*) &rect.left); + ClientToScreen(window.win32.handle, cast(POINT*) &rect.right); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + mixin(AdjustWindowRectExForDpi)(&rect, style, FALSE, exStyle, + mixin(GetDpiForWindow)(window.win32.handle)); + } + else + AdjustWindowRectEx(&rect, style, FALSE, exStyle); + + // Only update the restored window rect as the window may be maximized + GetWindowPlacement(window.win32.handle, &wp); + wp.rcNormalPosition = rect; + wp.showCmd = SW_HIDE; + SetWindowPlacement(window.win32.handle, &wp); + } + + DragAcceptFiles(window.win32.handle, TRUE); + + if (fbconfig.transparent) + { + updateFramebufferTransparency(window); + window.win32.transparent = GLFW_TRUE; + } + + return GLFW_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Registers the GLFW window class +// +GLFWbool _glfwRegisterWindowClassWin32() { + WNDCLASSEXW wc; + + memset(&wc, 0, typeof(wc).sizeof); + wc.cbSize = typeof(wc).sizeof; + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = cast(WNDPROC) &windowProc; + wc.hInstance = GetModuleHandleW(null); + wc.hCursor = LoadCursorW(null, IDC_ARROW); + wc.lpszClassName = _GLFW_WNDCLASSNAME.ptr; + + // Load user-provided icon if available + wc.hIcon = LoadImageW(GetModuleHandleW(null), + "GLFW_ICON"w.ptr, IMAGE_ICON, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + if (!wc.hIcon) + { + // No user-provided icon found, load default icon + wc.hIcon = LoadImageW(null, + IDI_APPLICATION, IMAGE_ICON, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + } + + if (!RegisterClassExW(&wc)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to register window class"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Unregisters the GLFW window class +// +void _glfwUnregisterWindowClassWin32() { + UnregisterClassW(_GLFW_WNDCLASSNAME.ptr, GetModuleHandleW(null)); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + if (!createNativeWindow(window, wndconfig, fbconfig)) + return GLFW_FALSE; + + if (ctxconfig.client != GLFW_NO_API) + { + if (ctxconfig.source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitWGL()) + return GLFW_FALSE; + if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig.source == GLFW_EGL_CONTEXT_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig.source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (window.monitor) + { + _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); + acquireMonitor(window); + fitToMonitor(window); + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { + if (window.monitor) + releaseMonitor(window); + + if (window.context.destroy) + window.context.destroy(window); + + if (_glfw.win32.disabledCursorWindow == window) + _glfw.win32.disabledCursorWindow = null; + + if (window.win32.handle) + { + RemovePropW(window.win32.handle, "GLFW"w.ptr); + DestroyWindow(window.win32.handle); + window.win32.handle = null; + } + + if (window.win32.bigIcon) + DestroyIcon(window.win32.bigIcon); + + if (window.win32.smallIcon) + DestroyIcon(window.win32.smallIcon); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const(char)* title) { + WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title); + if (!wideTitle) + return; + + SetWindowTextW(window.win32.handle, wideTitle); + free(wideTitle); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const(GLFWimage)* images) { + HICON bigIcon = null;HICON smallIcon = null; + + if (count) + { + const(GLFWimage)* bigImage = chooseImage(count, images, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON)); + const(GLFWimage)* smallImage = chooseImage(count, images, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON)); + + bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE); + smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE); + } + else + { + bigIcon = cast(HICON) GetClassLongPtrW(window.win32.handle, GCLP_HICON); + smallIcon = cast(HICON) GetClassLongPtrW(window.win32.handle, GCLP_HICONSM); + } + + SendMessage(window.win32.handle, WM_SETICON, ICON_BIG, cast(LPARAM) bigIcon); + SendMessage(window.win32.handle, WM_SETICON, ICON_SMALL, cast(LPARAM) smallIcon); + + if (window.win32.bigIcon) + DestroyIcon(window.win32.bigIcon); + + if (window.win32.smallIcon) + DestroyIcon(window.win32.smallIcon); + + if (count) + { + window.win32.bigIcon = bigIcon; + window.win32.smallIcon = smallIcon; + } +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { + POINT pos = POINT(0, 0); + ClientToScreen(window.win32.handle, &pos); + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = pos.y; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { + RECT rect = RECT( xpos, ypos, xpos, ypos ); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + mixin(AdjustWindowRectExForDpi)(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + mixin(GetDpiForWindow)(window.win32.handle)); + } + else + { + /*DynCall*/AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + + SetWindowPos(window.win32.handle, null, rect.left, rect.top, 0, 0, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { + RECT area; + GetClientRect(window.win32.handle, &area); + + if (width) + *width = area.right; + if (height) + *height = area.bottom; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { + if (window.monitor) + { + if (window.monitor.window == window) + { + acquireMonitor(window); + fitToMonitor(window); + } + } + else + { + RECT rect = RECT( 0, 0, width, height ); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + mixin(AdjustWindowRectExForDpi)(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + mixin(GetDpiForWindow)(window.win32.handle)); + } + else + { + /*DynCall*/AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + + SetWindowPos(window.win32.handle, HWND_TOP, + 0, 0, rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); + } +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { + RECT area; + + if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) && + (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)) + { + return; + } + + GetWindowRect(window.win32.handle, &area); + MoveWindow(window.win32.handle, + area.left, area.top, + area.right - area.left, + area.bottom - area.top, TRUE); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { + RECT area; + + if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) + return; + + GetWindowRect(window.win32.handle, &area); + applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area); + MoveWindow(window.win32.handle, + area.left, area.top, + area.right - area.left, + area.bottom - area.top, TRUE); +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { + RECT rect; + int width;int height; + + _glfwPlatformGetWindowSize(window, &width, &height); + SetRect(&rect, 0, 0, width, height); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + mixin(AdjustWindowRectExForDpi)(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + mixin(GetDpiForWindow)(window.win32.handle)); + } + else + { + /*DynCall*/AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + + if (left) + *left = -rect.left; + if (top) + *top = -rect.top; + if (right) + *right = rect.right - width; + if (bottom) + *bottom = rect.bottom - height; +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale) { + HANDLE handle = MonitorFromWindow(window.win32.handle, + MONITOR_DEFAULTTONEAREST); + _glfwGetMonitorContentScaleWin32(handle, xscale, yscale); +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) { + ShowWindow(window.win32.handle, SW_MINIMIZE); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) { + ShowWindow(window.win32.handle, SW_RESTORE); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { + ShowWindow(window.win32.handle, SW_MAXIMIZE); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) { + ShowWindow(window.win32.handle, SW_SHOWNA); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) { + ShowWindow(window.win32.handle, SW_HIDE); +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { + FlashWindow(window.win32.handle, TRUE); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) { + BringWindowToTop(window.win32.handle); + SetForegroundWindow(window.win32.handle); + SetFocus(window.win32.handle); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { + if (window.monitor == monitor) + { + if (monitor) + { + if (monitor.window == window) + { + acquireMonitor(window); + fitToMonitor(window); + } + } + else + { + RECT rect = RECT( xpos, ypos, xpos + width, ypos + height ); + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + mixin(AdjustWindowRectExForDpi)(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + mixin(GetDpiForWindow)(window.win32.handle)); + } + else + { + /*DynCall*/AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + + SetWindowPos(window.win32.handle, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER); + } + + return; + } + + if (window.monitor) + releaseMonitor(window); + + _glfwInputWindowMonitor(window, monitor); + + if (window.monitor) + { + MONITORINFO mi = MONITORINFO(MONITORINFO.sizeof); + UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window.decorated) + { + DWORD style = GetWindowLongW(window.win32.handle, GWL_STYLE); + style &= ~WS_OVERLAPPEDWINDOW; + style |= getWindowStyle(window); + SetWindowLongW(window.win32.handle, GWL_STYLE, style); + flags |= SWP_FRAMECHANGED; + } + + acquireMonitor(window); + + GetMonitorInfo(window.monitor.win32.handle, &mi); + SetWindowPos(window.win32.handle, HWND_TOPMOST, + mi.rcMonitor.left, + mi.rcMonitor.top, + mi.rcMonitor.right - mi.rcMonitor.left, + mi.rcMonitor.bottom - mi.rcMonitor.top, + flags); + } + else + { + HWND after; + RECT rect = RECT( xpos, ypos, xpos + width, ypos + height ); + DWORD style = GetWindowLongW(window.win32.handle, GWL_STYLE); + UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window.decorated) + { + style &= ~WS_POPUP; + style |= getWindowStyle(window); + SetWindowLongW(window.win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + if (window.floating) + after = HWND_TOPMOST; + else + after = HWND_NOTOPMOST; + + if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) + { + mixin(AdjustWindowRectExForDpi)(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + mixin(GetDpiForWindow)(window.win32.handle)); + } + else + { + /*DynCall*/AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + + SetWindowPos(window.win32.handle, after, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + flags); + } +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) { + return window.win32.handle == GetActiveWindow(); +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) { + return IsIconic(window.win32.handle); +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) { + return IsWindowVisible(window.win32.handle); +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { + return IsZoomed(window.win32.handle); +} + +int _glfwPlatformWindowHovered(_GLFWwindow* window) { + return cursorInContentArea(window); +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { + BOOL enabled; + + if (!window.win32.transparent) + return GLFW_FALSE; + + if (!IsWindowsVistaOrGreater()) + return GLFW_FALSE; + + return SUCCEEDED(_glfw.win32.dwmapi.IsCompositionEnabled(&enabled)) && enabled; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { + updateWindowStyles(window); +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { + updateWindowStyles(window); +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { + HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST; + SetWindowPos(window.win32.handle, after, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { + BYTE alpha; + DWORD flags; + + if ((GetWindowLongW(window.win32.handle, GWL_EXSTYLE) & WS_EX_LAYERED) && + GetLayeredWindowAttributes(window.win32.handle, null, &alpha, &flags)) + { + if (flags & LWA_ALPHA) + return alpha / 255.0f; + } + + return 1.0f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { + if (opacity < 1.0f) + { + const(BYTE) alpha = cast(BYTE) (255 * opacity); + DWORD style = GetWindowLongW(window.win32.handle, GWL_EXSTYLE); + style |= WS_EX_LAYERED; + SetWindowLongW(window.win32.handle, GWL_EXSTYLE, style); + SetLayeredWindowAttributes(window.win32.handle, 0, alpha, LWA_ALPHA); + } + else + { + DWORD style = GetWindowLongW(window.win32.handle, GWL_EXSTYLE); + style &= ~WS_EX_LAYERED; + SetWindowLongW(window.win32.handle, GWL_EXSTYLE, style); + } +} + +void _glfwPlatformSetRawMouseMotion(_GLFWwindow* window, GLFWbool enabled) { + if (_glfw.win32.disabledCursorWindow != window) + return; + + if (enabled) + enableRawMouseMotion(window); + else + disableRawMouseMotion(window); +} + +GLFWbool _glfwPlatformRawMouseMotionSupported() { + return GLFW_TRUE; +} + +void _glfwPlatformPollEvents() { + MSG msg; + HWND handle; + _GLFWwindow* window; + + while (PeekMessageW(&msg, null, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + // NOTE: While GLFW does not itself post WM_QUIT, other processes + // may post it to this one, for example Task Manager + // HACK: Treat WM_QUIT as a close on all windows + + window = _glfw.windowListHead; + while (window) + { + _glfwInputWindowCloseRequest(window); + window = window.next; + } + } + else + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + // HACK: Release modifier keys that the system did not emit KEYUP for + // NOTE: Shift keys on Windows tend to "stick" when both are pressed as + // no key up message is generated by the first key release + // NOTE: Windows key is not reported as released by the Win+V hotkey + // Other Win hotkeys are handled implicitly by _glfwInputWindowFocus + // because they change the input focus + // NOTE: The other half of this is in the WM_*KEY* handler in windowProc + handle = GetActiveWindow(); + if (handle) + { + window = cast(_GLFWwindow*) GetPropW(handle, "GLFW"w.ptr); + if (window) + { + int i; + const(int)[2][4] keys = [ + [ VK_LSHIFT, GLFW_KEY_LEFT_SHIFT ], + [ VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT ], + [ VK_LWIN, GLFW_KEY_LEFT_SUPER ], + [ VK_RWIN, GLFW_KEY_RIGHT_SUPER ] + ]; + + for (i = 0; i < 4; i++) + { + const(int) vk = keys[i][0]; + const(int) key = keys[i][1]; + const(int) scancode = _glfw.win32.scancodes[key]; + + if ((GetKeyState(vk) & 0x8000)) + continue; + if (window.keys[key] != GLFW_PRESS) + continue; + + _glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods()); + } + } + } + + window = _glfw.win32.disabledCursorWindow; + if (window) + { + int width;int height; + _glfwPlatformGetWindowSize(window, &width, &height); + + // NOTE: Re-center the cursor only if it has moved since the last call, + // to avoid breaking glfwWaitEvents with WM_MOUSEMOVE + if (window.win32.lastCursorPosX != width / 2 || + window.win32.lastCursorPosY != height / 2) + { + _glfwPlatformSetCursorPos(window, width / 2, height / 2); + } + } +} + +void _glfwPlatformWaitEvents() { + WaitMessage(); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) { + MsgWaitForMultipleObjects(0, null, FALSE, cast(DWORD) (timeout * 1e3), QS_ALLEVENTS); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent() { + PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { + POINT pos; + + if (GetCursorPos(&pos)) + { + ScreenToClient(window.win32.handle, &pos); + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = pos.y; + } +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) { + POINT pos = POINT( cast(int) xpos, cast(int) ypos ); + + // Store the new position so it can be recognized later + window.win32.lastCursorPosX = pos.x; + window.win32.lastCursorPosY = pos.y; + + ClientToScreen(window.win32.handle, &pos); + SetCursorPos(pos.x, pos.y); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { + if (mode == GLFW_CURSOR_DISABLED) + { + if (_glfwPlatformWindowFocused(window)) + disableCursor(window); + } + else if (_glfw.win32.disabledCursorWindow == window) + enableCursor(window); + else if (cursorInContentArea(window)) + updateCursorImage(window); +} + +const(char)* _glfwPlatformGetScancodeName(int scancode) { + if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) || + _glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); + return null; + } + + return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]].ptr; +} + +int _glfwPlatformGetKeyScancode(int key) { + return _glfw.win32.scancodes[key]; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const(GLFWimage)* image, int xhot, int yhot) { + cursor.win32.handle = cast(HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); + if (!cursor.win32.handle) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { + int id = 0; + + if (shape == GLFW_ARROW_CURSOR) + id = OCR_NORMAL; + else if (shape == GLFW_IBEAM_CURSOR) + id = OCR_IBEAM; + else if (shape == GLFW_CROSSHAIR_CURSOR) + id = OCR_CROSS; + else if (shape == GLFW_HAND_CURSOR) + id = OCR_HAND; + else if (shape == GLFW_HRESIZE_CURSOR) + id = OCR_SIZEWE; + else if (shape == GLFW_VRESIZE_CURSOR) + id = OCR_SIZENS; + else + return GLFW_FALSE; + + cursor.win32.handle = LoadImageW(null, + MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, + LR_DEFAULTSIZE | LR_SHARED); + if (!cursor.win32.handle) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to create standard cursor"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { + if (cursor.win32.handle) + DestroyIcon(cast(HICON) cursor.win32.handle); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { + if (cursorInContentArea(window)) + updateCursorImage(window); +} + +void _glfwPlatformSetClipboardString(const(char)* string) { + int characterCount; + HANDLE object; + WCHAR* buffer; + + characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, null, 0); + if (!characterCount) + return; + + object = GlobalAlloc(GMEM_MOVEABLE, characterCount * WCHAR.sizeof); + if (!object) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate global handle for clipboard"); + return; + } + + buffer = cast(WCHAR*) GlobalLock(object); // needless re-use of buffer variable? + if (!buffer) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to lock global handle"); + GlobalFree(object); + return; + } + + MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount); + GlobalUnlock(object); + + if (!OpenClipboard(_glfw.win32.helperWindowHandle)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to open clipboard"); + GlobalFree(object); + return; + } + + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, object); + CloseClipboard(); +} + +const(char)* _glfwPlatformGetClipboardString() { + HANDLE object; + WCHAR* buffer; + + if (!OpenClipboard(_glfw.win32.helperWindowHandle)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to open clipboard"); + return null; + } + + object = GetClipboardData(CF_UNICODETEXT); + if (!object) + { + _glfwInputErrorWin32(GLFW_FORMAT_UNAVAILABLE, + "Win32: Failed to convert clipboard to string"); + CloseClipboard(); + return null; + } + + buffer = cast(WCHAR*) GlobalLock(object); + if (!buffer) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to lock global handle"); + CloseClipboard(); + return null; + } + + free(_glfw.win32.clipboardString); + _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer); + + GlobalUnlock(object); + CloseClipboard(); + + return _glfw.win32.clipboardString; +} + +void _glfwPlatformGetRequiredInstanceExtensions(const(char)** extensions) { + if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface) + return; + + extensions[0] = "VK_KHR_surface".ptr; + extensions[1] = "VK_KHR_win32_surface".ptr; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint queuefamily) { + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = cast(PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) + mixin(vkGetInstanceProcAddr)(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); + if (!vkGetPhysicalDeviceWin32PresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily); +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const(VkAllocationCallbacks)* allocator, VkSurfaceKHR* surface) { + VkResult err; + VkWin32SurfaceCreateInfoKHR sci; + PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; + + vkCreateWin32SurfaceKHR = cast(PFN_vkCreateWin32SurfaceKHR) + mixin(vkGetInstanceProcAddr)(instance, "vkCreateWin32SurfaceKHR"); + if (!vkCreateWin32SurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); + return VkResult.VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, typeof(sci).sizeof); + sci.sType = VkStructureType.VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + sci.hinstance = GetModuleHandle(null); + sci.hwnd = window.win32.handle; + + err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +HWND glfwGetWin32Window(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return window.win32.handle; +} \ No newline at end of file diff --git a/source/glfw3/window.d b/source/glfw3/window.d new file mode 100644 index 0000000..ccd645c --- /dev/null +++ b/source/glfw3/window.d @@ -0,0 +1,1028 @@ +/// Translated from C to D +module glfw3.window; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// Copyright (c) 2012 Torsten Walluhn +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// Please use C89 style variable declarations in this file because VS 2010 +//======================================================================== + +import glfw3.internal; + +import core.stdc.assert_; +import core.stdc.string; +import core.stdc.stdlib; + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +// Notifies shared code that a window has lost or received input focus +// +void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) { + if (window.callbacks.focus) + window.callbacks.focus(cast(GLFWwindow*) window, focused); + + if (!focused) + { + int key;int button; + + for (key = 0; key <= GLFW_KEY_LAST; key++) + { + if (window.keys[key] == GLFW_PRESS) + { + const(int) scancode = _glfwPlatformGetKeyScancode(key); + _glfwInputKey(window, key, scancode, GLFW_RELEASE, 0); + } + } + + for (button = 0; button <= GLFW_MOUSE_BUTTON_LAST; button++) + { + if (window.mouseButtons[button] == GLFW_PRESS) + _glfwInputMouseClick(window, button, GLFW_RELEASE, 0); + } + } +} + +// Notifies shared code that a window has moved +// The position is specified in content area relative screen coordinates +// +void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) { + if (window.callbacks.pos) + window.callbacks.pos(cast(GLFWwindow*) window, x, y); +} + +// Notifies shared code that a window has been resized +// The size is specified in screen coordinates +// +void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) { + if (window.callbacks.size) + window.callbacks.size(cast(GLFWwindow*) window, width, height); +} + +// Notifies shared code that a window has been iconified or restored +// +void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified) { + if (window.callbacks.iconify) + window.callbacks.iconify(cast(GLFWwindow*) window, iconified); +} + +// Notifies shared code that a window has been maximized or restored +// +void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized) { + if (window.callbacks.maximize) + window.callbacks.maximize(cast(GLFWwindow*) window, maximized); +} + +// Notifies shared code that a window framebuffer has been resized +// The size is specified in pixels +// +void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) { + if (window.callbacks.fbsize) + window.callbacks.fbsize(cast(GLFWwindow*) window, width, height); +} + +// Notifies shared code that a window content scale has changed +// The scale is specified as the ratio between the current and default DPI +// +void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale) { + if (window.callbacks.scale) + window.callbacks.scale(cast(GLFWwindow*) window, xscale, yscale); +} + +// Notifies shared code that the window contents needs updating +// +void _glfwInputWindowDamage(_GLFWwindow* window) { + if (window.callbacks.refresh) + window.callbacks.refresh(cast(GLFWwindow*) window); +} + +// Notifies shared code that the user wishes to close a window +// +void _glfwInputWindowCloseRequest(_GLFWwindow* window) { + window.shouldClose = GLFW_TRUE; + + if (window.callbacks.close) + window.callbacks.close(cast(GLFWwindow*) window); +} + +// Notifies shared code that a window has changed its desired monitor +// +void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor) { + window.monitor = monitor; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWwindow* glfwCreateWindow(int width, int height, const(char)* title, GLFWmonitor* monitor, GLFWwindow* share) { + _GLFWfbconfig fbconfig; + _GLFWctxconfig ctxconfig; + _GLFWwndconfig wndconfig; + _GLFWwindow* window; + + assert(title != null); + assert(width >= 0); + assert(height >= 0); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + + if (width <= 0 || height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window size %ix%i", + width, height); + + return null; + } + + fbconfig = _glfw.hints.framebuffer; + ctxconfig = _glfw.hints.context; + wndconfig = _glfw.hints.window; + + wndconfig.width = width; + wndconfig.height = height; + wndconfig.title = title; + ctxconfig.share = cast(_GLFWwindow*) share; + + if (!_glfwIsValidContextConfig(&ctxconfig)) + return null; + + window = cast(_GLFWwindow*) calloc(1, _GLFWwindow.sizeof); + window.next = _glfw.windowListHead; + _glfw.windowListHead = window; + + window.videoMode.width = width; + window.videoMode.height = height; + window.videoMode.redBits = fbconfig.redBits; + window.videoMode.greenBits = fbconfig.greenBits; + window.videoMode.blueBits = fbconfig.blueBits; + window.videoMode.refreshRate = _glfw.hints.refreshRate; + + window.monitor = cast(_GLFWmonitor*) monitor; + window.resizable = wndconfig.resizable; + window.decorated = wndconfig.decorated; + window.autoIconify = wndconfig.autoIconify; + window.floating = wndconfig.floating; + window.focusOnShow = wndconfig.focusOnShow; + window.cursorMode = GLFW_CURSOR_NORMAL; + + window.minwidth = GLFW_DONT_CARE; + window.minheight = GLFW_DONT_CARE; + window.maxwidth = GLFW_DONT_CARE; + window.maxheight = GLFW_DONT_CARE; + window.numer = GLFW_DONT_CARE; + window.denom = GLFW_DONT_CARE; + + // Open the actual window and create its context + if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) + { + glfwDestroyWindow(cast(GLFWwindow*) window); + return null; + } + + if (ctxconfig.client != GLFW_NO_API) + { + if (!_glfwRefreshContextAttribs(window, &ctxconfig)) + { + glfwDestroyWindow(cast(GLFWwindow*) window); + return null; + } + } + + if (window.monitor) + { + if (wndconfig.centerCursor) + _glfwCenterCursorInContentArea(window); + } + else + { + if (wndconfig.visible) + { + _glfwPlatformShowWindow(window); + if (wndconfig.focused) + _glfwPlatformFocusWindow(window); + } + } + + return cast(GLFWwindow*) window; +} + +void glfwDefaultWindowHints() { + mixin(_GLFW_REQUIRE_INIT); + + // The default is OpenGL with minimum version 1.0 + memset(&_glfw.hints.context, 0, typeof((_glfw.hints.context)).sizeof); + _glfw.hints.context.client = GLFW_OPENGL_API; + _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API; + _glfw.hints.context.major = 1; + _glfw.hints.context.minor = 0; + + // The default is a focused, visible, resizable window with decorations + memset(&_glfw.hints.window, 0, typeof((_glfw.hints.window)).sizeof); + _glfw.hints.window.resizable = GLFW_TRUE; + _glfw.hints.window.visible = GLFW_TRUE; + _glfw.hints.window.decorated = GLFW_TRUE; + _glfw.hints.window.focused = GLFW_TRUE; + _glfw.hints.window.autoIconify = GLFW_TRUE; + _glfw.hints.window.centerCursor = GLFW_TRUE; + _glfw.hints.window.focusOnShow = GLFW_TRUE; + + // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, + // double buffered + memset(&_glfw.hints.framebuffer, 0, typeof((_glfw.hints.framebuffer)).sizeof); + _glfw.hints.framebuffer.redBits = 8; + _glfw.hints.framebuffer.greenBits = 8; + _glfw.hints.framebuffer.blueBits = 8; + _glfw.hints.framebuffer.alphaBits = 8; + _glfw.hints.framebuffer.depthBits = 24; + _glfw.hints.framebuffer.stencilBits = 8; + _glfw.hints.framebuffer.doublebuffer = GLFW_TRUE; + + // The default is to select the highest available refresh rate + _glfw.hints.refreshRate = GLFW_DONT_CARE; + + // The default is to use full Retina resolution framebuffers + _glfw.hints.window.ns.retina = GLFW_TRUE; +} + +void glfwWindowHint(int hint, int value) { + mixin(_GLFW_REQUIRE_INIT); + + switch (hint) + { + case GLFW_RED_BITS: + _glfw.hints.framebuffer.redBits = value; + return; + case GLFW_GREEN_BITS: + _glfw.hints.framebuffer.greenBits = value; + return; + case GLFW_BLUE_BITS: + _glfw.hints.framebuffer.blueBits = value; + return; + case GLFW_ALPHA_BITS: + _glfw.hints.framebuffer.alphaBits = value; + return; + case GLFW_DEPTH_BITS: + _glfw.hints.framebuffer.depthBits = value; + return; + case GLFW_STENCIL_BITS: + _glfw.hints.framebuffer.stencilBits = value; + return; + case GLFW_ACCUM_RED_BITS: + _glfw.hints.framebuffer.accumRedBits = value; + return; + case GLFW_ACCUM_GREEN_BITS: + _glfw.hints.framebuffer.accumGreenBits = value; + return; + case GLFW_ACCUM_BLUE_BITS: + _glfw.hints.framebuffer.accumBlueBits = value; + return; + case GLFW_ACCUM_ALPHA_BITS: + _glfw.hints.framebuffer.accumAlphaBits = value; + return; + case GLFW_AUX_BUFFERS: + _glfw.hints.framebuffer.auxBuffers = value; + return; + case GLFW_STEREO: + _glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_DOUBLEBUFFER: + _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_TRANSPARENT_FRAMEBUFFER: + _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_SAMPLES: + _glfw.hints.framebuffer.samples = value; + return; + case GLFW_SRGB_CAPABLE: + _glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_RESIZABLE: + _glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_DECORATED: + _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_FOCUSED: + _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_AUTO_ICONIFY: + _glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_FLOATING: + _glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_MAXIMIZED: + _glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_VISIBLE: + _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_COCOA_RETINA_FRAMEBUFFER: + _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_COCOA_GRAPHICS_SWITCHING: + _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_SCALE_TO_MONITOR: + _glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_CENTER_CURSOR: + _glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_FOCUS_ON_SHOW: + _glfw.hints.window.focusOnShow = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_CLIENT_API: + _glfw.hints.context.client = value; + return; + case GLFW_CONTEXT_CREATION_API: + _glfw.hints.context.source = value; + return; + case GLFW_CONTEXT_VERSION_MAJOR: + _glfw.hints.context.major = value; + return; + case GLFW_CONTEXT_VERSION_MINOR: + _glfw.hints.context.minor = value; + return; + case GLFW_CONTEXT_ROBUSTNESS: + _glfw.hints.context.robustness = value; + return; + case GLFW_OPENGL_FORWARD_COMPAT: + _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_OPENGL_DEBUG_CONTEXT: + _glfw.hints.context.debug_ = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_CONTEXT_NO_ERROR: + _glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_OPENGL_PROFILE: + _glfw.hints.context.profile = value; + return; + case GLFW_CONTEXT_RELEASE_BEHAVIOR: + _glfw.hints.context.release = value; + return; + case GLFW_REFRESH_RATE: + _glfw.hints.refreshRate = value; + return; + default: break; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); +} + +void glfwWindowHintString(int hint, const(char)* value) { + assert(value != null); + + mixin(_GLFW_REQUIRE_INIT); + + switch (hint) + { + case GLFW_COCOA_FRAME_NAME: + strncpy(_glfw.hints.window.ns.frameName.ptr, value, + _glfw.hints.window.ns.frameName.length - 1); + return; + case GLFW_X11_CLASS_NAME: + strncpy(_glfw.hints.window.x11.className.ptr, value, + _glfw.hints.window.x11.className.length - 1); + return; + case GLFW_X11_INSTANCE_NAME: + strncpy(_glfw.hints.window.x11.instanceName.ptr, value, + _glfw.hints.window.x11.instanceName.length - 1); + return; + default: break; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint); +} + +void glfwDestroyWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + + mixin(_GLFW_REQUIRE_INIT); + + // Allow closing of NULL (to match the behavior of free) + if (window == null) + return; + + // Clear all callbacks to avoid exposing a half torn-down window object + memset(&window.callbacks, 0, typeof((window.callbacks)).sizeof); + + // The window's context must not be current on another thread when the + // window is destroyed + if (window == _glfwPlatformGetTls(&_glfw.contextSlot)) + glfwMakeContextCurrent(null); + + _glfwPlatformDestroyWindow(window); + + // Unlink window from global linked list + { + _GLFWwindow** prev = &_glfw.windowListHead; + + while (*prev != window) + prev = &((*prev).next); + + *prev = window.next; + } + + free(window); +} + +int glfwWindowShouldClose(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0"); + return window.shouldClose; +} + +void glfwSetWindowShouldClose(GLFWwindow* handle, int value) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + window.shouldClose = value; +} + +void glfwSetWindowTitle(GLFWwindow* handle, const(char)* title) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + assert(title != null); + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformSetWindowTitle(window, title); +} + +void glfwSetWindowIcon(GLFWwindow* handle, int count, const(GLFWimage)* images) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + assert(count >= 0); + assert(count == 0 || images != null); + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformSetWindowIcon(window, count, images); +} + +void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformGetWindowPos(window, xpos, ypos); +} + +void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + if (window.monitor) + return; + + _glfwPlatformSetWindowPos(window, xpos, ypos); +} + +void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + if (width) + *width = 0; + if (height) + *height = 0; + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformGetWindowSize(window, width, height); +} + +void glfwSetWindowSize(GLFWwindow* handle, int width, int height) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + assert(width >= 0); + assert(height >= 0); + + mixin(_GLFW_REQUIRE_INIT); + + window.videoMode.width = width; + window.videoMode.height = height; + + _glfwPlatformSetWindowSize(window, width, height); +} + +void glfwSetWindowSizeLimits(GLFWwindow* handle, int minwidth, int minheight, int maxwidth, int maxheight) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE) + { + if (minwidth < 0 || minheight < 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window minimum size %ix%i", + minwidth, minheight); + return; + } + } + + if (maxwidth != GLFW_DONT_CARE && maxheight != GLFW_DONT_CARE) + { + if (maxwidth < 0 || maxheight < 0 || + maxwidth < minwidth || maxheight < minheight) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window maximum size %ix%i", + maxwidth, maxheight); + return; + } + } + + window.minwidth = minwidth; + window.minheight = minheight; + window.maxwidth = maxwidth; + window.maxheight = maxheight; + + if (window.monitor || !window.resizable) + return; + + _glfwPlatformSetWindowSizeLimits(window, + minwidth, minheight, + maxwidth, maxheight); +} + +void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + assert(numer != 0); + assert(denom != 0); + + mixin(_GLFW_REQUIRE_INIT); + + if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE) + { + if (numer <= 0 || denom <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window aspect ratio %i:%i", + numer, denom); + return; + } + } + + window.numer = numer; + window.denom = denom; + + if (window.monitor || !window.resizable) + return; + + _glfwPlatformSetWindowAspectRatio(window, numer, denom); +} + +void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + if (width) + *width = 0; + if (height) + *height = 0; + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformGetFramebufferSize(window, width, height); +} + +void glfwGetWindowFrameSize(GLFWwindow* handle, int* left, int* top, int* right, int* bottom) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + if (left) + *left = 0; + if (top) + *top = 0; + if (right) + *right = 0; + if (bottom) + *bottom = 0; + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); +} + +void glfwGetWindowContentScale(GLFWwindow* handle, float* xscale, float* yscale) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + if (xscale) + *xscale = 0.0f; + if (yscale) + *yscale = 0.0f; + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformGetWindowContentScale(window, xscale, yscale); +} + +float glfwGetWindowOpacity(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"1.0f"); + return _glfwPlatformGetWindowOpacity(window); +} + +void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + assert(opacity == opacity); + assert(opacity >= 0.0f); + assert(opacity <= 1.0f); + + mixin(_GLFW_REQUIRE_INIT); + + if (opacity != opacity || opacity < 0.0f || opacity > 1.0f) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid window opacity %f", opacity); + return; + } + + _glfwPlatformSetWindowOpacity(window, opacity); +} + +void glfwIconifyWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformIconifyWindow(window); +} + +void glfwRestoreWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformRestoreWindow(window); +} + +void glfwMaximizeWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + if (window.monitor) + return; + + _glfwPlatformMaximizeWindow(window); +} + +void glfwShowWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + if (window.monitor) + return; + + _glfwPlatformShowWindow(window); + + if (window.focusOnShow) + _glfwPlatformFocusWindow(window); +} + +void glfwRequestWindowAttention(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + _glfwPlatformRequestWindowAttention(window); +} + +void glfwHideWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + if (window.monitor) + return; + + _glfwPlatformHideWindow(window); +} + +void glfwFocusWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + _glfwPlatformFocusWindow(window); +} + +int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0"); + + switch (attrib) + { + case GLFW_FOCUSED: + return _glfwPlatformWindowFocused(window); + case GLFW_ICONIFIED: + return _glfwPlatformWindowIconified(window); + case GLFW_VISIBLE: + return _glfwPlatformWindowVisible(window); + case GLFW_MAXIMIZED: + return _glfwPlatformWindowMaximized(window); + case GLFW_HOVERED: + return _glfwPlatformWindowHovered(window); + case GLFW_FOCUS_ON_SHOW: + return window.focusOnShow; + case GLFW_TRANSPARENT_FRAMEBUFFER: + return _glfwPlatformFramebufferTransparent(window); + case GLFW_RESIZABLE: + return window.resizable; + case GLFW_DECORATED: + return window.decorated; + case GLFW_FLOATING: + return window.floating; + case GLFW_AUTO_ICONIFY: + return window.autoIconify; + case GLFW_CLIENT_API: + return window.context.client; + case GLFW_CONTEXT_CREATION_API: + return window.context.source; + case GLFW_CONTEXT_VERSION_MAJOR: + return window.context.major; + case GLFW_CONTEXT_VERSION_MINOR: + return window.context.minor; + case GLFW_CONTEXT_REVISION: + return window.context.revision; + case GLFW_CONTEXT_ROBUSTNESS: + return window.context.robustness; + case GLFW_OPENGL_FORWARD_COMPAT: + return window.context.forward; + case GLFW_OPENGL_DEBUG_CONTEXT: + return window.context.debug_; + case GLFW_OPENGL_PROFILE: + return window.context.profile; + case GLFW_CONTEXT_RELEASE_BEHAVIOR: + return window.context.release; + case GLFW_CONTEXT_NO_ERROR: + return window.context.noerror; + default: break; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); + return 0; +} + +void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + + value = value ? GLFW_TRUE : GLFW_FALSE; + + if (attrib == GLFW_AUTO_ICONIFY) + window.autoIconify = value; + else if (attrib == GLFW_RESIZABLE) + { + if (window.resizable == value) + return; + + window.resizable = value; + if (!window.monitor) + _glfwPlatformSetWindowResizable(window, value); + } + else if (attrib == GLFW_DECORATED) + { + if (window.decorated == value) + return; + + window.decorated = value; + if (!window.monitor) + _glfwPlatformSetWindowDecorated(window, value); + } + else if (attrib == GLFW_FLOATING) + { + if (window.floating == value) + return; + + window.floating = value; + if (!window.monitor) + _glfwPlatformSetWindowFloating(window, value); + } + else if (attrib == GLFW_FOCUS_ON_SHOW) + window.focusOnShow = value; + else + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); +} + +GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return cast(GLFWmonitor*) window.monitor; +} + +void glfwSetWindowMonitor(GLFWwindow* wh, GLFWmonitor* mh, int xpos, int ypos, int width, int height, int refreshRate) { + _GLFWwindow* window = cast(_GLFWwindow*) wh; + _GLFWmonitor* monitor = cast(_GLFWmonitor*) mh; + assert(window != null); + assert(width >= 0); + assert(height >= 0); + + mixin(_GLFW_REQUIRE_INIT); + + if (width <= 0 || height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid window size %ix%i", + width, height); + return; + } + + if (refreshRate < 0 && refreshRate != GLFW_DONT_CARE) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid refresh rate %i", + refreshRate); + return; + } + + window.videoMode.width = width; + window.videoMode.height = height; + window.videoMode.refreshRate = refreshRate; + + _glfwPlatformSetWindowMonitor(window, monitor, + xpos, ypos, width, height, + refreshRate); +} + +void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT); + window.userPointer = pointer; +} + +void* glfwGetWindowUserPointer(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return window.userPointer; +} + +GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, GLFWwindowposfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.pos, cbfun); + return cbfun; +} + +GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, GLFWwindowsizefun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.size, cbfun); + return cbfun; +} + +GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, GLFWwindowclosefun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.close, cbfun); + return cbfun; +} + +GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, GLFWwindowrefreshfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.refresh, cbfun); + return cbfun; +} + +GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, GLFWwindowfocusfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.focus, cbfun); + return cbfun; +} + +GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, GLFWwindowiconifyfun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.iconify, cbfun); + return cbfun; +} + +GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle, GLFWwindowmaximizefun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.maximize, cbfun); + return cbfun; +} + +GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle, GLFWframebuffersizefun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.fbsize, cbfun); + return cbfun; +} + +GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* handle, GLFWwindowcontentscalefun cbfun) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + assert(window != null); + + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + _GLFW_SWAP_POINTERS(window.callbacks.scale, cbfun); + return cbfun; +} + +void glfwPollEvents() { + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformPollEvents(); +} + +void glfwWaitEvents() { + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformWaitEvents(); +} + +void glfwWaitEventsTimeout(double timeout) { + mixin(_GLFW_REQUIRE_INIT); + assert(timeout == timeout); + assert(timeout >= 0.0); + assert(timeout <= double.max); + + if (timeout != timeout || timeout < 0.0 || timeout > double.max) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout); + return; + } + + _glfwPlatformWaitEventsTimeout(timeout); +} + +void glfwPostEmptyEvent() { + mixin(_GLFW_REQUIRE_INIT); + _glfwPlatformPostEmptyEvent(); +} \ No newline at end of file diff --git a/source/glfw3/wl_init.d b/source/glfw3/wl_init.d new file mode 100644 index 0000000..67a3e95 --- /dev/null +++ b/source/glfw3/wl_init.d @@ -0,0 +1,1234 @@ +/// Translated from C to D +module glfw3.wl_init; + +extern(C): @nogc: nothrow: __gshared: + +private template HasVersion(string versionId) { + mixin("version("~versionId~") {enum HasVersion = true;} else {enum HasVersion = false;}"); +} +import core.stdc.config: c_long, c_ulong; +//======================================================================== +// GLFW 3.3 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +public import glfw3.internal; + +import core.stdc.assert_; +import core.stdc.errno; +import core.stdc.limits; +import glfw3.linuxinput; +import core.stdc.stdio; +import core.stdc.stdlib; +import core.stdc.string; +import core.sys.posix.sys.mman; +import core.sys.linux.timerfd; +import core.sys.posix.unistd; +import xkbcommon.xkbcommon; + +//public import wayland-client; +//import wayland.native.util; + +pragma(inline, true) extern(D) static int min(int n1, int n2) { + return n1 < n2 ? n1 : n2; +} + +static _GLFWwindow* findWindowFromDecorationSurface(wl_surface* surface, int* which) { + int focus; + _GLFWwindow* window = _glfw.windowListHead; + if (!which) + which = &focus; + while (window) + { + if (surface == window.wl.decorations.top.surface) + { + *which = topDecoration; + break; + } + if (surface == window.wl.decorations.left.surface) + { + *which = leftDecoration; + break; + } + if (surface == window.wl.decorations.right.surface) + { + *which = rightDecoration; + break; + } + if (surface == window.wl.decorations.bottom.surface) + { + *which = bottomDecoration; + break; + } + window = window.next; + } + return window; +} + +static void pointerHandleEnter(void* data, wl_pointer* pointer, uint serial, wl_surface* surface, wl_fixed_t sx, wl_fixed_t sy) { + // Happens in the case we just destroyed the surface. + if (!surface) + return; + + int focus = 0; + _GLFWwindow* window = cast(_GLFWwindow*) wl_surface_get_user_data(surface); + if (!window) + { + window = findWindowFromDecorationSurface(surface, &focus); + if (!window) + return; + } + + window.wl.decorations.focus = focus; + _glfw.wl.serial = serial; + _glfw.wl.pointerFocus = window; + + window.wl.hovered = GLFW_TRUE; + + _glfwPlatformSetCursor(window, window.wl.currentCursor); + _glfwInputCursorEnter(window, GLFW_TRUE); +} + +static void pointerHandleLeave(void* data, wl_pointer* pointer, uint serial, wl_surface* surface) { + _GLFWwindow* window = _glfw.wl.pointerFocus; + + if (!window) + return; + + window.wl.hovered = GLFW_FALSE; + + _glfw.wl.serial = serial; + _glfw.wl.pointerFocus = null; + _glfwInputCursorEnter(window, GLFW_FALSE); + _glfw.wl.cursorPreviousName = null; +} + +static void setCursor(_GLFWwindow* window, const(char)* name) { + wl_buffer* buffer; + wl_cursor* cursor; + wl_cursor_image* image; + wl_surface* surface = _glfw.wl.cursorSurface; + wl_cursor_theme* theme = _glfw.wl.cursorTheme; + int scale = 1; + + if (window.wl.scale > 1 && _glfw.wl.cursorThemeHiDPI) + { + // We only support up to scale=2 for now, since libwayland-cursor + // requires us to load a different theme for each size. + scale = 2; + theme = _glfw.wl.cursorThemeHiDPI; + } + + cursor = _glfw.wl.cursor.theme_get_cursor(theme, name); + if (!cursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Standard cursor not found"); + return; + } + // TODO: handle animated cursors too. + image = cursor.images[0]; + + if (!image) + return; + + buffer = _glfw.wl.cursor.image_get_buffer(image); + if (!buffer) + return; + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, + surface, + image.hotspot_x / scale, + image.hotspot_y / scale); + wl_surface_set_buffer_scale(surface, scale); + wl_surface_attach(surface, buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + image.width, image.height); + wl_surface_commit(surface); + _glfw.wl.cursorPreviousName = name; +} + +static void pointerHandleMotion(void* data, wl_pointer* pointer, uint time, wl_fixed_t sx, wl_fixed_t sy) { + _GLFWwindow* window = _glfw.wl.pointerFocus; + const(char)* cursorName = null; + double x;double y; + + if (!window) + return; + + if (window.cursorMode == GLFW_CURSOR_DISABLED) + return; + x = wl_fixed_to_double(sx); + y = wl_fixed_to_double(sy); + + switch (window.wl.decorations.focus) + { + case mainWindow: + window.wl.cursorPosX = x; + window.wl.cursorPosY = y; + _glfwInputCursorPos(window, x, y); + _glfw.wl.cursorPreviousName = null; + return; + case topDecoration: + if (y < _GLFW_DECORATION_WIDTH) + cursorName = "n-resize"; + else + cursorName = "left_ptr"; + break; + case leftDecoration: + if (y < _GLFW_DECORATION_WIDTH) + cursorName = "nw-resize"; + else + cursorName = "w-resize"; + break; + case rightDecoration: + if (y < _GLFW_DECORATION_WIDTH) + cursorName = "ne-resize"; + else + cursorName = "e-resize"; + break; + case bottomDecoration: + if (x < _GLFW_DECORATION_WIDTH) + cursorName = "sw-resize"; + else if (x > window.wl.width + _GLFW_DECORATION_WIDTH) + cursorName = "se-resize"; + else + cursorName = "s-resize"; + break; + default: + assert(0); + } + if (_glfw.wl.cursorPreviousName != cursorName) + setCursor(window, cursorName); +} + +static void pointerHandleButton(void* data, wl_pointer* pointer, uint serial, uint time, uint button, uint state) { + _GLFWwindow* window = _glfw.wl.pointerFocus; + int glfwButton; + + // Both xdg-shell and wl_shell use the same values. + uint edges = WL_SHELL_SURFACE_RESIZE_NONE; + + if (!window) + return; + if (button == BTN_LEFT) + { + switch (window.wl.decorations.focus) + { + case mainWindow: + break; + case topDecoration: + if (window.wl.cursorPosY < _GLFW_DECORATION_WIDTH) + edges = WL_SHELL_SURFACE_RESIZE_TOP; + else + { + if (window.wl.xdg.toplevel) + xdg_toplevel_move(window.wl.xdg.toplevel, _glfw.wl.seat, serial); + else + wl_shell_surface_move(window.wl.shellSurface, _glfw.wl.seat, serial); + } + break; + case leftDecoration: + if (window.wl.cursorPosY < _GLFW_DECORATION_WIDTH) + edges = WL_SHELL_SURFACE_RESIZE_TOP_LEFT; + else + edges = WL_SHELL_SURFACE_RESIZE_LEFT; + break; + case rightDecoration: + if (window.wl.cursorPosY < _GLFW_DECORATION_WIDTH) + edges = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT; + else + edges = WL_SHELL_SURFACE_RESIZE_RIGHT; + break; + case bottomDecoration: + if (window.wl.cursorPosX < _GLFW_DECORATION_WIDTH) + edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT; + else if (window.wl.cursorPosX > window.wl.width + _GLFW_DECORATION_WIDTH) + edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; + else + edges = WL_SHELL_SURFACE_RESIZE_BOTTOM; + break; + default: + assert(0); + } + if (edges != WL_SHELL_SURFACE_RESIZE_NONE) + { + if (window.wl.xdg.toplevel) + xdg_toplevel_resize(window.wl.xdg.toplevel, _glfw.wl.seat, + serial, edges); + else + wl_shell_surface_resize(window.wl.shellSurface, _glfw.wl.seat, + serial, edges); + } + } + else if (button == BTN_RIGHT) + { + if (window.wl.decorations.focus != mainWindow && window.wl.xdg.toplevel) + { + xdg_toplevel_show_window_menu(window.wl.xdg.toplevel, + _glfw.wl.seat, serial, + window.wl.cursorPosX, + window.wl.cursorPosY); + return; + } + } + + // Don’t pass the button to the user if it was related to a decoration. + if (window.wl.decorations.focus != mainWindow) + return; + + _glfw.wl.serial = serial; + + /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev + * codes. */ + glfwButton = button - BTN_LEFT; + + _glfwInputMouseClick(window, + glfwButton, + state == WL_POINTER_BUTTON_STATE_PRESSED + ? GLFW_PRESS + : GLFW_RELEASE, + _glfw.wl.xkb.modifiers); +} + +static void pointerHandleAxis(void* data, wl_pointer* pointer, uint time, uint axis, wl_fixed_t value) { + _GLFWwindow* window = _glfw.wl.pointerFocus; + double x = 0.0;double y = 0.0; + // Wayland scroll events are in pointer motion coordinate space (think two + // finger scroll). The factor 10 is commonly used to convert to "scroll + // step means 1.0. + const(double) scrollFactor = 1.0 / 10.0; + + if (!window) + return; + + assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL || + axis == WL_POINTER_AXIS_VERTICAL_SCROLL); + + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) + x = wl_fixed_to_double(value) * scrollFactor; + else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + y = wl_fixed_to_double(value) * scrollFactor; + + _glfwInputScroll(window, x, y); +} + +static const(wl_pointer_listener) pointerListener = wl_pointer_listener( + &pointerHandleEnter, + &pointerHandleLeave, + &pointerHandleMotion, + &pointerHandleButton, + &pointerHandleAxis, +); + +static void keyboardHandleKeymap(void* data, wl_keyboard* keyboard, uint format, int fd, uint size) { + xkb_keymap* keymap; + xkb_state* state; + +version (HAVE_XKBCOMMON_COMPOSE_H) { + xkb_compose_table* composeTable; + xkb_compose_state* composeState; +} + + char* mapStr; + const(char)* locale; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + { + close(fd); + return; + } + + mapStr = cast(char*) mmap(null, size, PROT_READ, MAP_SHARED, fd, 0); + if (mapStr == MAP_FAILED) { + close(fd); + return; + } + + keymap = _glfw.wl.xkb.keymap_new_from_string(_glfw.wl.xkb.context, + mapStr, + XKB_KEYMAP_FORMAT_TEXT_V1, + 0); + munmap(mapStr, size); + close(fd); + + if (!keymap) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to compile keymap"); + return; + } + + state = _glfw.wl.xkb.state_new(keymap); + if (!state) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB state"); + _glfw.wl.xkb.keymap_unref(keymap); + return; + } + + // Look up the preferred locale, falling back to "C" as default. + locale = getenv("LC_ALL"); + if (!locale) + locale = getenv("LC_CTYPE"); + if (!locale) + locale = getenv("LANG"); + if (!locale) + locale = "C"; + +version (HAVE_XKBCOMMON_COMPOSE_H) { + composeTable = + xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, + XKB_COMPOSE_COMPILE_NO_FLAGS); + if (composeTable) + { + composeState = + xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS); + xkb_compose_table_unref(composeTable); + if (composeState) + _glfw.wl.xkb.composeState = composeState; + else + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB compose state"); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB compose table"); + } +} + + _glfw.wl.xkb.keymap_unref(_glfw.wl.xkb.keymap); + _glfw.wl.xkb.state_unref(_glfw.wl.xkb.state); + _glfw.wl.xkb.keymap = keymap; + _glfw.wl.xkb.state = state; + + _glfw.wl.xkb.controlMask = + 1 << _glfw.wl.xkb.keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control"); + _glfw.wl.xkb.altMask = + 1 << _glfw.wl.xkb.keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); + _glfw.wl.xkb.shiftMask = + 1 << _glfw.wl.xkb.keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); + _glfw.wl.xkb.superMask = + 1 << _glfw.wl.xkb.keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); + _glfw.wl.xkb.capsLockMask = + 1 << _glfw.wl.xkb.keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); + _glfw.wl.xkb.numLockMask = + 1 << _glfw.wl.xkb.keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); +} + +static void keyboardHandleEnter(void* data, wl_keyboard* keyboard, uint serial, wl_surface* surface, wl_array* keys) { + // Happens in the case we just destroyed the surface. + if (!surface) + return; + + _GLFWwindow* window = wl_surface_get_user_data(surface); + if (!window) + { + window = findWindowFromDecorationSurface(surface, null); + if (!window) + return; + } + + _glfw.wl.serial = serial; + _glfw.wl.keyboardFocus = window; + _glfwInputWindowFocus(window, GLFW_TRUE); +} + +static void keyboardHandleLeave(void* data, wl_keyboard* keyboard, uint serial, wl_surface* surface) { + _GLFWwindow* window = _glfw.wl.keyboardFocus; + + if (!window) + return; + + _glfw.wl.serial = serial; + _glfw.wl.keyboardFocus = null; + _glfwInputWindowFocus(window, GLFW_FALSE); +} + +static int toGLFWKeyCode(uint key) { + if (key < _glfw.wl.keycodes.length) + return _glfw.wl.keycodes[key]; + + return GLFW_KEY_UNKNOWN; +} + +version (HAVE_XKBCOMMON_COMPOSE_H) { +static xkb_keysym_t composeSymbol(xkb_keysym_t sym) { + if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState) + return sym; + if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym) + != XKB_COMPOSE_FEED_ACCEPTED) + return sym; + switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState)) + { + case XKB_COMPOSE_COMPOSED: + return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState); + case XKB_COMPOSE_COMPOSING: + case XKB_COMPOSE_CANCELLED: + return XKB_KEY_NoSymbol; + case XKB_COMPOSE_NOTHING: + default: + return sym; + } +} +} + +static GLFWbool inputChar(_GLFWwindow* window, uint key) { + uint code;uint numSyms; + c_long cp; + const(xkb_keysym_t)* syms; + xkb_keysym_t sym; + + code = key + 8; + numSyms = _glfw.wl.xkb.state_key_get_syms(_glfw.wl.xkb.state, code, &syms); + + if (numSyms == 1) + { +version (HAVE_XKBCOMMON_COMPOSE_H) { + sym = composeSymbol(syms[0]); +} else { + sym = syms[0]; +} + cp = _glfwKeySym2Unicode(sym); + if (cp != -1) + { + const(int) mods = _glfw.wl.xkb.modifiers; + const(int) plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + _glfwInputChar(window, cast(uint) cp, mods, plain); + } + } + + return _glfw.wl.xkb.keymap_key_repeats(_glfw.wl.xkb.keymap, syms[0]); +} + +static void keyboardHandleKey(void* data, wl_keyboard* keyboard, uint serial, uint time, uint key, uint state) { + int keyCode; + int action; + _GLFWwindow* window = _glfw.wl.keyboardFocus; + GLFWbool shouldRepeat; + itimerspec timer = {}; + + if (!window) + return; + + keyCode = toGLFWKeyCode(key); + action = state == WL_KEYBOARD_KEY_STATE_PRESSED + ? GLFW_PRESS : GLFW_RELEASE; + + _glfw.wl.serial = serial; + _glfwInputKey(window, keyCode, key, action, + _glfw.wl.xkb.modifiers); + + if (action == GLFW_PRESS) + { + shouldRepeat = inputChar(window, key); + + if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0) + { + _glfw.wl.keyboardLastKey = keyCode; + _glfw.wl.keyboardLastScancode = key; + if (_glfw.wl.keyboardRepeatRate > 1) + timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyboardRepeatRate; + else + timer.it_interval.tv_sec = 1; + timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000; + timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000; + } + } + timerfd_settime(_glfw.wl.timerfd, 0, &timer, null); +} + +static void keyboardHandleModifiers(void* data, wl_keyboard* keyboard, uint serial, uint modsDepressed, uint modsLatched, uint modsLocked, uint group) { + xkb_mod_mask_t mask; + uint modifiers = 0; + + _glfw.wl.serial = serial; + + if (!_glfw.wl.xkb.keymap) + return; + + _glfw.wl.xkb.state_update_mask(_glfw.wl.xkb.state, + modsDepressed, + modsLatched, + modsLocked, + 0, + 0, + group); + + mask = _glfw.wl.xkb.state_serialize_mods(_glfw.wl.xkb.state, + XKB_STATE_MODS_DEPRESSED | + XKB_STATE_LAYOUT_DEPRESSED | + XKB_STATE_MODS_LATCHED | + XKB_STATE_LAYOUT_LATCHED); + if (mask & _glfw.wl.xkb.controlMask) + modifiers |= GLFW_MOD_CONTROL; + if (mask & _glfw.wl.xkb.altMask) + modifiers |= GLFW_MOD_ALT; + if (mask & _glfw.wl.xkb.shiftMask) + modifiers |= GLFW_MOD_SHIFT; + if (mask & _glfw.wl.xkb.superMask) + modifiers |= GLFW_MOD_SUPER; + if (mask & _glfw.wl.xkb.capsLockMask) + modifiers |= GLFW_MOD_CAPS_LOCK; + if (mask & _glfw.wl.xkb.numLockMask) + modifiers |= GLFW_MOD_NUM_LOCK; + _glfw.wl.xkb.modifiers = modifiers; +} + +version (WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { + static void keyboardHandleRepeatInfo(void* data, wl_keyboard* keyboard, int rate, int delay) { + if (keyboard != _glfw.wl.keyboard) + return; + + _glfw.wl.keyboardRepeatRate = rate; + _glfw.wl.keyboardRepeatDelay = delay; + } + + static const(wl_keyboard_listener) keyboardListener = wl_keyboard_listener( + &keyboardHandleKeymap, + &keyboardHandleEnter, + &keyboardHandleLeave, + &keyboardHandleKey, + &keyboardHandleModifiers, + &keyboardHandleRepeatInfo, + ); +} else { + static const(wl_keyboard_listener) keyboardListener = wl_keyboard_listener( + &keyboardHandleKeymap, + &keyboardHandleEnter, + &keyboardHandleLeave, + &keyboardHandleKey, + &keyboardHandleModifiers, + // no keyboardHandleRepeatInfo, + ); +} + +static void seatHandleCapabilities(void* data, wl_seat* seat, /*enum wl_seat_capability*/ uint caps) { + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer) + { + _glfw.wl.pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, null); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) + { + wl_pointer_destroy(_glfw.wl.pointer); + _glfw.wl.pointer = null; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard) + { + _glfw.wl.keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, null); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) + { + wl_keyboard_destroy(_glfw.wl.keyboard); + _glfw.wl.keyboard = null; + } +} + +static void seatHandleName(void* data, wl_seat* seat, const(char)* name) { +} + +static const(wl_seat_listener) seatListener = wl_seat_listener( + &seatHandleCapabilities, + &seatHandleName, +); + +static void dataOfferHandleOffer(void* data, wl_data_offer* dataOffer, const(char)* mimeType) { +} + +static const(wl_data_offer_listener) dataOfferListener = wl_data_offer_listener( + &dataOfferHandleOffer, +); + +static void dataDeviceHandleDataOffer(void* data, wl_data_device* dataDevice, wl_data_offer* id) { + if (_glfw.wl.dataOffer) + wl_data_offer_destroy(_glfw.wl.dataOffer); + + _glfw.wl.dataOffer = id; + wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, null); +} + +static void dataDeviceHandleEnter(void* data, wl_data_device* dataDevice, uint serial, wl_surface* surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer* id) { +} + +static void dataDeviceHandleLeave(void* data, wl_data_device* dataDevice) { +} + +static void dataDeviceHandleMotion(void* data, wl_data_device* dataDevice, uint time, wl_fixed_t x, wl_fixed_t y) { +} + +static void dataDeviceHandleDrop(void* data, wl_data_device* dataDevice) { +} + +static void dataDeviceHandleSelection(void* data, wl_data_device* dataDevice, wl_data_offer* id) { +} + +static const(wl_data_device_listener) dataDeviceListener = wl_data_device_listener( + &dataDeviceHandleDataOffer, + &dataDeviceHandleEnter, + &dataDeviceHandleLeave, + &dataDeviceHandleMotion, + &dataDeviceHandleDrop, + &dataDeviceHandleSelection, +); + +static void wmBaseHandlePing(void* data, xdg_wm_base* wmBase, uint serial) { + xdg_wm_base_pong(wmBase, serial); +} + +static const(xdg_wm_base_listener) wmBaseListener = xdg_wm_base_listener( + &wmBaseHandlePing +); + +static void registryHandleGlobal(void* data, wl_registry* registry, uint name, const(char)* interface_, uint version_) { + if (strcmp(interface_, "wl_compositor") == 0) + { + _glfw.wl.compositorVersion = min(3, version_); + _glfw.wl.compositor = cast(wl_compositor*) + wl_registry_bind(registry, name, &wl_compositor_interface, + _glfw.wl.compositorVersion); + } + else if (strcmp(interface_, "wl_subcompositor") == 0) + { + _glfw.wl.subcompositor = cast(wl_subcompositor*) + wl_registry_bind(registry, name, &wl_subcompositor_interface, 1); + } + else if (strcmp(interface_, "wl_shm") == 0) + { + _glfw.wl.shm = cast(wl_shm*) + wl_registry_bind(registry, name, &wl_shm_interface, 1); + } + else if (strcmp(interface_, "wl_shell") == 0) + { + _glfw.wl.shell = cast(wl_shell*) + wl_registry_bind(registry, name, &wl_shell_interface, 1); + } + else if (strcmp(interface_, "wl_output") == 0) + { + _glfwAddOutputWayland(name, version_); + } + else if (strcmp(interface_, "wl_seat") == 0) + { + if (!_glfw.wl.seat) + { + _glfw.wl.seatVersion = min(4, version_); + _glfw.wl.seat = cast(wl_seat*) + wl_registry_bind(registry, name, &wl_seat_interface, + _glfw.wl.seatVersion); + wl_seat_add_listener(_glfw.wl.seat, &seatListener, null); + } + } + else if (strcmp(interface_, "wl_data_device_manager") == 0) + { + if (!_glfw.wl.dataDeviceManager) + { + _glfw.wl.dataDeviceManager = cast(wl_data_device_manager*) + wl_registry_bind(registry, name, + &wl_data_device_manager_interface, 1); + } + } + else if (strcmp(interface_, "xdg_wm_base") == 0) + { + _glfw.wl.wmBase = + wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, null); + } + else if (strcmp(interface_, "zxdg_decoration_manager_v1") == 0) + { + _glfw.wl.decorationManager = + wl_registry_bind(registry, name, + &zxdg_decoration_manager_v1_interface, + 1); + } + else if (strcmp(interface_, "wp_viewporter") == 0) + { + _glfw.wl.viewporter = + wl_registry_bind(registry, name, &wp_viewporter_interface, 1); + } + else if (strcmp(interface_, "zwp_relative_pointer_manager_v1") == 0) + { + _glfw.wl.relativePointerManager = + wl_registry_bind(registry, name, + &zwp_relative_pointer_manager_v1_interface, + 1); + } + else if (strcmp(interface_, "zwp_pointer_constraints_v1") == 0) + { + _glfw.wl.pointerConstraints = + wl_registry_bind(registry, name, + &zwp_pointer_constraints_v1_interface, + 1); + } + else if (strcmp(interface_, "zwp_idle_inhibit_manager_v1") == 0) + { + _glfw.wl.idleInhibitManager = + wl_registry_bind(registry, name, + &zwp_idle_inhibit_manager_v1_interface, + 1); + } +} + +static void registryHandleGlobalRemove(void* data, wl_registry* registry, uint name) { + int i; + _GLFWmonitor* monitor; + + for (i = 0; i < _glfw.monitorCount; ++i) + { + monitor = _glfw.monitors[i]; + if (monitor.wl.name == name) + { + _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0); + return; + } + } +} + + +static const(wl_registry_listener) registryListener = wl_registry_listener( + ®istryHandleGlobal, + ®istryHandleGlobalRemove +); + +// Create key code translation tables +// +static void createKeyTables() { + int scancode; + + memset(_glfw.wl.keycodes.ptr, -1, typeof(_glfw.wl.keycodes).sizeof); + memset(_glfw.wl.scancodes.ptr, -1, typeof(_glfw.wl.scancodes).sizeof); + + _glfw.wl.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; + _glfw.wl.keycodes[KEY_1] = GLFW_KEY_1; + _glfw.wl.keycodes[KEY_2] = GLFW_KEY_2; + _glfw.wl.keycodes[KEY_3] = GLFW_KEY_3; + _glfw.wl.keycodes[KEY_4] = GLFW_KEY_4; + _glfw.wl.keycodes[KEY_5] = GLFW_KEY_5; + _glfw.wl.keycodes[KEY_6] = GLFW_KEY_6; + _glfw.wl.keycodes[KEY_7] = GLFW_KEY_7; + _glfw.wl.keycodes[KEY_8] = GLFW_KEY_8; + _glfw.wl.keycodes[KEY_9] = GLFW_KEY_9; + _glfw.wl.keycodes[KEY_0] = GLFW_KEY_0; + _glfw.wl.keycodes[KEY_SPACE] = GLFW_KEY_SPACE; + _glfw.wl.keycodes[KEY_MINUS] = GLFW_KEY_MINUS; + _glfw.wl.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL; + _glfw.wl.keycodes[KEY_Q] = GLFW_KEY_Q; + _glfw.wl.keycodes[KEY_W] = GLFW_KEY_W; + _glfw.wl.keycodes[KEY_E] = GLFW_KEY_E; + _glfw.wl.keycodes[KEY_R] = GLFW_KEY_R; + _glfw.wl.keycodes[KEY_T] = GLFW_KEY_T; + _glfw.wl.keycodes[KEY_Y] = GLFW_KEY_Y; + _glfw.wl.keycodes[KEY_U] = GLFW_KEY_U; + _glfw.wl.keycodes[KEY_I] = GLFW_KEY_I; + _glfw.wl.keycodes[KEY_O] = GLFW_KEY_O; + _glfw.wl.keycodes[KEY_P] = GLFW_KEY_P; + _glfw.wl.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; + _glfw.wl.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; + _glfw.wl.keycodes[KEY_A] = GLFW_KEY_A; + _glfw.wl.keycodes[KEY_S] = GLFW_KEY_S; + _glfw.wl.keycodes[KEY_D] = GLFW_KEY_D; + _glfw.wl.keycodes[KEY_F] = GLFW_KEY_F; + _glfw.wl.keycodes[KEY_G] = GLFW_KEY_G; + _glfw.wl.keycodes[KEY_H] = GLFW_KEY_H; + _glfw.wl.keycodes[KEY_J] = GLFW_KEY_J; + _glfw.wl.keycodes[KEY_K] = GLFW_KEY_K; + _glfw.wl.keycodes[KEY_L] = GLFW_KEY_L; + _glfw.wl.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; + _glfw.wl.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; + _glfw.wl.keycodes[KEY_Z] = GLFW_KEY_Z; + _glfw.wl.keycodes[KEY_X] = GLFW_KEY_X; + _glfw.wl.keycodes[KEY_C] = GLFW_KEY_C; + _glfw.wl.keycodes[KEY_V] = GLFW_KEY_V; + _glfw.wl.keycodes[KEY_B] = GLFW_KEY_B; + _glfw.wl.keycodes[KEY_N] = GLFW_KEY_N; + _glfw.wl.keycodes[KEY_M] = GLFW_KEY_M; + _glfw.wl.keycodes[KEY_COMMA] = GLFW_KEY_COMMA; + _glfw.wl.keycodes[KEY_DOT] = GLFW_KEY_PERIOD; + _glfw.wl.keycodes[KEY_SLASH] = GLFW_KEY_SLASH; + _glfw.wl.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; + _glfw.wl.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE; + _glfw.wl.keycodes[KEY_TAB] = GLFW_KEY_TAB; + _glfw.wl.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; + _glfw.wl.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; + _glfw.wl.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; + _glfw.wl.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; + _glfw.wl.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; + _glfw.wl.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; + _glfw.wl.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; + _glfw.wl.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; + _glfw.wl.keycodes[KEY_MENU] = GLFW_KEY_MENU; + _glfw.wl.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; + _glfw.wl.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; + _glfw.wl.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; + _glfw.wl.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; + _glfw.wl.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE; + _glfw.wl.keycodes[KEY_DELETE] = GLFW_KEY_DELETE; + _glfw.wl.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; + _glfw.wl.keycodes[KEY_ENTER] = GLFW_KEY_ENTER; + _glfw.wl.keycodes[KEY_HOME] = GLFW_KEY_HOME; + _glfw.wl.keycodes[KEY_END] = GLFW_KEY_END; + _glfw.wl.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; + _glfw.wl.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; + _glfw.wl.keycodes[KEY_INSERT] = GLFW_KEY_INSERT; + _glfw.wl.keycodes[KEY_LEFT] = GLFW_KEY_LEFT; + _glfw.wl.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT; + _glfw.wl.keycodes[KEY_DOWN] = GLFW_KEY_DOWN; + _glfw.wl.keycodes[KEY_UP] = GLFW_KEY_UP; + _glfw.wl.keycodes[KEY_F1] = GLFW_KEY_F1; + _glfw.wl.keycodes[KEY_F2] = GLFW_KEY_F2; + _glfw.wl.keycodes[KEY_F3] = GLFW_KEY_F3; + _glfw.wl.keycodes[KEY_F4] = GLFW_KEY_F4; + _glfw.wl.keycodes[KEY_F5] = GLFW_KEY_F5; + _glfw.wl.keycodes[KEY_F6] = GLFW_KEY_F6; + _glfw.wl.keycodes[KEY_F7] = GLFW_KEY_F7; + _glfw.wl.keycodes[KEY_F8] = GLFW_KEY_F8; + _glfw.wl.keycodes[KEY_F9] = GLFW_KEY_F9; + _glfw.wl.keycodes[KEY_F10] = GLFW_KEY_F10; + _glfw.wl.keycodes[KEY_F11] = GLFW_KEY_F11; + _glfw.wl.keycodes[KEY_F12] = GLFW_KEY_F12; + _glfw.wl.keycodes[KEY_F13] = GLFW_KEY_F13; + _glfw.wl.keycodes[KEY_F14] = GLFW_KEY_F14; + _glfw.wl.keycodes[KEY_F15] = GLFW_KEY_F15; + _glfw.wl.keycodes[KEY_F16] = GLFW_KEY_F16; + _glfw.wl.keycodes[KEY_F17] = GLFW_KEY_F17; + _glfw.wl.keycodes[KEY_F18] = GLFW_KEY_F18; + _glfw.wl.keycodes[KEY_F19] = GLFW_KEY_F19; + _glfw.wl.keycodes[KEY_F20] = GLFW_KEY_F20; + _glfw.wl.keycodes[KEY_F21] = GLFW_KEY_F21; + _glfw.wl.keycodes[KEY_F22] = GLFW_KEY_F22; + _glfw.wl.keycodes[KEY_F23] = GLFW_KEY_F23; + _glfw.wl.keycodes[KEY_F24] = GLFW_KEY_F24; + _glfw.wl.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; + _glfw.wl.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; + _glfw.wl.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; + _glfw.wl.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; + _glfw.wl.keycodes[KEY_KP0] = GLFW_KEY_KP_0; + _glfw.wl.keycodes[KEY_KP1] = GLFW_KEY_KP_1; + _glfw.wl.keycodes[KEY_KP2] = GLFW_KEY_KP_2; + _glfw.wl.keycodes[KEY_KP3] = GLFW_KEY_KP_3; + _glfw.wl.keycodes[KEY_KP4] = GLFW_KEY_KP_4; + _glfw.wl.keycodes[KEY_KP5] = GLFW_KEY_KP_5; + _glfw.wl.keycodes[KEY_KP6] = GLFW_KEY_KP_6; + _glfw.wl.keycodes[KEY_KP7] = GLFW_KEY_KP_7; + _glfw.wl.keycodes[KEY_KP8] = GLFW_KEY_KP_8; + _glfw.wl.keycodes[KEY_KP9] = GLFW_KEY_KP_9; + _glfw.wl.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; + _glfw.wl.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; + _glfw.wl.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; + + for (scancode = 0; scancode < 256; scancode++) + { + if (_glfw.wl.keycodes[scancode] > 0) + _glfw.wl.scancodes[_glfw.wl.keycodes[scancode]] = scancode; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit() { + const(char)* cursorTheme; + const(char)* cursorSizeStr; + const(char)* cursorSizeEnd; + c_long cursorSizeLong; + int cursorSize; + + _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0"); + if (!_glfw.wl.cursor.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to open libwayland-cursor"); + return GLFW_FALSE; + } + + _glfw.wl.cursor.theme_load = cast(PFN_wl_cursor_theme_load) + _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load"); + _glfw.wl.cursor.theme_destroy = cast(PFN_wl_cursor_theme_destroy) + _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy"); + _glfw.wl.cursor.theme_get_cursor = cast(PFN_wl_cursor_theme_get_cursor) + _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor"); + _glfw.wl.cursor.image_get_buffer = cast(PFN_wl_cursor_image_get_buffer) + _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer"); + + _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1"); + if (!_glfw.wl.egl.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to open libwayland-egl"); + return GLFW_FALSE; + } + + _glfw.wl.egl.window_create = cast(PFN_wl_egl_window_create) + _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create"); + _glfw.wl.egl.window_destroy = cast(PFN_wl_egl_window_destroy) + _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy"); + _glfw.wl.egl.window_resize = cast(PFN_wl_egl_window_resize) + _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize"); + + _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0"); + if (!_glfw.wl.xkb.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to open libxkbcommon"); + return GLFW_FALSE; + } + + _glfw.wl.xkb.context_new = cast(PFN_xkb_context_new) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new"); + _glfw.wl.xkb.context_unref = cast(PFN_xkb_context_unref) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref"); + _glfw.wl.xkb.keymap_new_from_string = cast(PFN_xkb_keymap_new_from_string) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); + _glfw.wl.xkb.keymap_unref = cast(PFN_xkb_keymap_unref) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref"); + _glfw.wl.xkb.keymap_mod_get_index = cast(PFN_xkb_keymap_mod_get_index) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); + _glfw.wl.xkb.keymap_key_repeats = cast(PFN_xkb_keymap_key_repeats) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_key_repeats"); + _glfw.wl.xkb.state_new = cast(PFN_xkb_state_new) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new"); + _glfw.wl.xkb.state_unref = cast(PFN_xkb_state_unref) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref"); + _glfw.wl.xkb.state_key_get_syms = cast(PFN_xkb_state_key_get_syms) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); + _glfw.wl.xkb.state_update_mask = cast(PFN_xkb_state_update_mask) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_update_mask"); + _glfw.wl.xkb.state_serialize_mods = cast(PFN_xkb_state_serialize_mods) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_serialize_mods"); + +version (HAVE_XKBCOMMON_COMPOSE_H) { + _glfw.wl.xkb.compose_table_new_from_locale = cast(PFN_xkb_compose_table_new_from_locale) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_new_from_locale"); + _glfw.wl.xkb.compose_table_unref = cast(PFN_xkb_compose_table_unref) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); + _glfw.wl.xkb.compose_state_new = cast(PFN_xkb_compose_state_new) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_new"); + _glfw.wl.xkb.compose_state_unref = cast(PFN_xkb_compose_state_unref) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_unref"); + _glfw.wl.xkb.compose_state_feed = cast(PFN_xkb_compose_state_feed) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_feed"); + _glfw.wl.xkb.compose_state_get_status = cast(PFN_xkb_compose_state_get_status) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_status"); + _glfw.wl.xkb.compose_state_get_one_sym = cast(PFN_xkb_compose_state_get_one_sym) + _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); +} + + _glfw.wl.display = wl_display_connect(null); + if (!_glfw.wl.display) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to connect to display"); + return GLFW_FALSE; + } + + _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); + wl_registry_add_listener(_glfw.wl.registry, ®istryListener, null); + + createKeyTables(); + + _glfw.wl.xkb.context = _glfw.wl.xkb.context_new(0); + if (!_glfw.wl.xkb.context) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to initialize xkb context"); + return GLFW_FALSE; + } + + // Sync so we got all registry objects + wl_display_roundtrip(_glfw.wl.display); + + // Sync so we got all initial output events + wl_display_roundtrip(_glfw.wl.display); + +version (linux) { + if (!_glfwInitJoysticksLinux()) + return GLFW_FALSE; +} + + _glfwInitTimerPOSIX(); + + _glfw.wl.timerfd = -1; + if (_glfw.wl.seatVersion >= 4) + _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + + if (_glfw.wl.pointer && _glfw.wl.shm) + { + cursorTheme = getenv("XCURSOR_THEME"); + cursorSizeStr = getenv("XCURSOR_SIZE"); + cursorSize = 32; + if (cursorSizeStr) + { + errno = 0; + cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10); + if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX) + cursorSize = cast(int)cursorSizeLong; + } + _glfw.wl.cursorTheme = + _glfw.wl.cursor.theme_load(cursorTheme, cursorSize, _glfw.wl.shm); + if (!_glfw.wl.cursorTheme) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unable to load default cursor theme"); + return GLFW_FALSE; + } + // If this happens to be NULL, we just fallback to the scale=1 version. + _glfw.wl.cursorThemeHiDPI = + _glfw.wl.cursor.theme_load(cursorTheme, 2 * cursorSize, _glfw.wl.shm); + _glfw.wl.cursorSurface = + wl_compositor_create_surface(_glfw.wl.compositor); + _glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + } + + if (_glfw.wl.seat && _glfw.wl.dataDeviceManager) + { + _glfw.wl.dataDevice = + wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager, + _glfw.wl.seat); + wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, null); + _glfw.wl.clipboardString = cast(char*) malloc(4096); + if (!_glfw.wl.clipboardString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unable to allocate clipboard memory"); + return GLFW_FALSE; + } + _glfw.wl.clipboardSize = 4096; + } + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate() { +version (linux) { + _glfwTerminateJoysticksLinux(); +} + _glfwTerminateEGL(); + if (_glfw.wl.egl.handle) + { + _glfw_dlclose(_glfw.wl.egl.handle); + _glfw.wl.egl.handle = null; + } + +version (HAVE_XKBCOMMON_COMPOSE_H) { + if (_glfw.wl.xkb.composeState) + xkb_compose_state_unref(_glfw.wl.xkb.composeState); +} + if (_glfw.wl.xkb.keymap) + _glfw.wl.xkb.keymap_unref(_glfw.wl.xkb.keymap); + if (_glfw.wl.xkb.state) + _glfw.wl.xkb.state_unref(_glfw.wl.xkb.state); + if (_glfw.wl.xkb.context) + _glfw.wl.xkb.context_unref(_glfw.wl.xkb.context); + if (_glfw.wl.xkb.handle) + { + _glfw_dlclose(_glfw.wl.xkb.handle); + _glfw.wl.xkb.handle = null; + } + + if (_glfw.wl.cursorTheme) + _glfw.wl.cursor.theme_destroy(_glfw.wl.cursorTheme); + if (_glfw.wl.cursorThemeHiDPI) + _glfw.wl.cursor.theme_destroy(_glfw.wl.cursorThemeHiDPI); + if (_glfw.wl.cursor.handle) + { + _glfw_dlclose(_glfw.wl.cursor.handle); + _glfw.wl.cursor.handle = null; + } + + if (_glfw.wl.cursorSurface) + wl_surface_destroy(_glfw.wl.cursorSurface); + if (_glfw.wl.subcompositor) + wl_subcompositor_destroy(_glfw.wl.subcompositor); + if (_glfw.wl.compositor) + wl_compositor_destroy(_glfw.wl.compositor); + if (_glfw.wl.shm) + wl_shm_destroy(_glfw.wl.shm); + if (_glfw.wl.shell) + wl_shell_destroy(_glfw.wl.shell); + if (_glfw.wl.viewporter) + wp_viewporter_destroy(_glfw.wl.viewporter); + if (_glfw.wl.decorationManager) + zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager); + if (_glfw.wl.wmBase) + xdg_wm_base_destroy(_glfw.wl.wmBase); + if (_glfw.wl.dataSource) + wl_data_source_destroy(_glfw.wl.dataSource); + if (_glfw.wl.dataDevice) + wl_data_device_destroy(_glfw.wl.dataDevice); + if (_glfw.wl.dataOffer) + wl_data_offer_destroy(_glfw.wl.dataOffer); + if (_glfw.wl.dataDeviceManager) + wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager); + if (_glfw.wl.pointer) + wl_pointer_destroy(_glfw.wl.pointer); + if (_glfw.wl.keyboard) + wl_keyboard_destroy(_glfw.wl.keyboard); + if (_glfw.wl.seat) + wl_seat_destroy(_glfw.wl.seat); + if (_glfw.wl.relativePointerManager) + zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager); + if (_glfw.wl.pointerConstraints) + zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints); + if (_glfw.wl.idleInhibitManager) + zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager); + if (_glfw.wl.registry) + wl_registry_destroy(_glfw.wl.registry); + if (_glfw.wl.display) + { + wl_display_flush(_glfw.wl.display); + wl_display_disconnect(_glfw.wl.display); + } + + if (_glfw.wl.timerfd >= 0) + close(_glfw.wl.timerfd); + if (_glfw.wl.cursorTimerfd >= 0) + close(_glfw.wl.cursorTimerfd); + + if (_glfw.wl.clipboardString) + free(_glfw.wl.clipboardString); + if (_glfw.wl.clipboardSendString) + free(_glfw.wl.clipboardSendString); +} + +const(char)* _glfwPlatformGetVersionString() { + version (_POSIX_TIMERS) { + enum timeStr = " clock_gettime"; + } else version (_POSIX_MONOTONIC_CLOCK) { + enum timeStr = " gettimeofday"; + } else { + enum timeStr = " gettimeofday"; + } + version (_GLFW_BUILD_DLL) { + enum dllStr = " shared"; + } else { + enum dllStr = ""; + } + return _GLFW_VERSION_NUMBER ~ " Wayland EGL OSMesa" ~ timeStr ~ " evdev" ~ dllStr; +} \ No newline at end of file diff --git a/source/glfw3/wl_monitor.d b/source/glfw3/wl_monitor.d new file mode 100644 index 0000000..2f1d090 --- /dev/null +++ b/source/glfw3/wl_monitor.d @@ -0,0 +1,194 @@ +/// Translated from C to D +module glfw3.wl_monitor; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +public import glfw3.internal; + +public import core.stdc.stdio; +public import core.stdc.stdlib; +public import core.stdc.string; +public import core.stdc.errno; +public import core.stdc.math; + + +static void outputHandleGeometry(void* data, wl_output* output, int x, int y, int physicalWidth, int physicalHeight, int subpixel, const(char)* make, const(char)* model, int transform) { + auto monitor = cast(_GLFWmonitor*) data; + char[1024] name; + + monitor.wl.x = x; + monitor.wl.y = y; + monitor.widthMM = physicalWidth; + monitor.heightMM = physicalHeight; + + snprintf(name.ptr, name.sizeof, "%s %s", make, model); + monitor.name = _glfw_strdup(name.ptr); +} + +static void outputHandleMode(void* data, wl_output* output, uint flags, int width, int height, int refresh) { + auto monitor = cast(_GLFWmonitor*) data; + GLFWvidmode mode; + + mode.width = width; + mode.height = height; + mode.redBits = 8; + mode.greenBits = 8; + mode.blueBits = 8; + mode.refreshRate = cast(int) round(refresh / 1000.0); + + monitor.modeCount++; + monitor.modes = + cast(GLFWvidmode*) realloc(monitor.modes, monitor.modeCount * GLFWvidmode.sizeof); + monitor.modes[monitor.modeCount - 1] = mode; + + if (flags & WL_OUTPUT_MODE_CURRENT) + monitor.wl.currentMode = monitor.modeCount - 1; +} + +static void outputHandleDone(void* data, wl_output* output) { + auto monitor = cast(_GLFWmonitor*) data; + + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); +} + +static void outputHandleScale(void* data, wl_output* output, int factor) { + auto monitor = cast(_GLFWmonitor*) data; + + monitor.wl.scale = factor; +} + +static const(wl_output_listener) outputListener = wl_output_listener( + &outputHandleGeometry, + &outputHandleMode, + &outputHandleDone, + &outputHandleScale, +); + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwAddOutputWayland(uint name, uint version_) { + _GLFWmonitor* monitor; + wl_output* output; + + if (version_ < 2) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unsupported output interface version"); + return; + } + + // The actual name of this output will be set in the geometry handler. + monitor = _glfwAllocMonitor(null, 0, 0); + + output = cast(wl_output*) wl_registry_bind(_glfw.wl.registry, + name, + &wl_output_interface, + 2); + if (!output) + { + _glfwFreeMonitor(monitor); + return; + } + + monitor.wl.scale = 1; + monitor.wl.output = output; + monitor.wl.name = name; + + wl_output_add_listener(output, &outputListener, monitor); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { + if (monitor.wl.output) + wl_output_destroy(monitor.wl.output); +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { + if (xpos) + *xpos = monitor.wl.x; + if (ypos) + *ypos = monitor.wl.y; +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { + if (xscale) + *xscale = cast(float) monitor.wl.scale; + if (yscale) + *yscale = cast(float) monitor.wl.scale; +} + +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { + if (xpos) + *xpos = monitor.wl.x; + if (ypos) + *ypos = monitor.wl.y; + if (width) + *width = monitor.modes[monitor.wl.currentMode].width; + if (height) + *height = monitor.modes[monitor.wl.currentMode].height; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { + *found = monitor.modeCount; + return monitor.modes; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { + *mode = monitor.modes[monitor.wl.currentMode]; +} + +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Gamma ramp access is not available"); + return GLFW_FALSE; +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const(GLFWgammaramp)* ramp) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Gamma ramp access is not available"); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return monitor.wl.output; +} \ No newline at end of file diff --git a/source/glfw3/wl_platform.d b/source/glfw3/wl_platform.d new file mode 100644 index 0000000..3e9ec87 --- /dev/null +++ b/source/glfw3/wl_platform.d @@ -0,0 +1,363 @@ +/// Translated from C to D +module glfw3.wl_platform; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +//public import wayland.client; +//public import xkbcommon.xkbcommon; +version (HAVE_XKBCOMMON_COMPOSE_H) { + public import xkbcommon.xkbcommon_compose; +} +import xkbcommon.xkbcommon; +public import core.sys.posix.dlfcn; +import glfw3.internal; + +alias VkFlags VkWaylandSurfaceCreateFlagsKHR; + +struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const(void)* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + wl_display* display; + wl_surface* surface; +} + +alias VkResult function(VkInstance, const(VkWaylandSurfaceCreateInfoKHR)*, const(VkAllocationCallbacks)*, VkSurfaceKHR*) PFN_vkCreateWaylandSurfaceKHR; +alias VkBool32 function(VkPhysicalDevice, uint, wl_display*) PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR; + +public import glfw3.posix_thread; +public import glfw3.posix_time; +version (linux) { + public import glfw3.linux_joystick; +} else { + public import glfw3.null_joystick; +} +public import glfw3.xkb_unicode; +public import glfw3.egl_context; +public import glfw3.osmesa_context; +public import glfw3.wayland; +//public import wayland.client; +//public import wayland-xdg-shell-client-protocol; +//public import wayland-xdg-decoration-client-protocol; +//public import wayland-viewporter-client-protocol; +//public import wayland-relative-pointer-unstable-v1-client-protocol; +//public import wayland-pointer-constraints-unstable-v1-client-protocol; +//public import wayland-idle-inhibit-unstable-v1-client-protocol; + +auto _glfw_dlopen(const(char)* name) {return dlopen(name, RTLD_LAZY | RTLD_LOCAL);} +auto _glfw_dlclose(void* handle) {return dlclose(handle);} +auto _glfw_dlsym(void* handle, const(char)* name) {return dlsym(handle, name);} + +enum _GLFW_EGL_NATIVE_WINDOW = `(cast(EGLNativeWindowType) window.wl.native)`; +enum _GLFW_EGL_NATIVE_DISPLAY = `(cast(EGLNativeDisplayType) _glfw.wl.display)`; + +mixin template _GLFW_PLATFORM_WINDOW_STATE() { _GLFWwindowWayland wl;} +mixin template _GLFW_PLATFORM_LIBRARY_WINDOW_STATE() {_GLFWlibraryWayland wl;} +mixin template _GLFW_PLATFORM_MONITOR_STATE() { _GLFWmonitorWayland wl;} +mixin template _GLFW_PLATFORM_CURSOR_STATE() { _GLFWcursorWayland wl;} + +mixin template _GLFW_PLATFORM_CONTEXT_STATE() { int dummyContext; } +mixin template _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE() { int dummyLibraryContext; } + +struct wl_cursor_image { + uint width; + uint height; + uint hotspot_x; + uint hotspot_y; + uint delay; +} +struct wl_cursor { + uint image_count; + wl_cursor_image** images; + char* name; +} +alias wl_cursor_theme* function(const(char)*, int, wl_shm*) PFN_wl_cursor_theme_load; +alias void function(wl_cursor_theme*) PFN_wl_cursor_theme_destroy; +alias wl_cursor* function(wl_cursor_theme*, const(char)*) PFN_wl_cursor_theme_get_cursor; +alias wl_buffer* function(wl_cursor_image*) PFN_wl_cursor_image_get_buffer; +// wl_cursor_theme_load = _glfw.wl.cursor.theme_load; +// wl_cursor_theme_destroy = _glfw.wl.cursor.theme_destroy; +// wl_cursor_theme_get_cursor = _glfw.wl.cursor.theme_get_cursor; +// wl_cursor_image_get_buffer = _glfw.wl.cursor.image_get_buffer; +// wl_egl_window_create = _glfw.wl.egl.window_create; +// wl_egl_window_destroy = _glfw.wl.egl.window_destroy; +// wl_egl_window_resize = _glfw.wl.egl.window_resize; +// xkb_context_new = _glfw.wl.xkb.context_new; +// xkb_context_unref = _glfw.wl.xkb.context_unref; +// xkb_keymap_new_from_string = _glfw.wl.xkb.keymap_new_from_string; +// xkb_keymap_unref = _glfw.wl.xkb.keymap_unref; +// xkb_keymap_mod_get_index = _glfw.wl.xkb.keymap_mod_get_index; +// xkb_keymap_key_repeats = _glfw.wl.xkb.keymap_key_repeats; +// xkb_state_new = _glfw.wl.xkb.state_new; +// xkb_state_unref = _glfw.wl.xkb.state_unref; +// xkb_state_key_get_syms = _glfw.wl.xkb.state_key_get_syms; +// xkb_state_update_mask = _glfw.wl.xkb.state_update_mask; +// xkb_state_serialize_mods = _glfw.wl.xkb.state_serialize_mods; + +alias wl_egl_window* function(wl_surface*, int, int) PFN_wl_egl_window_create; +alias void function(wl_egl_window*) PFN_wl_egl_window_destroy; +alias void function(wl_egl_window*, int, int, int, int) PFN_wl_egl_window_resize; + +alias xkb_context* function(xkb_context_flags) PFN_xkb_context_new; +alias void function(xkb_context*) PFN_xkb_context_unref; +alias xkb_keymap* function(xkb_context*, const(char)*, xkb_keymap_format, xkb_keymap_compile_flags) PFN_xkb_keymap_new_from_string; +alias void function(xkb_keymap*) PFN_xkb_keymap_unref; +alias xkb_mod_index_t function(xkb_keymap*, const(char)*) PFN_xkb_keymap_mod_get_index; +alias int function(xkb_keymap*, xkb_keycode_t) PFN_xkb_keymap_key_repeats; +alias xkb_state* function(xkb_keymap*) PFN_xkb_state_new; +alias void function(xkb_state*) PFN_xkb_state_unref; +alias int function(xkb_state*, xkb_keycode_t, const(xkb_keysym_t)**) PFN_xkb_state_key_get_syms; +alias xkb_state_component function(xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t) PFN_xkb_state_update_mask; +alias xkb_mod_mask_t function(xkb_state*, xkb_state_component) PFN_xkb_state_serialize_mods; + +version (HAVE_XKBCOMMON_COMPOSE_H) { + alias xkb_compose_table* function(xkb_context*, const(char)*, xkb_compose_compile_flags) PFN_xkb_compose_table_new_from_locale; + alias void function(xkb_compose_table*) PFN_xkb_compose_table_unref; + alias xkb_compose_state* function(xkb_compose_table*, xkb_compose_state_flags) PFN_xkb_compose_state_new; + alias void function(xkb_compose_state*) PFN_xkb_compose_state_unref; + alias xkb_compose_feed_result function(xkb_compose_state*, xkb_keysym_t) PFN_xkb_compose_state_feed; + alias xkb_compose_status function(xkb_compose_state*) PFN_xkb_compose_state_get_status; + alias xkb_keysym_t function(xkb_compose_state*) PFN_xkb_compose_state_get_one_sym; + //enum xkb_compose_table_new_from_locale = _glfw.wl.xkb.compose_table_new_from_locale; + //enum xkb_compose_table_unref = _glfw.wl.xkb.compose_table_unref; + //enum xkb_compose_state_new = _glfw.wl.xkb.compose_state_new; + //enum xkb_compose_state_unref = _glfw.wl.xkb.compose_state_unref; + //enum xkb_compose_state_feed = _glfw.wl.xkb.compose_state_feed; + //enum xkb_compose_state_get_status = _glfw.wl.xkb.compose_state_get_status; + //enum xkb_compose_state_get_one_sym = _glfw.wl.xkb.compose_state_get_one_sym; +} + +enum _GLFW_DECORATION_WIDTH = 4; +enum _GLFW_DECORATION_TOP = 24; +enum _GLFW_DECORATION_VERTICAL = (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH); +enum _GLFW_DECORATION_HORIZONTAL = (2 * _GLFW_DECORATION_WIDTH); + +enum _GLFWdecorationSideWayland { + mainWindow, + topDecoration, + leftDecoration, + rightDecoration, + bottomDecoration, + +} +alias mainWindow = _GLFWdecorationSideWayland.mainWindow; +alias topDecoration = _GLFWdecorationSideWayland.topDecoration; +alias leftDecoration = _GLFWdecorationSideWayland.leftDecoration; +alias rightDecoration = _GLFWdecorationSideWayland.rightDecoration; +alias bottomDecoration = _GLFWdecorationSideWayland.bottomDecoration; + +struct _GLFWdecorationWayland { + wl_surface* surface; + wl_subsurface* subsurface; + wp_viewport* viewport; + +}/+alias _GLFWdecorationWayland _GLFWdecorationWayland;+/ + +// Wayland-specific per-window data +// +struct _GLFWwindowWayland { + int width;int height; + GLFWbool visible; + GLFWbool maximized; + GLFWbool hovered; + GLFWbool transparent; + wl_surface* surface; + wl_egl_window* native; + wl_shell_surface* shellSurface; + wl_callback* callback; + + struct _Xdg { + xdg_surface* surface; + xdg_toplevel* toplevel; + zxdg_toplevel_decoration_v1* decoration; + }_Xdg xdg; + + _GLFWcursor* currentCursor; + double cursorPosX;double cursorPosY; + + char* title; + + // We need to track the monitors the window spans on to calculate the + // optimal scaling factor. + int scale; + _GLFWmonitor** monitors; + int monitorsCount; + int monitorsSize; + + struct _PointerLock { + zwp_relative_pointer_v1* relativePointer; + zwp_locked_pointer_v1* lockedPointer; + }_PointerLock pointerLock; + + zwp_idle_inhibitor_v1* idleInhibitor; + + GLFWbool wasFullscreen; + + struct _Decorations { + GLFWbool serverSide; + wl_buffer* buffer; + _GLFWdecorationWayland top;_GLFWdecorationWayland left;_GLFWdecorationWayland right;_GLFWdecorationWayland bottom; + int focus; + }_Decorations decorations; + +}/+alias _GLFWwindowWayland _GLFWwindowWayland;+/ + +// Wayland-specific global data +// +struct _GLFWlibraryWayland { + wl_display* display; + wl_registry* registry; + wl_compositor* compositor; + wl_subcompositor* subcompositor; + wl_shell* shell; + wl_shm* shm; + wl_seat* seat; + wl_pointer* pointer; + wl_keyboard* keyboard; + wl_data_device_manager* dataDeviceManager; + wl_data_device* dataDevice; + wl_data_offer* dataOffer; + wl_data_source* dataSource; + xdg_wm_base* wmBase; + zxdg_decoration_manager_v1* decorationManager; + wp_viewporter* viewporter; + zwp_relative_pointer_manager_v1* relativePointerManager; + zwp_pointer_constraints_v1* pointerConstraints; + zwp_idle_inhibit_manager_v1* idleInhibitManager; + + int compositorVersion; + int seatVersion; + + wl_cursor_theme* cursorTheme; + wl_cursor_theme* cursorThemeHiDPI; + wl_surface* cursorSurface; + const(char)* cursorPreviousName; + int cursorTimerfd; + uint serial; + + int keyboardRepeatRate; + int keyboardRepeatDelay; + int keyboardLastKey; + int keyboardLastScancode; + char* clipboardString; + size_t clipboardSize; + char* clipboardSendString; + size_t clipboardSendSize; + int timerfd; + int[256] keycodes; + int[GLFW_KEY_LAST + 1] scancodes; + + struct _Xkb { + void* handle; + xkb_context* context; + xkb_keymap* keymap; + xkb_state* state; + +version (HAVE_XKBCOMMON_COMPOSE_H) { + xkb_compose_state* composeState; +} + + xkb_mod_mask_t controlMask; + xkb_mod_mask_t altMask; + xkb_mod_mask_t shiftMask; + xkb_mod_mask_t superMask; + xkb_mod_mask_t capsLockMask; + xkb_mod_mask_t numLockMask; + uint modifiers; + + PFN_xkb_context_new context_new; + PFN_xkb_context_unref context_unref; + PFN_xkb_keymap_new_from_string keymap_new_from_string; + PFN_xkb_keymap_unref keymap_unref; + PFN_xkb_keymap_mod_get_index keymap_mod_get_index; + PFN_xkb_keymap_key_repeats keymap_key_repeats; + PFN_xkb_state_new state_new; + PFN_xkb_state_unref state_unref; + PFN_xkb_state_key_get_syms state_key_get_syms; + PFN_xkb_state_update_mask state_update_mask; + PFN_xkb_state_serialize_mods state_serialize_mods; + +version (HAVE_XKBCOMMON_COMPOSE_H) { + PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale; + PFN_xkb_compose_table_unref compose_table_unref; + PFN_xkb_compose_state_new compose_state_new; + PFN_xkb_compose_state_unref compose_state_unref; + PFN_xkb_compose_state_feed compose_state_feed; + PFN_xkb_compose_state_get_status compose_state_get_status; + PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym; +} + }_Xkb xkb; + + _GLFWwindow* pointerFocus; + _GLFWwindow* keyboardFocus; + + struct _Cursor { + void* handle; + + PFN_wl_cursor_theme_load theme_load; + PFN_wl_cursor_theme_destroy theme_destroy; + PFN_wl_cursor_theme_get_cursor theme_get_cursor; + PFN_wl_cursor_image_get_buffer image_get_buffer; + }_Cursor cursor; + + struct _Egl { + void* handle; + + PFN_wl_egl_window_create window_create; + PFN_wl_egl_window_destroy window_destroy; + PFN_wl_egl_window_resize window_resize; + }_Egl egl; + +}/+alias _GLFWlibraryWayland _GLFWlibraryWayland;+/ + +// Wayland-specific per-monitor data +// +struct _GLFWmonitorWayland { + wl_output* output; + uint name; + int currentMode; + + int x; + int y; + int scale; + +}/+alias _GLFWmonitorWayland _GLFWmonitorWayland;+/ + +// Wayland-specific per-cursor data +// +struct _GLFWcursorWayland { + wl_cursor* cursor; + wl_cursor* cursorHiDPI; + wl_buffer* buffer; + int width;int height; + int xhot;int yhot; + int currentImage; +}/+alias _GLFWcursorWayland _GLFWcursorWayland;+/ + + +void _glfwAddOutputWayland(uint name, uint version_); \ No newline at end of file diff --git a/source/glfw3/wl_window.d b/source/glfw3/wl_window.d new file mode 100644 index 0000000..88b0452 --- /dev/null +++ b/source/glfw3/wl_window.d @@ -0,0 +1,1746 @@ +/// Translated from C to D +module glfw3.wl_window; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +public import glfw3.internal; + +public import core.stdc.stdio; +public import core.stdc.stdlib; +public import core.stdc.errno; +public import core.sys.posix.unistd; +public import core.stdc.string; +public import core.sys.posix.fcntl; +public import core.sys.posix.sys.mman; +public import core.sys.linux.timerfd; +public import core.sys.posix.poll; + +static void shellSurfaceHandlePing(void* data, wl_shell_surface* shellSurface, uint serial) { + wl_shell_surface_pong(shellSurface, serial); +} + +static void shellSurfaceHandleConfigure(void* data, wl_shell_surface* shellSurface, uint edges, int width, int height) { + auto window = cast(_GLFWwindow*) data; + float aspectRatio; + float targetRatio; + + if (!window.monitor) + { + if (_glfw.wl.viewporter && window.decorated) + { + width -= _GLFW_DECORATION_HORIZONTAL; + height -= _GLFW_DECORATION_VERTICAL; + } + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + if (window.numer != GLFW_DONT_CARE && window.denom != GLFW_DONT_CARE) + { + aspectRatio = cast(float)width / cast(float)height; + targetRatio = cast(float)window.numer / cast(float)window.denom; + if (aspectRatio < targetRatio) + height = cast(int) (width / targetRatio); + else if (aspectRatio > targetRatio) + width = cast(int) (height * targetRatio); + } + + if (window.minwidth != GLFW_DONT_CARE && width < window.minwidth) + width = window.minwidth; + else if (window.maxwidth != GLFW_DONT_CARE && width > window.maxwidth) + width = window.maxwidth; + + if (window.minheight != GLFW_DONT_CARE && height < window.minheight) + height = window.minheight; + else if (window.maxheight != GLFW_DONT_CARE && height > window.maxheight) + height = window.maxheight; + } + + _glfwInputWindowSize(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); + _glfwInputWindowDamage(window); +} + +static void shellSurfaceHandlePopupDone(void* data, wl_shell_surface* shellSurface) { +} + +static const(wl_shell_surface_listener) shellSurfaceListener = wl_shell_surface_listener( + &shellSurfaceHandlePing, + &shellSurfaceHandleConfigure, + &shellSurfaceHandlePopupDone +); + +static int createTmpfileCloexec(char* tmpname) { + int fd; + + fd = mkostemp(tmpname, O_CLOEXEC); + if (fd >= 0) + unlink(tmpname); + + return fd; +} + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * The file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + * + * posix_fallocate() is used to guarantee that disk space is available + * for the file at the given size. If disk space is insufficient, errno + * is set to ENOSPC. If posix_fallocate() is not supported, program may + * receive SIGBUS on accessing mmap()'ed file contents instead. + */ +static int createAnonymousFile(off_t size) { + static const(char)* template_ = "/glfw-shared-XXXXXX"; + const(char)* path; + char* name; + int fd; + int ret; + + auto inner() { + path = getenv("XDG_RUNTIME_DIR"); + if (!path) + { + errno = ENOENT; + return -1; + } + + name = cast(char*) calloc(strlen(path) + template_.sizeof, 1); + strcpy(name, path); + strcat(name, template_); + + fd = createTmpfileCloexec(name); + free(name); + if (fd < 0) + return -1; + + return 0; + } + +version (HAVE_MEMFD_CREATE) { + fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd >= 0) + { + // We can add this seal before calling posix_fallocate(), as the file + // is currently zero-sized anyway. + // + // There is also no need to check for the return value, we couldn’t do + // anything with it anyway. + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); + } + else + { + if (inner() < 0) { + return -1; + } + } +} else version (SHM_ANON) { + import std.conv: octal; + fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, octal!600); + if (fd < 0) { + if (inner() < 0) { + return -1; + } + } +} + +version (SHM_ANON) { + // posix_fallocate does not work on SHM descriptors + ret = ftruncate(fd, size); +} else { + ret = posix_fallocate(fd, 0, size); +} + if (ret != 0) + { + close(fd); + errno = ret; + return -1; + } + return fd; +} + +static wl_buffer* createShmBuffer(const(GLFWimage)* image) { + wl_shm_pool* pool; + wl_buffer* buffer; + int stride = image.width * 4; + int length = image.width * image.height * 4; + void* data; + int fd;int i; + + fd = createAnonymousFile(length); + if (fd < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Creating a buffer file for %d B failed: %m", + length); + return null; + } + + data = mmap(null, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: mmap failed: %m"); + close(fd); + return null; + } + + pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); + + close(fd); + ubyte* source = cast(ubyte*) image.pixels; + ubyte* target = data; + for (i = 0; i < image.width * image.height; i++, source += 4) + { + uint alpha = source[3]; + + *target++ = cast(ubyte) ((source[2] * alpha) / 255); + *target++ = cast(ubyte) ((source[1] * alpha) / 255); + *target++ = cast(ubyte) ((source[0] * alpha) / 255); + *target++ = cast(ubyte) alpha; + } + + buffer = + wl_shm_pool_create_buffer(pool, 0, + image.width, + image.height, + stride, WL_SHM_FORMAT_ARGB8888); + munmap(data, length); + wl_shm_pool_destroy(pool); + + return buffer; +} + +static void createDecoration(_GLFWdecorationWayland* decoration, wl_surface* parent, wl_buffer* buffer, GLFWbool opaque, int x, int y, int width, int height) { + wl_region* region; + + decoration.surface = wl_compositor_create_surface(_glfw.wl.compositor); + decoration.subsurface = + wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, + decoration.surface, parent); + wl_subsurface_set_position(decoration.subsurface, x, y); + decoration.viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter, + decoration.surface); + wp_viewport_set_destination(decoration.viewport, width, height); + wl_surface_attach(decoration.surface, buffer, 0, 0); + + if (opaque) + { + region = wl_compositor_create_region(_glfw.wl.compositor); + wl_region_add(region, 0, 0, width, height); + wl_surface_set_opaque_region(decoration.surface, region); + wl_surface_commit(decoration.surface); + wl_region_destroy(region); + } + else + wl_surface_commit(decoration.surface); +} + +static void createDecorations(_GLFWwindow* window) { + ubyte[4] data = [ 224, 224, 224, 255 ]; + const(GLFWimage) image = GLFWimage( 1, 1, data.ptr ); + GLFWbool opaque = (data[3] == 255); + + if (!_glfw.wl.viewporter || !window.decorated || window.wl.decorations.serverSide) + return; + + if (!window.wl.decorations.buffer) + window.wl.decorations.buffer = createShmBuffer(&image); + if (!window.wl.decorations.buffer) + return; + + createDecoration(&window.wl.decorations.top, window.wl.surface, + window.wl.decorations.buffer, opaque, + 0, -_GLFW_DECORATION_TOP, + window.wl.width, _GLFW_DECORATION_TOP); + createDecoration(&window.wl.decorations.left, window.wl.surface, + window.wl.decorations.buffer, opaque, + -_GLFW_DECORATION_WIDTH, -_GLFW_DECORATION_TOP, + _GLFW_DECORATION_WIDTH, window.wl.height + _GLFW_DECORATION_TOP); + createDecoration(&window.wl.decorations.right, window.wl.surface, + window.wl.decorations.buffer, opaque, + window.wl.width, -_GLFW_DECORATION_TOP, + _GLFW_DECORATION_WIDTH, window.wl.height + _GLFW_DECORATION_TOP); + createDecoration(&window.wl.decorations.bottom, window.wl.surface, + window.wl.decorations.buffer, opaque, + -_GLFW_DECORATION_WIDTH, window.wl.height, + window.wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); +} + +static void destroyDecoration(_GLFWdecorationWayland* decoration) { + if (decoration.surface) + wl_surface_destroy(decoration.surface); + if (decoration.subsurface) + wl_subsurface_destroy(decoration.subsurface); + if (decoration.viewport) + wp_viewport_destroy(decoration.viewport); + decoration.surface = null; + decoration.subsurface = null; + decoration.viewport = null; +} + +static void destroyDecorations(_GLFWwindow* window) { + destroyDecoration(&window.wl.decorations.top); + destroyDecoration(&window.wl.decorations.left); + destroyDecoration(&window.wl.decorations.right); + destroyDecoration(&window.wl.decorations.bottom); +} + +static void xdgDecorationHandleConfigure(void* data, zxdg_toplevel_decoration_v1* decoration, uint mode) { + _GLFWwindow* window = data; + + window.wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + + if (!window.wl.decorations.serverSide) + createDecorations(window); +} + +static const(zxdg_toplevel_decoration_v1_listener) xdgDecorationListener = zxdg_toplevel_decoration_v1_listener( + &xdgDecorationHandleConfigure, +); + +// Makes the surface considered as XRGB instead of ARGB. +static void setOpaqueRegion(_GLFWwindow* window) { + wl_region* region; + + region = wl_compositor_create_region(_glfw.wl.compositor); + if (!region) + return; + + wl_region_add(region, 0, 0, window.wl.width, window.wl.height); + wl_surface_set_opaque_region(window.wl.surface, region); + wl_surface_commit(window.wl.surface); + wl_region_destroy(region); +} + + +static void resizeWindow(_GLFWwindow* window) { + int scale = window.wl.scale; + int scaledWidth = window.wl.width * scale; + int scaledHeight = window.wl.height * scale; + wl_egl_window_resize(window.wl.native, scaledWidth, scaledHeight, 0, 0); + if (!window.wl.transparent) + setOpaqueRegion(window); + _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); + _glfwInputWindowContentScale(window, scale, scale); + + if (!window.wl.decorations.top.surface) + return; + + // Top decoration. + wp_viewport_set_destination(window.wl.decorations.top.viewport, + window.wl.width, _GLFW_DECORATION_TOP); + wl_surface_commit(window.wl.decorations.top.surface); + + // Left decoration. + wp_viewport_set_destination(window.wl.decorations.left.viewport, + _GLFW_DECORATION_WIDTH, window.wl.height + _GLFW_DECORATION_TOP); + wl_surface_commit(window.wl.decorations.left.surface); + + // Right decoration. + wl_subsurface_set_position(window.wl.decorations.right.subsurface, + window.wl.width, -_GLFW_DECORATION_TOP); + wp_viewport_set_destination(window.wl.decorations.right.viewport, + _GLFW_DECORATION_WIDTH, window.wl.height + _GLFW_DECORATION_TOP); + wl_surface_commit(window.wl.decorations.right.surface); + + // Bottom decoration. + wl_subsurface_set_position(window.wl.decorations.bottom.subsurface, + -_GLFW_DECORATION_WIDTH, window.wl.height); + wp_viewport_set_destination(window.wl.decorations.bottom.viewport, + window.wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); + wl_surface_commit(window.wl.decorations.bottom.surface); +} + +static void checkScaleChange(_GLFWwindow* window) { + int scale = 1; + int i; + int monitorScale; + + // Check if we will be able to set the buffer scale or not. + if (_glfw.wl.compositorVersion < 3) + return; + + // Get the scale factor from the highest scale monitor. + for (i = 0; i < window.wl.monitorsCount; ++i) + { + monitorScale = window.wl.monitors[i].wl.scale; + if (scale < monitorScale) + scale = monitorScale; + } + + // Only change the framebuffer size if the scale changed. + if (scale != window.wl.scale) + { + window.wl.scale = scale; + wl_surface_set_buffer_scale(window.wl.surface, scale); + resizeWindow(window); + } +} + +static void surfaceHandleEnter(void* data, wl_surface* surface, wl_output* output) { + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + + if (window.wl.monitorsCount + 1 > window.wl.monitorsSize) + { + ++window.wl.monitorsSize; + window.wl.monitors = + realloc(window.wl.monitors, + window.wl.monitorsSize * (_GLFWmonitor*).sizeof); + } + + window.wl.monitors[window.wl.monitorsCount++] = monitor; + + checkScaleChange(window); +} + +static void surfaceHandleLeave(void* data, wl_surface* surface, wl_output* output) { + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + GLFWbool found; + int i; + + for (i = 0, found = GLFW_FALSE; i < window.wl.monitorsCount - 1; ++i) + { + if (monitor == window.wl.monitors[i]) + found = GLFW_TRUE; + if (found) + window.wl.monitors[i] = window.wl.monitors[i + 1]; + } + window.wl.monitors[--window.wl.monitorsCount] = null; + + checkScaleChange(window); +} + +static const(wl_surface_listener) surfaceListener = wl_surface_listener( + &surfaceHandleEnter, + &surfaceHandleLeave +); + +static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) { + if (enable && !window.wl.idleInhibitor && _glfw.wl.idleInhibitManager) + { + window.wl.idleInhibitor = + zwp_idle_inhibit_manager_v1_create_inhibitor( + _glfw.wl.idleInhibitManager, window.wl.surface); + if (!window.wl.idleInhibitor) + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Idle inhibitor creation failed"); + } + else if (!enable && window.wl.idleInhibitor) + { + zwp_idle_inhibitor_v1_destroy(window.wl.idleInhibitor); + window.wl.idleInhibitor = null; + } +} + +static GLFWbool createSurface(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig) { + window.wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); + if (!window.wl.surface) + return GLFW_FALSE; + + wl_surface_add_listener(window.wl.surface, + &surfaceListener, + window); + + wl_surface_set_user_data(window.wl.surface, window); + + window.wl.native = wl_egl_window_create(window.wl.surface, + wndconfig.width, + wndconfig.height); + if (!window.wl.native) + return GLFW_FALSE; + + window.wl.width = wndconfig.width; + window.wl.height = wndconfig.height; + window.wl.scale = 1; + + if (!window.wl.transparent) + setOpaqueRegion(window); + + return GLFW_TRUE; +} + +static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refreshRate) { + if (window.wl.xdg.toplevel) + { + xdg_toplevel_set_fullscreen( + window.wl.xdg.toplevel, + monitor.wl.output); + } + else if (window.wl.shellSurface) + { + wl_shell_surface_set_fullscreen( + window.wl.shellSurface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + refreshRate * 1000, // Convert Hz to mHz. + monitor.wl.output); + } + setIdleInhibitor(window, GLFW_TRUE); + if (!window.wl.decorations.serverSide) + destroyDecorations(window); +} + +static GLFWbool createShellSurface(_GLFWwindow* window) { + if (!_glfw.wl.shell) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: wl_shell protocol not available"); + return GLFW_FALSE; + } + + window.wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell, + window.wl.surface); + if (!window.wl.shellSurface) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Shell surface creation failed"); + return GLFW_FALSE; + } + + wl_shell_surface_add_listener(window.wl.shellSurface, + &shellSurfaceListener, + window); + + if (window.wl.title) + wl_shell_surface_set_title(window.wl.shellSurface, window.wl.title); + + if (window.monitor) + { + setFullscreen(window, window.monitor, 0); + } + else if (window.wl.maximized) + { + wl_shell_surface_set_maximized(window.wl.shellSurface, null); + setIdleInhibitor(window, GLFW_FALSE); + createDecorations(window); + } + else + { + wl_shell_surface_set_toplevel(window.wl.shellSurface); + setIdleInhibitor(window, GLFW_FALSE); + createDecorations(window); + } + + wl_surface_commit(window.wl.surface); + + return GLFW_TRUE; +} + +static void xdgToplevelHandleConfigure(void* data, xdg_toplevel* toplevel, int width, int height, wl_array* states) { + _GLFWwindow* window = cast(_GLFWwindow*) data; + float aspectRatio; + float targetRatio; + uint* state; + GLFWbool maximized = GLFW_FALSE; + GLFWbool fullscreen = GLFW_FALSE; + GLFWbool activated = GLFW_FALSE; + + foreach(state; wl_array_for_each(states)) + { + switch (*state) + { + case XDG_TOPLEVEL_STATE_MAXIMIZED: + maximized = GLFW_TRUE; + break; + case XDG_TOPLEVEL_STATE_FULLSCREEN: + fullscreen = GLFW_TRUE; + break; + case XDG_TOPLEVEL_STATE_RESIZING: + break; + case XDG_TOPLEVEL_STATE_ACTIVATED: + activated = GLFW_TRUE; + break; + } + } + + if (width != 0 && height != 0) + { + if (!maximized && !fullscreen) + { + if (window.numer != GLFW_DONT_CARE && window.denom != GLFW_DONT_CARE) + { + aspectRatio = cast(float)width / cast(float)height; + targetRatio = cast(float)window.numer / cast(float)window.denom; + if (aspectRatio < targetRatio) + height = width / targetRatio; + else if (aspectRatio > targetRatio) + width = height * targetRatio; + } + } + + _glfwInputWindowSize(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); + _glfwInputWindowDamage(window); + } + + if (window.wl.wasFullscreen && window.autoIconify) + { + if (!activated || !fullscreen) + { + _glfwPlatformIconifyWindow(window); + window.wl.wasFullscreen = GLFW_FALSE; + } + } + if (fullscreen && activated) + window.wl.wasFullscreen = GLFW_TRUE; + _glfwInputWindowFocus(window, activated); +} + +static void xdgToplevelHandleClose(void* data, xdg_toplevel* toplevel) { + _GLFWwindow* window = data; + _glfwInputWindowCloseRequest(window); +} + +static const(xdg_toplevel_listener) xdgToplevelListener = xdg_toplevel_listener( + &xdgToplevelHandleConfigure, + &xdgToplevelHandleClose +); + +static void xdgSurfaceHandleConfigure(void* data, xdg_surface* surface, uint serial) { + xdg_surface_ack_configure(surface, serial); +} + +static const(xdg_surface_listener) xdgSurfaceListener = xdg_surface_listener( + &xdgSurfaceHandleConfigure +); + +static void setXdgDecorations(_GLFWwindow* window) { + if (_glfw.wl.decorationManager) + { + window.wl.xdg.decoration = + zxdg_decoration_manager_v1_get_toplevel_decoration( + _glfw.wl.decorationManager, window.wl.xdg.toplevel); + zxdg_toplevel_decoration_v1_add_listener(window.wl.xdg.decoration, + &xdgDecorationListener, + window); + zxdg_toplevel_decoration_v1_set_mode( + window.wl.xdg.decoration, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + else + { + window.wl.decorations.serverSide = GLFW_FALSE; + createDecorations(window); + } +} + +static GLFWbool createXdgSurface(_GLFWwindow* window) { + window.wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, + window.wl.surface); + if (!window.wl.xdg.surface) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: xdg-surface creation failed"); + return GLFW_FALSE; + } + + xdg_surface_add_listener(window.wl.xdg.surface, + &xdgSurfaceListener, + window); + + window.wl.xdg.toplevel = xdg_surface_get_toplevel(window.wl.xdg.surface); + if (!window.wl.xdg.toplevel) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: xdg-toplevel creation failed"); + return GLFW_FALSE; + } + + xdg_toplevel_add_listener(window.wl.xdg.toplevel, + &xdgToplevelListener, + window); + + if (window.wl.title) + xdg_toplevel_set_title(window.wl.xdg.toplevel, window.wl.title); + + if (window.minwidth != GLFW_DONT_CARE && window.minheight != GLFW_DONT_CARE) + xdg_toplevel_set_min_size(window.wl.xdg.toplevel, + window.minwidth, window.minheight); + if (window.maxwidth != GLFW_DONT_CARE && window.maxheight != GLFW_DONT_CARE) + xdg_toplevel_set_max_size(window.wl.xdg.toplevel, + window.maxwidth, window.maxheight); + + if (window.monitor) + { + xdg_toplevel_set_fullscreen(window.wl.xdg.toplevel, + window.monitor.wl.output); + setIdleInhibitor(window, GLFW_TRUE); + } + else if (window.wl.maximized) + { + xdg_toplevel_set_maximized(window.wl.xdg.toplevel); + setIdleInhibitor(window, GLFW_FALSE); + setXdgDecorations(window); + } + else + { + setIdleInhibitor(window, GLFW_FALSE); + setXdgDecorations(window); + } + + wl_surface_commit(window.wl.surface); + wl_display_roundtrip(_glfw.wl.display); + + return GLFW_TRUE; +} + +static void setCursorImage(_GLFWwindow* window, _GLFWcursorWayland* cursorWayland) { + itimerspec timer = {}; + wl_cursor* wlCursor = cursorWayland.cursor; + wl_cursor_image* image; + wl_buffer* buffer; + wl_surface* surface = _glfw.wl.cursorSurface; + int scale = 1; + + if (!wlCursor) + buffer = cursorWayland.buffer; + else + { + if (window.wl.scale > 1 && cursorWayland.cursorHiDPI) + { + wlCursor = cursorWayland.cursorHiDPI; + scale = 2; + } + + image = wlCursor.images[cursorWayland.currentImage]; + buffer = _glfw.wl.cursor.image_get_buffer(image); + if (!buffer) + return; + + timer.it_value.tv_sec = image.delay / 1000; + timer.it_value.tv_nsec = (image.delay % 1000) * 1000000; + timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, null); + + cursorWayland.width = image.width; + cursorWayland.height = image.height; + cursorWayland.xhot = image.hotspot_x; + cursorWayland.yhot = image.hotspot_y; + } + + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, + surface, + cursorWayland.xhot / scale, + cursorWayland.yhot / scale); + wl_surface_set_buffer_scale(surface, scale); + wl_surface_attach(surface, buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + cursorWayland.width, cursorWayland.height); + wl_surface_commit(surface); +} + +static void incrementCursorImage(_GLFWwindow* window) { + _GLFWcursor* cursor; + + if (!window || window.wl.decorations.focus != mainWindow) + return; + + cursor = window.wl.currentCursor; + if (cursor && cursor.wl.cursor) + { + cursor.wl.currentImage += 1; + cursor.wl.currentImage %= cursor.wl.cursor.image_count; + setCursorImage(window, &cursor.wl); + } +} + +static void handleEvents(int timeout) { + wl_display* display = _glfw.wl.display; + pollfd* fds = [ + [ wl_display_get_fd(display), POLLIN ], + [ _glfw.wl.timerfd, POLLIN ], + [ _glfw.wl.cursorTimerfd, POLLIN ], + ]; + ssize_t read_ret; + ulong repeats;ulong i; + + while (wl_display_prepare_read(display) != 0) + wl_display_dispatch_pending(display); + + // If an error different from EAGAIN happens, we have likely been + // disconnected from the Wayland session, try to handle that the best we + // can. + if (wl_display_flush(display) < 0 && errno != EAGAIN) + { + _GLFWwindow* window = _glfw.windowListHead; + while (window) + { + _glfwInputWindowCloseRequest(window); + window = window.next; + } + wl_display_cancel_read(display); + return; + } + + if (poll(fds, 3, timeout) > 0) + { + if (fds[0].revents & POLLIN) + { + wl_display_read_events(display); + wl_display_dispatch_pending(display); + } + else + { + wl_display_cancel_read(display); + } + + if (fds[1].revents & POLLIN) + { + read_ret = read(_glfw.wl.timerfd, &repeats, repeats.sizeof); + if (read_ret != 8) + return; + + for (i = 0; i < repeats; ++i) + _glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey, + _glfw.wl.keyboardLastScancode, GLFW_REPEAT, + _glfw.wl.xkb.modifiers); + } + + if (fds[2].revents & POLLIN) + { + read_ret = read(_glfw.wl.cursorTimerfd, &repeats, repeats.sizeof); + if (read_ret != 8) + return; + + incrementCursorImage(_glfw.wl.pointerFocus); + } + } + else + { + wl_display_cancel_read(display); + } +} + +// Translates a GLFW standard cursor to a theme cursor name +// +private const(char)* translateCursorShape(int shape) { + switch (shape) + { + case GLFW_ARROW_CURSOR: + return "left_ptr".ptr; + case GLFW_IBEAM_CURSOR: + return "xterm".ptr; + case GLFW_CROSSHAIR_CURSOR: + return "crosshair".ptr; + case GLFW_HAND_CURSOR: + return "hand2".ptr; + case GLFW_HRESIZE_CURSOR: + return "sb_h_double_arrow".ptr; + case GLFW_VRESIZE_CURSOR: + return "sb_v_double_arrow".ptr; + } + return null; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + window.wl.transparent = fbconfig.transparent; + + if (!createSurface(window, wndconfig)) + return GLFW_FALSE; + + if (ctxconfig.client != GLFW_NO_API) + { + if (ctxconfig.source == GLFW_EGL_CONTEXT_API || + ctxconfig.source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig.source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (wndconfig.title) + window.wl.title = _glfw_strdup(wndconfig.title); + + if (wndconfig.visible) + { + if (_glfw.wl.wmBase) + { + if (!createXdgSurface(window)) + return GLFW_FALSE; + } + else + { + if (!createShellSurface(window)) + return GLFW_FALSE; + } + + window.wl.visible = GLFW_TRUE; + } + else + { + window.wl.xdg.surface = null; + window.wl.xdg.toplevel = null; + window.wl.shellSurface = null; + window.wl.visible = GLFW_FALSE; + } + + window.wl.currentCursor = null; + + window.wl.monitors = cast(_GLFWmonitor**) calloc(1, (_GLFWmonitor*).sizeof); + window.wl.monitorsCount = 0; + window.wl.monitorsSize = 1; + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { + if (window == _glfw.wl.pointerFocus) + { + _glfw.wl.pointerFocus = null; + _glfwInputCursorEnter(window, GLFW_FALSE); + } + if (window == _glfw.wl.keyboardFocus) + { + _glfw.wl.keyboardFocus = null; + _glfwInputWindowFocus(window, GLFW_FALSE); + } + + if (window.wl.idleInhibitor) + zwp_idle_inhibitor_v1_destroy(window.wl.idleInhibitor); + + if (window.context.destroy) + window.context.destroy(window); + + destroyDecorations(window); + if (window.wl.xdg.decoration) + zxdg_toplevel_decoration_v1_destroy(window.wl.xdg.decoration); + + if (window.wl.decorations.buffer) + wl_buffer_destroy(window.wl.decorations.buffer); + + if (window.wl.native) + wl_egl_window_destroy(window.wl.native); + + if (window.wl.shellSurface) + wl_shell_surface_destroy(window.wl.shellSurface); + + if (window.wl.xdg.toplevel) + xdg_toplevel_destroy(window.wl.xdg.toplevel); + + if (window.wl.xdg.surface) + xdg_surface_destroy(window.wl.xdg.surface); + + if (window.wl.surface) + wl_surface_destroy(window.wl.surface); + + free(window.wl.title); + free(window.wl.monitors); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const(char)* title) { + if (window.wl.title) + free(window.wl.title); + window.wl.title = _glfw_strdup(title); + if (window.wl.xdg.toplevel) + xdg_toplevel_set_title(window.wl.xdg.toplevel, title); + else if (window.wl.shellSurface) + wl_shell_surface_set_title(window.wl.shellSurface, title); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const(GLFWimage)* images) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Setting window icon not supported"); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { + // A Wayland client is not aware of its position, so just warn and leave it + // as (0, 0) + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window position retrieval not supported"); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { + // A Wayland client can not set its position, so just warn + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window position setting not supported"); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { + if (width) + *width = window.wl.width; + if (height) + *height = window.wl.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { + window.wl.width = width; + window.wl.height = height; + resizeWindow(window); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { + if (_glfw.wl.wmBase) + { + if (window.wl.xdg.toplevel) + { + if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) + minwidth = minheight = 0; + if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE) + maxwidth = maxheight = 0; + xdg_toplevel_set_min_size(window.wl.xdg.toplevel, minwidth, minheight); + xdg_toplevel_set_max_size(window.wl.xdg.toplevel, maxwidth, maxheight); + wl_surface_commit(window.wl.surface); + } + } + else + { + // TODO: find out how to trigger a resize. + // The actual limits are checked in the wl_shell_surface::configure handler. + } +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { + // TODO: find out how to trigger a resize. + // The actual limits are checked in the wl_shell_surface::configure handler. +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { + _glfwPlatformGetWindowSize(window, width, height); + *width *= window.wl.scale; + *height *= window.wl.scale; +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { + if (window.decorated && !window.monitor && !window.wl.decorations.serverSide) + { + if (top) + *top = _GLFW_DECORATION_TOP; + if (left) + *left = _GLFW_DECORATION_WIDTH; + if (right) + *right = _GLFW_DECORATION_WIDTH; + if (bottom) + *bottom = _GLFW_DECORATION_WIDTH; + } +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale) { + if (xscale) + *xscale = cast(float) window.wl.scale; + if (yscale) + *yscale = cast(float) window.wl.scale; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) { + if (_glfw.wl.wmBase) + { + if (window.wl.xdg.toplevel) + xdg_toplevel_set_minimized(window.wl.xdg.toplevel); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Iconify window not supported on wl_shell"); + } +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) { + if (window.wl.xdg.toplevel) + { + if (window.monitor) + xdg_toplevel_unset_fullscreen(window.wl.xdg.toplevel); + if (window.wl.maximized) + xdg_toplevel_unset_maximized(window.wl.xdg.toplevel); + // There is no way to unset minimized, or even to know if we are + // minimized, so there is nothing to do here. + } + else if (window.wl.shellSurface) + { + if (window.monitor || window.wl.maximized) + wl_shell_surface_set_toplevel(window.wl.shellSurface); + } + _glfwInputWindowMonitor(window, null); + window.wl.maximized = GLFW_FALSE; +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { + if (window.wl.xdg.toplevel) + { + xdg_toplevel_set_maximized(window.wl.xdg.toplevel); + } + else if (window.wl.shellSurface) + { + // Let the compositor select the best output. + wl_shell_surface_set_maximized(window.wl.shellSurface, null); + } + window.wl.maximized = GLFW_TRUE; +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) { + if (!window.wl.visible) + { + if (_glfw.wl.wmBase) + createXdgSurface(window); + else if (!window.wl.shellSurface) + createShellSurface(window); + window.wl.visible = GLFW_TRUE; + } +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) { + if (window.wl.xdg.toplevel) + { + xdg_toplevel_destroy(window.wl.xdg.toplevel); + xdg_surface_destroy(window.wl.xdg.surface); + window.wl.xdg.toplevel = null; + window.wl.xdg.surface = null; + } + else if (window.wl.shellSurface) + { + wl_shell_surface_destroy(window.wl.shellSurface); + window.wl.shellSurface = null; + } + window.wl.visible = GLFW_FALSE; +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window attention request not implemented yet"); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Focusing a window requires user interaction"); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { + if (monitor) + { + setFullscreen(window, monitor, refreshRate); + } + else + { + if (window.wl.xdg.toplevel) + xdg_toplevel_unset_fullscreen(window.wl.xdg.toplevel); + else if (window.wl.shellSurface) + wl_shell_surface_set_toplevel(window.wl.shellSurface); + setIdleInhibitor(window, GLFW_FALSE); + if (!_glfw.wl.decorationManager) + createDecorations(window); + } + _glfwInputWindowMonitor(window, monitor); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) { + return _glfw.wl.keyboardFocus == window; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) { + // wl_shell doesn't have any iconified concept, and xdg-shell doesn’t give + // any way to request whether a surface is iconified. + return GLFW_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) { + return window.wl.visible; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { + return window.wl.maximized; +} + +int _glfwPlatformWindowHovered(_GLFWwindow* window) { + return window.wl.hovered; +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { + return window.wl.transparent; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window attribute setting not implemented yet"); +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { + if (!window.monitor) + { + if (enabled) + createDecorations(window); + else + destroyDecorations(window); + } +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { + // TODO + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window attribute setting not implemented yet"); +} + +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { + return 1.0f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { +} + +void _glfwPlatformSetRawMouseMotion(_GLFWwindow* window, GLFWbool enabled) { + // This is handled in relativePointerHandleRelativeMotion +} + +GLFWbool _glfwPlatformRawMouseMotionSupported() { + return GLFW_TRUE; +} + +void _glfwPlatformPollEvents() { + handleEvents(0); +} + +void _glfwPlatformWaitEvents() { + handleEvents(-1); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) { + handleEvents(cast(int) (timeout * 1e3)); +} + +void _glfwPlatformPostEmptyEvent() { + wl_display_sync(_glfw.wl.display); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { + if (xpos) + *xpos = window.wl.cursorPosX; + if (ypos) + *ypos = window.wl.cursorPosY; +} + +static GLFWbool isPointerLocked(_GLFWwindow* window); + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { + if (isPointerLocked(window)) + { + zwp_locked_pointer_v1_set_cursor_position_hint( + window.wl.pointerLock.lockedPointer, + wl_fixed_from_double(x), wl_fixed_from_double(y)); + wl_surface_commit(window.wl.surface); + } +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { + _glfwPlatformSetCursor(window, window.wl.currentCursor); +} + +const(char)* _glfwPlatformGetScancodeName(int scancode) { + // TODO + return null; +} + +int _glfwPlatformGetKeyScancode(int key) { + return _glfw.wl.scancodes[key]; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const(GLFWimage)* image, int xhot, int yhot) { + cursor.wl.buffer = createShmBuffer(image); + if (!cursor.wl.buffer) + return GLFW_FALSE; + + cursor.wl.width = image.width; + cursor.wl.height = image.height; + cursor.wl.xhot = xhot; + cursor.wl.yhot = yhot; + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { + wl_cursor* standardCursor; + + standardCursor = _glfw.wl.cursor.theme_get_cursor(_glfw.wl.cursorTheme, + translateCursorShape(shape)); + if (!standardCursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Standard cursor \"%s\" not found", + translateCursorShape(shape)); + return GLFW_FALSE; + } + + cursor.wl.cursor = standardCursor; + cursor.wl.currentImage = 0; + + if (_glfw.wl.cursorThemeHiDPI) + { + standardCursor = _glfw.wl.cursor.theme_get_cursor(_glfw.wl.cursorThemeHiDPI, + translateCursorShape(shape)); + cursor.wl.cursorHiDPI = standardCursor; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { + // If it's a standard cursor we don't need to do anything here + if (cursor.wl.cursor) + return; + + if (cursor.wl.buffer) + wl_buffer_destroy(cursor.wl.buffer); +} + +static void relativePointerHandleRelativeMotion(void* data, zwp_relative_pointer_v1* pointer, uint timeHi, uint timeLo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dxUnaccel, wl_fixed_t dyUnaccel) { + _GLFWwindow* window = data; + double xpos = window.virtualCursorPosX; + double ypos = window.virtualCursorPosY; + + if (window.cursorMode != GLFW_CURSOR_DISABLED) + return; + + if (window.rawMouseMotion) + { + xpos += wl_fixed_to_double(dxUnaccel); + ypos += wl_fixed_to_double(dyUnaccel); + } + else + { + xpos += wl_fixed_to_double(dx); + ypos += wl_fixed_to_double(dy); + } + + _glfwInputCursorPos(window, xpos, ypos); +} + +static const(zwp_relative_pointer_v1_listener) relativePointerListener = zwp_relative_pointer_v1_listener( + &relativePointerHandleRelativeMotion +); + +static void lockedPointerHandleLocked(void* data, zwp_locked_pointer_v1* lockedPointer) { +} + +static void unlockPointer(_GLFWwindow* window) { + zwp_relative_pointer_v1* relativePointer = window.wl.pointerLock.relativePointer; + zwp_locked_pointer_v1* lockedPointer = window.wl.pointerLock.lockedPointer; + + zwp_relative_pointer_v1_destroy(relativePointer); + zwp_locked_pointer_v1_destroy(lockedPointer); + + window.wl.pointerLock.relativePointer = null; + window.wl.pointerLock.lockedPointer = null; +} + +static void lockPointer(_GLFWwindow* window); + +static void lockedPointerHandleUnlocked(void* data, zwp_locked_pointer_v1* lockedPointer) { +} + +static const(zwp_locked_pointer_v1_listener) lockedPointerListener = zwp_locked_pointer_v1_listener( + &lockedPointerHandleLocked, + &lockedPointerHandleUnlocked +); + +static void lockPointer(_GLFWwindow* window) { + zwp_relative_pointer_v1* relativePointer; + zwp_locked_pointer_v1* lockedPointer; + + if (!_glfw.wl.relativePointerManager) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: no relative pointer manager"); + return; + } + + relativePointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + _glfw.wl.relativePointerManager, + _glfw.wl.pointer); + zwp_relative_pointer_v1_add_listener(relativePointer, + &relativePointerListener, + window); + + lockedPointer = + zwp_pointer_constraints_v1_lock_pointer( + _glfw.wl.pointerConstraints, + window.wl.surface, + _glfw.wl.pointer, + null, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + zwp_locked_pointer_v1_add_listener(lockedPointer, + &lockedPointerListener, + window); + + window.wl.pointerLock.relativePointer = relativePointer; + window.wl.pointerLock.lockedPointer = lockedPointer; + + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, + null, 0, 0); +} + +static GLFWbool isPointerLocked(_GLFWwindow* window) { + return window.wl.pointerLock.lockedPointer != null; +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { + wl_cursor* defaultCursor; + wl_cursor* defaultCursorHiDPI = null; + + if (!_glfw.wl.pointer) + return; + + window.wl.currentCursor = cursor; + + // If we're not in the correct window just save the cursor + // the next time the pointer enters the window the cursor will change + if (window != _glfw.wl.pointerFocus || window.wl.decorations.focus != mainWindow) + return; + + // Unlock possible pointer lock if no longer disabled. + if (window.cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window)) + unlockPointer(window); + + if (window.cursorMode == GLFW_CURSOR_NORMAL) + { + if (cursor) + setCursorImage(window, &cursor.wl); + else + { + defaultCursor = _glfw.wl.cursor.theme_get_cursor(_glfw.wl.cursorTheme, + "left_ptr"); + if (!defaultCursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Standard cursor not found"); + return; + } + if (_glfw.wl.cursorThemeHiDPI) + defaultCursorHiDPI = + _glfw.wl.cursor.theme_get_cursor(_glfw.wl.cursorThemeHiDPI, + "left_ptr"); + _GLFWcursorWayland cursorWayland = [ + defaultCursor, + defaultCursorHiDPI, + null, + 0, 0, + 0, 0, + 0 + ]; + setCursorImage(window, &cursorWayland); + } + } + else if (window.cursorMode == GLFW_CURSOR_DISABLED) + { + if (!isPointerLocked(window)) + lockPointer(window); + } + else if (window.cursorMode == GLFW_CURSOR_HIDDEN) + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, null, 0, 0); + } +} + +static void dataSourceHandleTarget(void* data, wl_data_source* dataSource, const(char)* mimeType) { + if (_glfw.wl.dataSource != dataSource) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unknown clipboard data source"); + return; + } +} + +static void dataSourceHandleSend(void* data, wl_data_source* dataSource, const(char)* mimeType, int fd) { + const(char)* string = _glfw.wl.clipboardSendString; + size_t len = _glfw.wl.clipboardSendSize; + int ret; + + if (_glfw.wl.dataSource != dataSource) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unknown clipboard data source"); + return; + } + + if (!string) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Copy requested from an invalid string"); + return; + } + + if (strcmp(mimeType, "text/plain;charset=utf-8") != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Wrong MIME type asked from clipboard"); + close(fd); + return; + } + + while (len > 0) + { + ret = write(fd, string, len); + if (ret == -1 && errno == EINTR) + continue; + if (ret == -1) + { + // TODO: also report errno maybe. + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Error while writing the clipboard"); + close(fd); + return; + } + len -= ret; + } + close(fd); +} + +static void dataSourceHandleCancelled(void* data, wl_data_source* dataSource) { + wl_data_source_destroy(dataSource); + + if (_glfw.wl.dataSource != dataSource) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unknown clipboard data source"); + return; + } + + _glfw.wl.dataSource = null; +} + +static const(wl_data_source_listener) dataSourceListener = wl_data_source_listener( + &dataSourceHandleTarget, + &dataSourceHandleSend, + &dataSourceHandleCancelled, +); + +void _glfwPlatformSetClipboardString(const(char)* string) { + if (_glfw.wl.dataSource) + { + wl_data_source_destroy(_glfw.wl.dataSource); + _glfw.wl.dataSource = null; + } + + if (_glfw.wl.clipboardSendString) + { + free(_glfw.wl.clipboardSendString); + _glfw.wl.clipboardSendString = null; + } + + _glfw.wl.clipboardSendString = strdup(string); + if (!_glfw.wl.clipboardSendString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to allocate clipboard string"); + return; + } + _glfw.wl.clipboardSendSize = strlen(string); + _glfw.wl.dataSource = + wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager); + if (!_glfw.wl.dataSource) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to create clipboard source"); + free(_glfw.wl.clipboardSendString); + return; + } + wl_data_source_add_listener(_glfw.wl.dataSource, + &dataSourceListener, + null); + wl_data_source_offer(_glfw.wl.dataSource, "text/plain;charset=utf-8"); + wl_data_device_set_selection(_glfw.wl.dataDevice, + _glfw.wl.dataSource, + _glfw.wl.serial); +} + +static GLFWbool growClipboardString() { + char* clipboard = _glfw.wl.clipboardString; + + clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2); + if (!clipboard) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to grow clipboard string"); + return GLFW_FALSE; + } + _glfw.wl.clipboardString = clipboard; + _glfw.wl.clipboardSize = _glfw.wl.clipboardSize * 2; + return GLFW_TRUE; +} + +const(char)* _glfwPlatformGetClipboardString() { + int[2] fds; + int ret; + size_t len = 0; + + if (!_glfw.wl.dataOffer) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "No clipboard data has been sent yet"); + return null; + } + + ret = pipe2(fds.ptr, O_CLOEXEC); + if (ret < 0) + { + // TODO: also report errno maybe? + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to create clipboard pipe fds"); + return null; + } + + wl_data_offer_receive(_glfw.wl.dataOffer, "text/plain;charset=utf-8", fds[1]); + close(fds[1]); + + // XXX: this is a huge hack, this function shouldn’t be synchronous! + handleEvents(-1); + + while (1) + { + // Grow the clipboard if we need to paste something bigger, there is no + // shrink operation yet. + if (len + 4096 > _glfw.wl.clipboardSize) + { + if (!growClipboardString()) + { + close(fds[0]); + return null; + } + } + + // Then read from the fd to the clipboard, handling all known errors. + ret = read(fds[0], _glfw.wl.clipboardString + len, 4096); + if (ret == 0) + break; + if (ret == -1 && errno == EINTR) + continue; + if (ret == -1) + { + // TODO: also report errno maybe. + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Impossible to read from clipboard fd"); + close(fds[0]); + return null; + } + len += ret; + } + close(fds[0]); + if (len + 1 > _glfw.wl.clipboardSize) + { + if (!growClipboardString()) + return null; + } + _glfw.wl.clipboardString[len] = '\0'; + return _glfw.wl.clipboardString; +} + +void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) { + if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface) + return; + + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_KHR_wayland_surface"; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint queuefamily) { + PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = cast(PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); + if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension"); + return VK_NULL_HANDLE; + } + + return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device, + queuefamily, + _glfw.wl.display); +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const(VkAllocationCallbacks)* allocator, VkSurfaceKHR* surface) { + VkResult err; + VkWaylandSurfaceCreateInfoKHR sci; + PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; + + vkCreateWaylandSurfaceKHR = cast(PFN_vkCreateWaylandSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR"); + if (!vkCreateWaylandSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension"); + return VkResult.VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sci.sizeof); + sci.sType = VkStructureType.VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + sci.display = _glfw.wl.display; + sci.surface = window.wl.surface; + + err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create Vulkan surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +wl_display* glfwGetWaylandDisplay() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return _glfw.wl.display; +} + +wl_surface* glfwGetWaylandWindow(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return window.wl.surface; +} \ No newline at end of file diff --git a/source/glfw3/x11_header.d b/source/glfw3/x11_header.d new file mode 100644 index 0000000..577cbb5 --- /dev/null +++ b/source/glfw3/x11_header.d @@ -0,0 +1,4957 @@ +/// C declarations for the X11 windowing system +module glfw3.x11_header; +/* +I started out using https://github.com/nomad-software/x11/, but I had some problems with it: +- many headers GLFW needs were missing +- missing @nogc / nothrow annotations +- I prefer to not have a dub dependency +So I fixed the existing files, added the missing files, concatenated the files, stripped comments, +and let Dustmite reduce it a bit (going from 20K lines to 5K), resulting in this single file. +Still a bit of a mess, but good enough for compiling GLFW in its current state. +*/ +import core.stdc.config: c_ulong, c_long; +import core.stdc.stddef: wchar_t; +import core.stdc.stdio: fopen; +import core.stdc.stdlib: free, malloc, calloc, realloc; + +extern(C) +nothrow: +@nogc: + +const uint X_PROTOCOL = 11; +const uint X_PROTOCOL_REVISION = 0; +alias XID = c_ulong; +alias Mask = XID; +alias Atom = XID; +alias VisualID = XID; +alias Time = XID; +alias Window = XID; +alias Drawable = XID; +alias Font = XID; +alias Pixmap = XID; +alias Cursor = XID; +alias Colormap = XID; +alias GContext = XID; +alias KeySym = XID; +alias KeyCode = ubyte; +const XID None = 0; +const XID ParentRelative = 1; +const XID CopyFromParent = 0; +const Window PointerWindow = 0; +const Window InputFocus = 1; +const Window PointerRoot = 1; +const Atom AnyPropertyType = 0; +const KeyCode AnyKey = 0; +enum c_long AnyButton = 0; +const XID AllTemporary = 0; +const Time CurrentTime = 0; +const KeySym NoSymbol = 0; + +enum { + NoEventMask = 0, + KeyPressMask = 1 << 0, + KeyReleaseMask = 1 << 1, + ButtonPressMask = 1 << 2, + ButtonReleaseMask = 1 << 3, + EnterWindowMask = 1 << 4, + LeaveWindowMask = 1 << 5, + PointerMotionMask = 1 << 6, + PointerMotionHintMask = 1 << 7, + Button1MotionMask = 1 << 8, + Button2MotionMask = 1 << 9, + Button3MotionMask = 1 << 10, + Button4MotionMask = 1 << 11, + Button5MotionMask = 1 << 12, + ButtonMotionMask = 1 << 13, + KeymapStateMask = 1 << 14, + ExposureMask = 1 << 15, + VisibilityChangeMask = 1 << 16, + StructureNotifyMask = 1 << 17, + ResizeRedirectMask = 1 << 18, + SubstructureNotifyMask = 1 << 19, + SubstructureRedirectMask = 1 << 20, + FocusChangeMask = 1 << 21, + PropertyChangeMask = 1 << 22, + ColormapChangeMask = 1 << 23, + OwnerGrabButtonMask = 1 << 24 +} +enum { + KeyPress = 2, + KeyRelease = 3, + ButtonPress = 4, + ButtonRelease = 5, + MotionNotify = 6, + EnterNotify = 7, + LeaveNotify = 8, + FocusIn = 9, + FocusOut = 10, + KeymapNotify = 11, + Expose = 12, + GraphicsExpose = 13, + NoExpose = 14, + VisibilityNotify = 15, + CreateNotify = 16, + DestroyNotify = 17, + UnmapNotify = 18, + MapNotify = 19, + MapRequest = 20, + ReparentNotify = 21, + ConfigureNotify = 22, + ConfigureRequest = 23, + GravityNotify = 24, + ResizeRequest = 25, + CirculateNotify = 26, + CirculateRequest = 27, + PropertyNotify = 28, + SelectionClear = 29, + SelectionRequest = 30, + SelectionNotify = 31, + ColormapNotify = 32, + ClientMessage = 33, + MappingNotify = 34, + GenericEvent = 35, + LASTEvent = 36 +} +enum { + ShiftMask = 1 << 0, + LockMask = 1 << 1, + ControlMask = 1 << 2, + Mod1Mask = 1 << 3, + Mod2Mask = 1 << 4, + Mod3Mask = 1 << 5, + Mod4Mask = 1 << 6, + Mod5Mask = 1 << 7 +} +enum { + ShiftMapIndex = 0, + LockMapIndex = 1, + ControlMapIndex = 2, + Mod1MapIndex = 3, + Mod2MapIndex = 4, + Mod3MapIndex = 5, + Mod4MapIndex = 6, + Mod5MapIndex = 7 +} +enum { + Button1Mask = 1 << 8, + Button2Mask = 1 << 9, + Button3Mask = 1 << 10, + Button4Mask = 1 << 11, + Button5Mask = 1 << 12, + AnyModifier = 1 << 15 +} +enum { + ShiftMap = 1 << 0, + LockMap = 1 << 1, + ControlMap = 1 << 2, + Mod1Map = 1 << 3, + Mod2Map = 1 << 4, + Mod3Map = 1 << 5, + Mod4Map = 1 << 6, + Mod5Map = 1 << 7, +} +enum { + Button1 = 1, + Button2 = 2, + Button3 = 3, + Button4 = 4, + Button5 = 5 +} +enum { + NotifyNormal = 0, + NotifyGrab = 1, + NotifyUngrab = 2, + NotifyWhileGrabbed = 3 +} +enum int NotifyHint = 1; +enum { + NotifyAncestor = 0, + NotifyVirtual = 1, + NotifyInferior = 2, + NotifyNonlinear = 3, + NotifyNonlinearVirtual = 4, + NotifyPointer = 5, + NotifyPointerRoot = 6, + NotifyDetailNone = 7 +} +enum { + VisibilityUnobscured = 0, + VisibilityPartiallyObscured = 1, + VisibilityFullyObscured = 2 +} +enum { + PlaceOnTop = 0, + PlaceOnBottom = 1 +} +enum { + FamilyInternet = 0, + FamilyDECnet = 1, + FamilyChaos = 2, + FamilyServerInterpreted = 5, + FamilyInternet6 = 6 +} +enum { + PropertyNewValue = 0, + PropertyDelete = 1 +} +enum { + ColormapUninstalled = 0, + ColormapInstalled = 1 +} +enum { + GrabModeSync = 0, + GrabModeAsync = 1 +} +enum { + GrabSuccess = 0, + AlreadyGrabbed = 1, + GrabInvalidTime = 2, + GrabNotViewable = 3, + GrabFrozen = 4 +} +enum { + AsyncPointer = 0, + SyncPointer = 1, + ReplayPointer = 2, + AsyncKeyboard = 3, + SyncKeyboard = 4, + ReplayKeyboard = 5, + AsyncBoth = 6, + SyncBoth = 7 +} +enum { + RevertToNone = None, + RevertToPointerRoot = PointerRoot, + RevertToParent = 2 +} +enum XErrorCode : int { + Success = 0, + BadRequest = 1, + BadValue = 2, + BadWindow = 3, + BadPixmap = 4, + BadAtom = 5, + BadCursor = 6, + BadFont = 7, + BadMatch = 8, + BadDrawable = 9, + BadAccess = 10, + BadAlloc = 11, + BadColor = 12, + BadGC = 13, + BadIDChoice = 14, + BadName = 15, + BadLength = 16, + BadImplementation = 17, + FirstExtensionError = 128, + LastExtensionError = 255 +} + +enum { + InputOutput = 1, + InputOnly = 2 +} +enum { + CWBackPixmap = 1 << 0, + CWBackPixel = 1 << 1, + CWBorderPixmap = 1 << 2, + CWBorderPixel = 1 << 3, + CWBitGravity = 1 << 4, + CWWinGravity = 1 << 5, + CWBackingStore = 1 << 6, + CWBackingPlanes = 1 << 7, + CWBackingPixel = 1 << 8, + CWOverrideRedirect = 1 << 9, + CWSaveUnder = 1 << 10, + CWEventMask = 1 << 11, + CWDontPropagate = 1 << 12, + CWColormap = 1 << 13, + CWCursor = 1 << 14 +} +enum { + CWX = 1 << 0, + CWY = 1 << 1, + CWWidth = 1 << 2, + CWHeight = 1 << 3, + CWBorderWidth = 1 << 4, + CWSibling = 1 << 5, + CWStackMode = 1 << 6 +} +enum { + ForgetGravity = 0, + NorthWestGravity = 1, + NorthGravity = 2, + NorthEastGravity = 3, + WestGravity = 4, + CenterGravity = 5, + EastGravity = 6, + SouthWestGravity = 7, + SouthGravity = 8, + SouthEastGravity = 9, + StaticGravity = 10 +} +const uint UnmapGravity = 0; +enum { + NotUseful = 0, + WhenMapped = 1, + Always = 2 +} +enum { + IsUnmapped = 0, + IsUnviewable = 1, + IsViewable = 2 +} +enum { + SetModeInsert = 0, + SetModeDelete = 1 +} +enum CloseDownMode : int { + DestroyAll = 0, + RetainPermanent = 1, + RetainTemporary = 2 +} +enum { + Above = 0, + Below = 1, + TopIf = 2, + BottomIf = 3, + Opposite = 4 +} +enum { + RaiseLowest = 0, + LowerHighest = 1 +} +enum { + PropModeReplace = 0, + PropModePrepend = 1, + PropModeAppend = 2 +} +enum { + ArcChord = 0, + ArcPieSlice = 1 +} +enum { + GCFunction = 1 << 0, + GCPlaneMask = 1 << 1, + GCForeground = 1 << 2, + GCBackground = 1 << 3, + GCLineWidth = 1 << 4, + GCLineStyle = 1 << 5, + GCCapStyle = 1 << 6, + GCJoinStyle = 1 << 7, + GCFillStyle = 1 << 8, + GCFillRule = 1 << 9, + GCTile = 1 << 10, + GCStipple = 1 << 11, + GCTileStipXOrigin = 1 << 12, + GCTileStipYOrigin = 1 << 13, + GCFont = 1 << 14, + GCSubwindowMode = 1 << 15, + GCGraphicsExposures = 1 << 16, + GCClipXOrigin = 1 << 17, + GCClipYOrigin = 1 << 18, + GCClipMask = 1 << 19, + GCDashOffset = 1 << 20, + GCDashList = 1 << 21, + GCArcMode = 1 << 22, +} +const uint GCLastBit = 22; +enum { + FontLeftToRight = 0, + FontRightToLeft = 1, + FontChange = 255 +} +enum { + XYBitmap = 0, + XYPixmap = 1, + ZPixmap = 2 +} +enum { + AllocNone = 0, + AllocAll = 1 +} +enum { + DoRed = 1 << 0, + DoGreen = 1 << 1, + DoBlue = 1 << 2 +} +enum { + CursorShape = 0, + TileShape = 1, + StippleShape = 2 +} +enum { + AutoRepeatModeOff = 0, + AutoRepeatModeOn = 1, + AutoRepeatModeDefault = 2 +} +enum { + LedModeOff = 0, + LedModeOn = 1 +} +enum { + KBKeyClickPercent = 1 << 0, + KBBellPercent = 1 << 1, + KBBellPitch = 1 << 2, + KBBellDuration = 1 << 3, + KBLed = 1 << 4, + KBLedMode = 1 << 5, + KBKey = 1 << 6, + KBAutoRepeatMode = 1 << 7 +} +enum { + MappingSuccess = 0, + MappingBusy = 1, + MappingFailed = 2 +} +enum { + MappingModifier = 0, + MappingKeyboard = 1, + MappingPointer = 2 +} +enum { + DontPreferBlanking = 0, + PreferBlanking = 1, + DefaultBlanking = 2 +} +enum { + DisableScreenSaver = 0, + DisableScreenInterval = 0 +} +enum { + DontAllowExposures = 0, + AllowExposures = 1, + DefaultExposures = 2 +} +enum { + ScreenSaverReset = 0, + ScreenSaverActive = 1 +} +enum { + HostInsert = 0, + HostDelete = 1 +} +enum { + EnableAccess = 1, + DisableAccess = 0 +} +enum { + StaticGray = 0, + GrayScale = 1, + StaticColor = 2, + PseudoColor = 3, + TrueColor = 4, + DirectColor = 5 +} +enum { + LSBFirst = 0, + MSBFirst = 1 +} +struct _XkbAnyEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + uint device; +} +alias _XkbAnyEvent XkbAnyEvent; +struct _XkbNewKeyboardNotify { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + int old_device; + int min_key_code; + int max_key_code; + int old_min_key_code; + int old_max_key_code; + uint changed; + char req_major; + char req_minor; +} +alias _XkbNewKeyboardNotify XkbNewKeyboardNotifyEvent; +struct _XkbMapNotifyEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + uint changed; + uint flags; + int first_type; + int num_types; + KeyCode min_key_code; + KeyCode max_key_code; + KeyCode first_key_sym; + KeyCode first_key_act; + KeyCode first_key_behavior; + KeyCode first_key_explicit; + KeyCode first_modmap_key; + KeyCode first_vmodmap_key; + int num_key_syms; + int num_key_acts; + int num_key_behaviors; + int num_key_explicit; + int num_modmap_keys; + int num_vmodmap_keys; + uint vmods; +} +alias _XkbMapNotifyEvent XkbMapNotifyEvent; +struct _XkbStateNotifyEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + uint changed; + int group; + int base_group; + int latched_group; + int locked_group; + uint mods; + uint base_mods; + uint latched_mods; + uint locked_mods; + int compat_state; + ubyte grab_mods; + ubyte compat_grab_mods; + ubyte lookup_mods; + ubyte compat_lookup_mods; + int ptr_buttons; + KeyCode keycode; + char event_type; + char req_major; + char req_minor; +} +alias _XkbStateNotifyEvent XkbStateNotifyEvent; +struct _XkbControlsNotify { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + uint changed_ctrls; + uint enabled_ctrls; + uint enabled_ctrl_changes; + int num_groups; + KeyCode keycode; + char event_type; + char req_major; + char req_minor; +} +alias _XkbControlsNotify XkbControlsNotifyEvent; +struct _XkbIndicatorNotify { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + uint changed; + uint state; +} +alias _XkbIndicatorNotify XkbIndicatorNotifyEvent; +struct _XkbNamesNotify { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + uint changed; + int first_type; + int num_types; + int first_lvl; + int num_lvls; + int num_aliases; + int num_radio_groups; + uint changed_vmods; + uint changed_groups; + uint changed_indicators; + int first_key; + int num_keys; +} +alias _XkbNamesNotify XkbNamesNotifyEvent; +struct _XkbCompatMapNotify { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + uint changed_groups; + int first_si; + int num_si; + int num_total_si; +} +alias _XkbCompatMapNotify XkbCompatMapNotifyEvent; +struct _XkbBellNotify { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + int percent; + int pitch; + int duration; + int bell_class; + int bell_id; + Atom name; + Window window; + Bool event_only; +} +alias _XkbBellNotify XkbBellNotifyEvent; +struct _XkbActionMessage { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + KeyCode keycode; + Bool press; + Bool key_event_follows; + int group; + uint mods; + char[XkbActionMessageLength + 1] message; +} +alias _XkbActionMessage XkbActionMessageEvent; +struct _XkbAccessXNotify { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + int detail; + int keycode; + int sk_delay; + int debounce_delay; +} +alias _XkbAccessXNotify XkbAccessXNotifyEvent; +struct _XkbExtensionDeviceNotify { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Time time; + int xkb_type; + int device; + uint reason; + uint supported; + uint unsupported; + int first_btn; + int num_btns; + uint leds_defined; + uint led_state; + int led_class; + int led_id; +} +alias _XkbExtensionDeviceNotify XkbExtensionDeviceNotifyEvent; +union _XkbEvent { + int type; + XkbAnyEvent any; + XkbNewKeyboardNotifyEvent new_kbd; + XkbMapNotifyEvent map; + XkbStateNotifyEvent state; + XkbControlsNotifyEvent ctrls; + XkbIndicatorNotifyEvent indicators; + XkbNamesNotifyEvent names; + XkbCompatMapNotifyEvent compat; + XkbBellNotifyEvent bell; + XkbActionMessageEvent message; + XkbAccessXNotifyEvent accessx; + XkbExtensionDeviceNotifyEvent device; + XEvent core; +} +alias _XkbEvent XkbEvent; +enum XkbLC_AllComposeControls = 0xc0000000; +enum XkbLC_AllControls = 0xc000001f; +Bool XkbIgnoreExtension(Bool); +Display* XkbOpenDisplay(char*, int*, int*, int*, int*, int*); +Bool XkbQueryExtension(Display*, int*, int*, int*, int*, int*); +Bool XkbUseExtension(Display*, int*, int*); +Bool XkbLibraryVersion(int*, int*); +uint XkbSetXlibControls(Display*, uint, uint); +uint XkbGetXlibControls(Display*); +uint XkbXlibControlsImplemented(); +alias Atom function(Display*, const(char)*, Bool) XkbInternAtomFunc; +alias char* function(Display*, Atom) XkbGetAtomNameFunc; +void XkbSetAtomFuncs(XkbInternAtomFunc, XkbGetAtomNameFunc); +KeySym XkbKeycodeToKeysym(Display*, KeyCode, int, int); +uint XkbKeysymToModifiers(Display*, KeySym); +Bool XkbLookupKeySym(Display*, KeyCode, uint, uint*, KeySym*); +Bool XkbDeviceBellEvent(Display*, Window, int, int, int, int, Atom); +Bool XkbBell(Display*, Window, int, Atom); +Bool XkbForceBell(Display*, int); +Bool XkbBellEvent(Display*, Window, int, Atom); +Bool XkbSelectEvents(Display*, uint, uint, uint); +Bool XkbSelectEventDetails(Display*, uint, uint, c_ulong, c_ulong); +void XkbNoteMapChanges(XkbMapChangesPtr, XkbMapNotifyEvent*, uint); +void XkbNoteNameChanges(XkbNameChangesPtr, XkbNamesNotifyEvent*, uint); +Bool XkbSetServerInternalMods(Display*, uint, uint, uint, uint, uint); +Bool XkbSetIgnoreLockMods(Display*, uint, uint, uint, uint, uint); +Bool XkbVirtualModsToReal(XkbDescPtr, uint, uint*); +Bool XkbComputeEffectiveMap(XkbDescPtr, XkbKeyTypePtr, ubyte*); +Status XkbInitCanonicalKeyTypes(XkbDescPtr, uint, int); +XkbDescPtr XkbAllocKeyboard(); +void XkbFreeKeyboard(XkbDescPtr, uint, Bool); +Status XkbAllocClientMap(XkbDescPtr, uint, uint); +Status XkbAllocServerMap(XkbDescPtr, uint, uint); +void XkbFreeClientMap(XkbDescPtr, uint, Bool); +void XkbFreeServerMap(XkbDescPtr, uint, Bool); +XkbKeyTypePtr XkbAddKeyType(XkbDescPtr, Atom, int, Bool, int); +Status XkbAllocIndicatorMaps(XkbDescPtr); +void XkbFreeIndicatorMaps(XkbDescPtr); +XkbDescPtr XkbGetMap(Display*, uint, uint); +Status XkbGetUpdatedMap(Display*, uint, XkbDescPtr); +Status XkbAllocCompatMap(XkbDescPtr, uint, uint); +void XkbFreeCompatMap(XkbDescPtr, uint, Bool); +Status XkbGetCompatMap(Display*, uint, XkbDescPtr); +Bool XkbSetCompatMap(Display*, uint, XkbDescPtr, Bool); +XkbSymInterpretPtr XkbAddSymInterpret(XkbDescPtr, XkbSymInterpretPtr, Bool, XkbChangesPtr); +Status XkbAllocNames(XkbDescPtr, uint, int, int); +Status XkbGetNames(Display*, uint, XkbDescPtr); +Bool XkbSetNames(Display*, uint, uint, uint, XkbDescPtr); +Bool XkbChangeNames(Display*, XkbDescPtr, XkbNameChangesPtr); +void XkbFreeNames(XkbDescPtr, uint, Bool); +Status XkbGetState(Display*, uint, XkbStatePtr); +Bool XkbSetMap(Display*, uint, XkbDescPtr); +Bool XkbChangeMap(Display*, XkbDescPtr, XkbMapChangesPtr); +Bool XkbSetDetectableAutoRepeat(Display*, Bool, Bool*); +Bool XkbGetDetectableAutoRepeat(Display*, Bool*); +Bool XkbSetDebuggingFlags(Display*, uint, uint, char*, uint, uint, uint*, uint*); +Bool XkbApplyVirtualModChanges(XkbDescPtr, uint, XkbChangesPtr); +Bool XkbUpdateActionVirtualMods(XkbDescPtr, XkbAction*, uint); +void XkbUpdateKeyTypeVirtualMods(XkbDescPtr, XkbKeyTypePtr, uint, XkbChangesPtr); +enum XA_PRIMARY = 1; +enum XA_SECONDARY = 2; +enum XA_ARC = 3; +enum XA_ATOM = 4; +enum XA_BITMAP = 5; +enum XA_CARDINAL = 6; +enum XA_COLORMAP = 7; +enum XA_CURSOR = 8; +enum XA_CUT_BUFFER0 = 9; +enum XA_CUT_BUFFER1 = 10; +enum XA_CUT_BUFFER2 = 11; +enum XA_CUT_BUFFER3 = 12; +enum XA_RGB_GREEN_MAP = 29; +enum XA_RGB_RED_MAP = 30; +enum XA_STRING = 31; +enum XA_VISUALID = 32; +enum XA_WINDOW = 33; +enum XA_WM_COMMAND = 34; +enum XA_WM_HINTS = 35; +enum XA_WM_CLIENT_MACHINE = 36; +alias int XcursorBool; +alias uint XcursorUInt; +alias XcursorUInt XcursorDim; +alias XcursorUInt XcursorPixel; +enum XcursorTrue = 1; +enum XcursorFalse = 0; +enum XCURSOR_MAGIC = 0x72756358; +enum XCURSOR_FILE_TOC_LEN = (3 * 4); +struct _XcursorFileToc { + XcursorUInt type; + XcursorUInt subtype; + XcursorUInt position; +} +alias _XcursorFileToc XcursorFileToc; +struct _XcursorFileHeader { + XcursorUInt magic; + XcursorUInt header; + XcursorUInt version_; + XcursorUInt ntoc; + XcursorFileToc* tocs; +} +alias _XcursorFileHeader XcursorFileHeader; +enum XCURSOR_CHUNK_HEADER_LEN = (4 * 4); +struct _XcursorChunkHeader { + XcursorUInt header; + XcursorUInt type; + XcursorUInt subtype; + XcursorUInt version_; +} +alias _XcursorChunkHeader XcursorChunkHeader; +enum XCURSOR_COMMENT_TYPE = 0xfffe0001; +enum XCURSOR_COMMENT_VERSION = 1; +enum XCURSOR_COMMENT_HEADER_LEN = (XCURSOR_CHUNK_HEADER_LEN + (1 * 4)); +enum XCURSOR_COMMENT_COPYRIGHT = 1; +enum XCURSOR_COMMENT_LICENSE = 2; +enum XCURSOR_COMMENT_OTHER = 3; +enum XCURSOR_COMMENT_MAX_LEN = 0x100000; +struct _XcursorComment { + XcursorUInt version_; + XcursorUInt comment_type; + char* comment; +} +alias _XcursorComment XcursorComment; +enum XCURSOR_IMAGE_TYPE = 0xfffd0002; +enum XCURSOR_IMAGE_VERSION = 1; +enum XCURSOR_IMAGE_HEADER_LEN = (XCURSOR_CHUNK_HEADER_LEN + (5 * 4)); +enum XCURSOR_IMAGE_MAX_SIZE = 0x7fff + ; +struct _XcursorImage { + XcursorUInt version_; + XcursorDim size; + XcursorDim width; + XcursorDim height; + XcursorDim xhot; + XcursorDim yhot; + XcursorUInt delay; + XcursorPixel* pixels; +} +alias _XcursorImage XcursorImage; +struct _XcursorImages { + int nimage; + XcursorImage** images; + char* name; +} +enum int XlibSpecificationRelease = 6; +enum int X_HAVE_UTF8_STRING = 1; +alias char* XPointer; +alias int Status; +alias int Bool; +enum { + False, + True +} +alias int QueueMode; +enum { + QueuedAlready, + QueuedAfterReading, + QueuedAfterFlush +} +int ConnectionNumber(Display* dpy) { + return dpy.fd; +} +Window RootWindow(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).root; +} +int DefaultScreen(Display* dpy) { + return dpy.default_screen; +} +Window DefaultRootWindow(Display* dpy) { + return ScreenOfDisplay(dpy, DefaultScreen(dpy)).root; +} +Visual* DefaultVisual(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).root_visual; +} +GC DefaultGC(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).default_gc; +} +c_ulong BlackPixel(Display* dpy, int scr) { + return cast(c_ulong) ScreenOfDisplay(dpy, scr).black_pixel; +} +c_ulong WhitePixel(Display* dpy, int scr) { + return cast(c_ulong) ScreenOfDisplay(dpy, scr).white_pixel; +} +c_ulong AllPlanes() { + return 0xFFFFFFFF; +} +int QLength(Display* dpy) { + return dpy.qlen; +} +int DisplayWidth(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).width; +} +int DisplayHeight(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).height; +} +int DisplayWidthMM(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).mwidth; +} +int DisplayHeightMM(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).mheight; +} +int DisplayPlanes(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).root_depth; +} +int DisplayCells(Display* dpy, int scr) { + return DefaultVisual(dpy, scr).map_entries; +} +int ScreenCount(Display* dpy) { + return dpy.nscreens; +} +int ProtocolVersion(Display* dpy) { + return dpy.proto_major_version; +} +int ProtocolRevision(Display* dpy) { + return dpy.proto_minor_version; +} +int VendorRelease(Display* dpy) { + return dpy.release; +} +char* DisplayString(Display* dpy) { + return dpy.display_name; +} +int DefaultDepth(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).root_depth; +} +Colormap DefaultColormap(Display* dpy, int scr) { + return ScreenOfDisplay(dpy, scr).cmap; +} +int BitmapUnit(Display* dpy) { + return dpy.bitmap_unit; +} +int BitmapBitOrder(Display* dpy) { + return dpy.bitmap_bit_order; +} +int BitmapPad(Display* dpy) { + return dpy.bitmap_pad; +} +uint NextRequest(Display* dpy) { + return cast(uint) dpy.request + 1; +} +uint LastKnownRequestProcessed(Display* dpy) { + return cast(uint) dpy.last_request_read; +} +Screen* ScreenOfDisplay(Display* dpy, int scr) { + return &dpy.screens[scr]; +} +Screen* DefaultScreenOfDisplay(Display* dpy) { + return ScreenOfDisplay(dpy, DefaultScreen(dpy)); +} +Display* DisplayOfScreen(Screen* s) { + return s.display; +} +int DoesBackingStore(Screen* s) { + return s.backing_store; +} +c_long EventMaskOfScreen(Screen* s) { + return s.root_input_mask; +} +struct XExtData { + int number; + XExtData* next; + extern(C) nothrow int function(XExtData* extension) free_private; + XPointer private_data; +} +struct XExtCodes { + int extension; + int major_opcode; + int first_event; + int first_error; +} +struct XPixmapFormatValues { + int depth; + int bits_per_pixel; + int scanline_pad; +} +struct XGCValues { + int function_; + c_ulong plane_mask; + c_ulong foreground; + c_ulong background; + int line_width; + int line_style; + int cap_style; + int join_style; + int fill_style; + int fill_rule; + int arc_mode; + Pixmap tile; + Pixmap stipple; + int ts_x_origin; + int ts_y_origin; + Font font; + int subwindow_mode; + Bool graphics_exposures; + int clip_x_origin; + int clip_y_origin; + Pixmap clip_mask; + int dash_offset; + char dashes; +} +alias _XGC* GC; +struct Visual { + XExtData* ext_data; + VisualID visualid; + int c_class; + c_ulong red_mask, green_mask, blue_mask; + int bits_per_rgb; + int map_entries; +} +struct Depth { + int depth; + int nvisuals; + Visual* visuals; +} +alias Display XDisplay; +struct Screen { + XExtData* ext_data; + XDisplay* display; + Window root; + int width, height; + int mwidth, mheight; + int ndepths; + Depth* depths; + int root_depth; + Visual* root_visual; + GC default_gc; + Colormap cmap; + c_ulong white_pixel; + c_ulong black_pixel; + int max_maps, min_maps; + int backing_store; + Bool save_unders; + c_long root_input_mask; +} +struct ScreenFormat { + XExtData* ext_data; + int depth; + int bits_per_pixel; + int scanline_pad; +} +struct XSetWindowAttributes { + Pixmap background_pixmap; + c_ulong background_pixel; + Pixmap border_pixmap; + c_ulong border_pixel; + int bit_gravity; + int win_gravity; + int backing_store; + c_ulong backing_planes; + c_ulong backing_pixel; + Bool save_under; + c_long event_mask; + c_long do_not_propagate_mask; + Bool override_redirect; + Colormap colormap; + Cursor cursor; +} +struct XWindowAttributes { + int x, y; + int width, height; + int border_width; + int depth; + Visual* visual; + Window root; + int c_class; + int bit_gravity; + int win_gravity; + int backing_store; + c_ulong backing_planes; + c_ulong backing_pixel; + Bool save_under; + Colormap colormap; + Bool map_installed; + int map_state; + c_long all_event_masks; + c_long your_event_mask; + c_long do_not_propagate_mask; + Bool override_redirect; + Screen* screen; +} +struct XHostAddress { + int family; + int length; + char* address; +} +struct XServerInterpretedAddress { + int typelength; + int valuelength; + char* type; + char* value; +} +struct XImage { + int width, height; + int xoffset; + int format; + char* data; + int char_order; + int bitmap_unit; + int bitmap_bit_order; + int bitmap_pad; + int depth; + int chars_per_line; + int bits_per_pixel; + c_ulong red_mask; + c_ulong green_mask; + c_ulong blue_mask; + XPointer obdata; + struct F { + extern(C) nothrow: + @nogc: + XImage* function(XDisplay*, Visual*, uint, int, int, char*, uint, uint, int, int) create_image; + int function(XImage*) destroy_image; + c_ulong function(XImage*, int, int) get_pixel; + int function(XImage*, int, int, c_ulong) put_pixel; + XImage function(XImage*, int, int, uint, uint) sub_image; + int function(XImage*, c_long) add_pixel; + } + F f; +} +struct XWindowChanges { + int x, y; + int width, height; + int border_width; + Window sibling; + int stack_mode; +} +struct XColor { + c_ulong pixel; + ushort red, green, blue; + char flags; + char pad; +} +struct XSegment { + short x1, y1, x2, y2; +} +struct XPoint { + short x, y; +} +struct XRectangle { + short x, y; + ushort width, height; +} +struct XArc { + short x, y; + ushort width, height; + short angle1, angle2; +} +struct XKeyboardControl { + int key_click_percent; + int bell_percent; + int bell_pitch; + int bell_duration; + int led; + int led_mode; + int key; + int auto_repeat_mode; +} +struct XKeyboardState { + int key_click_percent; + int bell_percent; + uint bell_pitch, bell_duration; + c_ulong led_mask; + int global_auto_repeat; + char[32] auto_repeats; +} +struct XTimeCoord { + Time time; + short x, y; +} +struct XModifierKeymap { + int max_keypermod; + KeyCode* modifiermap; +} +struct _XPrivate; +struct _XrmHashBucketRec; +alias _XDisplay Display; +alias _XDisplay* _XPrivDisplay; +struct XKeyEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + Window root; + Window subwindow; + Time time; + int x, y; + int x_root, y_root; + uint state; + uint keycode; + Bool same_screen; +} +alias XKeyEvent XKeyPressedEvent; +alias XKeyEvent XKeyReleasedEvent; +struct XButtonEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + Window root; + Window subwindow; + Time time; + int x, y; + int x_root, y_root; + uint state; + uint button; + Bool same_screen; +} +alias XButtonEvent XButtonPressedEvent; +alias XButtonEvent XButtonReleasedEvent; +struct XMotionEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + Window root; + Window subwindow; + Time time; + int x, y; + int x_root, y_root; + uint state; + char is_hint; + Bool same_screen; +} +alias XMotionEvent XPointerMovedEvent; +struct XCrossingEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + Window root; + Window subwindow; + Time time; + int x, y; + int x_root, y_root; + int mode; + int detail; + Bool same_screen; + Bool focus; + uint state; +} +alias XCrossingEvent XEnterWindowEvent; +alias XCrossingEvent XLeaveWindowEvent; +struct XFocusChangeEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + int mode; + int detail; +} +alias XFocusChangeEvent XFocusInEvent; +alias XFocusChangeEvent XFocusOutEvent; +struct XKeymapEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + char[32] key_vector; +} +struct XExposeEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + int x, y; + int width, height; + int count; +} +struct XGraphicsExposeEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Drawable drawable; + int x, y; + int width, height; + int count; + int major_code; + int minor_code; +} +struct XNoExposeEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Drawable drawable; + int major_code; + int minor_code; +} +struct XVisibilityEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + int state; +} +struct XCreateWindowEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window parent; + Window window; + int x, y; + int width, height; + int border_width; + Bool override_redirect; +} +struct XDestroyWindowEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window event; + Window window; +} +struct XUnmapEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window event; + Window window; + Bool from_configure; +} +struct XMapEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window event; + Window window; + Bool override_redirect; +} +struct XMapRequestEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window parent; + Window window; +} +struct XReparentEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window event; + Window window; + Window parent; + int x, y; + Bool override_redirect; +} +struct XConfigureEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window event; + Window window; + int x, y; + int width, height; + int border_width; + Window above; + Bool override_redirect; +} +struct XGravityEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window event; + Window window; + int x, y; +} +struct XResizeRequestEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + int width, height; +} +struct XConfigureRequestEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window parent; + Window window; + int x, y; + int width, height; + int border_width; + Window above; + int detail; + c_ulong value_mask; +} +struct XCirculateEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window event; + Window window; + int place; +} +struct XCirculateRequestEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window parent; + Window window; + int place; +} +struct XPropertyEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + Atom atom; + Time time; + int state; +} +struct XSelectionClearEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + Atom selection; + Time time; +} +struct XSelectionRequestEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window owner; + Window requestor; + Atom selection; + Atom target; + Atom property; + Time time; +} +struct XSelectionEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window requestor; + Atom selection; + Atom target; + Atom property; + Time time; +} +struct XColormapEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + Colormap colormap; + Bool c_new; + int state; +} +struct XClientMessageEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + Atom message_type; + int format; + union _data { + char[20] b; + short[10] s; + c_long[5] l; + } + _data data; +} +struct XMappingEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; + int request; + int first_keycode; + int count; +} +struct XErrorEvent { + int type; + Display* display; + XID resourceid; + c_ulong serial; + ubyte error_code; + ubyte request_code; + ubyte minor_code; +} +struct XAnyEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + Window window; +} +struct XGenericEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + int extension; + int evtype; +} +struct XGenericEventCookie { + int type; + c_ulong serial; + Bool send_event; + Display* display; + int extension; + int evtype; + uint cookie; + void* data; +} +union XEvent { + int type; + XAnyEvent xany; + XKeyEvent xkey; + XButtonEvent xbutton; + XMotionEvent xmotion; + XCrossingEvent xcrossing; + XFocusChangeEvent xfocus; + XExposeEvent xexpose; + XGraphicsExposeEvent xgraphicsexpose; + XNoExposeEvent xnoexpose; + XVisibilityEvent xvisibility; + XCreateWindowEvent xcreatewindow; + XDestroyWindowEvent xdestroywindow; + XUnmapEvent xunmap; + XMapEvent xmap; + XMapRequestEvent xmaprequest; + XReparentEvent xreparent; + XConfigureEvent xconfigure; + XGravityEvent xgravity; + XResizeRequestEvent xresizerequest; + XConfigureRequestEvent xconfigurerequest; + XCirculateEvent xcirculate; + XCirculateRequestEvent xcirculaterequest; + XPropertyEvent xproperty; + XSelectionClearEvent xselectionclear; + XSelectionRequestEvent xselectionrequest; + XSelectionEvent xselection; + XColormapEvent xcolormap; + XClientMessageEvent xclient; + XMappingEvent xmapping; + XErrorEvent xerror; + XKeymapEvent xkeymap; + XGenericEvent xgeneric; + XGenericEventCookie xcookie; + c_long[24] pad; +} +int XAllocID(Display* dpy) { + return cast(int) dpy.resource_alloc(dpy); +} +struct XCharStruct { + short lbearing; + short rbearing; + short width; + short ascent; + short descent; + ushort attributes; +} +struct XFontProp { + Atom name; + c_ulong card32; +} +struct XFontStruct { + XExtData* ext_data; + Font fid; + uint direction; + uint min_char_or_char2; + uint max_char_or_char2; + uint min_char1; + uint max_char1; + Bool all_chars_exist; + uint default_char; + int n_properties; + XFontProp* properties; + XCharStruct min_bounds; + XCharStruct max_bounds; + XCharStruct* per_char; + int ascent; + int descent; +} +struct XTextItem { + char* chars; + int nchars; + int delta; + Font font; +} +struct XChar2b { + ubyte char1; + ubyte char2; +} +struct XTextItem16 { + XChar2b* chars; + int nchars; + int delta; + Font font; +} +union XEDataObject { + Display* display; + GC gc; + Visual* visual; + Screen* screen; + ScreenFormat* pixmap_format; + XFontStruct* font; +} +struct XFontSetExtents { + XRectangle max_ink_extent; + XRectangle max_logical_extent; +} +struct _XOM {} +struct _XOC {} +alias _XOM* XOM; +alias _XOC* XOC; +alias _XOC* XFontSet; +struct XmbTextItem { + char* chars; + int nchars; + int delta; + XFontSet font_set; +} +struct XwcTextItem { + wchar* chars; + int nchars; + int delta; + XFontSet font_set; +} +const char* XNRequiredCharSet = "requiredCharSet"; +const char* XNQueryOrientation = "queryOrientation"; +const char* XNBaseFontName = "baseFontName"; +const char* XNOMAutomatic = "omAutomatic"; +const char* XNMissingCharSet = "missingCharSet"; +const char* XNDefaultString = "defaultString"; +const char* XNOrientation = "orientation"; +const char* XNDirectionalDependentDrawing = "directionalDependentDrawing"; +const char* XNContextualDrawing = "contextualDrawing"; +const char* XNFontInfo = "fontInfo"; +struct XOMCharSetList { + int charset_count; + char** charset_list; +} +alias int XOrientation; +enum { + XOMOrientation_LTR_TTB, + XOMOrientation_RTL_TTB, + XOMOrientation_TTB_LTR, + XOMOrientation_TTB_RTL, + XOMOrientation_Context +} +struct XOMOrientation { + int num_orientation; + XOrientation* orientation; +} +struct XOMFontInfo { + int num_font; + XFontStruct** font_struct_list; + char** font_name_list; +} +struct _XIM {} +struct _XIC {} +alias _XIM* XIM; +alias _XIC* XIC; +alias void function(XIM, XPointer, XPointer) XIMProc; +alias Bool function(XIC, XPointer, XPointer) XICProc; +alias void function(Display*, XPointer, XPointer) XIDProc; +struct XIMStyles { + ushort count_styles; + XIMStyle* supported_styles; +} +alias c_ulong XIMStyle; +enum { + XIMPreeditArea = 0x0001L, + XIMPreeditCallbacks = 0x0002L, + XIMPreeditPosition = 0x0004L, + XIMPreeditNothing = 0x0008L, + XIMPreeditNone = 0x0010L, + XIMStatusArea = 0x0100L, + XIMStatusCallbacks = 0x0200L, + XIMStatusNothing = 0x0400L, + XIMStatusNone = 0x0800L +} +const char* XNVaNestedList = "XNVaNestedList"; +const char* XNQueryInputStyle = "queryInputStyle"; +const char* XNClientWindow = "clientWindow"; +const char* XNInputStyle = "inputStyle"; +const char* XNFocusWindow = "focusWindow"; +const char* XNResourceName = "resourceName"; +const char* XNResourceClass = "resourceClass"; +const char* XNGeometryCallback = "geometryCallback"; +const char* XNDestroyCallback = "destroyCallback"; +const char* XNFilterEvents = "filterEvents"; +const char* XNPreeditStartCallback = "preeditStartCallback"; +const char* XNPreeditDoneCallback = "preeditDoneCallback"; +const char* XNStringConversion = "stringConversion"; +const char* XNResetState = "resetState"; +const char* XNHotKey = "hotKey"; +const char* XNHotKeyState = "hotKeyState"; +const char* XNPreeditState = "preeditState"; +const char* XNSeparatorofNestedList = "separatorofNestedList"; +enum int XBufferOverflow = -1; +enum int XLookupNone = 1; +enum int XLookupChars = 2; +enum int XLookupKeySym = 3; +enum int XLookupBoth = 4; +alias XVaNestedList = void*; +XImage* XGetImage(Display*, Drawable, int, int, uint, uint, c_ulong, int); +XImage* XGetSubImage(Display*, Drawable, int, int, uint, uint, c_ulong, int, XImage*, int, int); +Display* XOpenDisplay(char*); +void XrmInitialize(); +int function(Display*) XSetAfterFunction(Display*, int function(Display*)); +Atom XInternAtom(Display*, const char*, Bool); +Status XInternAtoms(Display*, char**, int, Bool, Atom*); +Colormap XCopyColormapAndFree(Display*, Colormap); +Colormap XCreateColormap(Display*, Window, Visual*, int); +Cursor XCreatePixmapCursor(Display*, Pixmap, Pixmap, XColor*, XColor*, uint, uint); +Cursor XCreateGlyphCursor(Display*, Font, Font, uint, uint, XColor*, XColor*); +Cursor XCreateFontCursor(Display*, uint); +Window XGetSelectionOwner(Display*, Atom); +Window XCreateWindow(Display*, Window, int, int, uint, uint, uint, int, uint, Visual*, c_ulong, XSetWindowAttributes*); +Colormap* XListInstalledColormaps(Display*, Window, int*); +char** XListFonts(Display*, char*, int, int*); +XHostAddress* XListHosts(Display*, int*, Bool*); +KeySym XKeycodeToKeysym(Display*, KeyCode, int); +KeySym XLookupKeysym(XKeyEvent*, int); +KeySym* XGetKeyboardMapping(Display*, KeyCode, int, int*); +KeySym XStringToKeysym(char*); +c_long XMaxRequestSize(Display*); +c_long XExtendedMaxRequestSize(Display*); +char* XResourceManagerString(Display*); +char* XScreenResourceString(Screen*); +c_ulong XDisplayMotionBufferSize(Display*); +VisualID XVisualIDFromVisual(Visual*); +Status XInitThreads(); +int XScreenNumberOfScreen(Screen*); +alias int function(Display*, XErrorEvent*) XErrorHandler; +XErrorHandler XSetErrorHandler(XErrorHandler); +alias int function(Display*) XIOErrorHandler; +Status XGetWMProtocols(Display*, Window, Atom**, int*); +Status XSetWMProtocols(Display*, Window, Atom*, int); +Status XIconifyWindow(Display*, Window, int); +Status XWithdrawWindow(Display*, Window, int); +int XChangeKeyboardControl(Display*, c_ulong, XKeyboardControl*); +int XChangeKeyboardMapping(Display*, int, int, KeySym*, int); +int XChangePointerControl(Display*, Bool, Bool, int, int, int); +int XChangeProperty(Display*, Window, Atom, Atom, int, int, ubyte*, int); +int XChangeSaveSet(Display*, Window, int); +int XChangeWindowAttributes(Display*, Window, uint, XSetWindowAttributes*); +Bool XCheckIfEvent(Display*, XEvent*, Bool function(Display*, XEvent*, XPointer), XPointer); +Bool XCheckMaskEvent(Display*, c_long, XEvent*); +Bool XCheckTypedEvent(Display*, int, XEvent*); +Bool XCheckTypedWindowEvent(Display*, Window, int, XEvent*); +Bool XCheckWindowEvent(Display*, Window, c_long, XEvent*); +int XCirculateSubwindows(Display*, Window, int); +int XCloseDisplay(Display*); +int XConfigureWindow(Display*, Window, c_ulong, XWindowChanges*); +int XConnectionNumber(Display*); +int XConvertSelection(Display*, Atom, Atom, Atom, Window, Time); +int XDefaultDepthOfScreen(Screen*); +int XDefaultScreen(Display*); +int XDefineCursor(Display*, Window, Cursor); +int XDeleteProperty(Display*, Window, Atom); +int XDestroyWindow(Display*, Window); +int XDestroySubwindows(Display*, Window); +int XDoesBackingStore(Screen*); +Bool XDoesSaveUnders(Screen*); +int XEventsQueued(Display*, int); +Status XFetchName(Display*, Window, char**); +int XFillArc(Display*, Drawable, GC, int, int, uint, uint, int, int); +int XFillArcs(Display*, Drawable, GC, XArc*, int); +int XFillPolygon(Display*, Drawable, GC, XPoint*, int, int, int); +int XFillRectangle(Display*, Drawable, GC, int, int, uint, uint); +int XFillRectangles(Display*, Drawable, GC, XRectangle*, int); +int XFlush(Display*); +int XForceScreenSaver(Display*, int); +int XFree(void*); +int XFreeColormap(Display*, Colormap); +int XFreeColors(Display*, Colormap, c_ulong*, int, c_ulong); +int XFreeCursor(Display*, Cursor); +int XFreeExtensionList(char**); +int XFreeFont(Display*, XFontStruct*); +int XFreeFontInfo(char**, XFontStruct*, int); +int XFreePixmap(Display*, Pixmap); +int XGeometry(Display*, int, char*, char*, uint, uint, uint, int, int, int*, int*, int*, int*); +int XGetErrorDatabaseText(Display*, char*, char*, char*, char*, int); +int XGetErrorText(Display*, int, char*, int); +int XGetInputFocus(Display*, Window*, int*); +int XGetKeyboardControl(Display*, XKeyboardState*); +int XGetPointerControl(Display*, int*, int*, int*); +int XGetPointerMapping(Display*, ubyte*, int); +int XGetScreenSaver(Display*, int*, int*, int*, int*); +Status XGetTransientForHint(Display*, Window, Window*); +int XGetWindowProperty(Display*, Window, Atom, c_long, c_long, Bool, Atom, Atom*, int*, c_ulong*, c_ulong*, ubyte**); +Status XGetWindowAttributes(Display*, Window, XWindowAttributes*); +int XGrabButton(Display*, uint, uint, Window, Bool, uint, int, int, Window, Cursor); +int XGrabKey(Display*, int, uint, Window, Bool, int, int); +int XGrabKeyboard(Display*, Window, Bool, int, int, Time); +int XGrabPointer(Display*, Window, Bool, uint, int, int, Window, Cursor, Time); +Status XLookupColor(Display*, Colormap, char*, XColor*, XColor*); +int XLowerWindow(Display*, Window); +int XMapRaised(Display*, Window); +int XMapSubwindows(Display*, Window); +int XMapWindow(Display*, Window); +int XMaskEvent(Display*, c_long, XEvent*); +int XMaxCmapsOfScreen(Screen*); +int XMinCmapsOfScreen(Screen*); +int XMoveResizeWindow(Display*, Window, int, int, uint, uint); +int XMoveWindow(Display*, Window, int, int); +int XNextEvent(Display*, XEvent*); +int XNoOp(Display*); +Status XParseColor(Display*, Colormap, char*, XColor*); +int XParseGeometry(char*, int*, int*, uint*, uint*); +int XPeekEvent(Display*, XEvent*); +int XPeekIfEvent(Display*, XEvent*, Bool function(Display*, XEvent*, XPointer), XPointer); +int XPending(Display*); +int XPlanesOfScreen(Screen*); +int XProtocolRevision(Display*); +int XProtocolVersion(Display*); +int XPutBackEvent(Display*, XEvent*); +int XPutImage(Display*, Drawable, GC, XImage*, int, int, int, int, uint, uint); +int XQLength(Display*); +Status XQueryBestCursor(Display*, Drawable, uint, uint, uint*, uint*); +int XQueryColors(Display*, Colormap, XColor*, int); +Bool XQueryExtension(Display*, const(char)*, int*, int*, int*); +int XQueryKeymap(Display*, char[32]); +Bool XQueryPointer(Display*, Window, Window*, Window*, int*, int*, int*, int*, uint*); +int XQueryTextExtents(Display*, XID, char*, int, int*, int*, int*, XCharStruct*); +int XQueryTextExtents16(Display*, XID, XChar2b*, int, int*, int*, int*, XCharStruct*); +Status XQueryTree(Display*, Window, Window*, Window*, Window**, uint*); +int XRaiseWindow(Display*, Window); +int XReparentWindow(Display*, Window, Window, int, int); +int XResetScreenSaver(Display*); +int XResizeWindow(Display*, Window, uint, uint); +int XRestackWindows(Display*, Window*, int); +int XRotateBuffers(Display*, int); +int XRotateWindowProperties(Display*, Window, Atom*, int, int); +int XScreenCount(Display*); +int XSelectInput(Display*, Window, c_long); +Status XSendEvent(Display*, Window, Bool, c_long, XEvent*); +int XSetAccessControl(Display*, int); +int XSetArcMode(Display*, GC, int); +int XSetBackground(Display*, GC, c_ulong); +int XSetGraphicsExposures(Display*, GC, Bool); +int XSetIconName(Display*, Window, char*); +int XSetInputFocus(Display*, Window, int, Time); +int XSetLineAttributes(Display*, GC, uint, int, int, int); +int XSetModifierMapping(Display*, XModifierKeymap*); +int XSetPlaneMask(Display*, GC, c_ulong); +int XSetPointerMapping(Display*, ubyte*, int); +int XSetScreenSaver(Display*, int, int, int, int); +int XSetSelectionOwner(Display*, Atom, Window, Time); +int XSetState(Display*, GC, c_ulong, c_ulong, int, c_ulong); +int XSetStipple(Display*, GC, Pixmap); +int XSetSubwindowMode(Display*, GC, int); +int XStoreName(Display*, Window, char*); +int XStoreNamedColor(Display*, Colormap, char*, c_ulong, int); +int XSync(Display*, Bool); +int XTextExtents(XFontStruct*, char*, int, int*, int*, int*, XCharStruct*); +int XTextExtents16(XFontStruct*, XChar2b*, int, int*, int*, int*, XCharStruct*); +int XTextWidth(XFontStruct*, char*, int); +int XTextWidth16(XFontStruct*, XChar2b*, int); +Bool XTranslateCoordinates(Display*, Window, Window, int, int, int*, int*, Window*); +int XUndefineCursor(Display*, Window); +int XUngrabButton(Display*, uint, uint, Window); +int XUngrabKey(Display*, int, uint, Window); +int XUngrabKeyboard(Display*, Time); +int XUngrabPointer(Display*, Time); +int XUngrabServer(Display*); +int XUninstallColormap(Display*, Colormap); +int XUnloadFont(Display*, Font); +int XUnmapSubwindows(Display*, Window); +int XUnmapWindow(Display*, Window); +int XVendorRelease(Display*); +int XWarpPointer(Display*, Window, Window, int, int, uint, uint, int, int); +Bool XSupportsLocale(); +char* XSetLocaleModifiers(const char*); +XOM XOpenOM(Display*, _XrmHashBucketRec*, char*, char*); +Status XCloseOM(XOM);XIM XOpenIM(Display*, _XrmHashBucketRec*, char*, char*); +Status XCloseIM(XIM);char* XGetIMValues(XIM, ...); +char* XSetIMValues(XIM, ...); +Display* XDisplayOfIM(XIM); +char* XLocaleOfIM(XIM); +XIC XCreateIC(XIM,...); +void XDestroyIC(XIC); +void XSetICFocus(XIC); +void XUnsetICFocus(XIC); +wchar* XwcResetIC(XIC); +char* XmbResetIC(XIC); +char* Xutf8ResetIC(XIC); +char* XSetICValues(XIC, ...); +char* XGetICValues(XIC, ...); +XIM XIMOfIC(XIC);Bool XFilterEvent(XEvent*, Window); +int XmbLookupString(XIC, XKeyPressedEvent*, char*, int, KeySym*, Status*);int XwcLookupString(XIC, XKeyPressedEvent*, wchar_t*, int, KeySym*, Status*);int Xutf8LookupString(XIC, XKeyPressedEvent*, char*, int, KeySym*, Status*);XVaNestedList XVaCreateNestedList(int, ...); +Bool XRegisterIMInstantiateCallback(Display*, _XrmHashBucketRec*, char*, char*, XIDProc, XPointer); +Bool XUnregisterIMInstantiateCallback(Display*, _XrmHashBucketRec*, char*, char*, XIDProc, XPointer); +alias void function(Display*, XPointer, int, Bool, XPointer*) XConnectionWatchProc; +void XSetAuthorization(char*, int, char*, int); +int _Xmbtowc(wchar*, char*, int); +int _Xwctomb(char*, wchar); +Bool XGetEventData(Display*, XGenericEventCookie*); +void XFreeEventData(Display*, XGenericEventCookie*); +enum bool XTHREADS = true; +enum bool XUSE_MTSAFE_API = true; +enum XEventQueueOwner { + XlibOwnsEventQueue = 0, + XCBOwnsEventQueue +} +const uint XCONN_CHECK_FREQ = 256; +struct _XGC { + XExtData* ext_data; + GContext gid; + Bool rects; + Bool dashes; + c_ulong dirty; + XGCValues values; +} +struct _XLockInfo {} +struct _XDisplayAtoms {} +struct _XContextDB {} +struct _XIMFilter {} +struct _XkbInfoRec {} +struct _XtransConnInfo {} +struct _X11XCBPrivate {} +//~ struct _XLockPtrs{} -- define in version XTHREAD +struct _XKeytrans {} +struct _XDisplay { + XExtData* ext_data; + _XFreeFuncs* free_funcs; + int fd; + int conn_checker; + int proto_major_version; + int proto_minor_version; + char* c_vendor; + XID resource_base; + XID resource_mask; + XID resource_id; + int resource_shift; + extern(C) @nogc nothrow XID function(_XDisplay*) resource_alloc; + int byte_order; + int bitmap_unit; + int bitmap_pad; + int bitmap_bit_order; + int nformats; + ScreenFormat* pixmap_format; + int vnumber; + int release; + _XSQEvent* head, tail; + int qlen; + c_ulong last_request_read; + c_ulong request; + char* last_req; + char* buffer; + char* bufptr; + char* bufmax; + uint max_request_size; + _XrmHashBucketRec* db; + extern(C) nothrow int function(_XDisplay*) synchandler; + char* display_name; + int default_screen; + int nscreens; + Screen* screens; + c_ulong motion_buffer; + c_ulong flags; + int min_keycode; + int max_keycode; + KeySym* keysyms; + XModifierKeymap* modifiermap; + int keysyms_per_keycode; + char* xdefaults; + char* scratch_buffer; + c_ulong scratch_length; + int ext_number; + _XExten* ext_procs; + extern(C) nothrow Bool function( + Display*, XEvent*, xEvent*)[128] event_vec; + extern(C) nothrow Status function( + Display*, XEvent*, xEvent*)[128] wire_vec; + KeySym lock_meaning; + _XLockInfo* lock; + _XInternalAsync* async_handlers; + c_ulong bigreq_size; + _XLockPtrs* lock_fns; + extern(C) @nogc nothrow void function( + Display*, XID*, int) idlist_alloc; + _XKeytrans* key_bindings; + Font cursor_font; + _XDisplayAtoms* atoms; + uint mode_switch; + uint num_lock; + _XContextDB* context_db; + extern(C) @nogc nothrow Bool function( + Display*, XErrorEvent*, xError*)* error_vec; + struct cms { + XPointer defaultCCCs; + XPointer clientCmaps; + XPointer perVisualIntensityMaps; + } + _XIMFilter* im_filters; + _XSQEvent* qfree; + c_ulong next_event_serial_num; + _XExten* flushes; + _XConnectionInfo* im_fd_info; + int im_fd_length; + _XConnWatchInfo* conn_watchers; + int watcher_count; + XPointer filedes; + extern(C) nothrow int function( + Display*) savedsynchandler; + XID resource_max; + int xcmisc_opcode; + _XkbInfoRec* xkb_info; + _XtransConnInfo* trans_conn; + _X11XCBPrivate* xcb; + uint next_cookie; + extern(C) nothrow Bool function(Display*, XGenericEventCookie*, xEvent*)[128] generic_event_vec; + extern(C) nothrow Bool function(Display*, XGenericEventCookie*, XGenericEventCookie*)[128] generic_event_copy_vec; + void* cookiejar; +} +void XAllocIDs(Display* dpy, XID* ids, int n) { + dpy.idlist_alloc(dpy, ids, n); +} +enum bool DataRoutineIsProcedure = false; +struct _XSQEvent { + _XSQEvent* next; + XEvent event; + c_ulong qserial_num; +} +alias _XSQEvent _XQEvent; +extern LockInfoPtr _Xglobal_lock; // warn put here for skip build error +struct _XLockPtrs {} +struct _LockInfoRec {} +alias _LockInfoRec* LockInfoPtr; + +void Xfree(void* ptr) { + free(ptr); +} +struct _XInternalAsync { + _XInternalAsync* next; + extern(C) nothrow Bool function(Display*, xReply*, char*, int, XPointer) handler; + XPointer data; +} +alias _XInternalAsync _XAsyncHandler; +struct _XAsyncEState { + c_ulong min_sequence_number; + c_ulong max_sequence_number; + ubyte error_code; + ubyte major_opcode; + ushort minor_opcode; + ubyte last_error_received; + int error_count; +} +alias _XAsyncEState _XAsyncErrorState; +void _XDeqAsyncHandler(Display* dpy, _XAsyncHandler* handler); +void DeqAsyncHandler(Display* dpy, _XAsyncHandler* handler) { + if (dpy.async_handlers == handler) + dpy.async_handlers = handler.next; + else + _XDeqAsyncHandler(dpy, handler); +} +alias void function(Display*) FreeFuncType; +alias int function(XModifierKeymap*) FreeModmapType; +struct _XFreeFuncs { + FreeFuncType atoms; + FreeModmapType modifiermap; + FreeFuncType key_bindings; + FreeFuncType context_db; + FreeFuncType defaultCCCs; + FreeFuncType clientCmaps; + FreeFuncType intensityMaps; + FreeFuncType im_filters; + FreeFuncType xkb; +} +alias _XFreeFuncs _XFreeFuncRec; +alias int function(Display*, GC, XExtCodes*) CreateGCType; +alias int function(Display*, GC, XExtCodes*) CopyGCType; +alias int function(Display*, GC, XExtCodes*) FlushGCType; +alias int function(Display*, GC, XExtCodes*) FreeGCType; +alias int function(Display*, XFontStruct*, XExtCodes*) CreateFontType; +alias int function(Display*, XFontStruct*, XExtCodes*) FreeFontType; +alias int function(Display*, XExtCodes*) CloseDisplayType; +alias int function(Display*, xError*, XExtCodes*, int*) ErrorType; +alias char* function(Display*, int, XExtCodes*, char*, int) ErrorStringType; +alias void function(Display*, XErrorEvent*, void*) PrintErrorType; +alias void function(Display*, XExtCodes*, const char*, c_long) BeforeFlushType; +struct _XExten { + _XExten* next; + XExtCodes codes; + CreateGCType create_GC; + CopyGCType copy_GC; + FlushGCType flush_GC; + FreeGCType free_GC; + CreateFontType create_Font; + FreeFontType free_Font; + CloseDisplayType close_display; + ErrorType error; + ErrorStringType error_string; + char* name; + PrintErrorType error_values; + BeforeFlushType before_flush; + _XExten* next_flush; +} +alias _XExten _XExtension; +alias void function(Display*, int, XPointer) _XInternalConnectionProc; +Status _XRegisterInternalConnection(Display*, int, _XInternalConnectionProc, XPointer); +void _XUnregisterInternalConnection(Display*, int); +void _XProcessInternalConnection(Display*, _XConnectionInfo*); +struct _XConnectionInfo { + int fd; + _XInternalConnectionProc read_callback; + XPointer call_data; + XPointer* watch_data; + _XConnectionInfo* next; +} +struct _XConnWatchInfo { + XConnectionWatchProc fn; + XPointer client_data; + _XConnWatchInfo* next; +} +version(X86_64) { + enum bool LONG64 = true; + enum bool MUSTCOPY = true; +} else { + enum bool LONG64 = false; + enum bool MUSTCOPY = false; +} +size_t _SIZEOF(T)() { + return T.sizeof; +} +alias _SIZEOF SIZEOF; +version(X86_64) { + alias long INT64; + alias uint INT32; + alias uint INT16; +} else { + static if (LONG64) { + alias c_long INT64; + alias int INT32; + } else + alias c_long INT32; + alias short INT16; +} +alias byte INT8; +static if (LONG64) { + alias c_ulong CARD64; + alias uint CARD32; +} else + alias c_ulong CARD32; +static if (!WORD64 && !LONG64) + alias ulong CARD64; +alias ushort CARD16; +alias byte CARD8; +alias CARD32 BITS32; +alias CARD16 BITS16; +alias CARD8 BYTE; +alias CARD8 BOOL; +static if (WORD64) { + template cvtINT8toInt(INT8 val) { + enum int cvtINT8toInt = cast(int)(val & 0x00000080) ? (val | 0xffffffffffffff00) : val; + } + template cvtINT16toInt(INT16 val) { + enum int cvtINT16toInt = cast(int)(val & 0x00008000) ? (val | 0xffffffffffff0000) : val; + } + template cvtINT32toInt(INT32 val) { + enum int cvtINT32toInt = cast(int)(val & 0x80000000) ? (val | 0xffffffff00000000) : val; + } + template cvtINT8toShort(INT8 val) { + enum short cvtINT8toShort = cast(short) cvtINT8toInt(val); + } + template cvtINT16toShort(INT16 val) { + enum short cvtINT16toShort = cast(short) cvtINT16toInt(val); + } + template cvtINT32toShort(INT32 val) { + enum short cvtINT32toShort = cast(short) cvtINT32toInt(val); + } + template cvtINT8toLong(INT8 val) { + enum c_long cvtINT8toLong = cast(c_long) cvtINT8toInt(val); + } + template cvtINT16toLong(INT16 val) { + enum c_long cvtINT16toLong = cast(c_long) cvtINT16toInt(val); + } + template cvtINT32toLong(INT32 val) { + enum c_long cvtINT32toLong = cast(c_long) cvtINT32toInt(val); + } +} else { + template cvtINT8toInt(INT8 val) { + enum int cvtINT8toInt = cast(int) val; + } + template cvtINT16toInt(INT16 val) { + enum int cvtINT16toInt = cast(int) val; + } + template cvtINT32toInt(INT32 val) { + enum int cvtINT32toInt = cast(int) val; + } + template cvtINT8toShort(INT8 val) { + enum short cvtINT8toShort = cast(short) val; + } + template cvtINT16toShort(INT16 val) { + enum short cvtINT16toShort = cast(short) val; + } + template cvtINT32toShort(INT32 val) { + enum short cvtINT32toShort = cast(short) val; + } + template cvtINT8toLong(INT8 val) { + enum c_long cvtINT8toLong = cast(c_long) val; + } + template cvtINT16toLong(INT16 val) { + enum c_long cvtINT16toLong = cast(c_long) val; + } + template cvtINT32toLong(INT32 val) { + enum c_long cvtINT32toLong = cast(c_long) val; + } +} +enum int xFalse = 0; +alias CARD16 KeyButMask; +struct xConnClientPrefix { + CARD8 byteOrder; + BYTE pad; + CARD16 majorVersion; + CARD16 minorVersion; + CARD16 nbytesAuthProto6; + CARD16 nbytesAuthString; + CARD16 pad2; +} +struct xConnSetupPrefix { + CARD8 success; + BYTE lengthReason; + CARD16 majorVersion, minorVersion; + CARD16 length; +} +struct xWindowRoot { + Window windowId; + Colormap defaultColormap; + CARD32 whitePixel, blackPixel; + CARD32 currentInputMask; + CARD16 pixWidth, pixHeight; + CARD16 mmWidth, mmHeight; + CARD16 minInstalledMaps, maxInstalledMaps; + VisualID rootVisualID; + CARD8 backingStore; + BOOL saveUnders; + CARD8 rootDepth; + CARD8 nDepths; +} +struct xTimecoord { + CARD32 time; + INT16 x, y; +} +struct xHostEntry { + CARD8 family; + BYTE pad; + CARD16 length; +} +struct xCharInfo { + INT16 leftSideBearing, rightSideBearing, characterWidth, ascent, descent; + CARD16 attributes; +} +alias CARD8 KEYCODE; +struct xGenericReply { + BYTE type; + BYTE data1; + CARD16 sequenceNumber; + CARD32 length; + CARD32 data00; + CARD32 data01; + CARD32 data02; + CARD32 data03; + CARD32 data04; + CARD32 data05; +} +struct xGetWindowAttributesReply { + BYTE type; + CARD8 backingStore; + CARD16 sequenceNumber; + CARD32 length; + VisualID visualID; + CARD16 c_class; + CARD8 bitGravity; + CARD8 winGravity; + CARD32 backingBitPlanes; + CARD32 backingPixel; + BOOL saveUnder; + BOOL mapInstalled; + CARD8 mapState; + BOOL c_override; + Colormap colormap; + CARD32 allEventMasks; + CARD32 yourEventMask; + CARD16 doNotPropagateMask; + CARD16 pad; +} +struct xGetGeometryReply { + BYTE type; + CARD8 depth; + CARD16 sequenceNumber; + CARD32 length; + Window root; + INT16 x, y; + CARD16 width, height; + CARD16 borderWidth; + CARD16 pad1; + CARD32 pad2; + CARD32 pad3; +} +struct xQueryTreeReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + Window root, parent; + CARD16 nChildren; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; +} +struct xInternAtomReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + Atom atom; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; +} +struct xGetAtomNameReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nameLength; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xGetPropertyReply { + BYTE type; + CARD8 format; + CARD16 sequenceNumber; + CARD32 length; + Atom propertyType; + CARD32 bytesAfter; + CARD32 nItems; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; +} +struct xListPropertiesReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nProperties; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xGetSelectionOwnerReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + Window owner; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; +} +struct xGrabPointerReply { + BYTE type; + BYTE status; + CARD16 sequenceNumber; + CARD32 length; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; +} +alias xGrabPointerReply xGrabKeyboardReply; +struct xQueryPointerReply { + BYTE type; + BOOL sameScreen; + CARD16 sequenceNumber; + CARD32 length; + Window root, child; + INT16 rootX, rootY, winX, winY; + CARD16 mask; + CARD16 pad1; + CARD32 pad; +} +struct xGetMotionEventsReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD32 nEvents; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; +} +struct xTranslateCoordsReply { + BYTE type; + BOOL sameScreen; + CARD16 sequenceNumber; + CARD32 length; + Window child; + INT16 dstX, dstY; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; +} +struct xGetInputFocusReply { + BYTE type; + CARD8 revertTo; + CARD16 sequenceNumber; + CARD32 length; + Window focus; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; +} +struct xQueryTextExtentsReply { + BYTE type; + CARD8 drawDirection; + CARD16 sequenceNumber; + CARD32 length; + INT16 fontAscent, fontDescent; + INT16 overallAscent, overallDescent; + INT32 overallWidth, overallLeft, overallRight; + CARD32 pad; +} +struct xListFontsReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nFonts; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +version(X86_64) { + struct xListFontsWithInfoReply { + BYTE type; + CARD8 nameLength; + CARD16 sequenceNumber; + CARD32 length; + xCharInfo minBounds; + xCharInfo maxBounds; + CARD16 minCharOrByte2, maxCharOrByte2; + CARD16 defaultChar; + CARD16 nFontProps; + CARD8 drawDirection; + CARD8 minByte1, maxByte1; + BOOL allCharsExist; + INT16 fontAscent, fontDescent; + CARD32 nReplies; + } +} else { + struct xListFontsWithInfoReply { + BYTE type; + CARD8 nameLength; + CARD16 sequenceNumber; + CARD32 length; + xCharInfo minBounds; + CARD32 walign1; + xCharInfo maxBounds; + CARD32 align2; + CARD16 minCharOrByte2, maxCharOrByte2; + CARD16 defaultChar; + CARD16 nFontProps; + CARD8 drawDirection; + CARD8 minByte1, maxByte1; + BOOL allCharsExist; + INT16 fontAscent, fontDescent; + CARD32 nReplies; + } +} +struct xGetFontPathReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nPaths; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xGetImageReply { + BYTE type; + CARD8 depth; + CARD16 sequenceNumber; + CARD32 length; + VisualID visual; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xListInstalledColormapsReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nColormaps; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xAllocColorReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 red, green, blue; + CARD16 pad2; + CARD32 pixel; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; +} +struct xAllocNamedColorReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD32 pixel; + CARD16 exactRed, exactGreen, exactBlue; + CARD16 screenRed, screenGreen, screenBlue; + CARD32 pad2; + CARD32 pad3; +} +struct xAllocColorCellsReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nPixels, nMasks; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xAllocColorPlanesReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nPixels; + CARD16 pad2; + CARD32 redMask, greenMask, blueMask; + CARD32 pad3; + CARD32 pad4; +} +struct xQueryColorsReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nColors; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xLookupColorReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 exactRed, exactGreen, exactBlue; + CARD16 screenRed, screenGreen, screenBlue; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; +} +struct xQueryBestSizeReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 width, height; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xQueryExtensionReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + BOOL present; + CARD8 major_opcode; + CARD8 first_event; + CARD8 first_error; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xListExtensionsReply { + BYTE type; + CARD8 nExtensions; + CARD16 sequenceNumber; + CARD32 length; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xSetMappingReply { + BYTE type; + CARD8 success; + CARD16 sequenceNumber; + CARD32 length; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +alias xSetMappingReply xSetPointerMappingReply; +alias xSetMappingReply xSetModifierMappingReply; +struct xGetPointerMappingReply { + BYTE type; + CARD8 nElts; + CARD16 sequenceNumber; + CARD32 length; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xGetKeyboardMappingReply { + BYTE type; + CARD8 keySymsPerKeyCode; + CARD16 sequenceNumber; + CARD32 length; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xGetModifierMappingReply { + BYTE type; + CARD8 numKeyPerModifier; + CARD16 sequenceNumber; + CARD32 length; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; +} +struct xGetKeyboardControlReply { + BYTE type; + BOOL globalAutoRepeat; + CARD16 sequenceNumber; + CARD32 length; + CARD32 ledMask; + CARD8 keyClickPercent, bellPercent; + CARD16 bellPitch, bellDuration; + CARD16 pad; + BYTE[32] map; +} +struct xGetPointerControlReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 accelNumerator, accelDenominator; + CARD16 threshold; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; +} +struct xGetScreenSaverReply { + BYTE type; + BYTE pad1; + CARD16 sequenceNumber; + CARD32 length; + CARD16 timeout, interval; + BOOL preferBlanking; + BOOL allowExposures; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; +} +struct xListHostsReply { + BYTE type; + BOOL enabled; + CARD16 sequenceNumber; + CARD32 length; + CARD16 nHosts; + CARD16 pad1; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xError { + BYTE type; + BYTE errorCode; + CARD16 sequenceNumber; + CARD32 resourceID; + CARD16 minorCode; + CARD8 majorCode; + BYTE pad1; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct _xEvent { + union u { + struct u { + BYTE type; + BYTE detail; + CARD16 sequenceNumber; + } + struct keyButtonPointer { + CARD32 pad00; + Time time; + Window root, event, child; + INT16 rootX, rootY, eventX, eventY; + KeyButMask state; + BOOL sameScreen; + BYTE pad1; + } + struct enterLeave { + CARD32 pad00; + Time time; + Window root, event, child; + INT16 rootX, rootY, eventX, eventY; + KeyButMask state; + BYTE mode; + BYTE flags; + enum int ELFlagFocus = 1 << 0; + enum int ELFlagSameScreen = 1 << 1; + } + struct focus { + CARD32 pad00; + Window window; + BYTE mode; + BYTE pad1, pad2, pad3; + } + struct expose { + CARD32 pad00; + Window window; + CARD16 x, y, width, height; + CARD16 count; + CARD16 pad2; + } + struct graphicsExposure { + CARD32 pad00; + Drawable drawable; + CARD16 x, y, width, height; + CARD16 minorEvent; + CARD16 count; + BYTE majorEvent; + BYTE pad1, pad2, pad3; + } + struct noExposure { + CARD32 pad00; + Drawable drawable; + CARD16 minorEvent; + BYTE majorEvent; + BYTE bpad; + } + struct visibility { + CARD32 pad00; + Window window; + CARD8 state; + BYTE pad1, pad2, pad3; + } + struct createNotify { + CARD32 pad00; + Window parent, window; + INT16 x, y; + CARD16 width, height, borderWidth; + BOOL c_override; + BYTE bpad; + } + struct destroyNotify { + CARD32 pad00; + Window event, window; + } + struct unmapNotify { + CARD32 pad00; + Window event, window; + BOOL fromConfigure; + BYTE pad1, pad2, pad3; + } + struct mapNotify { + CARD32 pad00; + Window event, window; + BOOL c_override; + BYTE pad1, pad2, pad3; + } + struct mapRequest { + CARD32 pad00; + Window parent, window; + } + struct reparent { + CARD32 pad00; + Window event, window, parent; + INT16 x, y; + BOOL c_override; + BYTE pad1, pad2, pad3; + } + struct configureNotify { + CARD32 pad00; + Window event, window, aboveSibling; + INT16 x, y; + CARD16 width, height, borderWidth; + BOOL c_override; + BYTE bpad; + } + struct configureRequest { + CARD32 pad00; + Window parent, window, sibling; + INT16 x, y; + CARD16 width, height, borderWidth; + CARD16 valueMask; + CARD32 pad1; + } + struct gravity { + CARD32 pad00; + Window event, window; + INT16 x, y; + CARD32 pad1, pad2, pad3, pad4; + } + struct resizeRequest { + CARD32 pad00; + Window window; + CARD16 width, height; + } + struct circulate { + CARD32 pad00; + Window event, window, parent; + BYTE place; + BYTE pad1, pad2, pad3; + } + struct property { + CARD32 pad00; + Window window; + Atom atom; + Time time; + BYTE state; + BYTE pad1; + CARD16 pad2; + } + struct selectionClear { + CARD32 pad00; + Time time; + Window window; + Atom atom; + } + struct selectionRequest { + CARD32 pad00; + Time time; + Window owner, requestor; + Atom selection, target, property; + } + struct selectionNotify { + CARD32 pad00; + Time time; + Window requestor; + Atom selection, target, property; + } + struct colormap { + CARD32 pad00; + Window window; + Colormap colormap; + BOOL c_new; + BYTE state; + BYTE pad1, pad2; + } + struct mappingNotify { + CARD32 pad00; + CARD8 request; + KeyCode firstKeyCode; + CARD8 count; + BYTE pad1; + } + struct clientMessage { + CARD32 pad00; + Window window; + union u { + struct l { + Atom type; + INT32 longs0; + INT32 longs1; + INT32 longs2; + INT32 longs3; + INT32 longs4; + } + struct s { + Atom type; + INT16 shorts0; + INT16 shorts1; + INT16 shorts2; + INT16 shorts3; + INT16 shorts4; + INT16 shorts5; + INT16 shorts6; + INT16 shorts7; + INT16 shorts8; + INT16 shorts9; + } + struct b { + Atom type; + INT8[20] bytes; + } + } + } + } +} +alias _xEvent xEvent; +struct xGenericEvent { + BYTE type; + CARD8 extension; + CARD16 sequenceNumber; + CARD32 length; + CARD16 evtype; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +struct xKeymapEvent { + BYTE type; + BYTE[31] map; +} +const size_t XEventSize = xEvent.sizeof; +union xReply { + xGenericReply generic; + xGetGeometryReply geom; + xQueryTreeReply tree; + xInternAtomReply atom; + xGetAtomNameReply atomName; + xGetPropertyReply propertyReply; + xListPropertiesReply listProperties; + xGetSelectionOwnerReply selection; + xGrabPointerReply grabPointer; + xGrabKeyboardReply grabKeyboard; + xQueryPointerReply pointer; + xGetMotionEventsReply motionEvents; + xTranslateCoordsReply coords; + xGetInputFocusReply inputFocus; + xQueryTextExtentsReply textExtents; + xListFontsReply fonts; + xGetFontPathReply fontPath; + xGetImageReply image; + xListInstalledColormapsReply colormaps; + xAllocColorReply allocColor; + xAllocNamedColorReply allocNamedColor; + xAllocColorCellsReply colorCells; + xAllocColorPlanesReply colorPlanes; + xQueryColorsReply colors; + xLookupColorReply lookupColor; + xQueryBestSizeReply bestSize; + xQueryExtensionReply extension; + xListExtensionsReply extensions; + xSetModifierMappingReply setModifierMapping; + xGetModifierMappingReply getModifierMapping; + xSetPointerMappingReply setPointerMapping; + xGetKeyboardMappingReply getKeyboardMapping; + xGetPointerMappingReply getPointerMapping; + xGetPointerControlReply pointerControl; + xGetScreenSaverReply screenSaver; + xListHostsReply hosts; + xError error; + xEvent event; +} +struct _xReq { + CARD8 reqType; + CARD8 data; + CARD16 length; +} +alias _xReq xReq; +struct xResourceReq { + CARD8 reqType; + BYTE pad; + CARD16 length; + CARD32 id; +} +struct Box { + short x1, x2, y1, y2; +} +alias Box BOX; +alias Box BoxRec; +int MAX(int a, int b) { + return (a < b) ? b : a; +} +int MIN(int a, int b) { + return (a > b) ? b : a; +} +struct _XRegion { + c_long size; + c_long numRects; + BOX* rects; + BOX extents; +} +alias _XRegion REGION; +alias int XrmQuark; +alias int* XrmQuarkList; +const XrmQuark NULLQUARK = 0; +alias char* XrmString; +const XrmString NULLSTRING = null; +XrmQuark XrmStringToQuark(const char*); +XrmQuark XrmPermStringToQuark(const char*); +XrmString XrmQuarkToString(XrmQuark); +XrmQuark XrmUniqueQuark(); +bool XrmStringsEqual(XrmString a1, XrmString a2) { + return *a1 == *a2; +} +alias int XrmBinding; +enum { + XrmBindTightly, + XrmBindLoosely +} +alias XrmBinding* XrmBindingList; +void XrmStringToQuarkList(const char*, XrmQuarkList); +void XrmStringToBindingQuarkList(const char*, XrmBindingList, XrmQuarkList); +alias XrmQuark XrmName; +alias XrmQuarkList XrmNameList; +XrmString XrmNameToString(XrmName name) { + return XrmQuarkToString(cast(XrmQuark) name); +} +XrmName XrmStringToName(XrmString string) { + return cast(XrmName) XrmStringToQuark(string); +} +void XrmStringToNameList(XrmString str, XrmNameList name) { + XrmStringToQuarkList(str, name); +} +alias XrmQuark XrmClass; +alias XrmQuarkList XrmClassList; +XrmString XrmClassToString(XrmClass c_class) { + return XrmQuarkToString(cast(XrmQuark) c_class); +} +XrmClass XrmStringToClass(XrmString c_class) { + return cast(XrmClass) XrmStringToQuark(c_class); +} +void XrmStringToClassList(XrmString str, XrmClassList c_class) { + XrmStringToQuarkList(str, c_class); +} +alias XrmQuark XrmRepresentation; +XrmRepresentation XrmStringToRepresentation(XrmString string) { + return cast(XrmRepresentation) XrmStringToQuark(string); +} +XrmString XrmRepresentationToString(XrmRepresentation type) { + return XrmQuarkToString(type); +} +struct XrmValue { + uint size; + XPointer addr; +} +alias XrmValue* XrmValuePtr; +alias _XrmHashBucketRec* XrmHashBucket; +alias XrmHashBucket* XrmHashTable; +alias XrmHashTable[] XrmSearchList; +alias _XrmHashBucketRec* XrmDatabase; +void XrmDestroyDatabase(XrmDatabase); +void XrmQPutResource(XrmDatabase*, XrmBindingList, XrmQuarkList, XrmRepresentation, XrmValue*); +Bool XrmQGetResource(XrmDatabase, XrmNameList, XrmClassList, XrmRepresentation*, XrmValue*);Bool XrmGetResource(XrmDatabase, const char*, const char*, char**, XrmValue*);Bool XrmQGetSearchList(XrmDatabase, XrmNameList, XrmClassList, XrmSearchList, int);Bool XrmQGetSearchResource(XrmSearchList, XrmName, XrmClass, XrmRepresentation*, XrmValue*);XrmDatabase XrmGetStringDatabase(const char*); +void XrmPutFileDatabase(XrmDatabase, const char*); +void XrmMergeDatabases(XrmDatabase, XrmDatabase*); +void XrmCombineDatabase(XrmDatabase, XrmDatabase*, Bool); +alias int XrmOptionKind; +enum { + XrmoptionNoArg, + XrmoptionIsArg, + XrmoptionStickyArg, + XrmoptionSepArg, + XrmoptionResArg, + XrmoptionSkipArg, + XrmoptionSkipLine, + XrmoptionSkipNArgs +} +struct XrmOptionDescRec { + char* option; + char* specifier; + XrmOptionKind argKind; + XPointer value; +} +alias XrmOptionDescRec* XrmOptionDescList; +void XrmParseCommand(XrmDatabase*, XrmOptionDescList, int, const char*, int*, char**); +enum bool WORD64 = false; +enum int NoValue = 0x0000; +enum int AllValues = 0x000F; +enum int XNegative = 0x0010; +enum int YNegative = 0x0020; +struct XSizeHints { + c_long flags; + int x, y; + int width, height; + int min_width, min_height; + int max_width, max_height; + int width_inc, height_inc; + struct aspect { + int x; + int y; + } + aspect min_aspect, max_aspect; + int base_width, base_height; + int win_gravity; +} +enum { + USPosition = 1L << 0, + USSize = 1L << 1, + PPosition = 1L << 2, + PSize = 1L << 3, + PMinSize = 1L << 4, + PMaxSize = 1L << 5, + PResizeInc = 1L << 6, + PAspect = 1L << 7, + PBaseSize = 1L << 8, + PWinGravity = 1L << 9 +} +c_long PAllHints = (PPosition | PSize | PMinSize | PMaxSize | PResizeInc | PAspect); +struct XWMHints { + c_long flags; + Bool input; + int initial_state; + Pixmap icon_pixmap; + Window icon_window; + int icon_x, icon_y; + Pixmap icon_mask; + XID window_group; +} +enum { + InputHint = (1L << 0), + StateHint = (1L << 1), + IconPixmapHint = (1L << 2), + IconWindowHint = (1L << 3), + IconPositionHint = (1L << 4), + IconMaskHint = (1L << 5), + WindowGroupHint = (1L << 6), + AllHints = (InputHint | StateHint | IconPixmapHint | IconWindowHint + | IconPositionHint | IconMaskHint | WindowGroupHint), + XUrgencyHint = (1L << 8) +} +enum { + WithdrawnState = 0, + NormalState = 1, + IconicState = 3 +} +enum { + DontCareState = 0, + ZoomState = 2, + InactiveState = 4 +} +struct XTextProperty { + ubyte* value; + Atom encoding; + int format; + c_ulong nitems; +} +enum int XNoMemory = -1; +struct XIconSize { + int min_width, min_height; + int max_width, max_height; + int width_inc, height_inc; +} +struct XClassHint { + char* res_name; + char* res_class; +} +struct XComposeStatus { + XPointer compose_ptr; + int chars_matched; +} +template IsKeypadKey(KeySym keysym) { + const bool IsKeypadKey = ((keysym >= XK_KP_Space) && (keysym <= XK_KP_Equal)); +} +template IsPrivateKeypadKey(KeySym keysym) { + const bool IsPrivateKeypadKey = ((keysym >= 0x11000000) && (keysym <= 0x1100FFFF)); +} +static if (XK_XKB_KEYS) { + template IsModifierKey(KeySym keysym) { + const bool IsModifierKey = (((keysym >= XK_Shift_L) && (keysym <= XK_Hyper_R)) + || ((keysym >= XK_ISO_Lock) && (keysym <= XK_ISO_Last_Group_Lock)) + || (keysym == XK_Mode_switch) || (keysym == XK_Num_Lock)); + } +} else { + template IsModifierKey(keysym) { + const bool IsModifierKey = (((keysym >= XK_Shift_L) && (keysym <= XK_Hyper_R)) + || (keysym == XK_Mode_switch) || (keysym == XK_Num_Lock)); + } +} +alias _XRegion* Region; +enum { + RectangleOut = 0, + RectangleIn = 1, + RectanglePart = 2 +} +struct XVisualInfo { + Visual* visual; + VisualID visualid; + int screen; + int depth; + int c_class; + c_ulong red_mask; + c_ulong green_mask; + c_ulong blue_mask; + int colormap_size; + int bits_per_rgb; +} +enum { + VisualNoMask = 0x0, + VisualIDMask = 0x1, + VisualScreenMask = 0x2, + VisualDepthMask = 0x4, + VisualClassMask = 0x8, + VisualRedMaskMask = 0x10, + VisualGreenMaskMask = 0x20, + VisualBlueMaskMask = 0x40, + VisualColormapSizeMask = 0x80, + VisualBitsPerRGBMask = 0x100, + VisualAllMask = 0x1FF +} +struct XStandardColormap { + Colormap colormap; + c_ulong red_max; + c_ulong red_mult; + c_ulong green_max; + c_ulong green_mult; + c_ulong blue_max; + c_ulong blue_mult; + c_ulong base_pixel; + VisualID visualid; + XID killid; +} +const XID ReleaseByFreeingColormap = 1L; +enum { + BitmapSuccess = 0, + BitmapOpenFailed = 1, + BitmapFileInvalid = 2, + BitmapNoMemory = 3 +} +enum { + XCSUCCESS = 0, + XCNOMEM = 1, + XCNOENT = 2, +} +alias int XContext; +extern(D) auto XUniqueContext() { + return cast(XContext) XrmUniqueQuark(); +} +XContext XStringToContext(char* statement) { + return XrmStringToQuark(statement); +} +XClassHint* XAllocClassHint(); +XIconSize* XAllocIconSize(); +XSizeHints* XAllocSizeHints(); +XStandardColormap* XAllocStandardColormap(); +XWMHints* XAllocWMHints(); +int XClipBox(Region, XRectangle*); +Region XCreateRegion(); +char* XDefaultString(); +int XDeleteContext(Display*, XID, XContext); +int XDestroyRegion(Region); +int XEmptyRegion(Region); +int XEqualRegion(Region, Region); +int XFindContext(Display*, XID, XContext, XPointer*); +Status XGetClassHint(Display*, Window, XClassHint*); +Status XGetIconSizes(Display*, Window, XIconSize**, int*); +Status XGetNormalHints(Display*, Window, XSizeHints*); +XVisualInfo* XGetVisualInfo(Display*, long, XVisualInfo*, int*); +Status XGetWMClientMachine(Display*, Window, XTextProperty*); +XWMHints* XGetWMHints(Display*, Window); +Status XGetWMIconName(Display*, Window, XTextProperty*); +Status XGetWMName(Display*, Window, XTextProperty*); +Status XGetWMNormalHints(Display*, Window, XSizeHints*, long*); +Status XGetWMSizeHints(Display*, Window, XSizeHints*, long*, Atom); +Status XGetZoomHints(Display*, Window, XSizeHints*); +int XIntersectRegion(Region, Region, Region); +void XConvertCase(KeySym, KeySym*, KeySym*); +int XLookupString(XKeyEvent*, char*, int, KeySym*, XComposeStatus*); +Status XMatchVisualInfo(Display*, int, int, int, XVisualInfo*); +int XSaveContext(Display*, XID, XContext, char*); +int XSetClassHint(Display*, Window, XClassHint*); +int XSetIconSizes(Display*, Window, XIconSize*, int); +int XSetNormalHints(Display*, Window, XSizeHints*); +void XSetWMClientMachine(Display*, Window, XTextProperty*); +int XSetWMHints(Display*, Window, XWMHints*); +void XSetWMIconName(Display*, Window, XTextProperty*); +void XSetWMName(Display*, Window, XTextProperty*); +void XSetWMNormalHints(Display*, Window, XSizeHints*); +void XSetWMProperties(Display*, Window, XTextProperty*, XTextProperty*, char**, int, XSizeHints*, XWMHints*, XClassHint*); +void XmbSetWMProperties(Display*, Window, const(char)*, const(char)*, const(char)**, int, XSizeHints*, XWMHints*, XClassHint*); +void Xutf8SetWMProperties(Display*, Window, char*, char*, char**, int, XSizeHints*, XWMHints*, XClassHint*); +enum XC_cross_reverse = 32; +enum XC_crosshair = 34; +enum XC_diamond_cross = 36; +enum XC_dot = 38; +enum XC_gumby = 56; +enum XC_hand1 = 58; +enum XC_hand2 = 60; +enum XC_heart = 62; +enum XC_icon = 64; +enum XC_iron_cross = 66; +enum XC_left_ptr = 68; +enum XC_left_side = 70; +enum XC_sailboat = 104; +enum XC_sb_down_arrow = 106; +enum XC_sb_h_double_arrow = 108; +enum XC_sb_left_arrow = 110; +enum XC_sb_right_arrow = 112; +enum XC_sb_up_arrow = 114; +enum XC_sb_v_double_arrow = 116; +enum XC_shuttle = 118; +enum XC_xterm = 152; +enum bool XK_MISCELLANY = true; +enum bool XK_XKB_KEYS = true; +enum bool XK_3270 = false; +enum bool XK_LATIN1 = true; +enum bool XK_LATIN2 = true; +enum bool XK_LATIN3 = true; +enum bool XK_LATIN4 = true; +enum bool XK_SINHALA = true; +enum int XK_VoidSymbol = 0xffffff; +static if (XK_MISCELLANY) { + enum int XK_BackSpace = 0xff08; + enum int XK_Tab = 0xff09; + enum int XK_Linefeed = 0xff0a; + enum int XK_Clear = 0xff0b; + enum int XK_Return = 0xff0d; + enum int XK_Pause = 0xff13; + enum int XK_Scroll_Lock = 0xff14; + enum int XK_Sys_Req = 0xff15; + enum int XK_Escape = 0xff1b; + enum int XK_Delete = 0xffff; + enum int XK_Multi_key = 0xff20; + enum int XK_Codeinput = 0xff37; + enum int XK_SingleCandidate = 0xff3c; + enum int XK_MultipleCandidate = 0xff3d; + enum int XK_PreviousCandidate = 0xff3e; + enum int XK_Kanji = 0xff21; + enum int XK_Muhenkan = 0xff22; + enum int XK_Henkan_Mode = 0xff23; + enum int XK_Henkan = 0xff23; + enum int XK_Romaji = 0xff24; + enum int XK_Hiragana = 0xff25; + enum int XK_Katakana = 0xff26; + enum int XK_Hiragana_Katakana = 0xff27; + enum int XK_Zenkaku = 0xff28; + enum int XK_Hankaku = 0xff29; + enum int XK_Zenkaku_Hankaku = 0xff2a; + enum int XK_Touroku = 0xff2b; + enum int XK_Massyo = 0xff2c; + enum int XK_Kana_Lock = 0xff2d; + enum int XK_Kana_Shift = 0xff2e; + enum int XK_Eisu_Shift = 0xff2f; + enum int XK_Eisu_toggle = 0xff30; + enum int XK_Kanji_Bangou = 0xff37; + enum int XK_Zen_Koho = 0xff3d; + enum int XK_Mae_Koho = 0xff3e; + enum int XK_Home = 0xff50; + enum int XK_Left = 0xff51; + enum int XK_Up = 0xff52; + enum int XK_Right = 0xff53; + enum int XK_Down = 0xff54; + enum int XK_Prior = 0xff55; + enum int XK_Page_Up = 0xff55; + enum int XK_Next = 0xff56; + enum int XK_Page_Down = 0xff56; + enum int XK_End = 0xff57; + enum int XK_Begin = 0xff58; + enum int XK_Select = 0xff60; + enum int XK_Print = 0xff61; + enum int XK_Execute = 0xff62; + enum int XK_Insert = 0xff63; + enum int XK_Undo = 0xff65; + enum int XK_Redo = 0xff66; + enum int XK_Menu = 0xff67; + enum int XK_Find = 0xff68; + enum int XK_Cancel = 0xff69; + enum int XK_Help = 0xff6a; + enum int XK_break = 0xff6b; + enum int XK_Mode_switch = 0xff7e; + enum int XK_script_switch = 0xff7e; + enum int XK_Num_Lock = 0xff7f; + enum int XK_KP_Space = 0xff80; + enum int XK_KP_Tab = 0xff89; + enum int XK_KP_Enter = 0xff8d; + enum int XK_KP_F1 = 0xff91; + enum int XK_KP_F2 = 0xff92; + enum int XK_KP_F3 = 0xff93; + enum int XK_KP_F4 = 0xff94; + enum int XK_KP_Home = 0xff95; + enum int XK_KP_Left = 0xff96; + enum int XK_KP_Up = 0xff97; + enum int XK_KP_Right = 0xff98; + enum int XK_KP_Down = 0xff99; + enum int XK_KP_Prior = 0xff9a; + enum int XK_KP_Page_Up = 0xff9a; + enum int XK_KP_Next = 0xff9b; + enum int XK_KP_Page_Down = 0xff9b; + enum int XK_KP_End = 0xff9c; + enum int XK_KP_Begin = 0xff9d; + enum int XK_KP_Insert = 0xff9e; + enum int XK_KP_Delete = 0xff9f; + enum int XK_KP_Equal = 0xffbd; + enum int XK_KP_Multiply = 0xffaa; + enum int XK_KP_Add = 0xffab; + enum int XK_KP_Separator = 0xffac; + enum int XK_KP_Subtract = 0xffad; + enum int XK_KP_Decimal = 0xffae; + enum int XK_KP_Divide = 0xffaf; + enum int XK_KP_0 = 0xffb0; + enum int XK_KP_1 = 0xffb1; + enum int XK_KP_2 = 0xffb2; + enum int XK_KP_3 = 0xffb3; + enum int XK_KP_4 = 0xffb4; + enum int XK_KP_5 = 0xffb5; + enum int XK_KP_6 = 0xffb6; + enum int XK_KP_7 = 0xffb7; + enum int XK_KP_8 = 0xffb8; + enum int XK_KP_9 = 0xffb9; + enum int XK_F1 = 0xffbe; + enum int XK_F2 = 0xffbf; + enum int XK_F3 = 0xffc0; + enum int XK_F4 = 0xffc1; + enum int XK_F5 = 0xffc2; + enum int XK_F6 = 0xffc3; + enum int XK_F7 = 0xffc4; + enum int XK_F8 = 0xffc5; + enum int XK_F9 = 0xffc6; + enum int XK_F10 = 0xffc7; + enum int XK_F11 = 0xffc8; + enum int XK_L1 = 0xffc8; + enum int XK_F12 = 0xffc9; + enum int XK_L2 = 0xffc9; + enum int XK_F13 = 0xffca; + enum int XK_L3 = 0xffca; + enum int XK_F14 = 0xffcb; + enum int XK_L4 = 0xffcb; + enum int XK_F15 = 0xffcc; + enum int XK_L5 = 0xffcc; + enum int XK_F16 = 0xffcd; + enum int XK_L6 = 0xffcd; + enum int XK_F17 = 0xffce; + enum int XK_L7 = 0xffce; + enum int XK_F18 = 0xffcf; + enum int XK_L8 = 0xffcf; + enum int XK_F19 = 0xffd0; + enum int XK_L9 = 0xffd0; + enum int XK_F20 = 0xffd1; + enum int XK_L10 = 0xffd1; + enum int XK_F21 = 0xffd2; + enum int XK_R1 = 0xffd2; + enum int XK_F22 = 0xffd3; + enum int XK_R2 = 0xffd3; + enum int XK_F23 = 0xffd4; + enum int XK_R3 = 0xffd4; + enum int XK_F24 = 0xffd5; + enum int XK_R4 = 0xffd5; + enum int XK_F25 = 0xffd6; + enum int XK_R5 = 0xffd6; + enum int XK_F26 = 0xffd7; + enum int XK_R6 = 0xffd7; + enum int XK_F27 = 0xffd8; + enum int XK_R7 = 0xffd8; + enum int XK_F28 = 0xffd9; + enum int XK_R8 = 0xffd9; + enum int XK_F29 = 0xffda; + enum int XK_R9 = 0xffda; + enum int XK_F30 = 0xffdb; + enum int XK_R10 = 0xffdb; + enum int XK_F31 = 0xffdc; + enum int XK_R11 = 0xffdc; + enum int XK_F32 = 0xffdd; + enum int XK_R12 = 0xffdd; + enum int XK_F33 = 0xffde; + enum int XK_R13 = 0xffde; + enum int XK_F34 = 0xffdf; + enum int XK_R14 = 0xffdf; + enum int XK_F35 = 0xffe0; + enum int XK_R15 = 0xffe0; + enum int XK_Shift_L = 0xffe1; + enum int XK_Shift_R = 0xffe2; + enum int XK_Control_L = 0xffe3; + enum int XK_Control_R = 0xffe4; + enum int XK_Caps_Lock = 0xffe5; + enum int XK_Shift_Lock = 0xffe6; + enum int XK_Meta_L = 0xffe7; + enum int XK_Meta_R = 0xffe8; + enum int XK_Alt_L = 0xffe9; + enum int XK_Alt_R = 0xffea; + enum int XK_Super_L = 0xffeb; + enum int XK_Super_R = 0xffec; + enum int XK_Hyper_L = 0xffed; + enum int XK_Hyper_R = 0xffee; +} +static if (XK_XKB_KEYS) { + enum int XK_ISO_Lock = 0xfe01; + enum int XK_ISO_Level2_Latch = 0xfe02; + enum int XK_ISO_Level3_Shift = 0xfe03; // used + enum int XK_ISO_Level3_Latch = 0xfe04; + enum int XK_ISO_Level3_Lock = 0xfe05; + enum int XK_ISO_Level5_Shift = 0xfe11; + enum int XK_ISO_Level5_Latch = 0xfe12; + enum int XK_ISO_Level5_Lock = 0xfe13; + enum int XK_ISO_Group_Shift = 0xff7e; + enum int XK_ISO_Group_Latch = 0xfe06; + enum int XK_ISO_Group_Lock = 0xfe07; + enum int XK_ISO_Next_Group = 0xfe08; + enum int XK_ISO_Next_Group_Lock = 0xfe09; + enum int XK_ISO_Prev_Group = 0xfe0a; + enum int XK_ISO_Prev_Group_Lock = 0xfe0b; + enum int XK_ISO_First_Group = 0xfe0c; + enum int XK_ISO_First_Group_Lock = 0xfe0d; + enum int XK_ISO_Last_Group = 0xfe0e; + enum int XK_ISO_Last_Group_Lock = 0xfe0f; + enum int XK_ISO_Left_Tab = 0xfe20; + enum int XK_ISO_Move_Line_Up = 0xfe21; + enum int XK_ISO_Move_Line_Down = 0xfe22; + enum int XK_ISO_Partial_Line_Up = 0xfe23; + enum int XK_ISO_Partial_Line_Down = 0xfe24; + enum int XK_ISO_Partial_Space_Left = 0xfe25; + enum int XK_ISO_Partial_Space_Right = 0xfe26; + enum int XK_ISO_Set_Margin_Left = 0xfe27; + enum int XK_ISO_Set_Margin_Right = 0xfe28; + enum int XK_ISO_Release_Margin_Left = 0xfe29; + enum int XK_ISO_Release_Margin_Right = 0xfe2a; + enum int XK_ISO_Release_Both_Margins = 0xfe2b; + enum int XK_ISO_Fast_Cursor_Left = 0xfe2c; + enum int XK_ISO_Fast_Cursor_Right = 0xfe2d; + enum int XK_ISO_Fast_Cursor_Up = 0xfe2e; + enum int XK_ISO_Fast_Cursor_Down = 0xfe2f; + enum int XK_ISO_Continuous_Underline = 0xfe30; + enum int XK_ISO_Discontinuous_Underline = 0xfe31; + enum int XK_ISO_Emphasize = 0xfe32; + enum int XK_ISO_Center_Object = 0xfe33; + enum int XK_ISO_Enter = 0xfe34; + enum int XK_dead_grave = 0xfe50; + enum int XK_dead_acute = 0xfe51; + enum int XK_dead_circumflex = 0xfe52; + enum int XK_dead_tilde = 0xfe53; + enum int XK_dead_perispomeni = 0xfe53; + enum int XK_dead_macron = 0xfe54; + enum int XK_dead_breve = 0xfe55; + enum int XK_dead_abovedot = 0xfe56; + enum int XK_dead_diaeresis = 0xfe57; + enum int XK_dead_abovering = 0xfe58; + enum int XK_dead_doubleacute = 0xfe59; + enum int XK_dead_caron = 0xfe5a; + enum int XK_dead_cedilla = 0xfe5b; + enum int XK_dead_ogonek = 0xfe5c; + enum int XK_dead_iota = 0xfe5d; + enum int XK_dead_voiced_sound = 0xfe5e; + enum int XK_dead_semivoiced_sound = 0xfe5f; + enum int XK_dead_belowdot = 0xfe60; + enum int XK_dead_hook = 0xfe61; + enum int XK_dead_horn = 0xfe62; + enum int XK_dead_stroke = 0xfe63; + enum int XK_dead_abovecomma = 0xfe64; + enum int XK_dead_psili = 0xfe64; + enum int XK_dead_abovereversedcomma = 0xfe65; + enum int XK_dead_dasia = 0xfe65; + enum int XK_dead_doublegrave = 0xfe66; + enum int XK_dead_belowring = 0xfe67; + enum int XK_dead_belowmacron = 0xfe68; + enum int XK_dead_belowcircumflex = 0xfe69; + enum int XK_dead_belowtilde = 0xfe6a; + enum int XK_dead_belowbreve = 0xfe6b; + enum int XK_dead_belowdiaeresis = 0xfe6c; + enum int XK_dead_invertedbreve = 0xfe6d; + enum int XK_dead_belowcomma = 0xfe6e; + enum int XK_dead_currency = 0xfe6f; + enum int XK_dead_a = 0xfe80; + enum int XK_dead_A = 0xfe81; + enum int XK_dead_e = 0xfe82; + enum int XK_dead_E = 0xfe83; + enum int XK_dead_i = 0xfe84; + enum int XK_dead_I = 0xfe85; + enum int XK_dead_o = 0xfe86; + enum int XK_dead_O = 0xfe87; + enum int XK_dead_u = 0xfe88; + enum int XK_dead_U = 0xfe89; + enum int XK_dead_small_schwa = 0xfe8a; + enum int XK_dead_capital_schwa = 0xfe8b; + enum int XK_First_Virtual_Screen = 0xfed0; + enum int XK_Prev_Virtual_Screen = 0xfed1; + enum int XK_Next_Virtual_Screen = 0xfed2; + enum int XK_Last_Virtual_Screen = 0xfed4; + enum int XK_Terminate_Server = 0xfed5; + enum int XK_AccessX_Enable = 0xfe70; + enum int XK_AccessX_Feedback_Enable = 0xfe71; + enum int XK_RepeatKeys_Enable = 0xfe72; + enum int XK_SlowKeys_Enable = 0xfe73; + enum int XK_BounceKeys_Enable = 0xfe74; + enum int XK_StickyKeys_Enable = 0xfe75; + enum int XK_MouseKeys_Enable = 0xfe76; + enum int XK_MouseKeys_Accel_Enable = 0xfe77; + enum int XK_Overlay1_Enable = 0xfe78; + enum int XK_Overlay2_Enable = 0xfe79; + enum int XK_AudibleBell_Enable = 0xfe7a; + enum int XK_Pointer_Left = 0xfee0; + enum int XK_Pointer_Right = 0xfee1; + enum int XK_Pointer_Up = 0xfee2; + enum int XK_Pointer_Down = 0xfee3; + enum int XK_Pointer_UpLeft = 0xfee4; + enum int XK_Pointer_UpRight = 0xfee5; + enum int XK_Pointer_DownLeft = 0xfee6; + enum int XK_Pointer_DownRight = 0xfee7; + enum int XK_Pointer_Button_Dflt = 0xfee8; + enum int XK_Pointer_Button1 = 0xfee9; + enum int XK_Pointer_Button2 = 0xfeea; + enum int XK_Pointer_Button3 = 0xfeeb; + enum int XK_Pointer_Button4 = 0xfeec; + enum int XK_Pointer_Button5 = 0xfeed; + enum int XK_Pointer_DblClick_Dflt = 0xfeee; + enum int XK_Pointer_DblClick1 = 0xfeef; + enum int XK_Pointer_DblClick2 = 0xfef0; + enum int XK_Pointer_DblClick3 = 0xfef1; + enum int XK_Pointer_DblClick4 = 0xfef2; + enum int XK_Pointer_DblClick5 = 0xfef3; + enum int XK_Pointer_Drag_Dflt = 0xfef4; + enum int XK_Pointer_Drag1 = 0xfef5; + enum int XK_Pointer_Drag2 = 0xfef6; + enum int XK_Pointer_Drag3 = 0xfef7; + enum int XK_Pointer_Drag4 = 0xfef8; + enum int XK_Pointer_Drag5 = 0xfefd; + enum int XK_Pointer_EnableKeys = 0xfef9; + enum int XK_Pointer_Accelerate = 0xfefa; + enum int XK_Pointer_DfltBtnNext = 0xfefb; + enum int XK_Pointer_DfltBtnPrev = 0xfefc; +} +static if (XK_LATIN1) { + enum int XK_space = 0x0020; + enum int XK_exclam = 0x0021; + enum int XK_quotedbl = 0x0022; + enum int XK_numbersign = 0x0023; + enum int XK_dollar = 0x0024; + enum int XK_percent = 0x0025; + enum int XK_ampersand = 0x0026; + enum int XK_apostrophe = 0x0027; + enum int XK_quoteright = 0x0027; + enum int XK_parenleft = 0x0028; + enum int XK_parenright = 0x0029; + enum int XK_asterisk = 0x002a; + enum int XK_plus = 0x002b; + enum int XK_comma = 0x002c; + enum int XK_minus = 0x002d; + enum int XK_period = 0x002e; + enum int XK_slash = 0x002f; + enum int XK_0 = 0x0030; + enum int XK_1 = 0x0031; + enum int XK_2 = 0x0032; + enum int XK_3 = 0x0033; + enum int XK_4 = 0x0034; + enum int XK_5 = 0x0035; + enum int XK_6 = 0x0036; + enum int XK_7 = 0x0037; + enum int XK_8 = 0x0038; + enum int XK_9 = 0x0039; + enum int XK_colon = 0x003a; + enum int XK_semicolon = 0x003b; + enum int XK_less = 0x003c; + enum int XK_equal = 0x003d; + enum int XK_greater = 0x003e; + enum int XK_question = 0x003f; + enum int XK_at = 0x0040; + enum int XK_A = 0x0041; + enum int XK_B = 0x0042; + enum int XK_C = 0x0043; + enum int XK_D = 0x0044; + enum int XK_E = 0x0045; + enum int XK_F = 0x0046; + enum int XK_G = 0x0047; + enum int XK_H = 0x0048; + enum int XK_I = 0x0049; + enum int XK_J = 0x004a; + enum int XK_K = 0x004b; + enum int XK_L = 0x004c; + enum int XK_M = 0x004d; + enum int XK_N = 0x004e; + enum int XK_O = 0x004f; + enum int XK_P = 0x0050; + enum int XK_Q = 0x0051; + enum int XK_R = 0x0052; + enum int XK_S = 0x0053; + enum int XK_T = 0x0054; + enum int XK_U = 0x0055; + enum int XK_V = 0x0056; + enum int XK_W = 0x0057; + enum int XK_X = 0x0058; + enum int XK_Y = 0x0059; + enum int XK_Z = 0x005a; + enum int XK_bracketleft = 0x005b; + enum int XK_backslash = 0x005c; + enum int XK_bracketright = 0x005d; + enum int XK_asciicircum = 0x005e; + enum int XK_underscore = 0x005f; + enum int XK_grave = 0x0060; + enum int XK_quoteleft = 0x0060; + enum int XK_a = 0x0061; + enum int XK_b = 0x0062; + enum int XK_c = 0x0063; + enum int XK_d = 0x0064; + enum int XK_e = 0x0065; + enum int XK_f = 0x0066; + enum int XK_g = 0x0067; + enum int XK_h = 0x0068; + enum int XK_i = 0x0069; + enum int XK_j = 0x006a; + enum int XK_k = 0x006b; + enum int XK_l = 0x006c; + enum int XK_m = 0x006d; + enum int XK_n = 0x006e; + enum int XK_o = 0x006f; + enum int XK_p = 0x0070; + enum int XK_q = 0x0071; + enum int XK_r = 0x0072; + enum int XK_s = 0x0073; + enum int XK_t = 0x0074; + enum int XK_u = 0x0075; + enum int XK_v = 0x0076; + enum int XK_w = 0x0077; + enum int XK_x = 0x0078; + enum int XK_y = 0x0079; + enum int XK_z = 0x007a; + enum int XK_braceleft = 0x007b; + enum int XK_bar = 0x007c; + enum int XK_braceright = 0x007d; + enum int XK_asciitilde = 0x007e; + enum int XK_nobreakspace = 0x00a0; + enum int XK_exclamdown = 0x00a1; + enum int XK_cent = 0x00a2; + enum int XK_sterling = 0x00a3; + enum int XK_currency = 0x00a4; + enum int XK_yen = 0x00a5; + enum int XK_brokenbar = 0x00a6; + enum int XK_section = 0x00a7; + enum int XK_diaeresis = 0x00a8; + enum int XK_copyright = 0x00a9; + enum int XK_ordfeminine = 0x00aa; + enum int XK_guillemotleft = 0x00ab; + enum int XK_notsign = 0x00ac; + enum int XK_hyphen = 0x00ad; + enum int XK_registered = 0x00ae; + enum int XK_macron = 0x00af; + enum int XK_degree = 0x00b0; + enum int XK_plusminus = 0x00b1; + enum int XK_twosuperior = 0x00b2; + enum int XK_threesuperior = 0x00b3; + enum int XK_acute = 0x00b4; + enum int XK_mu = 0x00b5; + enum int XK_paragraph = 0x00b6; + enum int XK_periodcentered = 0x00b7; + enum int XK_cedilla = 0x00b8; + enum int XK_onesuperior = 0x00b9; + enum int XK_masculine = 0x00ba; + enum int XK_guillemotright = 0x00bb; + enum int XK_onequarter = 0x00bc; + enum int XK_onehalf = 0x00bd; + enum int XK_threequarters = 0x00be; + enum int XK_questiondown = 0x00bf; + enum int XK_Agrave = 0x00c0; + enum int XK_Aacute = 0x00c1; + enum int XK_Acircumflex = 0x00c2; + enum int XK_Atilde = 0x00c3; + enum int XK_Adiaeresis = 0x00c4; + enum int XK_Aring = 0x00c5; + enum int XK_AE = 0x00c6; + enum int XK_Ccedilla = 0x00c7; + enum int XK_Egrave = 0x00c8; + enum int XK_Eacute = 0x00c9; + enum int XK_Ecircumflex = 0x00ca; + enum int XK_Ediaeresis = 0x00cb; + enum int XK_Igrave = 0x00cc; + enum int XK_Iacute = 0x00cd; + enum int XK_Icircumflex = 0x00ce; + enum int XK_Idiaeresis = 0x00cf; + enum int XK_ETH = 0x00d0; + enum int XK_Eth = 0x00d0; + enum int XK_Ntilde = 0x00d1; + enum int XK_Ograve = 0x00d2; + enum int XK_Oacute = 0x00d3; + enum int XK_Ocircumflex = 0x00d4; + enum int XK_Otilde = 0x00d5; + enum int XK_Odiaeresis = 0x00d6; + enum int XK_multiply = 0x00d7; + enum int XK_Oslash = 0x00d8; + enum int XK_Ooblique = 0x00d8; + enum int XK_Ugrave = 0x00d9; + enum int XK_Uacute = 0x00da; + enum int XK_Ucircumflex = 0x00db; + enum int XK_Udiaeresis = 0x00dc; + enum int XK_Yacute = 0x00dd; + enum int XK_THORN = 0x00de; + enum int XK_Thorn = 0x00de; + enum int XK_ssharp = 0x00df; + enum int XK_agrave = 0x00e0; + enum int XK_aacute = 0x00e1; + enum int XK_acircumflex = 0x00e2; + enum int XK_atilde = 0x00e3; + enum int XK_adiaeresis = 0x00e4; + enum int XK_aring = 0x00e5; + enum int XK_ae = 0x00e6; + enum int XK_ccedilla = 0x00e7; + enum int XK_egrave = 0x00e8; + enum int XK_eacute = 0x00e9; + enum int XK_ecircumflex = 0x00ea; + enum int XK_ediaeresis = 0x00eb; + enum int XK_igrave = 0x00ec; + enum int XK_iacute = 0x00ed; + enum int XK_icircumflex = 0x00ee; + enum int XK_idiaeresis = 0x00ef; + enum int XK_eth = 0x00f0; + enum int XK_ntilde = 0x00f1; + enum int XK_ograve = 0x00f2; + enum int XK_oacute = 0x00f3; + enum int XK_ocircumflex = 0x00f4; + enum int XK_otilde = 0x00f5; + enum int XK_odiaeresis = 0x00f6; + enum int XK_division = 0x00f7; + enum int XK_oslash = 0x00f8; + enum int XK_ooblique = 0x00f8; + enum int XK_ugrave = 0x00f9; + enum int XK_uacute = 0x00fa; + enum int XK_ucircumflex = 0x00fb; + enum int XK_udiaeresis = 0x00fc; + enum int XK_yacute = 0x00fd; + enum int XK_thorn = 0x00fe; + enum int XK_ydiaeresis = 0x00ff; +} +template XIClearMask(string ptr, int event) { + const ubyte XIClearMask = cast(ubyte)(ptr[(event) >> 3] &= ~(1 << ((event) & 7))); +} +auto XIMaskIsSet(T, U)(T ptr, U event) { + return cast(ubyte)((cast(ubyte*) ptr)[(event) >> 3] & (1 << ((event) & 7))); +} +auto XIMaskIsSet(T)(T event) { + return (((event) >> 3) + 1); +} +auto XIMaskLen(T)(T event) { + return (((event) >> 3) + 1); +} +enum { + XIAllDevices = 0, + XIAllMasterDevices = 1 +} +enum { + XI_DeviceChanged = 1, + XI_KeyPress = 2, + XI_KeyRelease = 3, + XI_ButtonPress = 4, + XI_ButtonRelease = 5, + XI_Motion = 6, + XI_Enter = 7, + XI_Leave = 8, + XI_FocusIn = 9, + XI_FocusOut = 10, + XI_HierarchyChanged = 11, + XI_PropertyEvent = 12, + XI_RawKeyPress = 13, + XI_RawKeyRelease = 14, + XI_RawButtonPress = 15, + XI_RawButtonRelease = 16, + XI_RawMotion = 17, + XI_LASTEVENT = XI_RawMotion +} +enum { + XI_DeviceChangedMask = (1 << XI_DeviceChanged), + XI_KeyPressMask = (1 << XI_KeyPress), + XI_KeyReleaseMask = (1 << XI_KeyRelease), + XI_ButtonPressMask = (1 << XI_ButtonPress), + XI_ButtonReleaseMask = (1 << XI_ButtonRelease), + XI_MotionMask = (1 << XI_Motion), + XI_EnterMask = (1 << XI_Enter), + XI_LeaveMask = (1 << XI_Leave), + XI_FocusInMask = (1 << XI_FocusIn), + XI_FocusOutMask = (1 << XI_FocusOut), + XI_HierarchyChangedMask = (1 << XI_HierarchyChanged), + XI_PropertyEventMask = (1 << XI_PropertyEvent), + XI_RawKeyPressMask = ( + 1 << XI_RawKeyPress), + XI_RawKeyReleaseMask = (1 << XI_RawKeyRelease), + XI_RawButtonPressMask = (1 << XI_RawButtonPress), + XI_RawButtonReleaseMask = ( + 1 << XI_RawButtonRelease), + XI_RawMotionMask = (1 << XI_RawMotion) +} +enum _deviceKeyPress = 0; +struct XDeviceCoreState { + XID control; + int length; + int status; + int iscore; +} +struct XDeviceEnableControl { + XID control; + int length; + int enable; +} +alias XDeviceEnableState = XDeviceEnableControl; +struct XAnyClassInfo { + XID class_; + int length; +} +alias XAnyClassPtr = XAnyClassInfo*; +struct XDeviceInfo { + XID id; + Atom type; + char* name; + int num_classes; + int use; + XAnyClassPtr inputclassinfo; +} +alias XDeviceInfoPtr = XDeviceInfo*; +struct XKeyInfo { + XID class_; + int length; + ushort min_keycode; + ushort max_keycode; + ushort num_keys; +} +alias XKeyInfoPtr = XKeyInfo*; +struct XButtonInfo { + XID class_; + int length; + short num_buttons; +} +alias XButtonInfoPtr = XButtonInfo*; +alias XAxisInfoPtr = XAxisInfo*; +struct XAxisInfo { + int resolution; + int min_value; + int max_value; +} +alias XValuatorInfoPtr = XValuatorInfo*; +struct XValuatorInfo { + XID class_; + int length; + ubyte num_axes; + ubyte mode; + ulong motion_buffer; + XAxisInfoPtr axes; +} +struct XInputClassInfo { + ubyte input_class; + ubyte event_type_base; +} +struct XIAddMasterInfo { + int type; + char* name; + Bool send_core; + Bool enable; +} +struct XIRemoveMasterInfo { + int type; + int deviceid; + int return_mode; + int return_pointer; + int return_keyboard; +} +struct XIAttachSlaveInfo { + int type; + int deviceid; + int new_master; +} +struct XIDetachSlaveInfo { + int type; + int deviceid; +} +union XIAnyHierarchyChangeInfo { + int type; + XIAddMasterInfo add; + XIRemoveMasterInfo remove; + XIAttachSlaveInfo attach; + XIDetachSlaveInfo detach; +} +struct XIModifierState { + int base; + int latched; + int locked; + int effective; +} +alias XIModifierState XIGroupState; +struct XIButtonState { + int mask_len; + ubyte* mask; +} +struct XIValuatorState { + int mask_len; + ubyte mask; + double* values; +} +struct XIEventMask { + int deviceid; + int mask_len; + ubyte* mask; +} +struct XIAnyClassInfo { + int type; + int sourceid; +} +struct XIButtonClassInfo { + int type; + int sourceid; + int num_buttons; + Atom* labels; + XIButtonState state; +} +struct XIDeviceEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + int extension; + int evtype; + Time time; + int deviceid; + int sourceid; + int detail; + Window root; + Window event; + Window child; + double root_x; + double root_y; + double event_x; + double event_y; + int flags; + XIButtonState buttons; + XIValuatorState valuators; + XIModifierState mods; + XIGroupState group; +} +struct XIRawEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + int extension; + int evtype; + Time time; + int deviceid; + int sourceid; + int detail; + int flags; + XIValuatorState valuators; + double* raw_values; +} +struct XIEnterEvent { + int type; + c_ulong serial; + Bool send_event; + Display* display; + int extension; + int evtype; + Time time; + int deviceid; + int sourceid; + int detail; + Window root; + Window event; + Window child; + double root_x; + double root_y; + double event_x; + double event_y; + int mode; + Bool focus; + Bool same_screen; + XIButtonState buttons; + XIModifierState mods; + XIGroupState group; +} +alias XIEnterEvent XILeaveEvent; +enum X_kbSetDeviceInfo = 25; +enum X_kbSetDebuggingFlags = 101; +enum XkbEventCode = 0; +enum XkbNumberEvents = (XkbEventCode + 1); +enum XkbNewKeyboardNotify = 0; +enum XkbMapNotify = 1; +enum XkbStateNotify = 2; +enum XkbControlsNotify = 3; +enum XkbModifierLockMask = (1L << 3); +enum XkbGroupStateMask = (1L << 4); +enum XkbGroupBaseMask = (1L << 5); +enum XkbGroupLatchMask = (1L << 6); +enum XkbLookupModsMask = (1L << 11); +enum XkbCompatLookupModsMask = (1L << 12); +enum XkbPointerButtonMask = (1L << 13); +enum XkbAllStateComponentsMask = (0x3fff); +enum XkbUseCoreKbd = 0x0100; +enum XkbUseCorePtr = 0x0200; +enum XkbDfltXIClass = 0x0300; +enum XkbDfltXIId = 0x0400; +enum XkbAllVirtualModsMask = 0xffff; +enum XkbNumKbdGroups = 4; +enum XkbMaxKbdGroup = (XkbNumKbdGroups - 1); +enum XkbMaxMouseKeysBtn = 4; +enum XkbKB_Overlay1 = 0x03; +enum XkbKB_Overlay2 = 0x04; +enum XkbKB_RGAllowNone = 0x80; +enum XkbMinLegalKeyCode = 8; +enum XkbMaxLegalKeyCode = 255; +enum XkbMaxKeyCount = (XkbMaxLegalKeyCode - XkbMinLegalKeyCode + 1); +enum XkbPerKeyBitArraySize = ((XkbMaxLegalKeyCode + 1) / 8); +enum XkbNumModifiers = 8; +enum XkbNumVirtualMods = 16; +enum XkbNumIndicators = 32; +enum XkbAllIndicatorsMask = (0xffffffff); +enum XkbRGMaxMembers = 12; +enum XkbActionMessageLength = 6; +enum XkbKeyNameLength = 4; +enum XkbMaxRedirectCount = 8; +enum XkbKTLevelNamesMask = (1 << 7); +enum XkbIndicatorNamesMask = (1 << 8); +enum XkbKeyNamesMask = (1 << 9); +enum XkbKeyAliasesMask = (1 << 10); +struct _xkbAnyEvent { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 pad1; + CARD16 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; + CARD32 pad6; + CARD32 pad7; +} +alias _xkbAnyEvent xkbAnyEvent; +enum sz_xkbAnyEvent = 32; +struct _xkbNewKeyboardNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 oldDeviceID; + KeyCode minKeyCode; + KeyCode maxKeyCode; + KeyCode oldMinKeyCode; + KeyCode oldMaxKeyCode; + CARD8 requestMajor; + CARD8 requestMinor; + CARD16 changed; + CARD8 detail; + CARD8 pad1; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; +} +alias _xkbNewKeyboardNotify xkbNewKeyboardNotify; +enum sz_xkbNewKeyboardNotify = 32; +struct _xkbMapNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 ptrBtnActions; + CARD16 changed; + KeyCode minKeyCode; + KeyCode maxKeyCode; + CARD8 firstType; + CARD8 nTypes; + KeyCode firstKeySym; + CARD8 nKeySyms; + KeyCode firstKeyAct; + CARD8 nKeyActs; + KeyCode firstKeyBehavior; + CARD8 nKeyBehaviors; + KeyCode firstKeyExplicit; + CARD8 nKeyExplicit; + KeyCode firstModMapKey; + CARD8 nModMapKeys; + KeyCode firstVModMapKey; + CARD8 nVModMapKeys; + CARD16 virtualMods; + CARD16 pad1; +} +alias _xkbMapNotify xkbMapNotify; +enum sz_xkbMapNotify = 32; +struct _xkbStateNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 mods; + CARD8 baseMods; + CARD8 latchedMods; + CARD8 lockedMods; + CARD8 group; + INT16 baseGroup; + INT16 latchedGroup; + CARD8 lockedGroup; + CARD8 compatState; + CARD8 grabMods; + CARD8 compatGrabMods; + CARD8 lookupMods; + CARD8 compatLookupMods; + CARD16 ptrBtnState; + CARD16 changed; + KeyCode keycode; + CARD8 eventType; + CARD8 requestMajor; + CARD8 requestMinor; +} +alias _xkbStateNotify xkbStateNotify; +enum sz_xkbStateNotify = 32; +struct _xkbControlsNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 numGroups; + CARD16 pad1; + CARD32 changedControls; + CARD32 enabledControls; + CARD32 enabledControlChanges; + KeyCode keycode; + CARD8 eventType; + CARD8 requestMajor; + CARD8 requestMinor; + CARD32 pad2; +} +alias _xkbControlsNotify xkbControlsNotify; +enum sz_xkbControlsNotify = 32; +struct _xkbIndicatorNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 pad1; + CARD16 pad2; + CARD32 state; + CARD32 changed; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; +} +alias _xkbIndicatorNotify xkbIndicatorNotify; +enum sz_xkbIndicatorNotify = 32; +struct _xkbNamesNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 pad1; + CARD16 changed; + CARD8 firstType; + CARD8 nTypes; + CARD8 firstLevelName; + CARD8 nLevelNames; + CARD8 pad2; + CARD8 nRadioGroups; + CARD8 nAliases; + CARD8 changedGroupNames; + CARD16 changedVirtualMods; + CARD8 firstKey; + CARD8 nKeys; + CARD32 changedIndicators; + CARD32 pad3; +} +alias _xkbNamesNotify xkbNamesNotify; +enum sz_xkbNamesNotify = 32; +struct _xkbCompatMapNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 changedGroups; + CARD16 firstSI; + CARD16 nSI; + CARD16 nTotalSI; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; +} +alias _xkbCompatMapNotify xkbCompatMapNotify; +enum sz_xkbCompatMapNotify = 32; +struct _xkbBellNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 bellClass; + CARD8 bellID; + CARD8 percent; + CARD16 pitch; + CARD16 duration; + Atom name; + Window window; + BOOL eventOnly; + CARD8 pad1; + CARD16 pad2; + CARD32 pad3; +} +alias _xkbBellNotify xkbBellNotify; +enum sz_xkbBellNotify = 32; +struct _xkbActionMessage { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + KeyCode keycode; + BOOL press; + BOOL keyEventFollows; + CARD8 mods; + CARD8 group; + CARD8[8] message; + CARD16 pad1; + CARD32 pad2; + CARD32 pad3; +} +alias _xkbActionMessage xkbActionMessage; +enum sz_xkbActionMessage = 32; +struct _xkbAccessXNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + KeyCode keycode; + CARD16 detail; + CARD16 slowKeysDelay; + CARD16 debounceDelay; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; +} +alias _xkbAccessXNotify xkbAccessXNotify; +enum sz_xkbAccessXNotify = 32; +struct _xkbExtensionDeviceNotify { + BYTE type; + BYTE xkbType; + CARD16 sequenceNumber; + Time time; + CARD8 deviceID; + CARD8 pad1; + CARD16 reason; + CARD16 ledClass; + CARD16 ledID; + CARD32 ledsDefined; + CARD32 ledState; + CARD8 firstBtn; + CARD8 nBtns; + CARD16 supported; + CARD16 unsupported; + CARD16 pad3; +} +alias _xkbExtensionDeviceNotify xkbExtensionDeviceNotify; +enum sz_xkbExtensionDeviceNotify = 32; +struct _xkbEvent { + union _U { + xkbAnyEvent any; + xkbNewKeyboardNotify new_kbd; + xkbMapNotify map; + xkbStateNotify state; + xkbControlsNotify ctrls; + xkbIndicatorNotify indicators; + xkbNamesNotify names; + xkbCompatMapNotify compat; + xkbBellNotify bell; + xkbActionMessage message; + xkbAccessXNotify accessx; + xkbExtensionDeviceNotify device; + } + _U u; +} +alias _xkbEvent xkbEvent; +enum sz_xkbEvent = 32; +/// Translated from C to D +struct _XkbStateRec { + ubyte group; + ubyte locked_group; + ushort base_group; + ushort latched_group; + ubyte mods; + ubyte base_mods; + ubyte latched_mods; + ubyte locked_mods; + ubyte compat_state; + ubyte grab_mods; + ubyte compat_grab_mods; + ubyte lookup_mods; + ubyte compat_lookup_mods; + ushort ptr_buttons; +} +alias _XkbStateRec XkbStateRec; +alias _XkbStateRec* XkbStatePtr; +struct _XkbMods { + ubyte mask; + ubyte real_mods; + ushort vmods; +} +alias _XkbMods XkbModsRec; +alias _XkbMods* XkbModsPtr; +struct _XkbKTMapEntry { + Bool active; + ubyte level; + XkbModsRec mods; +} +alias _XkbKTMapEntry XkbKTMapEntryRec; +alias _XkbKTMapEntry* XkbKTMapEntryPtr; +struct _XkbKeyType { + XkbModsRec mods; + ubyte num_levels; + ubyte map_count; + XkbKTMapEntryPtr map; + XkbModsPtr preserve; + Atom name; + Atom* level_names; +} +alias _XkbKeyType XkbKeyTypeRec; +alias _XkbKeyType* XkbKeyTypePtr; +struct _XkbBehavior { + ubyte type; + ubyte data; +} +alias _XkbBehavior XkbBehavior; +enum XkbAnyActionDataSize = 7; +struct _XkbAnyAction { + ubyte type; + ubyte[XkbAnyActionDataSize] data; +} +alias _XkbAnyAction XkbAnyAction; +struct _XkbModAction { + ubyte type; + ubyte flags; + ubyte mask; + ubyte real_mods; + ubyte vmods1; + ubyte vmods2; +} +alias _XkbModAction XkbModAction; +struct _XkbGroupAction { + ubyte type; + ubyte flags; + char group_XXX; +} +alias _XkbGroupAction XkbGroupAction; +struct _XkbISOAction { + ubyte type; + ubyte flags; + ubyte mask; + ubyte real_mods; + char group_XXX; + ubyte affect; + ubyte vmods1; + ubyte vmods2; +} +alias _XkbISOAction XkbISOAction; +struct _XkbPtrAction { + ubyte type; + ubyte flags; + ubyte high_XXX; + ubyte low_XXX; + ubyte high_YYY; + ubyte low_YYY; +} +alias _XkbPtrAction XkbPtrAction; +struct _XkbPtrBtnAction { + ubyte type; + ubyte flags; + ubyte count; + ubyte button; +} +alias _XkbPtrBtnAction XkbPtrBtnAction; +struct _XkbPtrDfltAction { + ubyte type; + ubyte flags; + ubyte affect; + char valueXXX; +} +alias _XkbPtrDfltAction XkbPtrDfltAction; +struct _XkbSwitchScreenAction { + ubyte type; + ubyte flags; + char screenXXX; +} +alias _XkbSwitchScreenAction XkbSwitchScreenAction; +struct _XkbCtrlsAction { + ubyte type; + ubyte flags; + ubyte ctrls3; + ubyte ctrls2; + ubyte ctrls1; + ubyte ctrls0; +} +alias _XkbCtrlsAction XkbCtrlsAction; +struct _XkbMessageAction { + ubyte type; + ubyte flags; + ubyte[6] message; +} +alias _XkbMessageAction XkbMessageAction; +struct _XkbRedirectKeyAction { + ubyte type; + ubyte new_key; + ubyte mods_mask; + ubyte mods; + ubyte vmods_mask0; + ubyte vmods_mask1; + ubyte vmods0; + ubyte vmods1; +} +alias _XkbRedirectKeyAction XkbRedirectKeyAction; +struct _XkbDeviceBtnAction { + ubyte type; + ubyte flags; + ubyte count; + ubyte button; + ubyte device; +} +alias _XkbDeviceBtnAction XkbDeviceBtnAction; +struct _XkbDeviceValuatorAction { + ubyte type; + ubyte device; + ubyte v1_what; + ubyte v1_ndx; + ubyte v1_value; + ubyte v2_what; + ubyte v2_ndx; + ubyte v2_value; +} +alias _XkbDeviceValuatorAction XkbDeviceValuatorAction; +union _XkbAction { + XkbAnyAction any; + XkbModAction mods; + XkbGroupAction group; + XkbISOAction iso; + XkbPtrAction ptr; + XkbPtrBtnAction btn; + XkbPtrDfltAction dflt; + XkbSwitchScreenAction screen; + XkbCtrlsAction ctrls; + XkbMessageAction msg; + XkbRedirectKeyAction redirect; + XkbDeviceBtnAction devbtn; + XkbDeviceValuatorAction devval; + ubyte type; +} +alias _XkbAction XkbAction; +struct _XkbControls { + ubyte mk_dflt_btn; + ubyte num_groups; + ubyte groups_wrap; + XkbModsRec internal; + XkbModsRec ignore_lock; + uint enabled_ctrls; + ushort repeat_delay; + ushort repeat_interval; + ushort slow_keys_delay; + ushort debounce_delay; + ushort mk_delay; + ushort mk_interval; + ushort mk_time_to_max; + ushort mk_max_speed; + short mk_curve; + ushort ax_options; + ushort ax_timeout; + ushort axt_opts_mask; + ushort axt_opts_values; + uint axt_ctrls_mask; + uint axt_ctrls_values; + ubyte[XkbPerKeyBitArraySize] per_key_repeat; +} +alias _XkbControls XkbControlsRec; +alias _XkbControls* XkbControlsPtr; +struct _XkbServerMapRec { + ushort num_acts; + ushort size_acts; + XkbAction* acts; + XkbBehavior* behaviors; + ushort* key_acts; + ubyte* explicit; + ubyte[XkbNumVirtualMods] vmods; + ushort* vmodmap; +} +alias _XkbServerMapRec XkbServerMapRec; +alias _XkbServerMapRec* XkbServerMapPtr; +struct _XkbSymMapRec { + ubyte[XkbNumKbdGroups] kt_index; + ubyte group_info; + ubyte width; + ushort offset; +} +alias _XkbSymMapRec XkbSymMapRec; +alias _XkbSymMapRec* XkbSymMapPtr; +struct _XkbClientMapRec { + ubyte size_types; + ubyte num_types; + XkbKeyTypePtr types; + ushort size_syms; + ushort num_syms; + KeySym* syms; + XkbSymMapPtr key_sym_map; + ubyte* modmap; +} +alias _XkbClientMapRec XkbClientMapRec; +alias _XkbClientMapRec* XkbClientMapPtr; +struct _XkbSymInterpretRec { + KeySym sym; + ubyte flags; + ubyte match; + ubyte mods; + ubyte virtual_mod; + XkbAnyAction act; +} +alias _XkbSymInterpretRec XkbSymInterpretRec; +alias _XkbSymInterpretRec* XkbSymInterpretPtr; +struct _XkbCompatMapRec { + XkbSymInterpretPtr sym_interpret; + XkbModsRec[XkbNumKbdGroups] groups; + ushort num_si; + ushort size_si; +} +alias _XkbCompatMapRec XkbCompatMapRec; +alias _XkbCompatMapRec* XkbCompatMapPtr; +struct _XkbIndicatorMapRec { + ubyte flags; + ubyte which_groups; + ubyte groups; + ubyte which_mods; + XkbModsRec mods; + uint ctrls; +} +alias _XkbIndicatorMapRec XkbIndicatorMapRec; +alias _XkbIndicatorMapRec* XkbIndicatorMapPtr; +struct _XkbIndicatorRec { + c_ulong phys_indicators; + XkbIndicatorMapRec[XkbNumIndicators] maps; +} +alias _XkbIndicatorRec XkbIndicatorRec; +alias _XkbIndicatorRec* XkbIndicatorPtr; +struct _XkbKeyNameRec { + char[XkbKeyNameLength] name; +} +alias _XkbKeyNameRec XkbKeyNameRec; +alias _XkbKeyNameRec* XkbKeyNamePtr; +struct _XkbKeyAliasRec { + char[XkbKeyNameLength] real_; + char[XkbKeyNameLength] alias_; +} +alias _XkbKeyAliasRec XkbKeyAliasRec; +alias _XkbKeyAliasRec* XkbKeyAliasPtr; +struct _XkbNamesRec { + Atom keycodes; + Atom geometry; + Atom symbols; + Atom types; + Atom compat; + Atom[XkbNumVirtualMods] vmods; + Atom[XkbNumIndicators] indicators; + Atom[XkbNumKbdGroups] groups; + XkbKeyNamePtr keys; + XkbKeyAliasPtr key_aliases; + Atom* radio_groups; + Atom phys_symbols; + ubyte num_keys; + ubyte num_key_aliases; + ushort num_rg; +} +alias _XkbNamesRec XkbNamesRec; +alias _XkbNamesRec* XkbNamesPtr; +struct _XkbGeometry; +alias _XkbGeometry* XkbGeometryPtr; +struct _XkbDesc { + struct _XDisplay; + _XDisplay* dpy; + ushort flags; + ushort device_spec; + KeyCode min_key_code; + KeyCode max_key_code; + XkbControlsPtr ctrls; + XkbServerMapPtr server; + XkbClientMapPtr map; + XkbIndicatorPtr indicators; + XkbNamesPtr names; + XkbCompatMapPtr compat; + XkbGeometryPtr geom; +} +alias _XkbDesc XkbDescRec; +alias _XkbDesc* XkbDescPtr; +struct _XkbMapChanges { + ushort changed; + KeyCode min_key_code; + KeyCode max_key_code; + ubyte first_type; + ubyte num_types; + KeyCode first_key_sym; + ubyte num_key_syms; + KeyCode first_key_act; + ubyte num_key_acts; + KeyCode first_key_behavior; + ubyte num_key_behaviors; + KeyCode first_key_explicit; + ubyte num_key_explicit; + KeyCode first_modmap_key; + ubyte num_modmap_keys; + KeyCode first_vmodmap_key; + ubyte num_vmodmap_keys; + ubyte pad; + ushort vmods; +} +alias _XkbMapChanges XkbMapChangesRec; +alias _XkbMapChanges* XkbMapChangesPtr; +struct _XkbControlsChanges { + uint changed_ctrls; + uint enabled_ctrls_changes; + Bool num_groups_changed; +} +alias _XkbControlsChanges XkbControlsChangesRec; +alias _XkbControlsChanges* XkbControlsChangesPtr; +struct _XkbIndicatorChanges { + uint state_changes; + uint map_changes; +} +alias _XkbIndicatorChanges XkbIndicatorChangesRec; +alias _XkbIndicatorChanges* XkbIndicatorChangesPtr; +struct _XkbNameChanges { + uint changed; + ubyte first_type; + ubyte num_types; + ubyte first_lvl; + ubyte num_lvls; + ubyte num_aliases; + ubyte num_rg; + ubyte first_key; + ubyte num_keys; + ushort changed_vmods; + c_ulong changed_indicators; + ubyte changed_groups; +} +alias _XkbNameChanges XkbNameChangesRec; +alias _XkbNameChanges* XkbNameChangesPtr; +struct _XkbCompatChanges { + ubyte changed_groups; + ushort first_si; + ushort num_si; +} +alias _XkbCompatChanges XkbCompatChangesRec; +alias _XkbCompatChanges* XkbCompatChangesPtr; +struct _XkbChanges { + ushort device_spec; + ushort state_changes; + XkbMapChangesRec map; + XkbControlsChangesRec ctrls; + XkbIndicatorChangesRec indicators; + XkbNameChangesRec names; + XkbCompatChangesRec compat; +} +alias _XkbChanges XkbChangesRec; +alias _XkbChanges* XkbChangesPtr; +struct XineramaScreenInfo { + int screen_number; + short x_org; + short y_org; + short width; + short height; +} +Bool XineramaQueryExtension(Display* dpy, int* event_base, int* error_base); +Status XineramaQueryVersion(Display* dpy, int* major_versionp, int* minor_versionp); +Bool XineramaIsActive(Display* dpy); +XineramaScreenInfo* XineramaQueryScreens(Display* dpy, int* number); +alias XID RROutput; +alias XID RRCrtc; +alias XID RRMode; +alias ulong XRRModeFlags; +struct _XRRModeInfo { + RRMode id; + uint width; + uint height; + ulong dotClock; + uint hSyncStart; + uint hSyncEnd; + uint hTotal; + uint hSkew; + uint vSyncStart; + uint vSyncEnd; + uint vTotal; + char* name; + uint nameLength; + XRRModeFlags modeFlags; +} +alias _XRRModeInfo XRRModeInfo; +struct _XRRScreenResources { + Time timestamp; + Time configTimestamp; + int ncrtc; + RRCrtc* crtcs; + int noutput; + RROutput* outputs; + int nmode; + XRRModeInfo* modes; +} +alias _XRRScreenResources XRRScreenResources; +XRRScreenResources* XRRGetScreenResources(Display* dpy, Window window); +void XRRFreeScreenResources(XRRScreenResources* resources); +struct _XRROutputInfo { + Time timestamp; + RRCrtc crtc; + char* name; + int nameLen; + ulong mm_width; + ulong mm_height; + Connection connection; + SubpixelOrder subpixel_order; + int ncrtc; + RRCrtc* crtcs; + int nclone; + RROutput* clones; + int nmode; + int npreferred; + RRMode* modes; +} +alias _XRROutputInfo XRROutputInfo; +XRROutputInfo* XRRGetOutputInfo(Display* dpy, XRRScreenResources* resources, RROutput output); +void XRRFreeOutputInfo(XRROutputInfo* outputInfo); +Atom* XRRListOutputProperties(Display* dpy, RROutput output, int* nprop); +struct _XRRCrtcInfo { + Time timestamp; + int x, y; + uint width, height; + RRMode mode; + Rotation rotation; + int noutput; + RROutput* outputs; + Rotation rotations; + int npossible; + RROutput* possible; +} +alias _XRRCrtcInfo XRRCrtcInfo; +XRRCrtcInfo* XRRGetCrtcInfo(Display* dpy, XRRScreenResources* resources, RRCrtc crtc); +void XRRFreeCrtcInfo(XRRCrtcInfo* crtcInfo); +Status XRRSetCrtcConfig(Display* dpy, XRRScreenResources* resources, RRCrtc crtc, + Time timestamp, int x, int y, RRMode mode, Rotation rotation, + RROutput* outputs, int noutputs); +int XRRGetCrtcGammaSize(Display* dpy, RRCrtc crtc); +struct _XRRCrtcGamma { + int size; + ushort* red; + ushort* green; + ushort* blue; +} +alias _XRRCrtcGamma XRRCrtcGamma; +RROutput XRRGetOutputPrimary(Display* dpy, Window window); +struct XRenderDirectFormat { + short red; + short redMask; + short green; + short greenMask; + short blue; + short blueMask; + short alpha; + short alphaMask; +} +struct XRenderPictFormat { + PictFormat id; + int type; + int depth; + XRenderDirectFormat direct; + Colormap colormap; +} +enum PictFormatID = (1 << 0); +alias ushort Rotation; +alias ushort SizeID; +alias ushort SubpixelOrder; +alias ushort Connection; +alias ushort XRandrRotation; +enum RRScreenChangeNotifyMask = (1L << 0); +enum RRCrtcChangeNotifyMask = (1L << 1); +enum RROutputChangeNotifyMask = (1L << 2); +enum RROutputPropertyNotifyMask = (1L << 3); +enum RRNotify = 1; +enum RRNotify_CrtcChange = 0; +enum RRNotify_OutputChange = 1; +enum RRNotify_OutputProperty = 2; +enum RR_Rotate_90 = 2; +enum RR_Rotate_180 = 4; +enum RR_Rotate_270 = 8; +enum RR_Reflect_X = 16; +enum RR_VSyncNegative = 0x00000008; +enum RR_Interlace = 0x00000010; +enum RR_DoubleScan = 0x00000020; +enum RR_CSync = 0x00000040; +enum RR_PixelMultiplex = 0x00000800; +enum RR_DoubleClock = 0x00001000; +enum RR_ClockDivideBy2 = 0x00002000; +enum RR_Connected = 0; +alias XID PictFormat; +enum RENDER_NAME = "RENDER"; +enum RENDER_MAJOR = 0; +enum RENDER_MINOR = 11; diff --git a/source/glfw3/x11_init.d b/source/glfw3/x11_init.d new file mode 100644 index 0000000..2d0fad4 --- /dev/null +++ b/source/glfw3/x11_init.d @@ -0,0 +1,1092 @@ +/// Translated from C to D +module x11_init; + +extern(C): @nogc: nothrow: __gshared: + +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +version(none) { + import x11.Xresource; + import x11.extensions.XKBsrv; + import x11.XKBlib; +} + +import core.stdc.stdlib; +import core.stdc.string; +import core.stdc.limits; +import core.stdc.stdio; +import core.stdc.locale; +import core.stdc.config: c_long, c_ulong; + +// Translate an X11 key code to a GLFW key code. +// +static int translateKeyCode(int scancode) { + int keySym; + + // Valid key code range is [8,255], according to the Xlib manual + if (scancode < 8 || scancode > 255) + return GLFW_KEY_UNKNOWN; + + if (_glfw.x11.xkb.available) + { + // Try secondary keysym, for numeric keypad keys + // Note: This way we always force "NumLock = ON", which is intentional + // since the returned key code should correspond to a physical + // location. + keySym = cast(int) XkbKeycodeToKeysym(_glfw.x11.display, cast(ubyte) scancode, cast(int) _glfw.x11.xkb.group, 1); + switch (keySym) + { + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; + } + + // Now try primary keysym for function keys (non-printable keys) + // These should not depend on the current keyboard layout + keySym = cast(int) XkbKeycodeToKeysym(_glfw.x11.display, cast(ubyte) scancode, _glfw.x11.xkb.group, 0); + } + else + { + int dummy; + KeySym* keySyms; + + keySyms = XGetKeyboardMapping(_glfw.x11.display, cast(ubyte) scancode, 1, &dummy); + keySym = cast(int) keySyms[0]; + XFree(keySyms); + } + + switch (keySym) + { + case XK_Escape: return GLFW_KEY_ESCAPE; + case XK_Tab: return GLFW_KEY_TAB; + case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT; + case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT; + case XK_Control_L: return GLFW_KEY_LEFT_CONTROL; + case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL; + case XK_Meta_L: + case XK_Alt_L: return GLFW_KEY_LEFT_ALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_ISO_Level3_Shift: // AltGr on at least some machines + case XK_Meta_R: + case XK_Alt_R: return GLFW_KEY_RIGHT_ALT; + case XK_Super_L: return GLFW_KEY_LEFT_SUPER; + case XK_Super_R: return GLFW_KEY_RIGHT_SUPER; + case XK_Menu: return GLFW_KEY_MENU; + case XK_Num_Lock: return GLFW_KEY_NUM_LOCK; + case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; + case XK_Print: return GLFW_KEY_PRINT_SCREEN; + case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; + case XK_Pause: return GLFW_KEY_PAUSE; + case XK_Delete: return GLFW_KEY_DELETE; + case XK_BackSpace: return GLFW_KEY_BACKSPACE; + case XK_Return: return GLFW_KEY_ENTER; + case XK_Home: return GLFW_KEY_HOME; + case XK_End: return GLFW_KEY_END; + case XK_Page_Up: return GLFW_KEY_PAGE_UP; + case XK_Page_Down: return GLFW_KEY_PAGE_DOWN; + case XK_Insert: return GLFW_KEY_INSERT; + case XK_Left: return GLFW_KEY_LEFT; + case XK_Right: return GLFW_KEY_RIGHT; + case XK_Down: return GLFW_KEY_DOWN; + case XK_Up: return GLFW_KEY_UP; + case XK_F1: return GLFW_KEY_F1; + case XK_F2: return GLFW_KEY_F2; + case XK_F3: return GLFW_KEY_F3; + case XK_F4: return GLFW_KEY_F4; + case XK_F5: return GLFW_KEY_F5; + case XK_F6: return GLFW_KEY_F6; + case XK_F7: return GLFW_KEY_F7; + case XK_F8: return GLFW_KEY_F8; + case XK_F9: return GLFW_KEY_F9; + case XK_F10: return GLFW_KEY_F10; + case XK_F11: return GLFW_KEY_F11; + case XK_F12: return GLFW_KEY_F12; + case XK_F13: return GLFW_KEY_F13; + case XK_F14: return GLFW_KEY_F14; + case XK_F15: return GLFW_KEY_F15; + case XK_F16: return GLFW_KEY_F16; + case XK_F17: return GLFW_KEY_F17; + case XK_F18: return GLFW_KEY_F18; + case XK_F19: return GLFW_KEY_F19; + case XK_F20: return GLFW_KEY_F20; + case XK_F21: return GLFW_KEY_F21; + case XK_F22: return GLFW_KEY_F22; + case XK_F23: return GLFW_KEY_F23; + case XK_F24: return GLFW_KEY_F24; + case XK_F25: return GLFW_KEY_F25; + + // Numeric keypad + case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; + case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; + case XK_KP_Add: return GLFW_KEY_KP_ADD; + + // These should have been detected in secondary keysym test above! + case XK_KP_Insert: return GLFW_KEY_KP_0; + case XK_KP_End: return GLFW_KEY_KP_1; + case XK_KP_Down: return GLFW_KEY_KP_2; + case XK_KP_Page_Down: return GLFW_KEY_KP_3; + case XK_KP_Left: return GLFW_KEY_KP_4; + case XK_KP_Right: return GLFW_KEY_KP_6; + case XK_KP_Home: return GLFW_KEY_KP_7; + case XK_KP_Up: return GLFW_KEY_KP_8; + case XK_KP_Page_Up: return GLFW_KEY_KP_9; + case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + + // Last resort: Check for printable keys (should not happen if the XKB + // extension is available). This will give a layout dependent mapping + // (which is wrong, and we may miss some keys, especially on non-US + // keyboards), but it's better than nothing... + case XK_a: return GLFW_KEY_A; + case XK_b: return GLFW_KEY_B; + case XK_c: return GLFW_KEY_C; + case XK_d: return GLFW_KEY_D; + case XK_e: return GLFW_KEY_E; + case XK_f: return GLFW_KEY_F; + case XK_g: return GLFW_KEY_G; + case XK_h: return GLFW_KEY_H; + case XK_i: return GLFW_KEY_I; + case XK_j: return GLFW_KEY_J; + case XK_k: return GLFW_KEY_K; + case XK_l: return GLFW_KEY_L; + case XK_m: return GLFW_KEY_M; + case XK_n: return GLFW_KEY_N; + case XK_o: return GLFW_KEY_O; + case XK_p: return GLFW_KEY_P; + case XK_q: return GLFW_KEY_Q; + case XK_r: return GLFW_KEY_R; + case XK_s: return GLFW_KEY_S; + case XK_t: return GLFW_KEY_T; + case XK_u: return GLFW_KEY_U; + case XK_v: return GLFW_KEY_V; + case XK_w: return GLFW_KEY_W; + case XK_x: return GLFW_KEY_X; + case XK_y: return GLFW_KEY_Y; + case XK_z: return GLFW_KEY_Z; + case XK_1: return GLFW_KEY_1; + case XK_2: return GLFW_KEY_2; + case XK_3: return GLFW_KEY_3; + case XK_4: return GLFW_KEY_4; + case XK_5: return GLFW_KEY_5; + case XK_6: return GLFW_KEY_6; + case XK_7: return GLFW_KEY_7; + case XK_8: return GLFW_KEY_8; + case XK_9: return GLFW_KEY_9; + case XK_0: return GLFW_KEY_0; + case XK_space: return GLFW_KEY_SPACE; + case XK_minus: return GLFW_KEY_MINUS; + case XK_equal: return GLFW_KEY_EQUAL; + case XK_bracketleft: return GLFW_KEY_LEFT_BRACKET; + case XK_bracketright: return GLFW_KEY_RIGHT_BRACKET; + case XK_backslash: return GLFW_KEY_BACKSLASH; + case XK_semicolon: return GLFW_KEY_SEMICOLON; + case XK_apostrophe: return GLFW_KEY_APOSTROPHE; + case XK_grave: return GLFW_KEY_GRAVE_ACCENT; + case XK_comma: return GLFW_KEY_COMMA; + case XK_period: return GLFW_KEY_PERIOD; + case XK_slash: return GLFW_KEY_SLASH; + case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts... + default: break; + } + + // No matching translation was found + return GLFW_KEY_UNKNOWN; +} + +// Create key code translation tables +// +static void createKeyTables() { + int scancode;int key; + + memset(_glfw.x11.keycodes.ptr, -1, typeof((_glfw.x11.keycodes)).sizeof); + memset(_glfw.x11.scancodes.ptr, -1, typeof((_glfw.x11.scancodes)).sizeof); + + if (_glfw.x11.xkb.available) + { + // Use XKB to determine physical key locations independently of the + // current keyboard layout + + char[XkbKeyNameLength + 1] name; + XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); + XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); + + // Find the X11 key code -> GLFW key code mapping + for (scancode = desc.min_key_code; scancode <= desc.max_key_code; scancode++) + { + memcpy(name.ptr, desc.names.keys[scancode].name.ptr, XkbKeyNameLength); + name[XkbKeyNameLength] = '\0'; + + // Map the key name to a GLFW key code. Note: We only map printable + // keys here, and we use the US keyboard layout. The rest of the + // keys (function keys) are mapped using traditional KeySym + // translations. + if (strcmp(name.ptr, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; + else if (strcmp(name.ptr, "AE01") == 0) key = GLFW_KEY_1; + else if (strcmp(name.ptr, "AE02") == 0) key = GLFW_KEY_2; + else if (strcmp(name.ptr, "AE03") == 0) key = GLFW_KEY_3; + else if (strcmp(name.ptr, "AE04") == 0) key = GLFW_KEY_4; + else if (strcmp(name.ptr, "AE05") == 0) key = GLFW_KEY_5; + else if (strcmp(name.ptr, "AE06") == 0) key = GLFW_KEY_6; + else if (strcmp(name.ptr, "AE07") == 0) key = GLFW_KEY_7; + else if (strcmp(name.ptr, "AE08") == 0) key = GLFW_KEY_8; + else if (strcmp(name.ptr, "AE09") == 0) key = GLFW_KEY_9; + else if (strcmp(name.ptr, "AE10") == 0) key = GLFW_KEY_0; + else if (strcmp(name.ptr, "AE11") == 0) key = GLFW_KEY_MINUS; + else if (strcmp(name.ptr, "AE12") == 0) key = GLFW_KEY_EQUAL; + else if (strcmp(name.ptr, "AD01") == 0) key = GLFW_KEY_Q; + else if (strcmp(name.ptr, "AD02") == 0) key = GLFW_KEY_W; + else if (strcmp(name.ptr, "AD03") == 0) key = GLFW_KEY_E; + else if (strcmp(name.ptr, "AD04") == 0) key = GLFW_KEY_R; + else if (strcmp(name.ptr, "AD05") == 0) key = GLFW_KEY_T; + else if (strcmp(name.ptr, "AD06") == 0) key = GLFW_KEY_Y; + else if (strcmp(name.ptr, "AD07") == 0) key = GLFW_KEY_U; + else if (strcmp(name.ptr, "AD08") == 0) key = GLFW_KEY_I; + else if (strcmp(name.ptr, "AD09") == 0) key = GLFW_KEY_O; + else if (strcmp(name.ptr, "AD10") == 0) key = GLFW_KEY_P; + else if (strcmp(name.ptr, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; + else if (strcmp(name.ptr, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; + else if (strcmp(name.ptr, "AC01") == 0) key = GLFW_KEY_A; + else if (strcmp(name.ptr, "AC02") == 0) key = GLFW_KEY_S; + else if (strcmp(name.ptr, "AC03") == 0) key = GLFW_KEY_D; + else if (strcmp(name.ptr, "AC04") == 0) key = GLFW_KEY_F; + else if (strcmp(name.ptr, "AC05") == 0) key = GLFW_KEY_G; + else if (strcmp(name.ptr, "AC06") == 0) key = GLFW_KEY_H; + else if (strcmp(name.ptr, "AC07") == 0) key = GLFW_KEY_J; + else if (strcmp(name.ptr, "AC08") == 0) key = GLFW_KEY_K; + else if (strcmp(name.ptr, "AC09") == 0) key = GLFW_KEY_L; + else if (strcmp(name.ptr, "AC10") == 0) key = GLFW_KEY_SEMICOLON; + else if (strcmp(name.ptr, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; + else if (strcmp(name.ptr, "AB01") == 0) key = GLFW_KEY_Z; + else if (strcmp(name.ptr, "AB02") == 0) key = GLFW_KEY_X; + else if (strcmp(name.ptr, "AB03") == 0) key = GLFW_KEY_C; + else if (strcmp(name.ptr, "AB04") == 0) key = GLFW_KEY_V; + else if (strcmp(name.ptr, "AB05") == 0) key = GLFW_KEY_B; + else if (strcmp(name.ptr, "AB06") == 0) key = GLFW_KEY_N; + else if (strcmp(name.ptr, "AB07") == 0) key = GLFW_KEY_M; + else if (strcmp(name.ptr, "AB08") == 0) key = GLFW_KEY_COMMA; + else if (strcmp(name.ptr, "AB09") == 0) key = GLFW_KEY_PERIOD; + else if (strcmp(name.ptr, "AB10") == 0) key = GLFW_KEY_SLASH; + else if (strcmp(name.ptr, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; + else if (strcmp(name.ptr, "LSGT") == 0) key = GLFW_KEY_WORLD_1; + else key = GLFW_KEY_UNKNOWN; + + if ((scancode >= 0) && (scancode < 256)) + _glfw.x11.keycodes[scancode] = key; + } + + XkbFreeNames(desc, XkbKeyNamesMask, True); + XkbFreeKeyboard(desc, 0, True); + } + + for (scancode = 0; scancode < 256; scancode++) + { + // Translate the un-translated key codes using traditional X11 KeySym + // lookups + if (_glfw.x11.keycodes[scancode] < 0) + _glfw.x11.keycodes[scancode] = translateKeyCode(scancode); + + // Store the reverse translation for faster key name lookup + if (_glfw.x11.keycodes[scancode] > 0) + _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; + } +} + +// Check whether the IM has a usable style +// +static GLFWbool hasUsableInputMethodStyle() { + GLFWbool found = GLFW_FALSE; + XIMStyles* styles = null; + + if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, null) != null) + return GLFW_FALSE; + + for (uint i = 0; i < styles.count_styles; i++) + { + if (styles.supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) + { + found = GLFW_TRUE; + break; + } + } + + XFree(styles); + return found; +} + +// Check whether the specified atom is supported +// +static Atom getSupportedAtom(Atom* supportedAtoms, c_ulong atomCount, const(char)* atomName) { + const(Atom) atom = XInternAtom(_glfw.x11.display, atomName, False); + + for (uint i = 0; i < atomCount; i++) + { + if (supportedAtoms[i] == atom) + return atom; + } + + return None; +} + +// Check whether the running window manager is EWMH-compliant +// +static void detectEWMH() { + // First we read the _NET_SUPPORTING_WM_CHECK property on the root window + + Window* windowFromRoot = null; + if (!_glfwGetWindowPropertyX11(_glfw.x11.root, + _glfw.x11.NET_SUPPORTING_WM_CHECK, + XA_WINDOW, + cast(ubyte**) &windowFromRoot)) + { + return; + } + + _glfwGrabErrorHandlerX11(); + + // If it exists, it should be the XID of a top-level window + // Then we look for the same property on that window + + Window* windowFromChild = null; + if (!_glfwGetWindowPropertyX11(*windowFromRoot, + _glfw.x11.NET_SUPPORTING_WM_CHECK, + XA_WINDOW, + cast(ubyte**) &windowFromChild)) + { + XFree(windowFromRoot); + return; + } + + _glfwReleaseErrorHandlerX11(); + + // If the property exists, it should contain the XID of the window + + if (*windowFromRoot != *windowFromChild) + { + XFree(windowFromRoot); + XFree(windowFromChild); + return; + } + + XFree(windowFromRoot); + XFree(windowFromChild); + + // We are now fairly sure that an EWMH-compliant WM is currently running + // We can now start querying the WM about what features it supports by + // looking in the _NET_SUPPORTED property on the root window + // It should contain a list of supported EWMH protocol and state atoms + + Atom* supportedAtoms = null; + c_ulong atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root, + _glfw.x11.NET_SUPPORTED, + XA_ATOM, + cast(ubyte**) &supportedAtoms); + + // See which of the atoms we support that are supported by the WM + + _glfw.x11.NET_WM_STATE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); + _glfw.x11.NET_WM_STATE_ABOVE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); + _glfw.x11.NET_WM_STATE_FULLSCREEN = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); + _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); + _glfw.x11.NET_WM_FULLSCREEN_MONITORS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); + _glfw.x11.NET_WM_WINDOW_TYPE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); + _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); + _glfw.x11.NET_WORKAREA = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA"); + _glfw.x11.NET_CURRENT_DESKTOP = + getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP"); + _glfw.x11.NET_ACTIVE_WINDOW = + getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); + _glfw.x11.NET_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); + _glfw.x11.NET_REQUEST_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); + + if (supportedAtoms) + XFree(supportedAtoms); +} + +// Look for and initialize supported X11 extensions +// +static GLFWbool initExtensions() { + _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1"); + if (_glfw.x11.vidmode.handle) + { + _glfw.x11.vidmode.QueryExtension = cast(PFN_XF86VidModeQueryExtension) + _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); + _glfw.x11.vidmode.GetGammaRamp = cast(PFN_XF86VidModeGetGammaRamp) + _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); + _glfw.x11.vidmode.SetGammaRamp = cast(PFN_XF86VidModeSetGammaRamp) + _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); + _glfw.x11.vidmode.GetGammaRampSize = cast(PFN_XF86VidModeGetGammaRampSize) + _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); + + _glfw.x11.vidmode.available = + _glfw.x11.vidmode.QueryExtension(_glfw.x11.display, + &_glfw.x11.vidmode.eventBase, + &_glfw.x11.vidmode.errorBase); + } + +version (Cygwin) { + _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so"); +} else { + _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6"); +} + if (_glfw.x11.xi.handle) + { + _glfw.x11.xi.QueryVersion = cast(PFN_XIQueryVersion) + _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); + _glfw.x11.xi.SelectEvents = cast(PFN_XISelectEvents) + _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents"); + + if (XQueryExtension(_glfw.x11.display, + "XInputExtension".ptr, + &_glfw.x11.xi.majorOpcode, + &_glfw.x11.xi.eventBase, + &_glfw.x11.xi.errorBase)) + { + _glfw.x11.xi.major = 2; + _glfw.x11.xi.minor = 0; + + if (_glfw.x11.xi.QueryVersion(_glfw.x11.display, + &_glfw.x11.xi.major, + &_glfw.x11.xi.minor) == XErrorCode.Success) + { + _glfw.x11.xi.available = GLFW_TRUE; + } + } + } + +version (Cygwin) { + _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so"); +} else { + _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2"); +} + if (_glfw.x11.randr.handle) + { + _glfw.x11.randr.AllocGamma = cast(PFN_XRRAllocGamma) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); + _glfw.x11.randr.FreeGamma = cast(PFN_XRRFreeGamma) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw.x11.randr.FreeCrtcInfo = cast(PFN_XRRFreeCrtcInfo) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); + _glfw.x11.randr.FreeGamma = cast(PFN_XRRFreeGamma) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw.x11.randr.FreeOutputInfo = cast(PFN_XRRFreeOutputInfo) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); + _glfw.x11.randr.FreeScreenResources = cast(PFN_XRRFreeScreenResources) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); + _glfw.x11.randr.GetCrtcGamma = cast(PFN_XRRGetCrtcGamma) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); + _glfw.x11.randr.GetCrtcGammaSize = cast(PFN_XRRGetCrtcGammaSize) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); + _glfw.x11.randr.GetCrtcInfo = cast(PFN_XRRGetCrtcInfo) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); + _glfw.x11.randr.GetOutputInfo = cast(PFN_XRRGetOutputInfo) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); + _glfw.x11.randr.GetOutputPrimary = cast(PFN_XRRGetOutputPrimary) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); + _glfw.x11.randr.GetScreenResourcesCurrent = cast(PFN_XRRGetScreenResourcesCurrent) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); + _glfw.x11.randr.QueryExtension = cast(PFN_XRRQueryExtension) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); + _glfw.x11.randr.QueryVersion = cast(PFN_XRRQueryVersion) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); + _glfw.x11.randr.SelectInput = cast(PFN_XRRSelectInput) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); + _glfw.x11.randr.SetCrtcConfig = cast(PFN_XRRSetCrtcConfig) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); + _glfw.x11.randr.SetCrtcGamma = cast(PFN_XRRSetCrtcGamma) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); + _glfw.x11.randr.UpdateConfiguration = cast(PFN_XRRUpdateConfiguration) + _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); + + if (_glfw.x11.randr.QueryExtension(_glfw.x11.display, + &_glfw.x11.randr.eventBase, + &_glfw.x11.randr.errorBase)) + { + if (_glfw.x11.randr.QueryVersion(_glfw.x11.display, + &_glfw.x11.randr.major, + &_glfw.x11.randr.minor)) + { + // The GLFW RandR path requires at least version 1.3 + if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) + _glfw.x11.randr.available = GLFW_TRUE; + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to query RandR version"); + } + } + } + + if (_glfw.x11.randr.available) + { + XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, + _glfw.x11.root); + + if (!sr.ncrtc || !_glfw.x11.randr.GetCrtcGammaSize(_glfw.x11.display, sr.crtcs[0])) + { + // This is likely an older Nvidia driver with broken gamma support + // Flag it as useless and fall back to xf86vm gamma, if available + _glfw.x11.randr.gammaBroken = GLFW_TRUE; + } + + if (!sr.ncrtc) + { + // A system without CRTCs is likely a system with broken RandR + // Disable the RandR monitor path and fall back to core functions + _glfw.x11.randr.monitorBroken = GLFW_TRUE; + } + + _glfw.x11.randr.FreeScreenResources(sr); + } + + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + _glfw.x11.randr.SelectInput(_glfw.x11.display, _glfw.x11.root, + RROutputChangeNotifyMask); + } + +version (Cygwin) { + _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so"); +} else { + _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1"); +} + if (_glfw.x11.xcursor.handle) + { + _glfw.x11.xcursor.ImageCreate = cast(PFN_XcursorImageCreate) + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); + _glfw.x11.xcursor.ImageDestroy = cast(PFN_XcursorImageDestroy) + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); + _glfw.x11.xcursor.ImageLoadCursor = cast(PFN_XcursorImageLoadCursor) + _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); + } + +version (Cygwin) { + _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so"); +} else { + _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1"); +} + if (_glfw.x11.xinerama.handle) + { + _glfw.x11.xinerama.IsActive = cast(PFN_XineramaIsActive) + _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); + _glfw.x11.xinerama.QueryExtension = cast(PFN_XineramaQueryExtension) + _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); + _glfw.x11.xinerama.QueryScreens = cast(PFN_XineramaQueryScreens) + _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); + + if (_glfw.x11.xinerama.QueryExtension(_glfw.x11.display, + &_glfw.x11.xinerama.major, + &_glfw.x11.xinerama.minor)) + { + if (_glfw.x11.xinerama.IsActive(_glfw.x11.display)) + _glfw.x11.xinerama.available = GLFW_TRUE; + } + } + + _glfw.x11.xkb.major = 1; + _glfw.x11.xkb.minor = 0; + _glfw.x11.xkb.available = + XkbQueryExtension(_glfw.x11.display, + &_glfw.x11.xkb.majorOpcode, + &_glfw.x11.xkb.eventBase, + &_glfw.x11.xkb.errorBase, + &_glfw.x11.xkb.major, + &_glfw.x11.xkb.minor); + + if (_glfw.x11.xkb.available) + { + Bool supported; + + if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + { + if (supported) + _glfw.x11.xkb.detectable = GLFW_TRUE; + } + + _glfw.x11.xkb.group = 0; + XkbStateRec state; + if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == XErrorCode.Success) + { + XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask); + _glfw.x11.xkb.group = cast(uint)state.group; + } + } + +version (Cygwin) { + _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so"); +} else { + _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); +} + if (_glfw.x11.x11xcb.handle) + { + _glfw.x11.x11xcb.GetXCBConnection = cast(PFN_XGetXCBConnection) + _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); + } + +version (Cygwin) { + _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so"); +} else { + _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); +} + if (_glfw.x11.xrender.handle) + { + _glfw.x11.xrender.QueryExtension = cast(PFN_XRenderQueryExtension) + _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); + _glfw.x11.xrender.QueryVersion = cast(PFN_XRenderQueryVersion) + _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); + _glfw.x11.xrender.FindVisualFormat = cast(PFN_XRenderFindVisualFormat) + _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); + + if (_glfw.x11.xrender.QueryExtension(_glfw.x11.display, + &_glfw.x11.xrender.errorBase, + &_glfw.x11.xrender.eventBase)) + { + if (_glfw.x11.xrender.QueryVersion(_glfw.x11.display, + &_glfw.x11.xrender.major, + &_glfw.x11.xrender.minor)) + { + _glfw.x11.xrender.available = GLFW_TRUE; + } + } + } + + // Update the key code LUT + // FIXME: We should listen to XkbMapNotify events to track changes to + // the keyboard mapping. + createKeyTables(); + + // String format atoms + _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); + _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False); + _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); + + // Custom selection property atom + _glfw.x11.GLFW_SELECTION = + XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); + + // ICCCM standard clipboard atoms + _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); + _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); + _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False); + _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False); + _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); + + // Clipboard manager atoms + _glfw.x11.CLIPBOARD_MANAGER = + XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); + _glfw.x11.SAVE_TARGETS = + XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); + + // Xdnd (drag and drop) atoms + _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False); + _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); + _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); + _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False); + _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False); + _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False); + _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); + _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); + _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False); + _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False); + + // ICCCM, EWMH and Motif window property atoms + // These can be set safely even without WM support + // The EWMH atoms that require WM support are handled in detectEWMH + _glfw.x11.WM_PROTOCOLS = + XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False); + _glfw.x11.WM_STATE = + XInternAtom(_glfw.x11.display, "WM_STATE", False); + _glfw.x11.WM_DELETE_WINDOW = + XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False); + _glfw.x11.NET_SUPPORTED = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); + _glfw.x11.NET_SUPPORTING_WM_CHECK = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); + _glfw.x11.NET_WM_ICON = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); + _glfw.x11.NET_WM_PING = + XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); + _glfw.x11.NET_WM_PID = + XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); + _glfw.x11.NET_WM_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); + _glfw.x11.NET_WM_ICON_NAME = + XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); + _glfw.x11.NET_WM_BYPASS_COMPOSITOR = + XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); + _glfw.x11.NET_WM_WINDOW_OPACITY = + XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False); + _glfw.x11.MOTIF_WM_HINTS = + XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + + // The compositing manager selection name contains the screen number + { + char[32] name; + snprintf(name.ptr, typeof(name).sizeof, "_NET_WM_CM_S%u", _glfw.x11.screen); + _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name.ptr, False); + } + + // Detect whether an EWMH-conformant window manager is running + detectEWMH(); + + return GLFW_TRUE; +} + +// Retrieve system content scale via folklore heuristics +// +static void getSystemContentScale(float* xscale, float* yscale) { + // Start by assuming the default X11 DPI + // NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it + // would be set to 96, so assume that is the case if we cannot find it + float xdpi = 96.0f;float ydpi = 96.0f; + + // NOTE: Basing the scale on Xft.dpi where available should provide the most + // consistent user experience (matches Qt, Gtk, etc), although not + // always the most accurate one + char* rms = XResourceManagerString(_glfw.x11.display); + if (rms) + { + XrmDatabase db = XrmGetStringDatabase(rms); + if (db) + { + XrmValue value; + char* type = null; + + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) + { + if (type && strcmp(type, "String") == 0) + xdpi = ydpi = atof(value.addr); + } + + XrmDestroyDatabase(db); + } + } + + *xscale = xdpi / 96.0f; + *yscale = ydpi / 96.0f; +} + +// Create a blank cursor for hidden and disabled cursor modes +// +static Cursor createHiddenCursor() { + ubyte[16 * 16 * 4] pixels = 0; + GLFWimage image = GLFWimage(16, 16, pixels.ptr); + return _glfwCreateCursorX11(&image, 0, 0); +} + +// Create a helper window for IPC +// +static Window createHelperWindow() { + XSetWindowAttributes wa; + wa.event_mask = PropertyChangeMask; + + return XCreateWindow(_glfw.x11.display, _glfw.x11.root, + 0, 0, 1, 1, 0, 0, + InputOnly, + DefaultVisual(_glfw.x11.display, _glfw.x11.screen), + CWEventMask, &wa); +} + +// X error handler +// +static int errorHandler(Display* display, XErrorEvent* event) { + _glfw.x11.errorCode = event.error_code; + return 0; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Sets the X error handler callback +// +void _glfwGrabErrorHandlerX11() { + _glfw.x11.errorCode = XErrorCode.Success; + XSetErrorHandler(&errorHandler); +} + +// Clears the X error handler callback +// +void _glfwReleaseErrorHandlerX11() { + // Synchronize to make sure all commands are processed + XSync(_glfw.x11.display, False); + XSetErrorHandler(null); +} + +// Reports the specified error, appending information about the last X error +// +void _glfwInputErrorX11(int error, const(char)* message) { + char[_GLFW_MESSAGE_SIZE] buffer; + XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode, + buffer.ptr, typeof(buffer).sizeof); + + _glfwInputError(error, "%s: %s", message, buffer.ptr); +} + +// Creates a native cursor object from the specified image and hotspot +// +Cursor _glfwCreateCursorX11(const(GLFWimage)* image, int xhot, int yhot) { + int i; + Cursor cursor; + + if (!_glfw.x11.xcursor.handle) + return None; + + XcursorImage* native = _glfw.x11.xcursor.ImageCreate(image.width, image.height); + if (native == null) + return None; + + native.xhot = xhot; + native.yhot = yhot; + + ubyte* source = cast(ubyte*) image.pixels; + XcursorPixel* target = native.pixels; + + for (i = 0; i < image.width * image.height; i++, target++, source += 4) + { + uint alpha = source[3]; + + *target = (alpha << 24) | + (cast(ubyte) ((source[0] * alpha) / 255) << 16) | + (cast(ubyte) ((source[1] * alpha) / 255) << 8) | + (cast(ubyte) ((source[2] * alpha) / 255) << 0); + } + + cursor = _glfw.x11.xcursor.ImageLoadCursor(_glfw.x11.display, native); + _glfw.x11.xcursor.ImageDestroy(native); + + return cursor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit() { +version (X_HAVE_UTF8_STRING) {} else { + // HACK: If the current locale is "C" and the Xlib UTF-8 functions are + // unavailable, apply the environment's locale in the hope that it's + // both available and not "C" + // This is done because the "C" locale breaks wide character input, + // which is what we fall back on when UTF-8 support is missing + if (strcmp(setlocale(LC_CTYPE, null), "C") == 0) + setlocale(LC_CTYPE, ""); +} + + XInitThreads(); + XrmInitialize(); + + _glfw.x11.display = XOpenDisplay(null); + if (!_glfw.x11.display) + { + const(char)* display = getenv("DISPLAY"); + if (display) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to open display %s", display); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: The DISPLAY environment variable is missing"); + } + + return GLFW_FALSE; + } + + _glfw.x11.screen = DefaultScreen(_glfw.x11.display); + _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); + _glfw.x11.context = XUniqueContext(); + + getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); + + if (!initExtensions()) + return GLFW_FALSE; + + _glfw.x11.helperWindowHandle = createHelperWindow(); + _glfw.x11.hiddenCursorHandle = createHiddenCursor(); + + if (XSupportsLocale()) + { + XSetLocaleModifiers(""); + + _glfw.x11.im = XOpenIM(_glfw.x11.display, null, null, null); + if (_glfw.x11.im) + { + if (!hasUsableInputMethodStyle()) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = null; + } + } + } + + version (linux) { + if (!_glfwInitJoysticksLinux()) + return GLFW_FALSE; + } + + _glfwInitTimerPOSIX(); + + _glfwPollMonitorsX11(); + return GLFW_TRUE; +} + +void _glfwPlatformTerminate() { + if (_glfw.x11.helperWindowHandle) + { + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == + _glfw.x11.helperWindowHandle) + { + _glfwPushSelectionToManagerX11(); + } + + XDestroyWindow(_glfw.x11.display, _glfw.x11.helperWindowHandle); + _glfw.x11.helperWindowHandle = None; + } + + if (_glfw.x11.hiddenCursorHandle) + { + XFreeCursor(_glfw.x11.display, _glfw.x11.hiddenCursorHandle); + _glfw.x11.hiddenCursorHandle = cast(Cursor) 0; + } + + free(_glfw.x11.primarySelectionString); + free(_glfw.x11.clipboardString); + + if (_glfw.x11.im) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = null; + } + + if (_glfw.x11.display) + { + XCloseDisplay(_glfw.x11.display); + _glfw.x11.display = null; + } + + if (_glfw.x11.x11xcb.handle) + { + _glfw_dlclose(_glfw.x11.x11xcb.handle); + _glfw.x11.x11xcb.handle = null; + } + + if (_glfw.x11.xcursor.handle) + { + _glfw_dlclose(_glfw.x11.xcursor.handle); + _glfw.x11.xcursor.handle = null; + } + + if (_glfw.x11.randr.handle) + { + _glfw_dlclose(_glfw.x11.randr.handle); + _glfw.x11.randr.handle = null; + } + + if (_glfw.x11.xinerama.handle) + { + _glfw_dlclose(_glfw.x11.xinerama.handle); + _glfw.x11.xinerama.handle = null; + } + + if (_glfw.x11.xrender.handle) + { + _glfw_dlclose(_glfw.x11.xrender.handle); + _glfw.x11.xrender.handle = null; + } + + if (_glfw.x11.vidmode.handle) + { + _glfw_dlclose(_glfw.x11.vidmode.handle); + _glfw.x11.vidmode.handle = null; + } + + if (_glfw.x11.xi.handle) + { + _glfw_dlclose(_glfw.x11.xi.handle); + _glfw.x11.xi.handle = null; + } + + // NOTE: These need to be unloaded after XCloseDisplay, as they register + // cleanup callbacks that get called by that function + _glfwTerminateEGL(); + _glfwTerminateGLX(); + + version (linux) { + _glfwTerminateJoysticksLinux(); + } +} + +const(char)* _glfwPlatformGetVersionString() { + version (linux) { + enum evdev = " evdev"; + } else { + enum evdev = ""; + } + version (_GLFW_BUILD_DLL) { + enum dllStr = " shared"; + } else { + enum dllStr = ""; + } + return _GLFW_VERSION_NUMBER ~ " X11 GLX EGL OSMesa" ~ evdev ~ dllStr; +} \ No newline at end of file diff --git a/source/glfw3/x11_monitor.d b/source/glfw3/x11_monitor.d new file mode 100644 index 0000000..e143658 --- /dev/null +++ b/source/glfw3/x11_monitor.d @@ -0,0 +1,591 @@ +/// Translated from C to D +module x11_monitor; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +import core.stdc.limits; +import core.stdc.stdlib; +import core.stdc.string; +import core.stdc.math; +import core.stdc.config: c_long, c_ulong; + +// Check whether the display mode should be included in enumeration +// +static GLFWbool modeIsGood(const(XRRModeInfo)* mi) { + return (mi.modeFlags & RR_Interlace) == 0; +} + +// Calculates the refresh rate, in Hz, from the specified RandR mode info +// +static int calculateRefreshRate(const(XRRModeInfo)* mi) { + if (mi.hTotal && mi.vTotal) + return cast(int) round(cast(double) mi.dotClock / (cast(double) mi.hTotal * cast(double) mi.vTotal)); + else + return 0; +} + +// Returns the mode info for a RandR mode XID +// +static const(XRRModeInfo)* getModeInfo(const(XRRScreenResources)* sr, RRMode id) { + for (int i = 0; i < sr.nmode; i++) + { + if (sr.modes[i].id == id) + return sr.modes + i; + } + + return null; +} + +// Convert RandR mode info to GLFW video mode +// +static GLFWvidmode vidmodeFromModeInfo(const(XRRModeInfo)* mi, const(XRRCrtcInfo)* ci) { + GLFWvidmode mode; + + if (ci.rotation == RR_Rotate_90 || ci.rotation == RR_Rotate_270) + { + mode.width = mi.height; + mode.height = mi.width; + } + else + { + mode.width = mi.width; + mode.height = mi.height; + } + + mode.refreshRate = calculateRefreshRate(mi); + + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode.redBits, &mode.greenBits, &mode.blueBits); + + return mode; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Poll for changes in the set of connected monitors +// +void _glfwPollMonitorsX11() { + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + int disconnectedCount;int screenCount = 0; + _GLFWmonitor** disconnected = null; + XineramaScreenInfo* screens = null; + XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, + _glfw.x11.root); + RROutput primary = _glfw.x11.randr.GetOutputPrimary(_glfw.x11.display, + _glfw.x11.root); + + if (_glfw.x11.xinerama.available) + screens = _glfw.x11.xinerama.QueryScreens(_glfw.x11.display, &screenCount); + + disconnectedCount = _glfw.monitorCount; + if (disconnectedCount) + { + disconnected = cast(_GLFWmonitor**) calloc(_glfw.monitorCount, (_GLFWmonitor*).sizeof); + memcpy(disconnected, + _glfw.monitors, + _glfw.monitorCount * (_GLFWmonitor*).sizeof); + } + + for (int i = 0; i < sr.noutput; i++) + { + int j;int type;int widthMM;int heightMM; + + XRROutputInfo* oi = _glfw.x11.randr.GetOutputInfo(_glfw.x11.display, sr, sr.outputs[i]); + if (oi.connection != RR_Connected || oi.crtc == None) + { + _glfw.x11.randr.FreeOutputInfo(oi); + continue; + } + + for (j = 0; j < disconnectedCount; j++) + { + if (disconnected[j] && + disconnected[j].x11.output == sr.outputs[i]) + { + disconnected[j] = null; + break; + } + } + + if (j < disconnectedCount) + { + _glfw.x11.randr.FreeOutputInfo(oi); + continue; + } + + XRRCrtcInfo* ci = _glfw.x11.randr.GetCrtcInfo(_glfw.x11.display, sr, oi.crtc); + if (ci.rotation == RR_Rotate_90 || ci.rotation == RR_Rotate_270) + { + widthMM = cast(int) oi.mm_height; + heightMM = cast(int) oi.mm_width; + } + else + { + widthMM = cast(int) oi.mm_width; + heightMM = cast(int) oi.mm_height; + } + + if (widthMM <= 0 || heightMM <= 0) + { + // HACK: If RandR does not provide a physical size, assume the + // X11 default 96 DPI and calcuate from the CRTC viewport + // NOTE: These members are affected by rotation, unlike the mode + // info and output info members + widthMM = cast(int) (ci.width * 25.4f / 96.0f); + heightMM = cast(int) (ci.height * 25.4f / 96.0f); + } + + _GLFWmonitor* monitor = _glfwAllocMonitor(oi.name, widthMM, heightMM); + monitor.x11.output = sr.outputs[i]; + monitor.x11.crtc = oi.crtc; + + for (j = 0; j < screenCount; j++) + { + if (screens[j].x_org == ci.x && + screens[j].y_org == ci.y && + screens[j].width == ci.width && + screens[j].height == ci.height) + { + monitor.x11.index = j; + break; + } + } + + if (monitor.x11.output == primary) + type = _GLFW_INSERT_FIRST; + else + type = _GLFW_INSERT_LAST; + + _glfwInputMonitor(monitor, GLFW_CONNECTED, type); + + _glfw.x11.randr.FreeOutputInfo(oi); + _glfw.x11.randr.FreeCrtcInfo(ci); + } + + _glfw.x11.randr.FreeScreenResources(sr); + + if (screens) + XFree(screens); + + for (int i = 0; i < disconnectedCount; i++) + { + if (disconnected[i]) + _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); + } + + free(disconnected); + } + else + { + const(int) widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); + const(int) heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); + + _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM), + GLFW_CONNECTED, + _GLFW_INSERT_FIRST); + } +} + +// Set the current video mode for the specified monitor +// +void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const(GLFWvidmode)* desired) { + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + GLFWvidmode current; + RRMode native = None; + + const(GLFWvidmode)* best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return; + + XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = _glfw.x11.randr.GetCrtcInfo(_glfw.x11.display, sr, monitor.x11.crtc); + XRROutputInfo* oi = _glfw.x11.randr.GetOutputInfo(_glfw.x11.display, sr, monitor.x11.output); + + for (int i = 0; i < oi.nmode; i++) + { + const(XRRModeInfo)* mi = getModeInfo(sr, oi.modes[i]); + if (!modeIsGood(mi)) + continue; + + const(GLFWvidmode) mode = vidmodeFromModeInfo(mi, ci); + if (_glfwCompareVideoModes(best, &mode) == 0) + { + native = mi.id; + break; + } + } + + if (native) + { + if (monitor.x11.oldMode == None) + monitor.x11.oldMode = ci.mode; + + _glfw.x11.randr.SetCrtcConfig(_glfw.x11.display, + sr, monitor.x11.crtc, + CurrentTime, + ci.x, ci.y, + native, + ci.rotation, + ci.outputs, + ci.noutput); + } + + _glfw.x11.randr.FreeOutputInfo(oi); + _glfw.x11.randr.FreeCrtcInfo(ci); + _glfw.x11.randr.FreeScreenResources(sr); + } +} + +// Restore the saved (original) video mode for the specified monitor +// +void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) { + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + if (monitor.x11.oldMode == None) + return; + + XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = _glfw.x11.randr.GetCrtcInfo(_glfw.x11.display, sr, monitor.x11.crtc); + + _glfw.x11.randr.SetCrtcConfig(_glfw.x11.display, + sr, monitor.x11.crtc, + CurrentTime, + ci.x, ci.y, + monitor.x11.oldMode, + ci.rotation, + ci.outputs, + ci.noutput); + + _glfw.x11.randr.FreeCrtcInfo(ci); + _glfw.x11.randr.FreeScreenResources(sr); + + monitor.x11.oldMode = None; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = _glfw.x11.randr.GetCrtcInfo(_glfw.x11.display, sr, monitor.x11.crtc); + + if (ci) + { + if (xpos) + *xpos = ci.x; + if (ypos) + *ypos = ci.y; + + _glfw.x11.randr.FreeCrtcInfo(ci); + } + + _glfw.x11.randr.FreeScreenResources(sr); + } +} + +void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { + if (xscale) + *xscale = _glfw.x11.contentScaleX; + if (yscale) + *yscale = _glfw.x11.contentScaleY; +} + +void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { + int areaX = 0;int areaY = 0;int areaWidth = 0;int areaHeight = 0; + + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = _glfw.x11.randr.GetCrtcInfo(_glfw.x11.display, sr, monitor.x11.crtc); + + areaX = ci.x; + areaY = ci.y; + + const(XRRModeInfo)* mi = getModeInfo(sr, ci.mode); + + if (ci.rotation == RR_Rotate_90 || ci.rotation == RR_Rotate_270) + { + areaWidth = mi.height; + areaHeight = mi.width; + } + else + { + areaWidth = mi.width; + areaHeight = mi.height; + } + + _glfw.x11.randr.FreeCrtcInfo(ci); + _glfw.x11.randr.FreeScreenResources(sr); + } + else + { + areaWidth = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); + areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); + } + + if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP) + { + Atom* extents = null; + Atom* desktop = null; + c_ulong extentCount = _glfwGetWindowPropertyX11(_glfw.x11.root, + _glfw.x11.NET_WORKAREA, + XA_CARDINAL, + cast(ubyte**) &extents); + + if (_glfwGetWindowPropertyX11(_glfw.x11.root, + _glfw.x11.NET_CURRENT_DESKTOP, + XA_CARDINAL, + cast(ubyte**) &desktop) > 0) + { + if (extentCount >= 4 && *desktop < extentCount / 4) + { + const int globalX = cast(int) extents[*desktop * 4 + 0]; + const int globalY = cast(int) extents[*desktop * 4 + 1]; + const int globalWidth = cast(int) extents[*desktop * 4 + 2]; + const int globalHeight = cast(int) extents[*desktop * 4 + 3]; + + if (areaX < globalX) + { + areaWidth -= globalX - areaX; + areaX = globalX; + } + + if (areaY < globalY) + { + areaHeight -= globalY - areaY; + areaY = globalY; + } + + if (areaX + areaWidth > globalX + globalWidth) + areaWidth = globalX - areaX + globalWidth; + if (areaY + areaHeight > globalY + globalHeight) + areaHeight = globalY - areaY + globalHeight; + } + } + + if (extents) + XFree(extents); + if (desktop) + XFree(desktop); + } + + if (xpos) + *xpos = areaX; + if (ypos) + *ypos = areaY; + if (width) + *width = areaWidth; + if (height) + *height = areaHeight; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { + GLFWvidmode* result; + + *count = 0; + + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = _glfw.x11.randr.GetCrtcInfo(_glfw.x11.display, sr, monitor.x11.crtc); + XRROutputInfo* oi = _glfw.x11.randr.GetOutputInfo(_glfw.x11.display, sr, monitor.x11.output); + + result = cast(GLFWvidmode*) calloc(oi.nmode, GLFWvidmode.sizeof); + + for (int i = 0; i < oi.nmode; i++) + { + const(XRRModeInfo)* mi = getModeInfo(sr, oi.modes[i]); + if (!modeIsGood(mi)) + continue; + + const(GLFWvidmode) mode = vidmodeFromModeInfo(mi, ci); + int j; + + for (j = 0; j < *count; j++) + { + if (_glfwCompareVideoModes(result + j, &mode) == 0) + break; + } + + // Skip duplicate modes + if (j < *count) + continue; + + (*count)++; + result[*count - 1] = mode; + } + + _glfw.x11.randr.FreeOutputInfo(oi); + _glfw.x11.randr.FreeCrtcInfo(ci); + _glfw.x11.randr.FreeScreenResources(sr); + } + else + { + *count = 1; + result = cast(GLFWvidmode*) calloc(1, GLFWvidmode.sizeof); + _glfwPlatformGetVideoMode(monitor, result); + } + + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr = _glfw.x11.randr.GetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = _glfw.x11.randr.GetCrtcInfo(_glfw.x11.display, sr, monitor.x11.crtc); + + if (ci) + { + const(XRRModeInfo)* mi = getModeInfo(sr, ci.mode); + if (mi) // mi can be NULL if the monitor has been disconnected + *mode = vidmodeFromModeInfo(mi, ci); + + _glfw.x11.randr.FreeCrtcInfo(ci); + } + + _glfw.x11.randr.FreeScreenResources(sr); + } + else + { + mode.width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); + mode.height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); + mode.refreshRate = 0; + + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode.redBits, &mode.greenBits, &mode.blueBits); + } +} + +GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + const(size_t) size = _glfw.x11.randr.GetCrtcGammaSize(_glfw.x11.display, + monitor.x11.crtc); + XRRCrtcGamma* gamma = _glfw.x11.randr.GetCrtcGamma(_glfw.x11.display, + monitor.x11.crtc); + + _glfwAllocGammaArrays(ramp, cast(uint) size); + + memcpy(ramp.red, gamma.red, size * ushort.sizeof); + memcpy(ramp.green, gamma.green, size * ushort.sizeof); + memcpy(ramp.blue, gamma.blue, size * ushort.sizeof); + + _glfw.x11.randr.FreeGamma(gamma); + return GLFW_TRUE; + } + else if (_glfw.x11.vidmode.available) + { + int size; + _glfw.x11.vidmode.GetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); + + _glfwAllocGammaArrays(ramp, size); + + _glfw.x11.vidmode.GetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp.size, ramp.red, ramp.green, ramp.blue); + return GLFW_TRUE; + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Gamma ramp access not supported by server"); + return GLFW_FALSE; + } +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const(GLFWgammaramp)* ramp) { + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + if (_glfw.x11.randr.GetCrtcGammaSize(_glfw.x11.display, monitor.x11.crtc) != ramp.size) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Gamma ramp size must match current ramp size"); + return; + } + + XRRCrtcGamma* gamma = _glfw.x11.randr.AllocGamma(ramp.size); + + memcpy(gamma.red, ramp.red, ramp.size * ushort.sizeof); + memcpy(gamma.green, ramp.green, ramp.size * ushort.sizeof); + memcpy(gamma.blue, ramp.blue, ramp.size * ushort.sizeof); + + _glfw.x11.randr.SetCrtcGamma(_glfw.x11.display, monitor.x11.crtc, gamma); + _glfw.x11.randr.FreeGamma(gamma); + } + else if (_glfw.x11.vidmode.available) + { + _glfw.x11.vidmode.SetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp.size, + cast(ushort*) ramp.red, + cast(ushort*) ramp.green, + cast(ushort*) ramp.blue); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Gamma ramp access not supported by server"); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"None"); + return monitor.x11.crtc; +} + +RROutput glfwGetX11Monitor(GLFWmonitor* handle) { + _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"None"); + return monitor.x11.output; +} \ No newline at end of file diff --git a/source/glfw3/x11_platform.d b/source/glfw3/x11_platform.d new file mode 100644 index 0000000..9b363f4 --- /dev/null +++ b/source/glfw3/x11_platform.d @@ -0,0 +1,455 @@ +/// Translated from C to D +module glfw3.x11_platform; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +import core.sys.posix.unistd; +import core.stdc.signal; +import core.stdc.stdint; +import core.sys.posix.dlfcn; +import core.stdc.config: c_long, c_ulong; + +version(none) { + public import x11.X; + public import x11.Xutil; + public import x11.extensions.Xrender; + public import x11.extensions.randr; + public import x11.Xcursor; + + public import x11.Xlib; + public import x11.keysym; + public import x11.Xatom; + + // The XRandR extension provides mode setting and gamma control + public import x11.extensions.Xrandr; + + // The Xkb extension provides improved keyboard support + //public import x11.XKBlib; + + // The Xinerama extension provides legacy monitor indices + public import x11.extensions.Xinerama; + + // The XInput extension provides raw mouse motion input + public import x11.extensions.XInput2; +} else { + public import glfw3.x11_header; +} + +alias XRRCrtcGamma* function(int) PFN_XRRAllocGamma; +alias void function(XRRCrtcInfo*) PFN_XRRFreeCrtcInfo; +alias void function(XRRCrtcGamma*) PFN_XRRFreeGamma; +alias void function(XRROutputInfo*) PFN_XRRFreeOutputInfo; +alias void function(XRRScreenResources*) PFN_XRRFreeScreenResources; +alias XRRCrtcGamma* function(Display*, RRCrtc) PFN_XRRGetCrtcGamma; +alias int function(Display*, RRCrtc) PFN_XRRGetCrtcGammaSize; +alias XRRCrtcInfo* function(Display*, XRRScreenResources*, RRCrtc) PFN_XRRGetCrtcInfo; +alias XRROutputInfo* function(Display*, XRRScreenResources*, RROutput) PFN_XRRGetOutputInfo; +alias RROutput function(Display*, Window) PFN_XRRGetOutputPrimary; +alias XRRScreenResources* function(Display*, Window) PFN_XRRGetScreenResourcesCurrent; +alias Bool function(Display*, int*, int*) PFN_XRRQueryExtension; +alias Status function(Display*, int*, int*) PFN_XRRQueryVersion; +alias void function(Display*, Window, int) PFN_XRRSelectInput; +alias Status function(Display*, XRRScreenResources*, RRCrtc, Time, int, int, RRMode, Rotation, RROutput*, int) PFN_XRRSetCrtcConfig; +alias void function(Display*, RRCrtc, XRRCrtcGamma*) PFN_XRRSetCrtcGamma; +alias int function(XEvent*) PFN_XRRUpdateConfiguration; +alias XRRAllocGamma = _glfw.x11.randr.AllocGamma; +alias XRRFreeCrtcInfo = _glfw.x11.randr.FreeCrtcInfo; +alias XRRFreeGamma = _glfw.x11.randr.FreeGamma; +alias XRRFreeOutputInfo = _glfw.x11.randr.FreeOutputInfo; +alias XRRFreeScreenResources = _glfw.x11.randr.FreeScreenResources; +alias XRRGetCrtcGamma = _glfw.x11.randr.GetCrtcGamma; +alias XRRGetCrtcGammaSize = _glfw.x11.randr.GetCrtcGammaSize; +alias XRRGetCrtcInfo = _glfw.x11.randr.GetCrtcInfo; +alias XRRGetOutputInfo = _glfw.x11.randr.GetOutputInfo; +alias XRRGetOutputPrimary = _glfw.x11.randr.GetOutputPrimary; +alias XRRGetScreenResourcesCurrent = _glfw.x11.randr.GetScreenResourcesCurrent; +alias XRRQueryExtension = _glfw.x11.randr.QueryExtension; +alias XRRQueryVersion = _glfw.x11.randr.QueryVersion; +alias XRRSelectInput = _glfw.x11.randr.SelectInput; +alias XRRSetCrtcConfig = _glfw.x11.randr.SetCrtcConfig; +alias XRRSetCrtcGamma = _glfw.x11.randr.SetCrtcGamma; +alias XRRUpdateConfiguration = _glfw.x11.randr.UpdateConfiguration; + +alias XcursorImage* function(int, int) PFN_XcursorImageCreate; +alias void function(XcursorImage*) PFN_XcursorImageDestroy; +alias Cursor function(Display*, const(XcursorImage)*) PFN_XcursorImageLoadCursor; +alias XcursorImageCreate = _glfw.x11.xcursor.ImageCreate; +alias XcursorImageDestroy = _glfw.x11.xcursor.ImageDestroy; +alias XcursorImageLoadCursor = _glfw.x11.xcursor.ImageLoadCursor; + +alias Bool function(Display*) PFN_XineramaIsActive; +alias Bool function(Display*, int*, int*) PFN_XineramaQueryExtension; +alias XineramaScreenInfo* function(Display*, int*) PFN_XineramaQueryScreens; +alias XineramaIsActive = _glfw.x11.xinerama.IsActive; +alias XineramaQueryExtension = _glfw.x11.xinerama.QueryExtension; +alias XineramaQueryScreens = _glfw.x11.xinerama.QueryScreens; + +alias XID xcb_window_t; +alias XID xcb_visualid_t; +struct xcb_connection_t ;/+alias xcb_connection_t xcb_connection_t;+/ +alias xcb_connection_t* function(Display*) PFN_XGetXCBConnection; +alias XGetXCBConnection = _glfw.x11.x11xcb.GetXCBConnection; + +alias Bool function(Display*, int*, int*) PFN_XF86VidModeQueryExtension; +alias Bool function(Display*, int, int, ushort*, ushort*, ushort*) PFN_XF86VidModeGetGammaRamp; +alias Bool function(Display*, int, int, ushort*, ushort*, ushort*) PFN_XF86VidModeSetGammaRamp; +alias Bool function(Display*, int, int*) PFN_XF86VidModeGetGammaRampSize; +alias XF86VidModeQueryExtension = _glfw.x11.vidmode.QueryExtension; +alias XF86VidModeGetGammaRamp = _glfw.x11.vidmode.GetGammaRamp; +alias XF86VidModeSetGammaRamp = _glfw.x11.vidmode.SetGammaRamp; +alias XF86VidModeGetGammaRampSize = _glfw.x11.vidmode.GetGammaRampSize; + +alias Status function(Display*, int*, int*) PFN_XIQueryVersion; +alias int function(Display*, Window, XIEventMask*, int) PFN_XISelectEvents; +alias XIQueryVersion = _glfw.x11.xi.QueryVersion; +alias XISelectEvents = _glfw.x11.xi.SelectEvents; + +alias Bool function(Display*, int*, int*) PFN_XRenderQueryExtension; +alias Status function(Display* dpy, int*, int*) PFN_XRenderQueryVersion; +alias XRenderPictFormat* function(Display*, const(Visual)*) PFN_XRenderFindVisualFormat; +alias XRenderQueryExtension = _glfw.x11.xrender.QueryExtension; +alias XRenderQueryVersion = _glfw.x11.xrender.QueryVersion; +alias XRenderFindVisualFormat = _glfw.x11.xrender.FindVisualFormat; + +alias VkFlags VkXlibSurfaceCreateFlagsKHR; +alias VkFlags VkXcbSurfaceCreateFlagsKHR; + +struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const(void)* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +}/+alias VkXlibSurfaceCreateInfoKHR VkXlibSurfaceCreateInfoKHR;+/ + +struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const(void)* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +}/+alias VkXcbSurfaceCreateInfoKHR VkXcbSurfaceCreateInfoKHR;+/ + +alias VkResult function(VkInstance, const(VkXlibSurfaceCreateInfoKHR)*, const(VkAllocationCallbacks)*, VkSurfaceKHR*) PFN_vkCreateXlibSurfaceKHR; +alias VkBool32 function(VkPhysicalDevice, uint, Display*, VisualID) PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR; +alias VkResult function(VkInstance, const(VkXcbSurfaceCreateInfoKHR)*, const(VkAllocationCallbacks)*, VkSurfaceKHR*) PFN_vkCreateXcbSurfaceKHR; +alias VkBool32 function(VkPhysicalDevice, uint, xcb_connection_t*, xcb_visualid_t) PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR; + +public import glfw3.posix_thread; +public import glfw3.posix_time; +public import glfw3.xkb_unicode; +public import glfw3.glx_context; +public import glfw3.egl_context; +public import glfw3.osmesa_context; +import glfw3.internal; + +version (linux) { + public import glfw3.linux_joystick; +} else { + public import glfw3.null_joystick; +} + +auto _glfw_dlopen(const(char)* name) {return dlopen(name, RTLD_LAZY | RTLD_LOCAL);} +auto _glfw_dlclose(void* handle) {return dlclose(handle);} +auto _glfw_dlsym(void* handle, const(char)* name) {return dlsym(handle, name);} + +enum _GLFW_EGL_NATIVE_WINDOW = `(cast(EGLNativeWindowType) window.x11.handle)`; +enum _GLFW_EGL_NATIVE_DISPLAY = `(cast(EGLNativeDisplayType) _glfw.x11.display)`; + +mixin template _GLFW_PLATFORM_WINDOW_STATE() { _GLFWwindowX11 x11;} +mixin template _GLFW_PLATFORM_LIBRARY_WINDOW_STATE() { _GLFWlibraryX11 x11;} +mixin template _GLFW_PLATFORM_MONITOR_STATE() { _GLFWmonitorX11 x11;} +mixin template _GLFW_PLATFORM_CURSOR_STATE() { _GLFWcursorX11 x11;} + +// X11-specific per-window data +// +struct _GLFWwindowX11 { + Colormap colormap; + Window handle; + Window parent; + XIC ic; + + GLFWbool overrideRedirect; + GLFWbool iconified; + GLFWbool maximized; + + // Whether the visual supports framebuffer transparency + GLFWbool transparent; + + // Cached position and size used to filter out duplicate events + int width;int height; + int xpos;int ypos; + + // The last received cursor position, regardless of source + int lastCursorPosX;int lastCursorPosY; + // The last position the cursor was warped to by GLFW + int warpCursorPosX;int warpCursorPosY; + + // The time of the last KeyPress event + Time lastKeyTime; + +}/+alias _GLFWwindowX11 _GLFWwindowX11;+/ + +// X11-specific global data +// +struct _GLFWlibraryX11 { + Display* display; + int screen; + Window root; + + // System content scale + float contentScaleX;float contentScaleY; + // Helper window for IPC + Window helperWindowHandle; + // Invisible cursor for hidden cursor mode + Cursor hiddenCursorHandle; + // Context for mapping window XIDs to _GLFWwindow pointers + XContext context; + // XIM input method + XIM im; + // Most recent error code received by X error handler + int errorCode; + // Primary selection string (while the primary selection is owned) + char* primarySelectionString; + // Clipboard string (while the selection is owned) + char* clipboardString; + // Key name string + char[5][GLFW_KEY_LAST + 1] keynames; + // X11 keycode to GLFW key LUT + int[256] keycodes; + // GLFW key to X11 keycode LUT + int[GLFW_KEY_LAST + 1] scancodes; + // Where to place the cursor when re-enabled + double restoreCursorPosX;double restoreCursorPosY; + // The window whose disabled cursor mode is active + _GLFWwindow* disabledCursorWindow; + + // Window manager atoms + Atom NET_SUPPORTED; + Atom NET_SUPPORTING_WM_CHECK; + Atom WM_PROTOCOLS; + Atom WM_STATE; + Atom WM_DELETE_WINDOW; + Atom NET_WM_NAME; + Atom NET_WM_ICON_NAME; + Atom NET_WM_ICON; + Atom NET_WM_PID; + Atom NET_WM_PING; + Atom NET_WM_WINDOW_TYPE; + Atom NET_WM_WINDOW_TYPE_NORMAL; + Atom NET_WM_STATE; + Atom NET_WM_STATE_ABOVE; + Atom NET_WM_STATE_FULLSCREEN; + Atom NET_WM_STATE_MAXIMIZED_VERT; + Atom NET_WM_STATE_MAXIMIZED_HORZ; + Atom NET_WM_STATE_DEMANDS_ATTENTION; + Atom NET_WM_BYPASS_COMPOSITOR; + Atom NET_WM_FULLSCREEN_MONITORS; + Atom NET_WM_WINDOW_OPACITY; + Atom NET_WM_CM_Sx; + Atom NET_WORKAREA; + Atom NET_CURRENT_DESKTOP; + Atom NET_ACTIVE_WINDOW; + Atom NET_FRAME_EXTENTS; + Atom NET_REQUEST_FRAME_EXTENTS; + Atom MOTIF_WM_HINTS; + + // Xdnd (drag and drop) atoms + Atom XdndAware; + Atom XdndEnter; + Atom XdndPosition; + Atom XdndStatus; + Atom XdndActionCopy; + Atom XdndDrop; + Atom XdndFinished; + Atom XdndSelection; + Atom XdndTypeList; + Atom text_uri_list; + + // Selection (clipboard) atoms + Atom TARGETS; + Atom MULTIPLE; + Atom INCR; + Atom CLIPBOARD; + Atom PRIMARY; + Atom CLIPBOARD_MANAGER; + Atom SAVE_TARGETS; + Atom NULL_; + Atom UTF8_STRING; + Atom COMPOUND_STRING; + Atom ATOM_PAIR; + Atom GLFW_SELECTION; + + struct _Randr { + GLFWbool available; + void* handle; + int eventBase; + int errorBase; + int major; + int minor; + GLFWbool gammaBroken; + GLFWbool monitorBroken; + PFN_XRRAllocGamma AllocGamma; + PFN_XRRFreeCrtcInfo FreeCrtcInfo; + PFN_XRRFreeGamma FreeGamma; + PFN_XRRFreeOutputInfo FreeOutputInfo; + PFN_XRRFreeScreenResources FreeScreenResources; + PFN_XRRGetCrtcGamma GetCrtcGamma; + PFN_XRRGetCrtcGammaSize GetCrtcGammaSize; + PFN_XRRGetCrtcInfo GetCrtcInfo; + PFN_XRRGetOutputInfo GetOutputInfo; + PFN_XRRGetOutputPrimary GetOutputPrimary; + PFN_XRRGetScreenResourcesCurrent GetScreenResourcesCurrent; + PFN_XRRQueryExtension QueryExtension; + PFN_XRRQueryVersion QueryVersion; + PFN_XRRSelectInput SelectInput; + PFN_XRRSetCrtcConfig SetCrtcConfig; + PFN_XRRSetCrtcGamma SetCrtcGamma; + PFN_XRRUpdateConfiguration UpdateConfiguration; + }_Randr randr; + + struct _Xkb { + GLFWbool available; + GLFWbool detectable; + int majorOpcode; + int eventBase; + int errorBase; + int major; + int minor; + uint group; + }_Xkb xkb; + + struct _Saver { + int count; + int timeout; + int interval; + int blanking; + int exposure; + }_Saver saver; + + struct _Xdnd { + int version_; + Window source; + Atom format; + }_Xdnd xdnd; + + struct _Xcursor { + void* handle; + PFN_XcursorImageCreate ImageCreate; + PFN_XcursorImageDestroy ImageDestroy; + PFN_XcursorImageLoadCursor ImageLoadCursor; + }_Xcursor xcursor; + + struct _Xinerama { + GLFWbool available; + void* handle; + int major; + int minor; + PFN_XineramaIsActive IsActive; + PFN_XineramaQueryExtension QueryExtension; + PFN_XineramaQueryScreens QueryScreens; + }_Xinerama xinerama; + + struct _X11xcb { + void* handle; + PFN_XGetXCBConnection GetXCBConnection; + }_X11xcb x11xcb; + + struct _Vidmode { + GLFWbool available; + void* handle; + int eventBase; + int errorBase; + PFN_XF86VidModeQueryExtension QueryExtension; + PFN_XF86VidModeGetGammaRamp GetGammaRamp; + PFN_XF86VidModeSetGammaRamp SetGammaRamp; + PFN_XF86VidModeGetGammaRampSize GetGammaRampSize; + }_Vidmode vidmode; + + struct _Xi { + GLFWbool available; + void* handle; + int majorOpcode; + int eventBase; + int errorBase; + int major; + int minor; + PFN_XIQueryVersion QueryVersion; + PFN_XISelectEvents SelectEvents; + }_Xi xi; + + struct _Xrender { + GLFWbool available; + void* handle; + int major; + int minor; + int eventBase; + int errorBase; + PFN_XRenderQueryExtension QueryExtension; + PFN_XRenderQueryVersion QueryVersion; + PFN_XRenderFindVisualFormat FindVisualFormat; + }_Xrender xrender; + +}/+alias _GLFWlibraryX11 _GLFWlibraryX11;+/ + +// X11-specific per-monitor data +// +struct _GLFWmonitorX11 { + RROutput output; + RRCrtc crtc; + RRMode oldMode; + + // Index of corresponding Xinerama screen, + // for EWMH full screen window placement + int index; + +}/+alias _GLFWmonitorX11 _GLFWmonitorX11;+/ + +// X11-specific per-cursor data +// +struct _GLFWcursorX11 { + Cursor handle; + +}/+alias _GLFWcursorX11 _GLFWcursorX11;+/ + + +void _glfwPollMonitorsX11(); +void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const(GLFWvidmode)* desired); +void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor); + +Cursor _glfwCreateCursorX11(const(GLFWimage)* image, int xhot, int yhot); + +c_ulong _glfwGetWindowPropertyX11(Window window, Atom property, Atom type, ubyte** value); +GLFWbool _glfwIsVisualTransparentX11(Visual* visual); + +void _glfwGrabErrorHandlerX11(); +void _glfwReleaseErrorHandlerX11(); +void _glfwInputErrorX11(int error, const(char)* message); + +void _glfwPushSelectionToManagerX11(); \ No newline at end of file diff --git a/source/glfw3/x11_window.d b/source/glfw3/x11_window.d new file mode 100644 index 0000000..390da1c --- /dev/null +++ b/source/glfw3/x11_window.d @@ -0,0 +1,3081 @@ +/// Translated from C to D +module glfw3.x11_window; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2019 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +version(none) { + import x11.cursorfont; + import x11.Xmd; + import x11.extensions.XI2; // XIMaskLen + import x11.XKBlib; +} + +import core.sys.posix.sys.select; + +import core.stdc.config: c_ulong, c_long; +import core.sys.posix.unistd: getpid; + +import core.stdc.string; +import core.stdc.stdio; +import core.stdc.stdlib; +import core.stdc.limits; +import core.stdc.errno; +import core.stdc.assert_; + +// Action for EWMH client messages +enum _NET_WM_STATE_REMOVE = 0; +enum _NET_WM_STATE_ADD = 1; +enum _NET_WM_STATE_TOGGLE = 2; + +// Additional mouse button names for XButtonEvent +enum Button6 = 6; +enum Button7 = 7; + +// Motif WM hints flags +enum MWM_HINTS_DECORATIONS = 2; +enum MWM_DECOR_ALL = 1; + +enum _GLFW_XDND_VERSION = 5; + + +// Wait for data to arrive using select +// This avoids blocking other threads via the per-display Xlib lock that also +// covers GLX functions +// +static GLFWbool waitForEvent(double* timeout) { + fd_set fds; + const(int) fd = ConnectionNumber(_glfw.x11.display); + int count = fd + 1; + +version (linux) { + if (_glfw.linjs.inotify > fd) + count = _glfw.linjs.inotify + 1; +} + for (;;) + { + FD_ZERO(&fds); + FD_SET(fd, &fds); +version (linux) { + if (_glfw.linjs.inotify > 0) + FD_SET(_glfw.linjs.inotify, &fds); +} + + if (timeout) + { + const(int) seconds = cast(int) *timeout; + const(int) microseconds = cast(int) ((*timeout - seconds) * 1e6); + timeval tv = timeval(seconds, microseconds); + const(ulong) base = _glfwPlatformGetTimerValue(); + + const(int) result = select(count, &fds, null, null, &tv); + const(int) error = errno; + + *timeout -= (_glfwPlatformGetTimerValue() - base) / + cast(double) _glfwPlatformGetTimerFrequency(); + + if (result > 0) + return GLFW_TRUE; + if ((result == -1 && error == EINTR) || *timeout <= 0.0) + return GLFW_FALSE; + } + else if (select(count, &fds, null, null, null) != -1 || errno != EINTR) + return GLFW_TRUE; + } +} + +// Waits until a VisibilityNotify event arrives for the specified window or the +// timeout period elapses (ICCCM section 4.2.2) +// +static GLFWbool waitForVisibilityNotify(_GLFWwindow* window) { + XEvent dummy; + double timeout = 0.1; + + while (!XCheckTypedWindowEvent(_glfw.x11.display, + window.x11.handle, + VisibilityNotify, + &dummy)) + { + if (!waitForEvent(&timeout)) + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +// Returns whether the window is iconified +// +static int getWindowState(_GLFWwindow* window) { + int result = WithdrawnState; + struct _State { + CARD32 state; + Window icon; + }_State* state = null; + + if (_glfwGetWindowPropertyX11(window.x11.handle, + _glfw.x11.WM_STATE, + _glfw.x11.WM_STATE, + cast(ubyte**) &state) >= 2) + { + result = state.state; + } + + if (state) + XFree(state); + + return result; +} + +// Returns whether the event is a selection event +// +static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer) { + if (event.xany.window != _glfw.x11.helperWindowHandle) + return False; + + return event.type == SelectionRequest || + event.type == SelectionNotify || + event.type == SelectionClear; +} + +// Returns whether it is a _NET_FRAME_EXTENTS event for the specified window +// +static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer) { + _GLFWwindow* window = cast(_GLFWwindow*) pointer; + return event.type == PropertyNotify && + event.xproperty.state == PropertyNewValue && + event.xproperty.window == window.x11.handle && + event.xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS; +} + +// Returns whether it is a property event for the specified selection transfer +// +static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer pointer) { + XEvent* notification = cast(XEvent*) pointer; + return event.type == PropertyNotify && + event.xproperty.state == PropertyNewValue && + event.xproperty.window == notification.xselection.requestor && + event.xproperty.atom == notification.xselection.property; +} + +// Translates an X event modifier state mask +// +static int translateState(int state) { + int mods = 0; + + if (state & ShiftMask) + mods |= GLFW_MOD_SHIFT; + if (state & ControlMask) + mods |= GLFW_MOD_CONTROL; + if (state & Mod1Mask) + mods |= GLFW_MOD_ALT; + if (state & Mod4Mask) + mods |= GLFW_MOD_SUPER; + if (state & LockMask) + mods |= GLFW_MOD_CAPS_LOCK; + if (state & Mod2Mask) + mods |= GLFW_MOD_NUM_LOCK; + + return mods; +} + +// Translates an X11 key code to a GLFW key token +// +static int translateKey(int scancode) { + // Use the pre-filled LUT (see createKeyTables() in x11_init.c) + if (scancode < 0 || scancode > 255) + return GLFW_KEY_UNKNOWN; + + return _glfw.x11.keycodes[scancode]; +} + +// Sends an EWMH or ICCCM event to the window manager +// +static void sendEventToWM(_GLFWwindow* window, Atom type, int a, int b, int c, int d, int e) { + XEvent event = XEvent(ClientMessage); + event.xclient.window = window.x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = type; + event.xclient.data.l[0] = a; + event.xclient.data.l[1] = b; + event.xclient.data.l[2] = c; + event.xclient.data.l[3] = d; + event.xclient.data.l[4] = e; + + XSendEvent(_glfw.x11.display, _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); +} + +// Updates the normal hints according to the window settings +// +static void updateNormalHints(_GLFWwindow* window, int width, int height) { + XSizeHints* hints = XAllocSizeHints(); + + if (!window.monitor) + { + if (window.resizable) + { + if (window.minwidth != GLFW_DONT_CARE && + window.minheight != GLFW_DONT_CARE) + { + hints.flags |= PMinSize; + hints.min_width = window.minwidth; + hints.min_height = window.minheight; + } + + if (window.maxwidth != GLFW_DONT_CARE && + window.maxheight != GLFW_DONT_CARE) + { + hints.flags |= PMaxSize; + hints.max_width = window.maxwidth; + hints.max_height = window.maxheight; + } + + if (window.numer != GLFW_DONT_CARE && + window.denom != GLFW_DONT_CARE) + { + hints.flags |= PAspect; + hints.min_aspect.x = hints.max_aspect.x = window.numer; + hints.min_aspect.y = hints.max_aspect.y = window.denom; + } + } + else + { + hints.flags |= (PMinSize | PMaxSize); + hints.min_width = hints.max_width = width; + hints.min_height = hints.max_height = height; + } + } + + hints.flags |= PWinGravity; + hints.win_gravity = StaticGravity; + + XSetWMNormalHints(_glfw.x11.display, window.x11.handle, hints); + XFree(hints); +} + +// Updates the full screen status of the window +// +static void updateWindowMode(_GLFWwindow* window) { + if (window.monitor) + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + sendEventToWM(window, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS, + window.monitor.x11.index, + window.monitor.x11.index, + window.monitor.x11.index, + window.monitor.x11.index, + 0); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + cast(int) _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + // This is the butcher's way of removing window decorations + // Setting the override-redirect attribute on a window makes the + // window manager ignore the window completely (ICCCM, section 4) + // The good thing is that this makes undecorated full screen windows + // easy to do; the bad thing is that we have to do everything + // manually and some things (like iconify/restore) won't work at + // all, as those are tasks usually performed by the window manager + + XSetWindowAttributes attributes; + attributes.override_redirect = True; + XChangeWindowAttributes(_glfw.x11.display, + window.x11.handle, + CWOverrideRedirect, + &attributes); + + window.x11.overrideRedirect = GLFW_TRUE; + } + + // Enable compositor bypass + if (!window.x11.transparent) + { + c_ulong value = 1; + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, + PropModeReplace, cast(ubyte*) &value, 1); + } + } + else + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + XDeleteProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + cast(int) _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + XSetWindowAttributes attributes; + attributes.override_redirect = False; + XChangeWindowAttributes(_glfw.x11.display, + window.x11.handle, + CWOverrideRedirect, + &attributes); + + window.x11.overrideRedirect = GLFW_FALSE; + } + + // Disable compositor bypass + if (!window.x11.transparent) + { + XDeleteProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR); + } + } +} + +// Splits and translates a text/uri-list into separate file paths +// NOTE: This function destroys the provided string +// +static char** parseUriList(char* text, int* count) { + const(char)* prefix = "file://"; + char** paths = null; + char* line; + + *count = 0; + + while (true) + { + line = strtok(text, "\r\n"); + if (!line) break; + + text = null; + + if (line[0] == '#') + continue; + + if (strncmp(line, prefix, strlen(prefix)) == 0) + { + line += strlen(prefix); + // TODO: Validate hostname + while (*line != '/') + line++; + } + + (*count)++; + + char* path = cast(char*) calloc(strlen(line) + 1, 1); + paths = cast(char**) realloc(paths, *count * (char*).sizeof); + paths[*count - 1] = path; + + while (*line) + { + if (line[0] == '%' && line[1] && line[2]) + { + const(char)[3] digits = [ line[1], line[2], '\0' ]; + *path = cast(char) strtol(digits.ptr, null, 16); + line += 2; + } + else + *path = *line; + + path++; + line++; + } + } + + return paths; +} + +// Encode a Unicode code point to a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +static size_t encodeUTF8(char* s, uint ch) { + size_t count = 0; + + if (ch < 0x80) + s[count++] = cast(char) ch; + else if (ch < 0x800) + { + s[count++] = cast(char) (ch >> 6) | 0xc0; + s[count++] = cast(char) (ch & 0x3f) | 0x80; + } + else if (ch < 0x10000) + { + s[count++] = cast(char) (ch >> 12) | 0xe0; + s[count++] = cast(char) ((ch >> 6) & 0x3f) | 0x80; + s[count++] = cast(char) (ch & 0x3f) | 0x80; + } + else if (ch < 0x110000) + { + s[count++] = cast(char) (ch >> 18) | 0xf0; + s[count++] = cast(char) ((ch >> 12) & 0x3f) | 0x80; + s[count++] = cast(char) ((ch >> 6) & 0x3f) | 0x80; + s[count++] = cast(char) (ch & 0x3f) | 0x80; + } + + return count; +} + +// Decode a Unicode code point from a UTF-8 stream +// Based on cutef8 by Jeff Bezanson (Public Domain) +// +version (X_HAVE_UTF8_STRING) { +static uint decodeUTF8(const(char)** s) { + uint ch = 0;uint count = 0; + static const(uint)* offsets = [ + 0x00000000u, 0x00003080u, 0x000e2080u, + 0x03c82080u, 0xfa082080u, 0x82082080u + ]; + + do + { + ch = (ch << 6) + cast(ubyte) **s; + (*s)++; + count++; + } while ((**s & 0xc0) == 0x80); + + assert(count <= 6); + return ch - offsets[count - 1]; +} +} /*X_HAVE_UTF8_STRING*/ + +// Convert the specified Latin-1 string to UTF-8 +// +static char* convertLatin1toUTF8(const(char)* source) { + size_t size = 1; + const(char)* sp; + + for (sp = source; *sp; sp++) + size += (*sp & 0x80) ? 2 : 1; + + char* target = cast(char*) calloc(size, 1); + char* tp = target; + + for (sp = source; *sp; sp++) + tp += encodeUTF8(tp, *sp); + + return target; +} + +// Updates the cursor image according to its cursor mode +// +static void updateCursorImage(_GLFWwindow* window) { + if (window.cursorMode == GLFW_CURSOR_NORMAL) + { + if (window.cursor) + { + XDefineCursor(_glfw.x11.display, window.x11.handle, + window.cursor.x11.handle); + } + else + XUndefineCursor(_glfw.x11.display, window.x11.handle); + } + else + { + XDefineCursor(_glfw.x11.display, window.x11.handle, + _glfw.x11.hiddenCursorHandle); + } +} + +// Enable XI2 raw mouse motion events +// +static void enableRawMouseMotion(_GLFWwindow* window) { + XIEventMask em; + ubyte[XIMaskLen(XI_RawMotion)] mask = 0; + + em.deviceid = XIAllMasterDevices; + em.mask_len = mask.length; + em.mask = mask.ptr; + //XISetMask(mask, XI_RawMotion); + em.mask[XI_RawMotion>>3] |= (1 << (XI_RawMotion & 7)); + + _glfw.x11.xi.SelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); +} + +// Disable XI2 raw mouse motion events +// +static void disableRawMouseMotion(_GLFWwindow* window) { + XIEventMask em; + ubyte[1] mask = [0]; + + em.deviceid = XIAllMasterDevices; + em.mask_len = mask.length; + em.mask = mask.ptr; + + _glfw.x11.xi.SelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); +} + +// Apply disabled cursor mode to a focused window +// +static void disableCursor(_GLFWwindow* window) { + if (window.rawMouseMotion) + enableRawMouseMotion(window); + + _glfw.x11.disabledCursorWindow = window; + _glfwPlatformGetCursorPos(window, + &_glfw.x11.restoreCursorPosX, + &_glfw.x11.restoreCursorPosY); + updateCursorImage(window); + _glfwCenterCursorInContentArea(window); + XGrabPointer(_glfw.x11.display, window.x11.handle, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + window.x11.handle, + _glfw.x11.hiddenCursorHandle, + CurrentTime); +} + +// Exit disabled cursor mode for the specified window +// +static void enableCursor(_GLFWwindow* window) { + if (window.rawMouseMotion) + disableRawMouseMotion(window); + + _glfw.x11.disabledCursorWindow = null; + XUngrabPointer(_glfw.x11.display, CurrentTime); + _glfwPlatformSetCursorPos(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); + updateCursorImage(window); +} + +// Create the X11 window (and its colormap) +// +static GLFWbool createNativeWindow(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig, Visual* visual, int depth) { + int width = wndconfig.width; + int height = wndconfig.height; + + if (wndconfig.scaleToMonitor) + { + width = cast(int) (width * _glfw.x11.contentScaleX); + height = cast(int) (height * _glfw.x11.contentScaleY); + } + + // Create a colormap based on the visual used by the current context + window.x11.colormap = XCreateColormap(_glfw.x11.display, + _glfw.x11.root, + visual, + AllocNone); + + window.x11.transparent = _glfwIsVisualTransparentX11(visual); + + XSetWindowAttributes wa = XSetWindowAttributes(0); + wa.colormap = window.x11.colormap; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask | + EnterWindowMask | LeaveWindowMask | PropertyChangeMask; + + _glfwGrabErrorHandlerX11(); + + window.x11.parent = _glfw.x11.root; + window.x11.handle = XCreateWindow(_glfw.x11.display, + _glfw.x11.root, + 0, 0, // Position + width, height, + 0, // Border width + depth, // Color depth + InputOutput, + visual, + CWBorderPixel | CWColormap | CWEventMask, + &wa); + + _glfwReleaseErrorHandlerX11(); + + if (!window.x11.handle) + { + _glfwInputErrorX11(GLFW_PLATFORM_ERROR, + "X11: Failed to create window"); + return GLFW_FALSE; + } + + XSaveContext(_glfw.x11.display, + window.x11.handle, + _glfw.x11.context, + cast(XPointer) window); + + if (!wndconfig.decorated) + _glfwPlatformSetWindowDecorated(window, GLFW_FALSE); + + if (_glfw.x11.NET_WM_STATE && !window.monitor) + { + Atom[3] states; + int count = 0; + + if (wndconfig.floating) + { + if (_glfw.x11.NET_WM_STATE_ABOVE) + states[count++] = _glfw.x11.NET_WM_STATE_ABOVE; + } + + if (wndconfig.maximized) + { + if (_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT; + states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ; + window.x11.maximized = GLFW_TRUE; + } + } + + if (count) + { + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, cast(ubyte*) states, count); + } + } + + // Declare the WM protocols supported by GLFW + { + Atom[2] protocols = [ + _glfw.x11.WM_DELETE_WINDOW, + _glfw.x11.NET_WM_PING + ]; + + XSetWMProtocols(_glfw.x11.display, window.x11.handle, + protocols.ptr, protocols.length); + } + + // Declare our PID + { + const(int) pid = getpid(); + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_PID, XA_CARDINAL, 32, + PropModeReplace, + cast(ubyte*) &pid, 1); + } + + if (_glfw.x11.NET_WM_WINDOW_TYPE && _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL) + { + Atom type = _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL; + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32, + PropModeReplace, cast(ubyte*) &type, 1); + } + + // Set ICCCM WM_HINTS property + { + XWMHints* hints = XAllocWMHints(); + if (!hints) + { + _glfwInputError(GLFW_OUT_OF_MEMORY, + "X11: Failed to allocate WM hints"); + return GLFW_FALSE; + } + + hints.flags = StateHint; + hints.initial_state = NormalState; + + XSetWMHints(_glfw.x11.display, window.x11.handle, hints); + XFree(hints); + } + + updateNormalHints(window, width, height); + + // Set ICCCM WM_CLASS property + { + XClassHint* hint = XAllocClassHint(); + + if (strlen(wndconfig.x11.instanceName.ptr) && + strlen(wndconfig.x11.className.ptr)) + { + hint.res_name = cast(char*) wndconfig.x11.instanceName; + hint.res_class = cast(char*) wndconfig.x11.className; + } + else + { + const(char)* resourceName = getenv("RESOURCE_NAME"); + if (resourceName && strlen(resourceName)) + hint.res_name = cast(char*) resourceName; + else if (strlen(wndconfig.title)) + hint.res_name = cast(char*) wndconfig.title; + else + hint.res_name = cast(char*) "glfw-application"; + + if (strlen(wndconfig.title)) + hint.res_class = cast(char*) wndconfig.title; + else + hint.res_class = cast(char*) "GLFW-Application"; + } + + XSetClassHint(_glfw.x11.display, window.x11.handle, hint); + XFree(hint); + } + + // Announce support for Xdnd (drag and drop) + { + const(Atom) version_ = _GLFW_XDND_VERSION; + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.XdndAware, XA_ATOM, 32, + PropModeReplace, cast(ubyte*) &version_, 1); + } + + _glfwPlatformSetWindowTitle(window, wndconfig.title); + + if (_glfw.x11.im) + { + window.x11.ic = XCreateIC(_glfw.x11.im, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + window.x11.handle, + XNFocusWindow, + window.x11.handle, + null); + } + + if (window.x11.ic) + { + uint filter = 0; + if (XGetICValues(window.x11.ic, XNFilterEvents, &filter, null) == null) + XSelectInput(_glfw.x11.display, window.x11.handle, wa.event_mask | filter); + } + + _glfwPlatformGetWindowPos(window, &window.x11.xpos, &window.x11.ypos); + _glfwPlatformGetWindowSize(window, &window.x11.width, &window.x11.height); + + return GLFW_TRUE; +} + +// Set the specified property to the selection converted to the requested target +// +static Atom writeTargetToProperty(const(XSelectionRequestEvent)* request) { + char* selectionString = null; + const(Atom)[2] formats = [ _glfw.x11.UTF8_STRING, XA_STRING ]; + const(int) formatCount = formats.length; //sizeof / typeof((formats[0])).sizeof; + + if (request.selection == _glfw.x11.PRIMARY) + selectionString = _glfw.x11.primarySelectionString; + else + selectionString = _glfw.x11.clipboardString; + + if (request.property == None) + { + // The requester is a legacy client (ICCCM section 2.2) + // We don't support legacy clients, so fail here + return None; + } + + if (request.target == _glfw.x11.TARGETS) + { + // The list of supported targets was requested + + const(Atom)[4] targets = [ _glfw.x11.TARGETS, + _glfw.x11.MULTIPLE, + _glfw.x11.UTF8_STRING, + XA_STRING ]; + + XChangeProperty(_glfw.x11.display, + request.requestor, + request.property, + XA_ATOM, + 32, + PropModeReplace, + cast(ubyte*) targets.ptr, + targets.sizeof / typeof(targets[0]).sizeof); + + return request.property; + } + + if (request.target == _glfw.x11.MULTIPLE) + { + // Multiple conversions were requested + + Atom* targets; + c_ulong i, count; + + count = _glfwGetWindowPropertyX11(request.requestor, + request.property, + _glfw.x11.ATOM_PAIR, + cast(ubyte**) &targets); + + for (i = 0; i < count; i += 2) + { + int j; + + for (j = 0; j < formatCount; j++) + { + if (targets[i] == formats[j]) + break; + } + + if (j < formatCount) + { + XChangeProperty(_glfw.x11.display, + request.requestor, + targets[i + 1], + targets[i], + 8, + PropModeReplace, + cast(ubyte*) selectionString, + cast(uint) strlen(selectionString)); + } + else + targets[i + 1] = None; + } + + XChangeProperty(_glfw.x11.display, + request.requestor, + request.property, + _glfw.x11.ATOM_PAIR, + 32, + PropModeReplace, + cast(ubyte*) targets, + cast(int) count); + + XFree(targets); + + return request.property; + } + + if (request.target == _glfw.x11.SAVE_TARGETS) + { + // The request is a check whether we support SAVE_TARGETS + // It should be handled as a no-op side effect target + + XChangeProperty(_glfw.x11.display, + request.requestor, + request.property, + _glfw.x11.NULL_, + 32, + PropModeReplace, + null, + 0); + + return request.property; + } + + // Conversion to a data target was requested + int i; + for (i = 0; i < formatCount; i++) + { + if (request.target == formats[i]) + { + // The requested target is one we support + + XChangeProperty(_glfw.x11.display, + request.requestor, + request.property, + request.target, + 8, + PropModeReplace, + cast(ubyte*) selectionString, + cast(uint) strlen(selectionString)); + + return request.property; + } + } + + // The requested target is not supported + + return None; +} + +static void handleSelectionClear(XEvent* event) { + if (event.xselectionclear.selection == _glfw.x11.PRIMARY) + { + free(_glfw.x11.primarySelectionString); + _glfw.x11.primarySelectionString = null; + } + else + { + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = null; + } +} + +static void handleSelectionRequest(XEvent* event) { + XSelectionRequestEvent* request = &event.xselectionrequest; + + XEvent reply = XEvent(SelectionNotify); + reply.xselection.property = writeTargetToProperty(request); + reply.xselection.display = request.display; + reply.xselection.requestor = request.requestor; + reply.xselection.selection = request.selection; + reply.xselection.target = request.target; + reply.xselection.time = request.time; + + XSendEvent(_glfw.x11.display, request.requestor, False, 0, &reply); +} + +static const(char)* getSelectionString(Atom selection) { + char** selectionString = null; + const(Atom)[2] targets = [ _glfw.x11.UTF8_STRING, XA_STRING ]; + const(size_t) targetCount = targets.length; //targets.sizeof / typeof((targets[0])).sizeof; + + if (selection == _glfw.x11.PRIMARY) + selectionString = &_glfw.x11.primarySelectionString; + else + selectionString = &_glfw.x11.clipboardString; + + if (XGetSelectionOwner(_glfw.x11.display, selection) == + _glfw.x11.helperWindowHandle) + { + // Instead of doing a large number of X round-trips just to put this + // string into a window property and then read it back, just return it + return *selectionString; + } + + free(*selectionString); + *selectionString = null; + + for (size_t i = 0; i < targetCount; i++) + { + char* data; + Atom actualType; + int actualFormat; + import core.stdc.config: c_ulong; + c_ulong itemCount;c_ulong bytesAfter; + XEvent notification;XEvent dummy; + + XConvertSelection(_glfw.x11.display, + selection, + targets[i], + _glfw.x11.GLFW_SELECTION, + _glfw.x11.helperWindowHandle, + CurrentTime); + + while (!XCheckTypedWindowEvent(_glfw.x11.display, + _glfw.x11.helperWindowHandle, + SelectionNotify, + ¬ification)) + { + waitForEvent(null); + } + + if (notification.xselection.property == None) + continue; + + XCheckIfEvent(_glfw.x11.display, + &dummy, + &isSelPropNewValueNotify, + cast(XPointer) ¬ification); + + XGetWindowProperty(_glfw.x11.display, + notification.xselection.requestor, + notification.xselection.property, + 0, + LONG_MAX, + True, + AnyPropertyType, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + cast(ubyte**) &data); + + if (actualType == _glfw.x11.INCR) + { + size_t size = 1; + char* string_ = null; + + for (;;) + { + while (!XCheckIfEvent(_glfw.x11.display, + &dummy, + &isSelPropNewValueNotify, + cast(XPointer) ¬ification)) + { + waitForEvent(null); + } + + XFree(data); + XGetWindowProperty(_glfw.x11.display, + notification.xselection.requestor, + notification.xselection.property, + 0, + LONG_MAX, + True, + AnyPropertyType, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + cast(ubyte**) &data); + + if (itemCount) + { + size += itemCount; + string_ = cast(char*) realloc(string_, size); + string_[size - itemCount - 1] = '\0'; + strcat(string_, data); + } + + if (!itemCount) + { + if (targets[i] == XA_STRING) + { + *selectionString = convertLatin1toUTF8(string_); + free(string_); + } + else + *selectionString = string_; + + break; + } + } + } + else if (actualType == targets[i]) + { + if (targets[i] == XA_STRING) + *selectionString = convertLatin1toUTF8(data); + else + *selectionString = _glfw_strdup(data); + } + + XFree(data); + + if (*selectionString) + break; + } + + if (!*selectionString) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "X11: Failed to convert selection to string"); + } + + return *selectionString; +} + +// Make the specified window and its video mode active on its monitor +// +static void acquireMonitor(_GLFWwindow* window) { + if (_glfw.x11.saver.count == 0) + { + // Remember old screen saver settings + XGetScreenSaver(_glfw.x11.display, + &_glfw.x11.saver.timeout, + &_glfw.x11.saver.interval, + &_glfw.x11.saver.blanking, + &_glfw.x11.saver.exposure); + + // Disable screen saver + XSetScreenSaver(_glfw.x11.display, 0, 0, DontPreferBlanking, + DefaultExposures); + } + + if (!window.monitor.window) + _glfw.x11.saver.count++; + + _glfwSetVideoModeX11(window.monitor, &window.videoMode); + + if (window.x11.overrideRedirect) + { + int xpos;int ypos; + GLFWvidmode mode; + + // Manually position the window over its monitor + _glfwPlatformGetMonitorPos(window.monitor, &xpos, &ypos); + _glfwPlatformGetVideoMode(window.monitor, &mode); + + XMoveResizeWindow(_glfw.x11.display, window.x11.handle, + xpos, ypos, mode.width, mode.height); + } + + _glfwInputMonitorWindow(window.monitor, window); +} + +// Remove the window and restore the original video mode +// +static void releaseMonitor(_GLFWwindow* window) { + if (window.monitor.window != window) + return; + + _glfwInputMonitorWindow(window.monitor, null); + _glfwRestoreVideoModeX11(window.monitor); + + _glfw.x11.saver.count--; + + if (_glfw.x11.saver.count == 0) + { + // Restore old screen saver settings + XSetScreenSaver(_glfw.x11.display, + _glfw.x11.saver.timeout, + _glfw.x11.saver.interval, + _glfw.x11.saver.blanking, + _glfw.x11.saver.exposure); + } +} + +// Process the specified X event +// +static void processEvent(XEvent* event) { + int keycode = 0; + Bool filtered = False; + + // HACK: Save scancode as some IMs clear the field in XFilterEvent + if (event.type == KeyPress || event.type == KeyRelease) + keycode = event.xkey.keycode; + + if (_glfw.x11.im) + filtered = XFilterEvent(event, None); + + if (_glfw.x11.randr.available) + { + if (event.type == _glfw.x11.randr.eventBase + RRNotify) + { + _glfw.x11.randr.UpdateConfiguration(event); + _glfwPollMonitorsX11(); + return; + } + } + + if (_glfw.x11.xkb.available) + { + if (event.type == _glfw.x11.xkb.eventBase + XkbEventCode) + { + if ((cast(XkbEvent*) event).any.xkb_type == XkbStateNotify && + ((cast(XkbEvent*) event).state.changed & XkbGroupStateMask)) + { + _glfw.x11.xkb.group = (cast(XkbEvent*) event).state.group; + } + } + } + + if (event.type == GenericEvent) + { + if (_glfw.x11.xi.available) + { + _GLFWwindow* window = _glfw.x11.disabledCursorWindow; + + if (window && + window.rawMouseMotion && + event.xcookie.extension == _glfw.x11.xi.majorOpcode && + XGetEventData(_glfw.x11.display, &event.xcookie) && + event.xcookie.evtype == XI_RawMotion) + { + XIRawEvent* re = cast(XIRawEvent*) event.xcookie.data; + if (re.valuators.mask_len) + { + const(double)* values = re.raw_values; + double xpos = window.virtualCursorPosX; + double ypos = window.virtualCursorPosY; + + if (XIMaskIsSet(re.valuators.mask, 0)) + { + xpos += *values; + values++; + } + + if (XIMaskIsSet(re.valuators.mask, 1)) + ypos += *values; + + _glfwInputCursorPos(window, xpos, ypos); + } + } + + XFreeEventData(_glfw.x11.display, &event.xcookie); + } + + return; + } + + if (event.type == SelectionClear) + { + handleSelectionClear(event); + return; + } + else if (event.type == SelectionRequest) + { + handleSelectionRequest(event); + return; + } + + _GLFWwindow* window = null; + if (XFindContext(_glfw.x11.display, + event.xany.window, + _glfw.x11.context, + cast(XPointer*) &window) != 0) + { + // This is an event for a window that has already been destroyed + return; + } + + switch (event.type) + { + case ReparentNotify: + { + window.x11.parent = event.xreparent.parent; + return; + } + + case KeyPress: + { + const(int) key = translateKey(keycode); + const(int) mods = translateState(event.xkey.state); + const(int) plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + + if (window.x11.ic) + { + // HACK: Ignore duplicate key press events generated by ibus + // These have the same timestamp as the original event + // Corresponding release events are filtered out + // implicitly by the GLFW key repeat logic + if (window.x11.lastKeyTime < event.xkey.time) + { + if (keycode) + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); + + window.x11.lastKeyTime = event.xkey.time; + } + + if (!filtered) + { + int count; + Status status; +version (X_HAVE_UTF8_STRING) { + char[100] buffer; + char* chars = buffer; + + count = Xutf8LookupString(window.x11.ic, + &event.xkey, + buffer, typeof((buffer) - 1).sizeof, + null, &status); + + if (status == XBufferOverflow) + { + chars = calloc(count + 1, 1); + count = Xutf8LookupString(window.x11.ic, + &event.xkey, + chars, count, + null, &status); + } + + if (status == XLookupChars || status == XLookupBoth) + { + const(char)* c = chars; + chars[count] = '\0'; + while (c - chars < count) + _glfwInputChar(window, decodeUTF8(&c), mods, plain); + } +} else { /*X_HAVE_UTF8_STRING*/ + wchar_t[16] buffer; + wchar_t* chars = buffer.ptr; + + count = XwcLookupString(window.x11.ic, + &event.xkey, + buffer.ptr, + buffer.length, + null, + &status); + + if (status == XBufferOverflow) + { + chars = cast(wchar_t*) calloc(count, wchar_t.sizeof); + count = XwcLookupString(window.x11.ic, + &event.xkey, + chars, count, + null, &status); + } + + if (status == XLookupChars || status == XLookupBoth) + { + int i; + for (i = 0; i < count; i++) + _glfwInputChar(window, chars[i], mods, plain); + } +} /*X_HAVE_UTF8_STRING*/ + + if (chars != buffer.ptr) + free(chars); + } + } + else + { + KeySym keysym; + XLookupString(&event.xkey, null, 0, &keysym, null); + + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); + + const int character = cast(int) _glfwKeySym2Unicode(cast(int) keysym); + if (character != -1) + _glfwInputChar(window, character, mods, plain); + } + + return; + } + + case KeyRelease: + { + const int key = translateKey(keycode); + const int mods = translateState(event.xkey.state); + + if (!_glfw.x11.xkb.detectable) + { + // HACK: Key repeat events will arrive as KeyRelease/KeyPress + // pairs with similar or identical time stamps + // The key repeat logic in _glfwInputKey expects only key + // presses to repeat, so detect and discard release events + if (XEventsQueued(_glfw.x11.display, QueuedAfterReading)) + { + XEvent next; + XPeekEvent(_glfw.x11.display, &next); + + if (next.type == KeyPress && + next.xkey.window == event.xkey.window && + next.xkey.keycode == keycode) + { + // HACK: The time of repeat events sometimes doesn't + // match that of the press event, so add an + // epsilon + // Toshiyuki Takahashi can press a button + // 16 times per second so it's fairly safe to + // assume that no human is pressing the key 50 + // times per second (value is ms) + if ((next.xkey.time - event.xkey.time) < 20) + { + // This is very likely a server-generated key repeat + // event, so ignore it + return; + } + } + } + } + + _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods); + return; + } + + case ButtonPress: + { + const(int) mods = translateState(event.xbutton.state); + + if (event.xbutton.button == Button1) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); + else if (event.xbutton.button == Button2) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); + else if (event.xbutton.button == Button3) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); + + // Modern X provides scroll events as mouse button presses + else if (event.xbutton.button == Button4) + _glfwInputScroll(window, 0.0, 1.0); + else if (event.xbutton.button == Button5) + _glfwInputScroll(window, 0.0, -1.0); + else if (event.xbutton.button == Button6) + _glfwInputScroll(window, 1.0, 0.0); + else if (event.xbutton.button == Button7) + _glfwInputScroll(window, -1.0, 0.0); + + else + { + // Additional buttons after 7 are treated as regular buttons + // We subtract 4 to fill the gap left by scroll input above + _glfwInputMouseClick(window, + event.xbutton.button - Button1 - 4, + GLFW_PRESS, + mods); + } + + return; + } + + case ButtonRelease: + { + const(int) mods = translateState(event.xbutton.state); + + if (event.xbutton.button == Button1) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE, + mods); + } + else if (event.xbutton.button == Button2) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_MIDDLE, + GLFW_RELEASE, + mods); + } + else if (event.xbutton.button == Button3) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE, + mods); + } + else if (event.xbutton.button > Button7) + { + // Additional buttons after 7 are treated as regular buttons + // We subtract 4 to fill the gap left by scroll input above + _glfwInputMouseClick(window, + event.xbutton.button - Button1 - 4, + GLFW_RELEASE, + mods); + } + + return; + } + + case EnterNotify: + { + // XEnterWindowEvent is XCrossingEvent + const(int) x = event.xcrossing.x; + const(int) y = event.xcrossing.y; + + // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise + // ignore the defined cursor for hidden cursor mode + if (window.cursorMode == GLFW_CURSOR_HIDDEN) + updateCursorImage(window); + + _glfwInputCursorEnter(window, GLFW_TRUE); + _glfwInputCursorPos(window, x, y); + + window.x11.lastCursorPosX = x; + window.x11.lastCursorPosY = y; + return; + } + + case LeaveNotify: + { + _glfwInputCursorEnter(window, GLFW_FALSE); + return; + } + + case MotionNotify: + { + const(int) x = event.xmotion.x; + const(int) y = event.xmotion.y; + + if (x != window.x11.warpCursorPosX || + y != window.x11.warpCursorPosY) + { + // The cursor was moved by something other than GLFW + + if (window.cursorMode == GLFW_CURSOR_DISABLED) + { + if (_glfw.x11.disabledCursorWindow != window) + return; + if (window.rawMouseMotion) + return; + + const(int) dx = x - window.x11.lastCursorPosX; + const(int) dy = y - window.x11.lastCursorPosY; + + _glfwInputCursorPos(window, + window.virtualCursorPosX + dx, + window.virtualCursorPosY + dy); + } + else + _glfwInputCursorPos(window, x, y); + } + + window.x11.lastCursorPosX = x; + window.x11.lastCursorPosY = y; + return; + } + + case ConfigureNotify: + { + if (event.xconfigure.width != window.x11.width || + event.xconfigure.height != window.x11.height) + { + _glfwInputFramebufferSize(window, + event.xconfigure.width, + event.xconfigure.height); + + _glfwInputWindowSize(window, + event.xconfigure.width, + event.xconfigure.height); + + window.x11.width = event.xconfigure.width; + window.x11.height = event.xconfigure.height; + } + + int xpos = event.xconfigure.x; + int ypos = event.xconfigure.y; + + // NOTE: ConfigureNotify events from the server are in local + // coordinates, so if we are reparented we need to translate + // the position into root (screen) coordinates + if (!event.xany.send_event && window.x11.parent != _glfw.x11.root) + { + Window dummy; + XTranslateCoordinates(_glfw.x11.display, + window.x11.parent, + _glfw.x11.root, + xpos, ypos, + &xpos, &ypos, + &dummy); + } + + if (xpos != window.x11.xpos || ypos != window.x11.ypos) + { + _glfwInputWindowPos(window, xpos, ypos); + window.x11.xpos = xpos; + window.x11.ypos = ypos; + } + + return; + } + + case ClientMessage: + { + // Custom client message, probably from the window manager + + if (filtered) + return; + + if (event.xclient.message_type == None) + return; + + if (event.xclient.message_type == _glfw.x11.WM_PROTOCOLS) + { + const(Atom) protocol = event.xclient.data.l[0]; + if (protocol == None) + return; + + if (protocol == _glfw.x11.WM_DELETE_WINDOW) + { + // The window manager was asked to close the window, for + // example by the user pressing a 'close' window decoration + // button + _glfwInputWindowCloseRequest(window); + } + else if (protocol == _glfw.x11.NET_WM_PING) + { + // The window manager is pinging the application to ensure + // it's still responding to events + + XEvent reply = *event; + reply.xclient.window = _glfw.x11.root; + + XSendEvent(_glfw.x11.display, _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &reply); + } + } + else if (event.xclient.message_type == _glfw.x11.XdndEnter) + { + // A drag operation has entered the window + uint i;uint count; + Atom* formats = null; + const(GLFWbool) list = event.xclient.data.l[1] & 1; + + _glfw.x11.xdnd.source = event.xclient.data.l[0]; + _glfw.x11.xdnd.version_ = cast(int) (event.xclient.data.l[1] >> 24); + _glfw.x11.xdnd.format = None; + + if (_glfw.x11.xdnd.version_ > _GLFW_XDND_VERSION) + return; + + if (list) + { + count = cast(int) _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source, + _glfw.x11.XdndTypeList, + XA_ATOM, + cast(ubyte**) &formats); + } + else + { + count = 3; + formats = cast(Atom*) event.xclient.data.l + 2; + } + + for (i = 0; i < count; i++) + { + if (formats[i] == _glfw.x11.text_uri_list) + { + _glfw.x11.xdnd.format = _glfw.x11.text_uri_list; + break; + } + } + + if (list && formats) + XFree(formats); + } + else if (event.xclient.message_type == _glfw.x11.XdndDrop) + { + // The drag operation has finished by dropping on the window + Time time = CurrentTime; + + if (_glfw.x11.xdnd.version_ > _GLFW_XDND_VERSION) + return; + + if (_glfw.x11.xdnd.format) + { + if (_glfw.x11.xdnd.version_ >= 1) + time = event.xclient.data.l[2]; + + // Request the chosen format from the source window + XConvertSelection(_glfw.x11.display, + _glfw.x11.XdndSelection, + _glfw.x11.xdnd.format, + _glfw.x11.XdndSelection, + window.x11.handle, + time); + } + else if (_glfw.x11.xdnd.version_ >= 2) + { + XEvent reply = XEvent(ClientMessage); + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window.x11.handle; + reply.xclient.data.l[1] = 0; // The drag was rejected + reply.xclient.data.l[2] = None; + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + } + else if (event.xclient.message_type == _glfw.x11.XdndPosition) + { + // The drag operation has moved over the window + const(int) xabs = (event.xclient.data.l[2] >> 16) & 0xffff; + const(int) yabs = (event.xclient.data.l[2]) & 0xffff; + Window dummy; + int xpos;int ypos; + + if (_glfw.x11.xdnd.version_ > _GLFW_XDND_VERSION) + return; + + XTranslateCoordinates(_glfw.x11.display, + _glfw.x11.root, + window.x11.handle, + xabs, yabs, + &xpos, &ypos, + &dummy); + + _glfwInputCursorPos(window, xpos, ypos); + + XEvent reply = XEvent(ClientMessage); + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndStatus; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window.x11.handle; + reply.xclient.data.l[2] = 0; // Specify an empty rectangle + reply.xclient.data.l[3] = 0; + + if (_glfw.x11.xdnd.format) + { + // Reply that we are ready to copy the dragged data + reply.xclient.data.l[1] = 1; // Accept with no rectangle + if (_glfw.x11.xdnd.version_ >= 2) + reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; + } + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + + return; + } + + case SelectionNotify: + { + if (event.xselection.property == _glfw.x11.XdndSelection) + { + // The converted data from the drag operation has arrived + char* data; + const(c_ulong) result = _glfwGetWindowPropertyX11(event.xselection.requestor, + event.xselection.property, + event.xselection.target, + cast(ubyte**) &data); + + if (result) + { + int i;int count; + char** paths = parseUriList(data, &count); + + _glfwInputDrop(window, count, cast(const(char)**) paths); + + for (i = 0; i < count; i++) + free(paths[i]); + free(paths); + } + + if (data) + XFree(data); + + if (_glfw.x11.xdnd.version_ >= 2) + { + XEvent reply = XEvent(ClientMessage); + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window.x11.handle; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + } + + return; + } + + case FocusIn: + { + if (event.xfocus.mode == NotifyGrab || + event.xfocus.mode == NotifyUngrab) + { + // Ignore focus events from popup indicator windows, window menu + // key chords and window dragging + return; + } + + if (window.cursorMode == GLFW_CURSOR_DISABLED) + disableCursor(window); + + if (window.x11.ic) + XSetICFocus(window.x11.ic); + + _glfwInputWindowFocus(window, GLFW_TRUE); + return; + } + + case FocusOut: + { + if (event.xfocus.mode == NotifyGrab || + event.xfocus.mode == NotifyUngrab) + { + // Ignore focus events from popup indicator windows, window menu + // key chords and window dragging + return; + } + + if (window.cursorMode == GLFW_CURSOR_DISABLED) + enableCursor(window); + + if (window.x11.ic) + XUnsetICFocus(window.x11.ic); + + if (window.monitor && window.autoIconify) + _glfwPlatformIconifyWindow(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); + return; + } + + case Expose: + { + _glfwInputWindowDamage(window); + return; + } + + case PropertyNotify: + { + if (event.xproperty.state != PropertyNewValue) + return; + + if (event.xproperty.atom == _glfw.x11.WM_STATE) + { + const(int) state = getWindowState(window); + if (state != IconicState && state != NormalState) + return; + + const(GLFWbool) iconified = (state == IconicState); + if (window.x11.iconified != iconified) + { + if (window.monitor) + { + if (iconified) + releaseMonitor(window); + else + acquireMonitor(window); + } + + window.x11.iconified = iconified; + _glfwInputWindowIconify(window, iconified); + } + } + else if (event.xproperty.atom == _glfw.x11.NET_WM_STATE) + { + const(GLFWbool) maximized = _glfwPlatformWindowMaximized(window); + if (window.x11.maximized != maximized) + { + window.x11.maximized = maximized; + _glfwInputWindowMaximize(window, maximized); + } + } + + return; + } + + case DestroyNotify: + return; + default: break; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Retrieve a single window property of the specified type +// Inspired by fghGetWindowProperty from freeglut +// +c_ulong _glfwGetWindowPropertyX11(Window window, Atom property, Atom type, ubyte** value) { + Atom actualType; + int actualFormat; + c_ulong itemCount;c_ulong bytesAfter; + + XGetWindowProperty(_glfw.x11.display, + window, + property, + 0, + LONG_MAX, + False, + type, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + value); + + return itemCount; +} + +GLFWbool _glfwIsVisualTransparentX11(Visual* visual) { + if (!_glfw.x11.xrender.available) + return GLFW_FALSE; + + XRenderPictFormat* pf = _glfw.x11.xrender.FindVisualFormat(_glfw.x11.display, visual); + return pf && pf.direct.alphaMask; +} + +// Push contents of our selection to clipboard manager +// +void _glfwPushSelectionToManagerX11() { + XConvertSelection(_glfw.x11.display, + _glfw.x11.CLIPBOARD_MANAGER, + _glfw.x11.SAVE_TARGETS, + None, + _glfw.x11.helperWindowHandle, + CurrentTime); + + for (;;) + { + XEvent event; + + while (XCheckIfEvent(_glfw.x11.display, &event, &isSelectionEvent, null)) + { + switch (event.type) + { + case SelectionRequest: + handleSelectionRequest(&event); + break; + + case SelectionClear: + handleSelectionClear(&event); + break; + + case SelectionNotify: + { + if (event.xselection.target == _glfw.x11.SAVE_TARGETS) + { + // This means one of two things; either the selection + // was not owned, which means there is no clipboard + // manager, or the transfer to the clipboard manager has + // completed + // In either case, it means we are done here + return; + } + + break; + } + default: break; + } + } + + waitForEvent(null); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, const(_GLFWwndconfig)* wndconfig, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { + Visual* visual; + int depth; + + if (ctxconfig.client != GLFW_NO_API) + { + if (ctxconfig.source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwInitGLX()) + return GLFW_FALSE; + if (!_glfwChooseVisualGLX(wndconfig, ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } + else if (ctxconfig.source == GLFW_EGL_CONTEXT_API) + { + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwChooseVisualEGL(wndconfig, ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } + else if (ctxconfig.source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + } + } + + if (ctxconfig.client == GLFW_NO_API || + ctxconfig.source == GLFW_OSMESA_CONTEXT_API) + { + visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); + depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); + } + + if (!createNativeWindow(window, wndconfig, visual, depth)) + return GLFW_FALSE; + + if (ctxconfig.client != GLFW_NO_API) + { + if (ctxconfig.source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig.source == GLFW_EGL_CONTEXT_API) + { + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else if (ctxconfig.source == GLFW_OSMESA_CONTEXT_API) + { + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + } + + if (window.monitor) + { + _glfwPlatformShowWindow(window); + updateWindowMode(window); + acquireMonitor(window); + } + + XFlush(_glfw.x11.display); + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) { + if (_glfw.x11.disabledCursorWindow == window) + _glfw.x11.disabledCursorWindow = null; + + if (window.monitor) + releaseMonitor(window); + + if (window.x11.ic) + { + XDestroyIC(window.x11.ic); + window.x11.ic = null; + } + + if (window.context.destroy) + window.context.destroy(window); + + if (window.x11.handle) + { + XDeleteContext(_glfw.x11.display, window.x11.handle, _glfw.x11.context); + XUnmapWindow(_glfw.x11.display, window.x11.handle); + XDestroyWindow(_glfw.x11.display, window.x11.handle); + window.x11.handle = cast(Window) 0; + } + + if (window.x11.colormap) + { + XFreeColormap(_glfw.x11.display, window.x11.colormap); + window.x11.colormap = cast(Colormap) 0; + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const(char)* title) { +version (X_HAVE_UTF8_STRING) { + Xutf8SetWMProperties(_glfw.x11.display, + window.x11.handle, + title, title, + null, 0, + null, null, null); +} else { + // This may be a slightly better fallback than using XStoreName and + // XSetIconName, which always store their arguments using STRING + XmbSetWMProperties(_glfw.x11.display, + window.x11.handle, + title, title, + null, 0, + null, null, null); +} + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + cast(ubyte*) title, cast(int) strlen(title)); + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + cast(ubyte*) title, cast(int) strlen(title)); + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, const(GLFWimage)* images) { + if (count) + { + int i;int j;int longCount = 0; + + for (i = 0; i < count; i++) + longCount += 2 + images[i].width * images[i].height; + + int* icon = cast(int*) calloc(longCount, long.sizeof); + int* target = icon; + + for (i = 0; i < count; i++) + { + *target++ = images[i].width; + *target++ = images[i].height; + + for (j = 0; j < images[i].width * images[i].height; j++) + { + *target++ = (images[i].pixels[j * 4 + 0] << 16) | + (images[i].pixels[j * 4 + 1] << 8) | + (images[i].pixels[j * 4 + 2] << 0) | + (images[i].pixels[j * 4 + 3] << 24); + } + } + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_ICON, + XA_CARDINAL, 32, + PropModeReplace, + cast(ubyte*) icon, + longCount); + + free(icon); + } + else + { + XDeleteProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_ICON); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { + Window dummy; + int x;int y; + + XTranslateCoordinates(_glfw.x11.display, window.x11.handle, _glfw.x11.root, + 0, 0, &x, &y, &dummy); + + if (xpos) + *xpos = x; + if (ypos) + *ypos = y; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) { + // HACK: Explicitly setting PPosition to any value causes some WMs, notably + // Compiz and Metacity, to honor the position of unmapped windows + if (!_glfwPlatformWindowVisible(window)) + { + c_long supplied; + XSizeHints* hints = XAllocSizeHints(); + + if (XGetWMNormalHints(_glfw.x11.display, window.x11.handle, hints, &supplied)) + { + hints.flags |= PPosition; + hints.x = hints.y = 0; + + XSetWMNormalHints(_glfw.x11.display, window.x11.handle, hints); + } + + XFree(hints); + } + + XMoveWindow(_glfw.x11.display, window.x11.handle, xpos, ypos); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) { + XWindowAttributes attribs; + XGetWindowAttributes(_glfw.x11.display, window.x11.handle, &attribs); + + if (width) + *width = attribs.width; + if (height) + *height = attribs.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { + if (window.monitor) + { + if (window.monitor.window == window) + acquireMonitor(window); + } + else + { + if (!window.resizable) + updateNormalHints(window, width, height); + + XResizeWindow(_glfw.x11.display, window.x11.handle, width, height); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { + int width;int height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { + int width;int height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { + int* extents = null; + + if (window.monitor || !window.decorated) + return; + + if (_glfw.x11.NET_FRAME_EXTENTS == None) + return; + + if (!_glfwPlatformWindowVisible(window) && + _glfw.x11.NET_REQUEST_FRAME_EXTENTS) + { + XEvent event; + double timeout = 0.5; + + // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to + // function before the window is mapped + sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS, + 0, 0, 0, 0, 0); + + // HACK: Use a timeout because earlier versions of some window managers + // (at least Unity, Fluxbox and Xfwm) failed to send the reply + // They have been fixed but broken versions are still in the wild + // If you are affected by this and your window manager is NOT + // listed above, PLEASE report it to their and our issue trackers + while (!XCheckIfEvent(_glfw.x11.display, + &event, + &isFrameExtentsEvent, + cast(XPointer) window)) + { + if (!waitForEvent(&timeout)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); + return; + } + } + } + + if (_glfwGetWindowPropertyX11(window.x11.handle, + _glfw.x11.NET_FRAME_EXTENTS, + XA_CARDINAL, + cast(ubyte**) &extents) == 4) + { + if (left) + *left = extents[0]; + if (top) + *top = extents[2]; + if (right) + *right = extents[1]; + if (bottom) + *bottom = extents[3]; + } + + if (extents) + XFree(extents); +} + +void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale) { + if (xscale) + *xscale = _glfw.x11.contentScaleX; + if (yscale) + *yscale = _glfw.x11.contentScaleY; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) { + if (window.x11.overrideRedirect) + { + // Override-redirect windows cannot be iconified or restored, as those + // tasks are performed by the window manager + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Iconification of full screen windows requires a WM that supports EWMH full screen"); + return; + } + + XIconifyWindow(_glfw.x11.display, window.x11.handle, _glfw.x11.screen); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) { + if (window.x11.overrideRedirect) + { + // Override-redirect windows cannot be iconified or restored, as those + // tasks are performed by the window manager + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Iconification of full screen windows requires a WM that supports EWMH full screen"); + return; + } + + if (_glfwPlatformWindowIconified(window)) + { + XMapWindow(_glfw.x11.display, window.x11.handle); + waitForVisibilityNotify(window); + } + else if (_glfwPlatformWindowVisible(window)) + { + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + cast(int) _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + cast(int) _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); + } + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) { + if (!_glfw.x11.NET_WM_STATE || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + return; + } + + if (_glfwPlatformWindowVisible(window)) + { + sendEventToWM(window, + cast(int) _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + cast(int) _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + cast(int) _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); + } + else + { + Atom* states = null; + c_ulong count = _glfwGetWindowPropertyX11(window.x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + cast(ubyte**) &states); + + // NOTE: We don't check for failure as this property may not exist yet + // and that's fine (and we'll create it implicitly with append) + + Atom[2] missing = [ + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ + ]; + uint missingCount = 2; + + for (uint i = 0; i < count; i++) + { + for (uint j = 0; j < missingCount; j++) + { + if (states[i] == missing[j]) + { + missing[j] = missing[missingCount - 1]; + missingCount--; + } + } + } + + if (states) + XFree(states); + + if (!missingCount) + return; + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeAppend, + cast(ubyte*) missing, + missingCount); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) { + if (_glfwPlatformWindowVisible(window)) + return; + + XMapWindow(_glfw.x11.display, window.x11.handle); + waitForVisibilityNotify(window); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) { + XUnmapWindow(_glfw.x11.display, window.x11.handle); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { + if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION) + return; + + sendEventToWM(window, + cast(int) _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + cast(int) _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION, + 0, 1, 0); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) { + if (_glfw.x11.NET_ACTIVE_WINDOW) + sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); + else if (_glfwPlatformWindowVisible(window)) + { + XRaiseWindow(_glfw.x11.display, window.x11.handle); + XSetInputFocus(_glfw.x11.display, window.x11.handle, + RevertToParent, CurrentTime); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { + if (window.monitor == monitor) + { + if (monitor) + { + if (monitor.window == window) + acquireMonitor(window); + } + else + { + if (!window.resizable) + updateNormalHints(window, width, height); + + XMoveResizeWindow(_glfw.x11.display, window.x11.handle, + xpos, ypos, width, height); + } + + XFlush(_glfw.x11.display); + return; + } + + if (window.monitor) + releaseMonitor(window); + + _glfwInputWindowMonitor(window, monitor); + updateNormalHints(window, width, height); + + if (window.monitor) + { + if (!_glfwPlatformWindowVisible(window)) + { + XMapRaised(_glfw.x11.display, window.x11.handle); + waitForVisibilityNotify(window); + } + + updateWindowMode(window); + acquireMonitor(window); + } + else + { + updateWindowMode(window); + XMoveResizeWindow(_glfw.x11.display, window.x11.handle, + xpos, ypos, width, height); + } + + XFlush(_glfw.x11.display); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) { + Window focused; + int state; + + XGetInputFocus(_glfw.x11.display, &focused, &state); + return window.x11.handle == focused; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) { + return getWindowState(window) == IconicState; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) { + XWindowAttributes wa; + XGetWindowAttributes(_glfw.x11.display, window.x11.handle, &wa); + return wa.map_state == IsViewable; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { + Atom* states; + uint i; + GLFWbool maximized = GLFW_FALSE; + + if (!_glfw.x11.NET_WM_STATE || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + return maximized; + } + + c_ulong count = _glfwGetWindowPropertyX11(window.x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + cast(ubyte**) &states); + + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + maximized = GLFW_TRUE; + break; + } + } + + if (states) + XFree(states); + + return maximized; +} + +int _glfwPlatformWindowHovered(_GLFWwindow* window) { + Window w = _glfw.x11.root; + while (w) + { + Window root; + int rootX;int rootY;int childX;int childY; + uint mask; + + if (!XQueryPointer(_glfw.x11.display, w, + &root, &w, &rootX, &rootY, &childX, &childY, &mask)) + { + return GLFW_FALSE; + } + + if (w == window.x11.handle) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { + if (!window.x11.transparent) + return GLFW_FALSE; + + return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None; +} + +void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) { + int width;int height; + _glfwPlatformGetWindowSize(window, &width, &height); + updateNormalHints(window, width, height); +} + +void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) { + static struct _Hints { + uint flags = 0; + uint functions = 0; + uint decorations = 0; + int input_mode = 0; + uint status = 0; + } + _Hints hints = _Hints.init; + + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = enabled ? MWM_DECOR_ALL : 0; + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.MOTIF_WM_HINTS, + _glfw.x11.MOTIF_WM_HINTS, 32, + PropModeReplace, + cast(ubyte*) &hints, + hints.sizeof / long.sizeof); +} + +void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { + if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_ABOVE) + return; + + if (_glfwPlatformWindowVisible(window)) + { + const(int) action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + sendEventToWM(window, + cast(int) _glfw.x11.NET_WM_STATE, + action, + cast(int) _glfw.x11.NET_WM_STATE_ABOVE, + 0, 1, 0); + } + else + { + Atom* states = null; + c_ulong i, count; + + count = _glfwGetWindowPropertyX11(window.x11.handle, + cast(int) _glfw.x11.NET_WM_STATE, + XA_ATOM, + cast(ubyte**) &states); + + // NOTE: We don't check for failure as this property may not exist yet + // and that's fine (and we'll create it implicitly with append) + + if (enabled) + { + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) + break; + } + + if (i < count) + return; + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeAppend, + cast(ubyte*) &_glfw.x11.NET_WM_STATE_ABOVE, + 1); + } + else if (states) + { + for (i = 0; i < count; i++) + { + if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) + break; + } + + if (i == count) + return; + + states[i] = states[count - 1]; + count--; + + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, cast(ubyte*) states, cast(int) count); + } + + if (states) + XFree(states); + } + + XFlush(_glfw.x11.display); +} + +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { + float opacity = 1.0f; + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx)) + { + CARD32* value = null; + + if (_glfwGetWindowPropertyX11(window.x11.handle, + _glfw.x11.NET_WM_WINDOW_OPACITY, + XA_CARDINAL, + cast(ubyte**) &value)) + { + opacity = cast(float) (*value / cast(double) 0xffffffffu); + } + + if (value) + XFree(value); + } + + return opacity; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) { + CARD32 value = cast(CARD32) (0xffffffffu * cast(double) opacity); + XChangeProperty(_glfw.x11.display, window.x11.handle, + _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, + PropModeReplace, cast(ubyte*) &value, 1); +} + +void _glfwPlatformSetRawMouseMotion(_GLFWwindow* window, GLFWbool enabled) { + if (!_glfw.x11.xi.available) + return; + + if (_glfw.x11.disabledCursorWindow != window) + return; + + if (enabled) + enableRawMouseMotion(window); + else + disableRawMouseMotion(window); +} + +GLFWbool _glfwPlatformRawMouseMotionSupported() { + return _glfw.x11.xi.available; +} + +void _glfwPlatformPollEvents() { + _GLFWwindow* window; + +version (linux) { + _glfwDetectJoystickConnectionLinux(); +} + XPending(_glfw.x11.display); + + while (XQLength(_glfw.x11.display)) + { + XEvent event; + XNextEvent(_glfw.x11.display, &event); + processEvent(&event); + } + + window = _glfw.x11.disabledCursorWindow; + if (window) + { + int width;int height; + _glfwPlatformGetWindowSize(window, &width, &height); + + // NOTE: Re-center the cursor only if it has moved since the last call, + // to avoid breaking glfwWaitEvents with MotionNotify + if (window.x11.lastCursorPosX != width / 2 || + window.x11.lastCursorPosY != height / 2) + { + _glfwPlatformSetCursorPos(window, width / 2, height / 2); + } + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformWaitEvents() { + while (!XPending(_glfw.x11.display)) + waitForEvent(null); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) { + while (!XPending(_glfw.x11.display)) + { + if (!waitForEvent(&timeout)) + break; + } + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent() { + XEvent event = XEvent(ClientMessage); + event.xclient.window = _glfw.x11.helperWindowHandle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NULL_; + + XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { + Window root;Window child; + int rootX;int rootY;int childX;int childY; + uint mask; + + XQueryPointer(_glfw.x11.display, window.x11.handle, + &root, &child, + &rootX, &rootY, &childX, &childY, + &mask); + + if (xpos) + *xpos = childX; + if (ypos) + *ypos = childY; +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { + // Store the new position so it can be recognized later + window.x11.warpCursorPosX = cast(int) x; + window.x11.warpCursorPosY = cast(int) y; + + XWarpPointer(_glfw.x11.display, None, window.x11.handle, + 0,0,0,0, cast(int) x, cast(int) y); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) { + if (mode == GLFW_CURSOR_DISABLED) + { + if (_glfwPlatformWindowFocused(window)) + disableCursor(window); + } + else if (_glfw.x11.disabledCursorWindow == window) + enableCursor(window); + else + updateCursorImage(window); + + XFlush(_glfw.x11.display); +} + +const(char)* _glfwPlatformGetScancodeName(int scancode) { + if (!_glfw.x11.xkb.available) + return null; + + if (scancode < 0 || scancode > 0xff || + _glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); + return null; + } + + const(int) key = _glfw.x11.keycodes[scancode]; + const(KeySym) keysym = XkbKeycodeToKeysym(_glfw.x11.display, + cast(ubyte) scancode, _glfw.x11.xkb.group, 0); + if (keysym == NoSymbol) + return null; + + const(int) ch = _glfwKeySym2Unicode(cast(int) keysym); + if (ch == -1) + return null; + + const(size_t) count = encodeUTF8(_glfw.x11.keynames[key].ptr, cast(uint) ch); + if (count == 0) + return null; + + _glfw.x11.keynames[key][count] = '\0'; + return _glfw.x11.keynames[key].ptr; +} + +int _glfwPlatformGetKeyScancode(int key) { + return _glfw.x11.scancodes[key]; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const(GLFWimage)* image, int xhot, int yhot) { + cursor.x11.handle = _glfwCreateCursorX11(image, xhot, yhot); + if (!cursor.x11.handle) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { + int native = 0; + + if (shape == GLFW_ARROW_CURSOR) + native = XC_left_ptr; + else if (shape == GLFW_IBEAM_CURSOR) + native = XC_xterm; + else if (shape == GLFW_CROSSHAIR_CURSOR) + native = XC_crosshair; + else if (shape == GLFW_HAND_CURSOR) + native = XC_hand2; + else if (shape == GLFW_HRESIZE_CURSOR) + native = XC_sb_h_double_arrow; + else if (shape == GLFW_VRESIZE_CURSOR) + native = XC_sb_v_double_arrow; + else + return GLFW_FALSE; + + cursor.x11.handle = XCreateFontCursor(_glfw.x11.display, native); + if (!cursor.x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create standard cursor"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) { + if (cursor.x11.handle) + XFreeCursor(_glfw.x11.display, cursor.x11.handle); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { + if (window.cursorMode == GLFW_CURSOR_NORMAL) + { + updateCursorImage(window); + XFlush(_glfw.x11.display); + } +} + +void _glfwPlatformSetClipboardString(const(char)* string) { + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = _glfw_strdup(string); + + XSetSelectionOwner(_glfw.x11.display, + _glfw.x11.CLIPBOARD, + _glfw.x11.helperWindowHandle, + CurrentTime); + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) != + _glfw.x11.helperWindowHandle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to become owner of clipboard selection"); + } +} + +const(char)* _glfwPlatformGetClipboardString() { + return getSelectionString(_glfw.x11.CLIPBOARD); +} + +void _glfwPlatformGetRequiredInstanceExtensions(const(char)** extensions) { + if (!_glfw.vk.KHR_surface) + return; + + if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle) + { + if (!_glfw.vk.KHR_xlib_surface) + return; + } + + extensions[0] = "VK_KHR_surface"; + + // NOTE: VK_KHR_xcb_surface is preferred due to some early ICDs exposing but + // not correctly implementing VK_KHR_xlib_surface + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + extensions[1] = "VK_KHR_xcb_surface"; + else + extensions[1] = "VK_KHR_xlib_surface"; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint queuefamily) { + VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display, + _glfw.x11.screen)); + + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + { + version (_GLFW_VULKAN_STATIC) { + PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = cast(PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); + } else { + PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = cast(PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) + _glfw.vk.GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); + } + if (!vkGetPhysicalDeviceXcbPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xcb_surface extension"); + return GLFW_FALSE; + } + + xcb_connection_t* connection = _glfw.x11.x11xcb.GetXCBConnection(_glfw.x11.display); + if (!connection) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to retrieve XCB connection"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceXcbPresentationSupportKHR(device, + queuefamily, + connection, + visualID); + } + else + { + version (_GLFW_VULKAN_STATIC) { + PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = cast(PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); + } else { + PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = cast(PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) + _glfw.vk.GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); + } + if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); + return GLFW_FALSE; + } + + return vkGetPhysicalDeviceXlibPresentationSupportKHR(device, + queuefamily, + _glfw.x11.display, + visualID); + } +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const(VkAllocationCallbacks)* allocator, VkSurfaceKHR* surface) { + if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) + { + VkResult err; + VkXcbSurfaceCreateInfoKHR sci; + PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; + + xcb_connection_t* connection = _glfw.x11.x11xcb.GetXCBConnection(_glfw.x11.display); + if (!connection) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to retrieve XCB connection"); + return VkResult.VK_ERROR_EXTENSION_NOT_PRESENT; + } + + version (_GLFW_VULKAN_STATIC) { + vkCreateXcbSurfaceKHR = cast(PFN_vkCreateXcbSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR"); + } else { + vkCreateXcbSurfaceKHR = cast(PFN_vkCreateXcbSurfaceKHR) + _glfw.vk.GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR"); + } + + if (!vkCreateXcbSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xcb_surface extension"); + return VkResult.VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, typeof(sci).sizeof); + sci.sType = VkStructureType.VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + sci.connection = connection; + sci.window = window.x11.handle; + + err = vkCreateXcbSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create Vulkan XCB surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; + } + else + { + VkResult err; + VkXlibSurfaceCreateInfoKHR sci; + PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; + + version (_GLFW_VULKAN_STATIC) { + vkCreateXlibSurfaceKHR = cast(PFN_vkCreateXlibSurfaceKHR) + vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"); + } else { + vkCreateXlibSurfaceKHR = cast(PFN_vkCreateXlibSurfaceKHR) + _glfw.vk.GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"); + } + + if (!vkCreateXlibSurfaceKHR) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Vulkan instance missing VK_KHR_xlib_surface extension"); + return VkResult.VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, typeof(sci).sizeof); + sci.sType = VkStructureType.VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + sci.dpy = _glfw.x11.display; + sci.window = window.x11.handle; + + err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface); + if (err) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create Vulkan X11 surface: %s", + _glfwGetVulkanResultString(err)); + } + + return err; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +Display* glfwGetX11Display() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return _glfw.x11.display; +} + +Window glfwGetX11Window(GLFWwindow* handle) { + _GLFWwindow* window = cast(_GLFWwindow*) handle; + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"None"); + return window.x11.handle; +} + +void glfwSetX11SelectionString(const(char)* string) { + mixin(_GLFW_REQUIRE_INIT); + + free(_glfw.x11.primarySelectionString); + _glfw.x11.primarySelectionString = _glfw_strdup(string); + + XSetSelectionOwner(_glfw.x11.display, + _glfw.x11.PRIMARY, + _glfw.x11.helperWindowHandle, + CurrentTime); + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.PRIMARY) != + _glfw.x11.helperWindowHandle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to become owner of primary selection"); + } +} + +const(char)* glfwGetX11SelectionString() { + mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); + return getSelectionString(_glfw.x11.PRIMARY); +} \ No newline at end of file diff --git a/source/glfw3/xinput.d b/source/glfw3/xinput.d new file mode 100644 index 0000000..5ae29cf --- /dev/null +++ b/source/glfw3/xinput.d @@ -0,0 +1,243 @@ +/// Translated from C to D +module glfw3.xinput; + +extern(Windows): @nogc: nothrow: __gshared: +/* + * The Wine project - Xinput Joystick Library + * Copyright 2008 Andrew Fenn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +import core.sys.windows.windef; + +/* + * Bitmasks for the joysticks buttons, determines what has + * been pressed on the joystick, these need to be mapped + * to whatever device you're using instead of an xbox 360 + * joystick + */ + +enum XINPUT_GAMEPAD_DPAD_UP = 0x0001; +enum XINPUT_GAMEPAD_DPAD_DOWN = 0x0002; +enum XINPUT_GAMEPAD_DPAD_LEFT = 0x0004; +enum XINPUT_GAMEPAD_DPAD_RIGHT = 0x0008; +enum XINPUT_GAMEPAD_START = 0x0010; +enum XINPUT_GAMEPAD_BACK = 0x0020; +enum XINPUT_GAMEPAD_LEFT_THUMB = 0x0040; +enum XINPUT_GAMEPAD_RIGHT_THUMB = 0x0080; +enum XINPUT_GAMEPAD_LEFT_SHOULDER = 0x0100; +enum XINPUT_GAMEPAD_RIGHT_SHOULDER = 0x0200; +enum XINPUT_GAMEPAD_A = 0x1000; +enum XINPUT_GAMEPAD_B = 0x2000; +enum XINPUT_GAMEPAD_X = 0x4000; +enum XINPUT_GAMEPAD_Y = 0x8000; + +/* + * Defines the flags used to determine if the user is pushing + * down on a button, not holding a button, etc + */ + +enum XINPUT_KEYSTROKE_KEYDOWN = 0x0001; +enum XINPUT_KEYSTROKE_KEYUP = 0x0002; +enum XINPUT_KEYSTROKE_REPEAT = 0x0004; + +/* + * Defines the codes which are returned by XInputGetKeystroke + */ + +enum VK_PAD_A = 0x5800; +enum VK_PAD_B = 0x5801; +enum VK_PAD_X = 0x5802; +enum VK_PAD_Y = 0x5803; +enum VK_PAD_RSHOULDER = 0x5804; +enum VK_PAD_LSHOULDER = 0x5805; +enum VK_PAD_LTRIGGER = 0x5806; +enum VK_PAD_RTRIGGER = 0x5807; +enum VK_PAD_DPAD_UP = 0x5810; +enum VK_PAD_DPAD_DOWN = 0x5811; +enum VK_PAD_DPAD_LEFT = 0x5812; +enum VK_PAD_DPAD_RIGHT = 0x5813; +enum VK_PAD_START = 0x5814; +enum VK_PAD_BACK = 0x5815; +enum VK_PAD_LTHUMB_PRESS = 0x5816; +enum VK_PAD_RTHUMB_PRESS = 0x5817; +enum VK_PAD_LTHUMB_UP = 0x5820; +enum VK_PAD_LTHUMB_DOWN = 0x5821; +enum VK_PAD_LTHUMB_RIGHT = 0x5822; +enum VK_PAD_LTHUMB_LEFT = 0x5823; +enum VK_PAD_LTHUMB_UPLEFT = 0x5824; +enum VK_PAD_LTHUMB_UPRIGHT = 0x5825; +enum VK_PAD_LTHUMB_DOWNRIGHT = 0x5826; +enum VK_PAD_LTHUMB_DOWNLEFT = 0x5827; +enum VK_PAD_RTHUMB_UP = 0x5830; +enum VK_PAD_RTHUMB_DOWN = 0x5831; +enum VK_PAD_RTHUMB_RIGHT = 0x5832; +enum VK_PAD_RTHUMB_LEFT = 0x5833; +enum VK_PAD_RTHUMB_UPLEFT = 0x5834; +enum VK_PAD_RTHUMB_UPRIGHT = 0x5835; +enum VK_PAD_RTHUMB_DOWNRIGHT = 0x5836; +enum VK_PAD_RTHUMB_DOWNLEFT = 0x5837; + +/* + * Deadzones are for analogue joystick controls on the joypad + * which determine when input should be assumed to be in the + * middle of the pad. This is a threshold to stop a joypad + * controlling the game when the player isn't touching the + * controls. + */ + +enum XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE = 7849; +enum XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE = 8689; +enum XINPUT_GAMEPAD_TRIGGER_THRESHOLD = 30; + + +/* + * Defines what type of abilities the type of joystick has + * DEVTYPE_GAMEPAD is available for all joysticks, however + * there may be more specific identifiers for other joysticks + * which are being used. + */ + +enum XINPUT_DEVTYPE_GAMEPAD = 0x01; +enum XINPUT_DEVSUBTYPE_GAMEPAD = 0x01; +enum XINPUT_DEVSUBTYPE_WHEEL = 0x02; +enum XINPUT_DEVSUBTYPE_ARCADE_STICK = 0x03; +enum XINPUT_DEVSUBTYPE_FLIGHT_SICK = 0x04; +enum XINPUT_DEVSUBTYPE_DANCE_PAD = 0x05; +enum XINPUT_DEVSUBTYPE_GUITAR = 0x06; +enum XINPUT_DEVSUBTYPE_DRUM_KIT = 0x08; + +/* + * These are used with the XInputGetCapabilities function to + * determine the abilities to the joystick which has been + * plugged in. + */ + +enum XINPUT_CAPS_VOICE_SUPPORTED = 0x0004; +enum XINPUT_FLAG_GAMEPAD = 0x00000001; + +/* + * Defines the status of the battery if one is used in the + * attached joystick. The first two define if the joystick + * supports a battery. Disconnected means that the joystick + * isn't connected. Wired shows that the joystick is a wired + * joystick. + */ + +enum BATTERY_DEVTYPE_GAMEPAD = 0x00; +enum BATTERY_DEVTYPE_HEADSET = 0x01; +enum BATTERY_TYPE_DISCONNECTED = 0x00; +enum BATTERY_TYPE_WIRED = 0x01; +enum BATTERY_TYPE_ALKALINE = 0x02; +enum BATTERY_TYPE_NIMH = 0x03; +enum BATTERY_TYPE_UNKNOWN = 0xFF; +enum BATTERY_LEVEL_EMPTY = 0x00; +enum BATTERY_LEVEL_LOW = 0x01; +enum BATTERY_LEVEL_MEDIUM = 0x02; +enum BATTERY_LEVEL_FULL = 0x03; + +/* + * How many joysticks can be used with this library. Games that + * use the xinput library will not go over this number. + */ + +enum XUSER_MAX_COUNT = 4; +enum XUSER_INDEX_ANY = 0x000000FF; + +/* + * Defines the structure of an xbox 360 joystick. + */ + +struct _XINPUT_GAMEPAD { + WORD wButtons; + BYTE bLeftTrigger; + BYTE bRightTrigger; + SHORT sThumbLX; + SHORT sThumbLY; + SHORT sThumbRX; + SHORT sThumbRY; +} +alias _XINPUT_GAMEPAD XINPUT_GAMEPAD; +alias _XINPUT_GAMEPAD* PXINPUT_GAMEPAD; + +struct _XINPUT_STATE { + DWORD dwPacketNumber; + XINPUT_GAMEPAD Gamepad; +} +alias _XINPUT_STATE XINPUT_STATE; +alias _XINPUT_STATE* PXINPUT_STATE; + +/* + * Defines the structure of how much vibration is set on both the + * right and left motors in a joystick. If you're not using a 360 + * joystick you will have to map these to your device. + */ + +struct _XINPUT_VIBRATION { + WORD wLeftMotorSpeed; + WORD wRightMotorSpeed; +} +alias _XINPUT_VIBRATION XINPUT_VIBRATION; +alias _XINPUT_VIBRATION* PXINPUT_VIBRATION; + +/* + * Defines the structure for what kind of abilities the joystick has + * such abilities are things such as if the joystick has the ability + * to send and receive audio, if the joystick is in fact a driving + * wheel or perhaps if the joystick is some kind of dance pad or + * guitar. + */ + +struct _XINPUT_CAPABILITIES { + BYTE Type; + BYTE SubType; + WORD Flags; + XINPUT_GAMEPAD Gamepad; + XINPUT_VIBRATION Vibration; +} +alias _XINPUT_CAPABILITIES XINPUT_CAPABILITIES; +alias _XINPUT_CAPABILITIES* PXINPUT_CAPABILITIES; + +/* + * Defines the structure for a joystick input event which is + * retrieved using the function XInputGetKeystroke + */ +struct _XINPUT_KEYSTROKE { + WORD VirtualKey; + WCHAR Unicode; + WORD Flags; + BYTE UserIndex; + BYTE HidCode; +} +alias _XINPUT_KEYSTROKE XINPUT_KEYSTROKE; +alias _XINPUT_KEYSTROKE* PXINPUT_KEYSTROKE; + +struct _XINPUT_BATTERY_INFORMATION { + BYTE BatteryType; + BYTE BatteryLevel; +} +alias _XINPUT_BATTERY_INFORMATION XINPUT_BATTERY_INFORMATION; +alias _XINPUT_BATTERY_INFORMATION* PXINPUT_BATTERY_INFORMATION; + +import core.sys.windows.basetyps: GUID; + +void XInputEnable(WINBOOL); +DWORD XInputSetState(DWORD, XINPUT_VIBRATION*); +DWORD XInputGetState(DWORD, XINPUT_STATE*); +DWORD XInputGetKeystroke(DWORD, DWORD, PXINPUT_KEYSTROKE); +DWORD XInputGetCapabilities(DWORD, DWORD, XINPUT_CAPABILITIES*); +DWORD XInputGetDSoundAudioDeviceGuids(DWORD, GUID*, GUID*); +DWORD XInputGetBatteryInformation(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*); diff --git a/source/glfw3/xkb_unicode.d b/source/glfw3/xkb_unicode.d new file mode 100644 index 0000000..8e976dd --- /dev/null +++ b/source/glfw3/xkb_unicode.d @@ -0,0 +1,945 @@ +/// Translated from C to D +module glfw3.xkb_unicode; + +extern(C): @nogc: nothrow: __gshared: +//======================================================================== +// GLFW 3.3 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2017 Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// It is fine to use C99 in this file because it will not be built with VS +//======================================================================== + +import glfw3.internal; + +/* + * Marcus: This code was originally written by Markus G. Kuhn. + * I have made some slight changes (trimmed it down a bit from >60 KB to + * 20 KB), but the functionality is the same. + */ + +/* + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary + * search, therefore keysymtab[] must remain SORTED by keysym value. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * Original author: Markus G. Kuhn , University of + * Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven for preparing + * an initial draft of the mapping table. + * + */ + + +//************************************************************************ +//**** KeySym to Unicode mapping table **** +//************************************************************************ + +struct codepair { + ushort keysym; + ushort ucs; +} +private alias P = codepair; + +private immutable codepair[828] keysymtab = [ + P( 0x01a1, 0x0104 ), + P( 0x01a2, 0x02d8 ), + P( 0x01a3, 0x0141 ), + P( 0x01a5, 0x013d ), + P( 0x01a6, 0x015a ), + P( 0x01a9, 0x0160 ), + P( 0x01aa, 0x015e ), + P( 0x01ab, 0x0164 ), + P( 0x01ac, 0x0179 ), + P( 0x01ae, 0x017d ), + P( 0x01af, 0x017b ), + P( 0x01b1, 0x0105 ), + P( 0x01b2, 0x02db ), + P( 0x01b3, 0x0142 ), + P( 0x01b5, 0x013e ), + P( 0x01b6, 0x015b ), + P( 0x01b7, 0x02c7 ), + P( 0x01b9, 0x0161 ), + P( 0x01ba, 0x015f ), + P( 0x01bb, 0x0165 ), + P( 0x01bc, 0x017a ), + P( 0x01bd, 0x02dd ), + P( 0x01be, 0x017e ), + P( 0x01bf, 0x017c ), + P( 0x01c0, 0x0154 ), + P( 0x01c3, 0x0102 ), + P( 0x01c5, 0x0139 ), + P( 0x01c6, 0x0106 ), + P( 0x01c8, 0x010c ), + P( 0x01ca, 0x0118 ), + P( 0x01cc, 0x011a ), + P( 0x01cf, 0x010e ), + P( 0x01d0, 0x0110 ), + P( 0x01d1, 0x0143 ), + P( 0x01d2, 0x0147 ), + P( 0x01d5, 0x0150 ), + P( 0x01d8, 0x0158 ), + P( 0x01d9, 0x016e ), + P( 0x01db, 0x0170 ), + P( 0x01de, 0x0162 ), + P( 0x01e0, 0x0155 ), + P( 0x01e3, 0x0103 ), + P( 0x01e5, 0x013a ), + P( 0x01e6, 0x0107 ), + P( 0x01e8, 0x010d ), + P( 0x01ea, 0x0119 ), + P( 0x01ec, 0x011b ), + P( 0x01ef, 0x010f ), + P( 0x01f0, 0x0111 ), + P( 0x01f1, 0x0144 ), + P( 0x01f2, 0x0148 ), + P( 0x01f5, 0x0151 ), + P( 0x01f8, 0x0159 ), + P( 0x01f9, 0x016f ), + P( 0x01fb, 0x0171 ), + P( 0x01fe, 0x0163 ), + P( 0x01ff, 0x02d9 ), + P( 0x02a1, 0x0126 ), + P( 0x02a6, 0x0124 ), + P( 0x02a9, 0x0130 ), + P( 0x02ab, 0x011e ), + P( 0x02ac, 0x0134 ), + P( 0x02b1, 0x0127 ), + P( 0x02b6, 0x0125 ), + P( 0x02b9, 0x0131 ), + P( 0x02bb, 0x011f ), + P( 0x02bc, 0x0135 ), + P( 0x02c5, 0x010a ), + P( 0x02c6, 0x0108 ), + P( 0x02d5, 0x0120 ), + P( 0x02d8, 0x011c ), + P( 0x02dd, 0x016c ), + P( 0x02de, 0x015c ), + P( 0x02e5, 0x010b ), + P( 0x02e6, 0x0109 ), + P( 0x02f5, 0x0121 ), + P( 0x02f8, 0x011d ), + P( 0x02fd, 0x016d ), + P( 0x02fe, 0x015d ), + P( 0x03a2, 0x0138 ), + P( 0x03a3, 0x0156 ), + P( 0x03a5, 0x0128 ), + P( 0x03a6, 0x013b ), + P( 0x03aa, 0x0112 ), + P( 0x03ab, 0x0122 ), + P( 0x03ac, 0x0166 ), + P( 0x03b3, 0x0157 ), + P( 0x03b5, 0x0129 ), + P( 0x03b6, 0x013c ), + P( 0x03ba, 0x0113 ), + P( 0x03bb, 0x0123 ), + P( 0x03bc, 0x0167 ), + P( 0x03bd, 0x014a ), + P( 0x03bf, 0x014b ), + P( 0x03c0, 0x0100 ), + P( 0x03c7, 0x012e ), + P( 0x03cc, 0x0116 ), + P( 0x03cf, 0x012a ), + P( 0x03d1, 0x0145 ), + P( 0x03d2, 0x014c ), + P( 0x03d3, 0x0136 ), + P( 0x03d9, 0x0172 ), + P( 0x03dd, 0x0168 ), + P( 0x03de, 0x016a ), + P( 0x03e0, 0x0101 ), + P( 0x03e7, 0x012f ), + P( 0x03ec, 0x0117 ), + P( 0x03ef, 0x012b ), + P( 0x03f1, 0x0146 ), + P( 0x03f2, 0x014d ), + P( 0x03f3, 0x0137 ), + P( 0x03f9, 0x0173 ), + P( 0x03fd, 0x0169 ), + P( 0x03fe, 0x016b ), + P( 0x047e, 0x203e ), + P( 0x04a1, 0x3002 ), + P( 0x04a2, 0x300c ), + P( 0x04a3, 0x300d ), + P( 0x04a4, 0x3001 ), + P( 0x04a5, 0x30fb ), + P( 0x04a6, 0x30f2 ), + P( 0x04a7, 0x30a1 ), + P( 0x04a8, 0x30a3 ), + P( 0x04a9, 0x30a5 ), + P( 0x04aa, 0x30a7 ), + P( 0x04ab, 0x30a9 ), + P( 0x04ac, 0x30e3 ), + P( 0x04ad, 0x30e5 ), + P( 0x04ae, 0x30e7 ), + P( 0x04af, 0x30c3 ), + P( 0x04b0, 0x30fc ), + P( 0x04b1, 0x30a2 ), + P( 0x04b2, 0x30a4 ), + P( 0x04b3, 0x30a6 ), + P( 0x04b4, 0x30a8 ), + P( 0x04b5, 0x30aa ), + P( 0x04b6, 0x30ab ), + P( 0x04b7, 0x30ad ), + P( 0x04b8, 0x30af ), + P( 0x04b9, 0x30b1 ), + P( 0x04ba, 0x30b3 ), + P( 0x04bb, 0x30b5 ), + P( 0x04bc, 0x30b7 ), + P( 0x04bd, 0x30b9 ), + P( 0x04be, 0x30bb ), + P( 0x04bf, 0x30bd ), + P( 0x04c0, 0x30bf ), + P( 0x04c1, 0x30c1 ), + P( 0x04c2, 0x30c4 ), + P( 0x04c3, 0x30c6 ), + P( 0x04c4, 0x30c8 ), + P( 0x04c5, 0x30ca ), + P( 0x04c6, 0x30cb ), + P( 0x04c7, 0x30cc ), + P( 0x04c8, 0x30cd ), + P( 0x04c9, 0x30ce ), + P( 0x04ca, 0x30cf ), + P( 0x04cb, 0x30d2 ), + P( 0x04cc, 0x30d5 ), + P( 0x04cd, 0x30d8 ), + P( 0x04ce, 0x30db ), + P( 0x04cf, 0x30de ), + P( 0x04d0, 0x30df ), + P( 0x04d1, 0x30e0 ), + P( 0x04d2, 0x30e1 ), + P( 0x04d3, 0x30e2 ), + P( 0x04d4, 0x30e4 ), + P( 0x04d5, 0x30e6 ), + P( 0x04d6, 0x30e8 ), + P( 0x04d7, 0x30e9 ), + P( 0x04d8, 0x30ea ), + P( 0x04d9, 0x30eb ), + P( 0x04da, 0x30ec ), + P( 0x04db, 0x30ed ), + P( 0x04dc, 0x30ef ), + P( 0x04dd, 0x30f3 ), + P( 0x04de, 0x309b ), + P( 0x04df, 0x309c ), + P( 0x05ac, 0x060c ), + P( 0x05bb, 0x061b ), + P( 0x05bf, 0x061f ), + P( 0x05c1, 0x0621 ), + P( 0x05c2, 0x0622 ), + P( 0x05c3, 0x0623 ), + P( 0x05c4, 0x0624 ), + P( 0x05c5, 0x0625 ), + P( 0x05c6, 0x0626 ), + P( 0x05c7, 0x0627 ), + P( 0x05c8, 0x0628 ), + P( 0x05c9, 0x0629 ), + P( 0x05ca, 0x062a ), + P( 0x05cb, 0x062b ), + P( 0x05cc, 0x062c ), + P( 0x05cd, 0x062d ), + P( 0x05ce, 0x062e ), + P( 0x05cf, 0x062f ), + P( 0x05d0, 0x0630 ), + P( 0x05d1, 0x0631 ), + P( 0x05d2, 0x0632 ), + P( 0x05d3, 0x0633 ), + P( 0x05d4, 0x0634 ), + P( 0x05d5, 0x0635 ), + P( 0x05d6, 0x0636 ), + P( 0x05d7, 0x0637 ), + P( 0x05d8, 0x0638 ), + P( 0x05d9, 0x0639 ), + P( 0x05da, 0x063a ), + P( 0x05e0, 0x0640 ), + P( 0x05e1, 0x0641 ), + P( 0x05e2, 0x0642 ), + P( 0x05e3, 0x0643 ), + P( 0x05e4, 0x0644 ), + P( 0x05e5, 0x0645 ), + P( 0x05e6, 0x0646 ), + P( 0x05e7, 0x0647 ), + P( 0x05e8, 0x0648 ), + P( 0x05e9, 0x0649 ), + P( 0x05ea, 0x064a ), + P( 0x05eb, 0x064b ), + P( 0x05ec, 0x064c ), + P( 0x05ed, 0x064d ), + P( 0x05ee, 0x064e ), + P( 0x05ef, 0x064f ), + P( 0x05f0, 0x0650 ), + P( 0x05f1, 0x0651 ), + P( 0x05f2, 0x0652 ), + P( 0x06a1, 0x0452 ), + P( 0x06a2, 0x0453 ), + P( 0x06a3, 0x0451 ), + P( 0x06a4, 0x0454 ), + P( 0x06a5, 0x0455 ), + P( 0x06a6, 0x0456 ), + P( 0x06a7, 0x0457 ), + P( 0x06a8, 0x0458 ), + P( 0x06a9, 0x0459 ), + P( 0x06aa, 0x045a ), + P( 0x06ab, 0x045b ), + P( 0x06ac, 0x045c ), + P( 0x06ae, 0x045e ), + P( 0x06af, 0x045f ), + P( 0x06b0, 0x2116 ), + P( 0x06b1, 0x0402 ), + P( 0x06b2, 0x0403 ), + P( 0x06b3, 0x0401 ), + P( 0x06b4, 0x0404 ), + P( 0x06b5, 0x0405 ), + P( 0x06b6, 0x0406 ), + P( 0x06b7, 0x0407 ), + P( 0x06b8, 0x0408 ), + P( 0x06b9, 0x0409 ), + P( 0x06ba, 0x040a ), + P( 0x06bb, 0x040b ), + P( 0x06bc, 0x040c ), + P( 0x06be, 0x040e ), + P( 0x06bf, 0x040f ), + P( 0x06c0, 0x044e ), + P( 0x06c1, 0x0430 ), + P( 0x06c2, 0x0431 ), + P( 0x06c3, 0x0446 ), + P( 0x06c4, 0x0434 ), + P( 0x06c5, 0x0435 ), + P( 0x06c6, 0x0444 ), + P( 0x06c7, 0x0433 ), + P( 0x06c8, 0x0445 ), + P( 0x06c9, 0x0438 ), + P( 0x06ca, 0x0439 ), + P( 0x06cb, 0x043a ), + P( 0x06cc, 0x043b ), + P( 0x06cd, 0x043c ), + P( 0x06ce, 0x043d ), + P( 0x06cf, 0x043e ), + P( 0x06d0, 0x043f ), + P( 0x06d1, 0x044f ), + P( 0x06d2, 0x0440 ), + P( 0x06d3, 0x0441 ), + P( 0x06d4, 0x0442 ), + P( 0x06d5, 0x0443 ), + P( 0x06d6, 0x0436 ), + P( 0x06d7, 0x0432 ), + P( 0x06d8, 0x044c ), + P( 0x06d9, 0x044b ), + P( 0x06da, 0x0437 ), + P( 0x06db, 0x0448 ), + P( 0x06dc, 0x044d ), + P( 0x06dd, 0x0449 ), + P( 0x06de, 0x0447 ), + P( 0x06df, 0x044a ), + P( 0x06e0, 0x042e ), + P( 0x06e1, 0x0410 ), + P( 0x06e2, 0x0411 ), + P( 0x06e3, 0x0426 ), + P( 0x06e4, 0x0414 ), + P( 0x06e5, 0x0415 ), + P( 0x06e6, 0x0424 ), + P( 0x06e7, 0x0413 ), + P( 0x06e8, 0x0425 ), + P( 0x06e9, 0x0418 ), + P( 0x06ea, 0x0419 ), + P( 0x06eb, 0x041a ), + P( 0x06ec, 0x041b ), + P( 0x06ed, 0x041c ), + P( 0x06ee, 0x041d ), + P( 0x06ef, 0x041e ), + P( 0x06f0, 0x041f ), + P( 0x06f1, 0x042f ), + P( 0x06f2, 0x0420 ), + P( 0x06f3, 0x0421 ), + P( 0x06f4, 0x0422 ), + P( 0x06f5, 0x0423 ), + P( 0x06f6, 0x0416 ), + P( 0x06f7, 0x0412 ), + P( 0x06f8, 0x042c ), + P( 0x06f9, 0x042b ), + P( 0x06fa, 0x0417 ), + P( 0x06fb, 0x0428 ), + P( 0x06fc, 0x042d ), + P( 0x06fd, 0x0429 ), + P( 0x06fe, 0x0427 ), + P( 0x06ff, 0x042a ), + P( 0x07a1, 0x0386 ), + P( 0x07a2, 0x0388 ), + P( 0x07a3, 0x0389 ), + P( 0x07a4, 0x038a ), + P( 0x07a5, 0x03aa ), + P( 0x07a7, 0x038c ), + P( 0x07a8, 0x038e ), + P( 0x07a9, 0x03ab ), + P( 0x07ab, 0x038f ), + P( 0x07ae, 0x0385 ), + P( 0x07af, 0x2015 ), + P( 0x07b1, 0x03ac ), + P( 0x07b2, 0x03ad ), + P( 0x07b3, 0x03ae ), + P( 0x07b4, 0x03af ), + P( 0x07b5, 0x03ca ), + P( 0x07b6, 0x0390 ), + P( 0x07b7, 0x03cc ), + P( 0x07b8, 0x03cd ), + P( 0x07b9, 0x03cb ), + P( 0x07ba, 0x03b0 ), + P( 0x07bb, 0x03ce ), + P( 0x07c1, 0x0391 ), + P( 0x07c2, 0x0392 ), + P( 0x07c3, 0x0393 ), + P( 0x07c4, 0x0394 ), + P( 0x07c5, 0x0395 ), + P( 0x07c6, 0x0396 ), + P( 0x07c7, 0x0397 ), + P( 0x07c8, 0x0398 ), + P( 0x07c9, 0x0399 ), + P( 0x07ca, 0x039a ), + P( 0x07cb, 0x039b ), + P( 0x07cc, 0x039c ), + P( 0x07cd, 0x039d ), + P( 0x07ce, 0x039e ), + P( 0x07cf, 0x039f ), + P( 0x07d0, 0x03a0 ), + P( 0x07d1, 0x03a1 ), + P( 0x07d2, 0x03a3 ), + P( 0x07d4, 0x03a4 ), + P( 0x07d5, 0x03a5 ), + P( 0x07d6, 0x03a6 ), + P( 0x07d7, 0x03a7 ), + P( 0x07d8, 0x03a8 ), + P( 0x07d9, 0x03a9 ), + P( 0x07e1, 0x03b1 ), + P( 0x07e2, 0x03b2 ), + P( 0x07e3, 0x03b3 ), + P( 0x07e4, 0x03b4 ), + P( 0x07e5, 0x03b5 ), + P( 0x07e6, 0x03b6 ), + P( 0x07e7, 0x03b7 ), + P( 0x07e8, 0x03b8 ), + P( 0x07e9, 0x03b9 ), + P( 0x07ea, 0x03ba ), + P( 0x07eb, 0x03bb ), + P( 0x07ec, 0x03bc ), + P( 0x07ed, 0x03bd ), + P( 0x07ee, 0x03be ), + P( 0x07ef, 0x03bf ), + P( 0x07f0, 0x03c0 ), + P( 0x07f1, 0x03c1 ), + P( 0x07f2, 0x03c3 ), + P( 0x07f3, 0x03c2 ), + P( 0x07f4, 0x03c4 ), + P( 0x07f5, 0x03c5 ), + P( 0x07f6, 0x03c6 ), + P( 0x07f7, 0x03c7 ), + P( 0x07f8, 0x03c8 ), + P( 0x07f9, 0x03c9 ), + P( 0x08a1, 0x23b7 ), + P( 0x08a2, 0x250c ), + P( 0x08a3, 0x2500 ), + P( 0x08a4, 0x2320 ), + P( 0x08a5, 0x2321 ), + P( 0x08a6, 0x2502 ), + P( 0x08a7, 0x23a1 ), + P( 0x08a8, 0x23a3 ), + P( 0x08a9, 0x23a4 ), + P( 0x08aa, 0x23a6 ), + P( 0x08ab, 0x239b ), + P( 0x08ac, 0x239d ), + P( 0x08ad, 0x239e ), + P( 0x08ae, 0x23a0 ), + P( 0x08af, 0x23a8 ), + P( 0x08b0, 0x23ac ), + P( 0x08bc, 0x2264 ), + P( 0x08bd, 0x2260 ), + P( 0x08be, 0x2265 ), + P( 0x08bf, 0x222b ), + P( 0x08c0, 0x2234 ), + P( 0x08c1, 0x221d ), + P( 0x08c2, 0x221e ), + P( 0x08c5, 0x2207 ), + P( 0x08c8, 0x223c ), + P( 0x08c9, 0x2243 ), + P( 0x08cd, 0x21d4 ), + P( 0x08ce, 0x21d2 ), + P( 0x08cf, 0x2261 ), + P( 0x08d6, 0x221a ), + P( 0x08da, 0x2282 ), + P( 0x08db, 0x2283 ), + P( 0x08dc, 0x2229 ), + P( 0x08dd, 0x222a ), + P( 0x08de, 0x2227 ), + P( 0x08df, 0x2228 ), + P( 0x08ef, 0x2202 ), + P( 0x08f6, 0x0192 ), + P( 0x08fb, 0x2190 ), + P( 0x08fc, 0x2191 ), + P( 0x08fd, 0x2192 ), + P( 0x08fe, 0x2193 ), + P( 0x09e0, 0x25c6 ), + P( 0x09e1, 0x2592 ), + P( 0x09e2, 0x2409 ), + P( 0x09e3, 0x240c ), + P( 0x09e4, 0x240d ), + P( 0x09e5, 0x240a ), + P( 0x09e8, 0x2424 ), + P( 0x09e9, 0x240b ), + P( 0x09ea, 0x2518 ), + P( 0x09eb, 0x2510 ), + P( 0x09ec, 0x250c ), + P( 0x09ed, 0x2514 ), + P( 0x09ee, 0x253c ), + P( 0x09ef, 0x23ba ), + P( 0x09f0, 0x23bb ), + P( 0x09f1, 0x2500 ), + P( 0x09f2, 0x23bc ), + P( 0x09f3, 0x23bd ), + P( 0x09f4, 0x251c ), + P( 0x09f5, 0x2524 ), + P( 0x09f6, 0x2534 ), + P( 0x09f7, 0x252c ), + P( 0x09f8, 0x2502 ), + P( 0x0aa1, 0x2003 ), + P( 0x0aa2, 0x2002 ), + P( 0x0aa3, 0x2004 ), + P( 0x0aa4, 0x2005 ), + P( 0x0aa5, 0x2007 ), + P( 0x0aa6, 0x2008 ), + P( 0x0aa7, 0x2009 ), + P( 0x0aa8, 0x200a ), + P( 0x0aa9, 0x2014 ), + P( 0x0aaa, 0x2013 ), + P( 0x0aae, 0x2026 ), + P( 0x0aaf, 0x2025 ), + P( 0x0ab0, 0x2153 ), + P( 0x0ab1, 0x2154 ), + P( 0x0ab2, 0x2155 ), + P( 0x0ab3, 0x2156 ), + P( 0x0ab4, 0x2157 ), + P( 0x0ab5, 0x2158 ), + P( 0x0ab6, 0x2159 ), + P( 0x0ab7, 0x215a ), + P( 0x0ab8, 0x2105 ), + P( 0x0abb, 0x2012 ), + P( 0x0abc, 0x2329 ), + P( 0x0abe, 0x232a ), + P( 0x0ac3, 0x215b ), + P( 0x0ac4, 0x215c ), + P( 0x0ac5, 0x215d ), + P( 0x0ac6, 0x215e ), + P( 0x0ac9, 0x2122 ), + P( 0x0aca, 0x2613 ), + P( 0x0acc, 0x25c1 ), + P( 0x0acd, 0x25b7 ), + P( 0x0ace, 0x25cb ), + P( 0x0acf, 0x25af ), + P( 0x0ad0, 0x2018 ), + P( 0x0ad1, 0x2019 ), + P( 0x0ad2, 0x201c ), + P( 0x0ad3, 0x201d ), + P( 0x0ad4, 0x211e ), + P( 0x0ad6, 0x2032 ), + P( 0x0ad7, 0x2033 ), + P( 0x0ad9, 0x271d ), + P( 0x0adb, 0x25ac ), + P( 0x0adc, 0x25c0 ), + P( 0x0add, 0x25b6 ), + P( 0x0ade, 0x25cf ), + P( 0x0adf, 0x25ae ), + P( 0x0ae0, 0x25e6 ), + P( 0x0ae1, 0x25ab ), + P( 0x0ae2, 0x25ad ), + P( 0x0ae3, 0x25b3 ), + P( 0x0ae4, 0x25bd ), + P( 0x0ae5, 0x2606 ), + P( 0x0ae6, 0x2022 ), + P( 0x0ae7, 0x25aa ), + P( 0x0ae8, 0x25b2 ), + P( 0x0ae9, 0x25bc ), + P( 0x0aea, 0x261c ), + P( 0x0aeb, 0x261e ), + P( 0x0aec, 0x2663 ), + P( 0x0aed, 0x2666 ), + P( 0x0aee, 0x2665 ), + P( 0x0af0, 0x2720 ), + P( 0x0af1, 0x2020 ), + P( 0x0af2, 0x2021 ), + P( 0x0af3, 0x2713 ), + P( 0x0af4, 0x2717 ), + P( 0x0af5, 0x266f ), + P( 0x0af6, 0x266d ), + P( 0x0af7, 0x2642 ), + P( 0x0af8, 0x2640 ), + P( 0x0af9, 0x260e ), + P( 0x0afa, 0x2315 ), + P( 0x0afb, 0x2117 ), + P( 0x0afc, 0x2038 ), + P( 0x0afd, 0x201a ), + P( 0x0afe, 0x201e ), + P( 0x0ba3, 0x003c ), + P( 0x0ba6, 0x003e ), + P( 0x0ba8, 0x2228 ), + P( 0x0ba9, 0x2227 ), + P( 0x0bc0, 0x00af ), + P( 0x0bc2, 0x22a5 ), + P( 0x0bc3, 0x2229 ), + P( 0x0bc4, 0x230a ), + P( 0x0bc6, 0x005f ), + P( 0x0bca, 0x2218 ), + P( 0x0bcc, 0x2395 ), + P( 0x0bce, 0x22a4 ), + P( 0x0bcf, 0x25cb ), + P( 0x0bd3, 0x2308 ), + P( 0x0bd6, 0x222a ), + P( 0x0bd8, 0x2283 ), + P( 0x0bda, 0x2282 ), + P( 0x0bdc, 0x22a2 ), + P( 0x0bfc, 0x22a3 ), + P( 0x0cdf, 0x2017 ), + P( 0x0ce0, 0x05d0 ), + P( 0x0ce1, 0x05d1 ), + P( 0x0ce2, 0x05d2 ), + P( 0x0ce3, 0x05d3 ), + P( 0x0ce4, 0x05d4 ), + P( 0x0ce5, 0x05d5 ), + P( 0x0ce6, 0x05d6 ), + P( 0x0ce7, 0x05d7 ), + P( 0x0ce8, 0x05d8 ), + P( 0x0ce9, 0x05d9 ), + P( 0x0cea, 0x05da ), + P( 0x0ceb, 0x05db ), + P( 0x0cec, 0x05dc ), + P( 0x0ced, 0x05dd ), + P( 0x0cee, 0x05de ), + P( 0x0cef, 0x05df ), + P( 0x0cf0, 0x05e0 ), + P( 0x0cf1, 0x05e1 ), + P( 0x0cf2, 0x05e2 ), + P( 0x0cf3, 0x05e3 ), + P( 0x0cf4, 0x05e4 ), + P( 0x0cf5, 0x05e5 ), + P( 0x0cf6, 0x05e6 ), + P( 0x0cf7, 0x05e7 ), + P( 0x0cf8, 0x05e8 ), + P( 0x0cf9, 0x05e9 ), + P( 0x0cfa, 0x05ea ), + P( 0x0da1, 0x0e01 ), + P( 0x0da2, 0x0e02 ), + P( 0x0da3, 0x0e03 ), + P( 0x0da4, 0x0e04 ), + P( 0x0da5, 0x0e05 ), + P( 0x0da6, 0x0e06 ), + P( 0x0da7, 0x0e07 ), + P( 0x0da8, 0x0e08 ), + P( 0x0da9, 0x0e09 ), + P( 0x0daa, 0x0e0a ), + P( 0x0dab, 0x0e0b ), + P( 0x0dac, 0x0e0c ), + P( 0x0dad, 0x0e0d ), + P( 0x0dae, 0x0e0e ), + P( 0x0daf, 0x0e0f ), + P( 0x0db0, 0x0e10 ), + P( 0x0db1, 0x0e11 ), + P( 0x0db2, 0x0e12 ), + P( 0x0db3, 0x0e13 ), + P( 0x0db4, 0x0e14 ), + P( 0x0db5, 0x0e15 ), + P( 0x0db6, 0x0e16 ), + P( 0x0db7, 0x0e17 ), + P( 0x0db8, 0x0e18 ), + P( 0x0db9, 0x0e19 ), + P( 0x0dba, 0x0e1a ), + P( 0x0dbb, 0x0e1b ), + P( 0x0dbc, 0x0e1c ), + P( 0x0dbd, 0x0e1d ), + P( 0x0dbe, 0x0e1e ), + P( 0x0dbf, 0x0e1f ), + P( 0x0dc0, 0x0e20 ), + P( 0x0dc1, 0x0e21 ), + P( 0x0dc2, 0x0e22 ), + P( 0x0dc3, 0x0e23 ), + P( 0x0dc4, 0x0e24 ), + P( 0x0dc5, 0x0e25 ), + P( 0x0dc6, 0x0e26 ), + P( 0x0dc7, 0x0e27 ), + P( 0x0dc8, 0x0e28 ), + P( 0x0dc9, 0x0e29 ), + P( 0x0dca, 0x0e2a ), + P( 0x0dcb, 0x0e2b ), + P( 0x0dcc, 0x0e2c ), + P( 0x0dcd, 0x0e2d ), + P( 0x0dce, 0x0e2e ), + P( 0x0dcf, 0x0e2f ), + P( 0x0dd0, 0x0e30 ), + P( 0x0dd1, 0x0e31 ), + P( 0x0dd2, 0x0e32 ), + P( 0x0dd3, 0x0e33 ), + P( 0x0dd4, 0x0e34 ), + P( 0x0dd5, 0x0e35 ), + P( 0x0dd6, 0x0e36 ), + P( 0x0dd7, 0x0e37 ), + P( 0x0dd8, 0x0e38 ), + P( 0x0dd9, 0x0e39 ), + P( 0x0dda, 0x0e3a ), + P( 0x0ddf, 0x0e3f ), + P( 0x0de0, 0x0e40 ), + P( 0x0de1, 0x0e41 ), + P( 0x0de2, 0x0e42 ), + P( 0x0de3, 0x0e43 ), + P( 0x0de4, 0x0e44 ), + P( 0x0de5, 0x0e45 ), + P( 0x0de6, 0x0e46 ), + P( 0x0de7, 0x0e47 ), + P( 0x0de8, 0x0e48 ), + P( 0x0de9, 0x0e49 ), + P( 0x0dea, 0x0e4a ), + P( 0x0deb, 0x0e4b ), + P( 0x0dec, 0x0e4c ), + P( 0x0ded, 0x0e4d ), + P( 0x0df0, 0x0e50 ), + P( 0x0df1, 0x0e51 ), + P( 0x0df2, 0x0e52 ), + P( 0x0df3, 0x0e53 ), + P( 0x0df4, 0x0e54 ), + P( 0x0df5, 0x0e55 ), + P( 0x0df6, 0x0e56 ), + P( 0x0df7, 0x0e57 ), + P( 0x0df8, 0x0e58 ), + P( 0x0df9, 0x0e59 ), + P( 0x0ea1, 0x3131 ), + P( 0x0ea2, 0x3132 ), + P( 0x0ea3, 0x3133 ), + P( 0x0ea4, 0x3134 ), + P( 0x0ea5, 0x3135 ), + P( 0x0ea6, 0x3136 ), + P( 0x0ea7, 0x3137 ), + P( 0x0ea8, 0x3138 ), + P( 0x0ea9, 0x3139 ), + P( 0x0eaa, 0x313a ), + P( 0x0eab, 0x313b ), + P( 0x0eac, 0x313c ), + P( 0x0ead, 0x313d ), + P( 0x0eae, 0x313e ), + P( 0x0eaf, 0x313f ), + P( 0x0eb0, 0x3140 ), + P( 0x0eb1, 0x3141 ), + P( 0x0eb2, 0x3142 ), + P( 0x0eb3, 0x3143 ), + P( 0x0eb4, 0x3144 ), + P( 0x0eb5, 0x3145 ), + P( 0x0eb6, 0x3146 ), + P( 0x0eb7, 0x3147 ), + P( 0x0eb8, 0x3148 ), + P( 0x0eb9, 0x3149 ), + P( 0x0eba, 0x314a ), + P( 0x0ebb, 0x314b ), + P( 0x0ebc, 0x314c ), + P( 0x0ebd, 0x314d ), + P( 0x0ebe, 0x314e ), + P( 0x0ebf, 0x314f ), + P( 0x0ec0, 0x3150 ), + P( 0x0ec1, 0x3151 ), + P( 0x0ec2, 0x3152 ), + P( 0x0ec3, 0x3153 ), + P( 0x0ec4, 0x3154 ), + P( 0x0ec5, 0x3155 ), + P( 0x0ec6, 0x3156 ), + P( 0x0ec7, 0x3157 ), + P( 0x0ec8, 0x3158 ), + P( 0x0ec9, 0x3159 ), + P( 0x0eca, 0x315a ), + P( 0x0ecb, 0x315b ), + P( 0x0ecc, 0x315c ), + P( 0x0ecd, 0x315d ), + P( 0x0ece, 0x315e ), + P( 0x0ecf, 0x315f ), + P( 0x0ed0, 0x3160 ), + P( 0x0ed1, 0x3161 ), + P( 0x0ed2, 0x3162 ), + P( 0x0ed3, 0x3163 ), + P( 0x0ed4, 0x11a8 ), + P( 0x0ed5, 0x11a9 ), + P( 0x0ed6, 0x11aa ), + P( 0x0ed7, 0x11ab ), + P( 0x0ed8, 0x11ac ), + P( 0x0ed9, 0x11ad ), + P( 0x0eda, 0x11ae ), + P( 0x0edb, 0x11af ), + P( 0x0edc, 0x11b0 ), + P( 0x0edd, 0x11b1 ), + P( 0x0ede, 0x11b2 ), + P( 0x0edf, 0x11b3 ), + P( 0x0ee0, 0x11b4 ), + P( 0x0ee1, 0x11b5 ), + P( 0x0ee2, 0x11b6 ), + P( 0x0ee3, 0x11b7 ), + P( 0x0ee4, 0x11b8 ), + P( 0x0ee5, 0x11b9 ), + P( 0x0ee6, 0x11ba ), + P( 0x0ee7, 0x11bb ), + P( 0x0ee8, 0x11bc ), + P( 0x0ee9, 0x11bd ), + P( 0x0eea, 0x11be ), + P( 0x0eeb, 0x11bf ), + P( 0x0eec, 0x11c0 ), + P( 0x0eed, 0x11c1 ), + P( 0x0eee, 0x11c2 ), + P( 0x0eef, 0x316d ), + P( 0x0ef0, 0x3171 ), + P( 0x0ef1, 0x3178 ), + P( 0x0ef2, 0x317f ), + P( 0x0ef3, 0x3181 ), + P( 0x0ef4, 0x3184 ), + P( 0x0ef5, 0x3186 ), + P( 0x0ef6, 0x318d ), + P( 0x0ef7, 0x318e ), + P( 0x0ef8, 0x11eb ), + P( 0x0ef9, 0x11f0 ), + P( 0x0efa, 0x11f9 ), + P( 0x0eff, 0x20a9 ), + P( 0x13a4, 0x20ac ), + P( 0x13bc, 0x0152 ), + P( 0x13bd, 0x0153 ), + P( 0x13be, 0x0178 ), + P( 0x20ac, 0x20ac ), + P( 0xfe50, '`' ), + P( 0xfe51, 0x00b4 ), + P( 0xfe52, '^' ), + P( 0xfe53, '~' ), + P( 0xfe54, 0x00af ), + P( 0xfe55, 0x02d8 ), + P( 0xfe56, 0x02d9 ), + P( 0xfe57, 0x00a8 ), + P( 0xfe58, 0x02da ), + P( 0xfe59, 0x02dd ), + P( 0xfe5a, 0x02c7 ), + P( 0xfe5b, 0x00b8 ), + P( 0xfe5c, 0x02db ), + P( 0xfe5d, 0x037a ), + P( 0xfe5e, 0x309b ), + P( 0xfe5f, 0x309c ), + P( 0xfe63, '/' ), + P( 0xfe64, 0x02bc ), + P( 0xfe65, 0x02bd ), + P( 0xfe66, 0x02f5 ), + P( 0xfe67, 0x02f3 ), + P( 0xfe68, 0x02cd ), + P( 0xfe69, 0xa788 ), + P( 0xfe6a, 0x02f7 ), + P( 0xfe6e, ',' ), + P( 0xfe6f, 0x00a4 ), + P( 0xfe80, 'a' ), // XK_dead_a + P( 0xfe81, 'A' ), // XK_dead_A + P( 0xfe82, 'e' ), // XK_dead_e + P( 0xfe83, 'E' ), // XK_dead_E + P( 0xfe84, 'i' ), // XK_dead_i + P( 0xfe85, 'I' ), // XK_dead_I + P( 0xfe86, 'o' ), // XK_dead_o + P( 0xfe87, 'O' ), // XK_dead_O + P( 0xfe88, 'u' ), // XK_dead_u + P( 0xfe89, 'U' ), // XK_dead_U + P( 0xfe8a, 0x0259 ), + P( 0xfe8b, 0x018f ), + P( 0xfe8c, 0x00b5 ), + P( 0xfe90, '_' ), + P( 0xfe91, 0x02c8 ), + P( 0xfe92, 0x02cc ), + P( 0xff80 /*XKB_KEY_KP_Space*/, ' ' ), + P( 0xff95 /*XKB_KEY_KP_7*/, 0x0037 ), + P( 0xff96 /*XKB_KEY_KP_4*/, 0x0034 ), + P( 0xff97 /*XKB_KEY_KP_8*/, 0x0038 ), + P( 0xff98 /*XKB_KEY_KP_6*/, 0x0036 ), + P( 0xff99 /*XKB_KEY_KP_2*/, 0x0032 ), + P( 0xff9a /*XKB_KEY_KP_9*/, 0x0039 ), + P( 0xff9b /*XKB_KEY_KP_3*/, 0x0033 ), + P( 0xff9c /*XKB_KEY_KP_1*/, 0x0031 ), + P( 0xff9d /*XKB_KEY_KP_5*/, 0x0035 ), + P( 0xff9e /*XKB_KEY_KP_0*/, 0x0030 ), + P( 0xffaa /*XKB_KEY_KP_Multiply*/, '*' ), + P( 0xffab /*XKB_KEY_KP_Add*/, '+' ), + P( 0xffac /*XKB_KEY_KP_Separator*/, ',' ), + P( 0xffad /*XKB_KEY_KP_Subtract*/, '-' ), + P( 0xffae /*XKB_KEY_KP_Decimal*/, '.' ), + P( 0xffaf /*XKB_KEY_KP_Divide*/, '/' ), + P( 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 ), + P( 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 ), + P( 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 ), + P( 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 ), + P( 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 ), + P( 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 ), + P( 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 ), + P( 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 ), + P( 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 ), + P( 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 ), + P( 0xffbd /*XKB_KEY_KP_Equal*/, '=' ) +]; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Convert XKB KeySym to Unicode +int _glfwKeySym2Unicode(uint keysym) { + int min = 0; + int max = keysymtab.length; + int mid; + + // First check for Latin-1 characters (1:1 mapping) + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + { + return keysym; + } + + // Also check for directly encoded 24-bit UCS characters + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + // Binary search in table + while (max >= min) + { + mid = (min + max) / 2; + if (keysymtab[mid].keysym < keysym) + min = mid + 1; + else if (keysymtab[mid].keysym > keysym) + max = mid - 1; + else + return keysymtab[mid].ucs; + } + + // No matching Unicode value found + return -1; +} \ No newline at end of file