summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Hashimoto <m@mitchellh.com>2025-03-13 21:18:41 -0700
committerGitHub <noreply@github.com>2025-03-13 21:18:41 -0700
commit8eacde92e6b63924f4d6c5392fd2a31af248381f (patch)
treef606b6838675576de5e0577318a6d8bcce5f9afc
parent73c7943fff38f679a9a434457b5089bc5722411d (diff)
parent221f905a1c5332a96f04918ea87d1c85a05af035 (diff)
Replace mach-glfw with pkg/glfw (#6708)
Closes #6702 This removes our mach-glfw dependency and replaces it with an in-tree pkg/glfw that includes both the source for compiling glfw as well as the Zig bindings. This matches the pattern from our other packages. This is based on the upstream mach-glfw work and therefore includes the original license and copyright information. The reasoning is stated in the issue but to summarize for the commit: - mach-glfw is no longer maintained, so we have to take ownership - mach-glfw depended on some large blobs of header files to enable cross-compilation but this isn't something we actually care about, so we can (and do) drop the blobs - mach-glfw blobs were hosted on mach hosts. given mach-glfw is unmaintained, we can't rely on this hosting - mach-glfw relied on a "glfw" package which was owned by another person to be Zig 0.14 compatible, but we no longer need to rely on this - mach-glfw builds were outdated based on latest Zig practices
-rw-r--r--.gitattributes1
-rw-r--r--.github/workflows/test.yml88
-rw-r--r--build.zig.zon7
-rw-r--r--build.zig.zon.nix56
-rw-r--r--build.zig.zon.txt9
-rw-r--r--build.zig.zon2json-lock35
-rw-r--r--nix/devShell.nix3
-rw-r--r--pkg/glfw/Cursor.zig209
-rw-r--r--pkg/glfw/GammaRamp.zig74
-rw-r--r--pkg/glfw/Image.zig82
-rw-r--r--pkg/glfw/Joystick.zig642
-rw-r--r--pkg/glfw/LICENSE26
-rw-r--r--pkg/glfw/Monitor.zig599
-rw-r--r--pkg/glfw/VideoMode.zig50
-rw-r--r--pkg/glfw/Window.zig3551
-rw-r--r--pkg/glfw/action.zig13
-rw-r--r--pkg/glfw/allocator.zig143
-rw-r--r--pkg/glfw/build.zig272
-rw-r--r--pkg/glfw/build.zig.zon15
-rw-r--r--pkg/glfw/c.zig6
-rw-r--r--pkg/glfw/clipboard.zig71
-rw-r--r--pkg/glfw/errors.zig338
-rw-r--r--pkg/glfw/gamepad_axis.zig16
-rw-r--r--pkg/glfw/gamepad_button.zig37
-rw-r--r--pkg/glfw/hat.zig100
-rw-r--r--pkg/glfw/internal_debug.zig14
-rw-r--r--pkg/glfw/key.zig266
-rw-r--r--pkg/glfw/main.zig586
-rw-r--r--pkg/glfw/mod.zig167
-rw-r--r--pkg/glfw/mouse_button.zig23
-rw-r--r--pkg/glfw/native.zig393
-rw-r--r--pkg/glfw/opengl.zig256
-rw-r--r--pkg/glfw/shims.zig84
-rw-r--r--pkg/glfw/time.zig153
-rw-r--r--pkg/glfw/version.zig18
-rw-r--r--pkg/glfw/vulkan.zig290
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-client-protocol-code.h524
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-idle-inhibit-unstable-v1-client-protocol-code.h68
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-idle-inhibit-unstable-v1-client-protocol.h232
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-pointer-constraints-unstable-v1-client-protocol-code.h108
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-pointer-constraints-unstable-v1-client-protocol.h667
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-relative-pointer-unstable-v1-client-protocol-code.h79
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-relative-pointer-unstable-v1-client-protocol.h297
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-viewporter-client-protocol-code.h74
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-viewporter-client-protocol.h398
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-xdg-decoration-client-protocol-code.h75
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-xdg-decoration-client-protocol.h378
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-xdg-shell-client-protocol-code.h183
-rwxr-xr-xpkg/glfw/wayland-headers/wayland-xdg-shell-client-protocol.h2307
-rw-r--r--src/build/Config.zig9
-rw-r--r--src/build/SharedDeps.zig11
51 files changed, 13979 insertions, 124 deletions
diff --git a/.gitattributes b/.gitattributes
index 7e39ed959..f9ed139eb 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -5,6 +5,7 @@ vendor/** linguist-vendored
website/** linguist-documentation
pkg/breakpad/vendor/** linguist-vendored
pkg/cimgui/vendor/** linguist-vendored
+pkg/glfw/wayland-headers/** linguist-vendored
pkg/libintl/config.h linguist-generated=true
pkg/libintl/libintl.h linguist-generated=true
pkg/simdutf/vendor/** linguist-vendored
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index bd9b26414..55a6a1732 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -10,14 +10,15 @@ jobs:
name: "Required Checks: Test"
runs-on: namespace-profile-ghostty-sm
needs:
- - build
- build-bench
+ - build-linux
- build-linux-libghostty
- build-nix
- build-snap
- build-macos
- build-macos-matrix
- build-windows
+ - build-windows-cross
- test
- test-gtk
- test-sentry-linux
@@ -48,23 +49,9 @@ jobs:
echo "One or more required build workflows failed: ${{ steps.status.outputs.results }}"
exit 1
- build:
- strategy:
- fail-fast: false
- matrix:
- os: ["namespace-profile-ghostty-md"]
-
- target: [
- aarch64-linux,
- x86_64-linux,
- x86-windows-gnu,
- x86_64-windows-gnu,
- # We don't support cross-compiling to macOS because the macOS build
- # requires xcode due to the swift harness.
- #aarch64-macos,
- #x86_64-macos,
- ]
- runs-on: ${{ matrix.os }}
+ build-bench:
+ # We build benchmarks on large because it uses ReleaseFast
+ runs-on: namespace-profile-ghostty-lg
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
@@ -89,14 +76,15 @@ jobs:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- # Cross-compile the binary. We always use static building for this
- # because its the only way to access the headers.
- - name: Test Build
- run: nix develop -c zig build -Dapp-runtime=glfw -Dtarget=${{ matrix.target }}
+ - name: Build Benchmarks
+ run: nix develop -c zig build -Dapp-runtime=glfw -Demit-bench
- build-bench:
- # We build benchmarks on large because it uses ReleaseFast
- runs-on: namespace-profile-ghostty-lg
+ build-linux:
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [namespace-profile-ghostty-md, namespace-profile-ghostty-md-arm64]
+ runs-on: ${{ matrix.os }}
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
@@ -121,8 +109,8 @@ jobs:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- - name: Build Benchmarks
- run: nix develop -c zig build -Dapp-runtime=glfw -Demit-bench
+ - name: Test Build
+ run: nix develop -c zig build -Dapp-runtime=glfw
build-linux-libghostty:
runs-on: namespace-profile-ghostty-md
@@ -373,6 +361,52 @@ jobs:
shell: pwsh
run: Get-Content -Path ".\build.log"
+ build-windows-cross:
+ strategy:
+ fail-fast: false
+ matrix:
+ os: ["namespace-profile-ghostty-md"]
+
+ target: [
+ x86-windows-gnu,
+ x86_64-windows-gnu,
+ # We don't support cross-compiling to macOS or Linux because
+ # we require system libraries.
+ #aarch64-linux,
+ #x86_64-linux,
+ #aarch64-macos,
+ #x86_64-macos,
+ ]
+ runs-on: ${{ matrix.os }}
+ needs: test
+ env:
+ ZIG_LOCAL_CACHE_DIR: /zig/local-cache
+ ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Cache
+ uses: namespacelabs/nscloud-cache-action@v1.2.0
+ with:
+ path: |
+ /nix
+ /zig
+
+ # Install Nix and use that to run our tests so our environment matches exactly.
+ - uses: cachix/install-nix-action@v30
+ with:
+ nix_path: nixpkgs=channel:nixos-unstable
+ - uses: cachix/cachix-action@v15
+ with:
+ name: ghostty
+ authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
+
+ # Cross-compile the binary. We always use static building for this
+ # because its the only way to access the headers.
+ - name: Test Build
+ run: nix develop -c zig build -Dapp-runtime=glfw -Dtarget=${{ matrix.target }}
+
test:
if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-md
diff --git a/build.zig.zon b/build.zig.zon
index 5c13e4dcf..9a14ce919 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -11,12 +11,6 @@
.url = "https://github.com/mitchellh/libxev/archive/3df9337a9e84450a58a2c4af434ec1a036f7b494.tar.gz",
.hash = "libxev-0.0.0-86vtc-ziEgDbLP0vihUn1MhsxNKY4GJEga6BEr7oyHpz",
},
- .mach_glfw = .{
- // mitchellh/mach-glfw
- .url = "https://github.com/mitchellh/mach-glfw/archive/d84bc11b0601cdad71035a0e9cf21572d76aa0d2.zip",
- .hash = "mach_glfw-0.2.0-EJSQm2M9BQCiYGTd9VcKjg2DhSD7WT4kS-MfX68ORRT_",
- .lazy = true,
- },
.vaxis = .{
// rockorager/libvaxis
.url = "git+https://github.com/rockorager/libvaxis#1e24e0dfb509e974e1c8713bcd119d0ae032a8c7",
@@ -62,6 +56,7 @@
.cimgui = .{ .path = "./pkg/cimgui" },
.fontconfig = .{ .path = "./pkg/fontconfig" },
.freetype = .{ .path = "./pkg/freetype" },
+ .glfw = .{ .path = "./pkg/glfw" },
.gtk4_layer_shell = .{ .path = "./pkg/gtk4-layer-shell" },
.harfbuzz = .{ .path = "./pkg/harfbuzz" },
.highway = .{ .path = "./pkg/highway" },
diff --git a/build.zig.zon.nix b/build.zig.zon.nix
index 3f29ad693..9d7e94b40 100644
--- a/build.zig.zon.nix
+++ b/build.zig.zon.nix
@@ -92,54 +92,6 @@ in
};
}
{
- name = "mach_glfw-0.2.0-EJSQm2M9BQCiYGTd9VcKjg2DhSD7WT4kS-MfX68ORRT_";
- path = fetchZigArtifact {
- name = "mach_glfw";
- url = "https://github.com/mitchellh/mach-glfw/archive/d84bc11b0601cdad71035a0e9cf21572d76aa0d2.zip";
- hash = "sha256-Sh1DvCmawdN+a2JEhNP3wTX43/i5FDlDVOIx7Um/d0U=";
- };
- }
- {
- name = "glfw-0.0.0-bOgnngiqGQCt5HJK25zx1lf9emPYDNtEuQPYmrTCdOoN";
- path = fetchZigArtifact {
- name = "glfw";
- url = "git+https://github.com/der-teufel-programming/glfw.git#206deaa2485703ac700d0f3020a8854282aecdbb";
- hash = "sha256-GFeN4J4ZpKvQV8Gw6fxJ+KSpzzdjIYBbO/fTZ0Ooiuk=";
- };
- }
- {
- name = "N-V-__8AABHMqAWYuRdIlflwi8gksPnlUMQBiSxAqQAAZFms";
- path = fetchZigArtifact {
- name = "xcode_frameworks";
- url = "https://pkg.machengine.org/xcode-frameworks/9a45f3ac977fd25dff77e58c6de1870b6808c4a7.tar.gz";
- hash = "sha256-jWMT0p7klpkgX9GOUNAhrR2e6Ej7MobbqT5ZxJrNQoM=";
- };
- }
- {
- name = "N-V-__8AAAIGzwDju1iAEUEqIbBeI3K4JhQ0vBdNzmETnIRQ";
- path = fetchZigArtifact {
- name = "vulkan_headers";
- url = "https://pkg.machengine.org/vulkan-headers/53e3ee66a78b97075863135b429956f225b149a5.tar.gz";
- hash = "sha256-kXOn43ntsvxnufobQO0xfzg1cg0R97BmFOU3WRqFsH0=";
- };
- }
- {
- name = "N-V-__8AAJfbCQBWPD1WA6AuYSk8LAIj4Bo_KY-2Br8NEIKT";
- path = fetchZigArtifact {
- name = "wayland_headers";
- url = "https://pkg.machengine.org/wayland-headers/7c53e7483c3cfb5c6780ae542c9f5cfa712a826a.tar.gz";
- hash = "sha256-uGIvMyp+xR1jQXTDr6RqYl40Ukiw9l3fW1t6XpYztPY=";
- };
- }
- {
- name = "N-V-__8AACbnQQDnnaLV79Xp3YtkU_g6nseVNOLiA7MzF2a4";
- path = fetchZigArtifact {
- name = "x11_headers";
- url = "https://pkg.machengine.org/x11-headers/29aefb525d5c08b05b0351e34b1623854a138c21.tar.gz";
- hash = "sha256-UsbWkOmedS4ygY9C1g7OiPVnTcXzfGKdXImmztYAAiI=";
- };
- }
- {
name = "vaxis-0.1.0-BWNV_MHyCAARemSCSwwc3sA1etNgv7ge0BCIXspX6CZv";
path = fetchZigArtifact {
name = "vaxis";
@@ -308,6 +260,14 @@ in
};
}
{
+ name = "N-V-__8AADTkRwBjUvVwTLOnV96QhN0J5Nyg7YzvnISe-Eax";
+ path = fetchZigArtifact {
+ name = "glfw";
+ url = "https://github.com/glfw/glfw/archive/73948e6c0f15b1053cf74b7c4e6b04fd36e97e29.zip";
+ hash = "sha256-k7wBKiQpgxBhqHRwSEgZjmfncltlGG8BgY3FhyycM5E=";
+ };
+ }
+ {
name = "N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr";
path = fetchZigArtifact {
name = "gtk4_layer_shell";
diff --git a/build.zig.zon.txt b/build.zig.zon.txt
index fb71f4a7a..2279552d7 100644
--- a/build.zig.zon.txt
+++ b/build.zig.zon.txt
@@ -1,8 +1,7 @@
git+https://codeberg.org/atman/zg#4a002763419a34d61dcbb1f415821b83b9bf8ddc
-git+https://github.com/TUSF/zigimg#5102e09be233d372e9e05f4cb2ffbefba30bc1c0
-git+https://github.com/der-teufel-programming/glfw.git#206deaa2485703ac700d0f3020a8854282aecdbb
git+https://github.com/rockorager/libvaxis#1e24e0dfb509e974e1c8713bcd119d0ae032a8c7
git+https://github.com/rockorager/libvaxis/?ref=main#6a37605dde55898dcca4769dd3eb1e333959c209
+git+https://github.com/TUSF/zigimg#5102e09be233d372e9e05f4cb2ffbefba30bc1c0
https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz
https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz
https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz
@@ -27,14 +26,10 @@ https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d6
https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz
https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
+https://github.com/glfw/glfw/archive/73948e6c0f15b1053cf74b7c4e6b04fd36e97e29.zip
https://github.com/jcollie/ghostty-gobject/releases/download/0.14.0-2025-03-11-16-1/ghostty-gobject-0.14.0-2025-03-11-16-1.tar.gz
https://github.com/mbadolato/iTerm2-Color-Schemes/archive/e21d5ffd19605741d0e3e19d7c5a8c6c25648673.tar.gz
https://github.com/mitchellh/libxev/archive/3df9337a9e84450a58a2c4af434ec1a036f7b494.tar.gz
-https://github.com/mitchellh/mach-glfw/archive/d84bc11b0601cdad71035a0e9cf21572d76aa0d2.zip
https://github.com/mitchellh/zig-objc/archive/3ab0d37c7d6b933d6ded1b3a35b6b60f05590a98.tar.gz
https://github.com/natecraddock/zf/archive/03176fcf23fda543cc02a8675e92c1fe3b1ee2eb.tar.gz
https://github.com/vancluever/z2d/archive/1e89605a624940c310c7a1d81b46a7c5c05919e3.tar.gz
-https://pkg.machengine.org/vulkan-headers/53e3ee66a78b97075863135b429956f225b149a5.tar.gz
-https://pkg.machengine.org/wayland-headers/7c53e7483c3cfb5c6780ae542c9f5cfa712a826a.tar.gz
-https://pkg.machengine.org/x11-headers/29aefb525d5c08b05b0351e34b1623854a138c21.tar.gz
-https://pkg.machengine.org/xcode-frameworks/9a45f3ac977fd25dff77e58c6de1870b6808c4a7.tar.gz
diff --git a/build.zig.zon2json-lock b/build.zig.zon2json-lock
index 74fa1c12a..5170d698c 100644
--- a/build.zig.zon2json-lock
+++ b/build.zig.zon2json-lock
@@ -4,36 +4,6 @@
"url": "https://github.com/mitchellh/libxev/archive/3df9337a9e84450a58a2c4af434ec1a036f7b494.tar.gz",
"hash": "sha256-oKZqA9d79jHnp/HsqJWQE33Ffn5Ee5G4VnlQepQuY4o="
},
- "mach_glfw-0.2.0-EJSQm2M9BQCiYGTd9VcKjg2DhSD7WT4kS-MfX68ORRT_": {
- "name": "mach_glfw",
- "url": "https://github.com/mitchellh/mach-glfw/archive/d84bc11b0601cdad71035a0e9cf21572d76aa0d2.zip",
- "hash": "sha256-Sh1DvCmawdN+a2JEhNP3wTX43/i5FDlDVOIx7Um/d0U="
- },
- "glfw-0.0.0-bOgnngiqGQCt5HJK25zx1lf9emPYDNtEuQPYmrTCdOoN": {
- "name": "glfw",
- "url": "git+https://github.com/der-teufel-programming/glfw.git#206deaa2485703ac700d0f3020a8854282aecdbb",
- "hash": "sha256-GFeN4J4ZpKvQV8Gw6fxJ+KSpzzdjIYBbO/fTZ0Ooiuk="
- },
- "N-V-__8AABHMqAWYuRdIlflwi8gksPnlUMQBiSxAqQAAZFms": {
- "name": "xcode_frameworks",
- "url": "https://pkg.machengine.org/xcode-frameworks/9a45f3ac977fd25dff77e58c6de1870b6808c4a7.tar.gz",
- "hash": "sha256-jWMT0p7klpkgX9GOUNAhrR2e6Ej7MobbqT5ZxJrNQoM="
- },
- "N-V-__8AAAIGzwDju1iAEUEqIbBeI3K4JhQ0vBdNzmETnIRQ": {
- "name": "vulkan_headers",
- "url": "https://pkg.machengine.org/vulkan-headers/53e3ee66a78b97075863135b429956f225b149a5.tar.gz",
- "hash": "sha256-kXOn43ntsvxnufobQO0xfzg1cg0R97BmFOU3WRqFsH0="
- },
- "N-V-__8AAJfbCQBWPD1WA6AuYSk8LAIj4Bo_KY-2Br8NEIKT": {
- "name": "wayland_headers",
- "url": "https://pkg.machengine.org/wayland-headers/7c53e7483c3cfb5c6780ae542c9f5cfa712a826a.tar.gz",
- "hash": "sha256-uGIvMyp+xR1jQXTDr6RqYl40Ukiw9l3fW1t6XpYztPY="
- },
- "N-V-__8AACbnQQDnnaLV79Xp3YtkU_g6nseVNOLiA7MzF2a4": {
- "name": "x11_headers",
- "url": "https://pkg.machengine.org/x11-headers/29aefb525d5c08b05b0351e34b1623854a138c21.tar.gz",
- "hash": "sha256-UsbWkOmedS4ygY9C1g7OiPVnTcXzfGKdXImmztYAAiI="
- },
"vaxis-0.1.0-BWNV_MHyCAARemSCSwwc3sA1etNgv7ge0BCIXspX6CZv": {
"name": "vaxis",
"url": "git+https://github.com/rockorager/libvaxis#1e24e0dfb509e974e1c8713bcd119d0ae032a8c7",
@@ -139,6 +109,11 @@
"url": "https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz",
"hash": "sha256-bCgFni4+60K1tLFkieORamNGwQladP7jvGXNxdiaYhU="
},
+ "N-V-__8AADTkRwBjUvVwTLOnV96QhN0J5Nyg7YzvnISe-Eax": {
+ "name": "glfw",
+ "url": "https://github.com/glfw/glfw/archive/73948e6c0f15b1053cf74b7c4e6b04fd36e97e29.zip",
+ "hash": "sha256-k7wBKiQpgxBhqHRwSEgZjmfncltlGG8BgY3FhyycM5E="
+ },
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
"name": "gtk4_layer_shell",
"url": "https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz",
diff --git a/nix/devShell.nix b/nix/devShell.nix
index 67821f896..c6cb84abf 100644
--- a/nix/devShell.nix
+++ b/nix/devShell.nix
@@ -41,6 +41,7 @@
harfbuzz,
libpng,
libGL,
+ libxkbcommon,
libX11,
libXcursor,
libXext,
@@ -83,6 +84,7 @@
glslang
spirv-cross
+ libxkbcommon
libX11
libXcursor
libXi
@@ -162,6 +164,7 @@ in
glslang
spirv-cross
+ libxkbcommon
libX11
libXcursor
libXext
diff --git a/pkg/glfw/Cursor.zig b/pkg/glfw/Cursor.zig
new file mode 100644
index 000000000..cd79e8848
--- /dev/null
+++ b/pkg/glfw/Cursor.zig
@@ -0,0 +1,209 @@
+//! Represents a cursor and provides facilities for setting cursor images.
+
+const std = @import("std");
+const testing = std.testing;
+
+const c = @import("c.zig").c;
+const Image = @import("Image.zig");
+
+const internal_debug = @import("internal_debug.zig");
+
+const Cursor = @This();
+
+ptr: *c.GLFWcursor,
+
+/// Standard system cursor shapes.
+///
+/// These are the standard cursor shapes that can be requested from the platform (window system).
+pub const Shape = enum(i32) {
+ /// The regular arrow cursor shape.
+ arrow = c.GLFW_ARROW_CURSOR,
+
+ /// The text input I-beam cursor shape.
+ ibeam = c.GLFW_IBEAM_CURSOR,
+
+ /// The crosshair cursor shape.
+ crosshair = c.GLFW_CROSSHAIR_CURSOR,
+
+ /// The pointing hand cursor shape.
+ ///
+ /// NOTE: This supersedes the old `hand` enum.
+ pointing_hand = c.GLFW_POINTING_HAND_CURSOR,
+
+ /// The horizontal resize/move arrow shape.
+ ///
+ /// The horizontal resize/move arrow shape. This is usually a horizontal double-headed arrow.
+ //
+ // NOTE: This supersedes the old `hresize` enum.
+ resize_ew = c.GLFW_RESIZE_EW_CURSOR,
+
+ /// The vertical resize/move arrow shape.
+ ///
+ /// The vertical resize/move shape. This is usually a vertical double-headed arrow.
+ ///
+ /// NOTE: This supersedes the old `vresize` enum.
+ resize_ns = c.GLFW_RESIZE_NS_CURSOR,
+
+ /// The top-left to bottom-right diagonal resize/move arrow shape.
+ ///
+ /// The top-left to bottom-right diagonal resize/move shape. This is usually a diagonal
+ /// double-headed arrow.
+ ///
+ /// macos: This shape is provided by a private system API and may fail CursorUnavailable in the
+ /// future.
+ ///
+ /// x11: This shape is provided by a newer standard not supported by all cursor themes.
+ ///
+ /// wayland: This shape is provided by a newer standard not supported by all cursor themes.
+ resize_nwse = c.GLFW_RESIZE_NWSE_CURSOR,
+
+ /// The top-right to bottom-left diagonal resize/move arrow shape.
+ ///
+ /// The top-right to bottom-left diagonal resize/move shape. This is usually a diagonal
+ /// double-headed arrow.
+ ///
+ /// macos: This shape is provided by a private system API and may fail with CursorUnavailable
+ /// in the future.
+ ///
+ /// x11: This shape is provided by a newer standard not supported by all cursor themes.
+ ///
+ /// wayland: This shape is provided by a newer standard not supported by all cursor themes.
+ resize_nesw = c.GLFW_RESIZE_NESW_CURSOR,
+
+ /// The omni-directional resize/move cursor shape.
+ ///
+ /// The omni-directional resize cursor/move shape. This is usually either a combined horizontal
+ /// and vertical double-headed arrow or a grabbing hand.
+ resize_all = c.GLFW_RESIZE_ALL_CURSOR,
+
+ /// The operation-not-allowed shape.
+ ///
+ /// The operation-not-allowed shape. This is usually a circle with a diagonal line through it.
+ ///
+ /// x11: This shape is provided by a newer standard not supported by all cursor themes.
+ ///
+ /// wayland: This shape is provided by a newer standard not supported by all cursor themes.
+ not_allowed = c.GLFW_NOT_ALLOWED_CURSOR,
+};
+
+/// Creates a custom cursor.
+///
+/// Creates a new custom cursor image that can be set for a window with glfw.Cursor.set. The cursor
+/// can be destroyed with glfwCursor.destroy. Any remaining cursors are destroyed by glfw.terminate.
+///
+/// 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.
+///
+/// @param[in] image The desired cursor image.
+/// @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot.
+/// @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot.
+/// @return The handle of the created cursor.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError and glfw.ErrorCode.InvalidValue
+/// null is returned in the event of an 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.
+///
+/// see also: cursor_object, glfw.Cursor.destroy, glfw.Cursor.createStandard
+pub inline fn create(image: Image, xhot: i32, yhot: i32) ?Cursor {
+ internal_debug.assertInitialized();
+ const img = image.toC();
+ if (c.glfwCreateCursor(&img, @as(c_int, @intCast(xhot)), @as(c_int, @intCast(yhot)))) |cursor| return Cursor{ .ptr = cursor };
+ return null;
+}
+
+/// Creates a cursor with a standard shape.
+///
+/// Returns a cursor with a standard shape, that can be set for a window with glfw.Window.setCursor.
+/// The images for these cursors come from the system cursor theme and their exact appearance will
+/// vary between platforms.
+///
+/// Most of these shapes are guaranteed to exist on every supported platform but a few may not be
+/// present. See the table below for details.
+///
+/// | Cursor shape | Windows | macOS | X11 | Wayland |
+/// |------------------|---------|-----------------|-------------------|-------------------|
+/// | `.arrow` | Yes | Yes | Yes | Yes |
+/// | `.ibeam` | Yes | Yes | Yes | Yes |
+/// | `.crosshair` | Yes | Yes | Yes | Yes |
+/// | `.pointing_hand` | Yes | Yes | Yes | Yes |
+/// | `.resize_ew` | Yes | Yes | Yes | Yes |
+/// | `.resize_ns` | Yes | Yes | Yes | Yes |
+/// | `.resize_nwse` | Yes | Yes<sup>1</sup> | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
+/// | `.resize_nesw` | Yes | Yes<sup>1</sup> | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
+/// | `.resize_all` | Yes | Yes | Yes | Yes |
+/// | `.not_allowed` | Yes | Yes | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
+///
+/// 1. This uses a private system API and may fail in the future.
+/// 2. This uses a newer standard that not all cursor themes support.
+///
+/// If the requested shape is not available, this function emits a CursorUnavailable error
+/// Possible errors include glfw.ErrorCode.PlatformError and glfw.ErrorCode.CursorUnavailable.
+/// null is returned in the event of an error.
+///
+/// thread_safety: This function must only be called from the main thread.
+///
+/// see also: cursor_object, glfwCreateCursor
+pub inline fn createStandard(shape: Shape) ?Cursor {
+ internal_debug.assertInitialized();
+ if (c.glfwCreateStandardCursor(@as(c_int, @intCast(@intFromEnum(shape))))) |cursor| return Cursor{ .ptr = cursor };
+ return null;
+}
+
+/// Destroys a cursor.
+///
+/// This function destroys a cursor previously created with glfw.Cursor.create. Any remaining
+/// cursors will be destroyed by glfw.terminate.
+///
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @reentrancy This function must not be called from a callback.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: cursor_object, glfw.createCursor
+pub inline fn destroy(self: Cursor) void {
+ internal_debug.assertInitialized();
+ c.glfwDestroyCursor(self.ptr);
+}
+
+test "create" {
+ const allocator = testing.allocator;
+
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const image = try Image.init(allocator, 32, 32, 32 * 32 * 4);
+ defer image.deinit(allocator);
+
+ const cursor = glfw.Cursor.create(image, 0, 0);
+ if (cursor) |cur| cur.destroy();
+}
+
+test "createStandard" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const cursor = glfw.Cursor.createStandard(.ibeam);
+ if (cursor) |cur| cur.destroy();
+}
diff --git a/pkg/glfw/GammaRamp.zig b/pkg/glfw/GammaRamp.zig
new file mode 100644
index 000000000..7b5a1c3fd
--- /dev/null
+++ b/pkg/glfw/GammaRamp.zig
@@ -0,0 +1,74 @@
+//! Gamma ramp for monitors and related functions.
+//!
+//! It may be .owned (e.g. in the case of a gamma ramp initialized by you for passing into
+//! glfw.Monitor.setGammaRamp) or not .owned (e.g. in the case of one gotten via
+//! glfw.Monitor.getGammaRamp.) If it is .owned, deinit should be called to free the memory. It is
+//! safe to call deinit even if not .owned.
+//!
+//! see also: monitor_gamma, glfw.Monitor.getGammaRamp
+
+const std = @import("std");
+const testing = std.testing;
+const mem = std.mem;
+const c = @import("c.zig").c;
+
+const GammaRamp = @This();
+
+red: []u16,
+green: []u16,
+blue: []u16,
+owned: ?[]u16,
+
+/// Initializes a new owned gamma ramp with the given array size and undefined values.
+///
+/// see also: glfw.Monitor.getGammaRamp
+pub inline fn init(allocator: mem.Allocator, size: usize) !GammaRamp {
+ const buf = try allocator.alloc(u16, size * 3);
+ return GammaRamp{
+ .red = buf[size * 0 .. (size * 0) + size],
+ .green = buf[size * 1 .. (size * 1) + size],
+ .blue = buf[size * 2 .. (size * 2) + size],
+ .owned = buf,
+ };
+}
+
+/// Turns a GLFW / C gamma ramp into the nicer Zig type, and sets `.owned = false`.
+///
+/// The returned memory is valid for as long as the GLFW C memory is valid.
+pub inline fn fromC(native: c.GLFWgammaramp) GammaRamp {
+ return GammaRamp{
+ .red = native.red[0..native.size],
+ .green = native.green[0..native.size],
+ .blue = native.blue[0..native.size],
+ .owned = null,
+ };
+}
+
+/// Turns the nicer Zig type into a GLFW / C gamma ramp, for passing into GLFW C functions.
+///
+/// The returned memory is valid for as long as the Zig memory is valid.
+pub inline fn toC(self: GammaRamp) c.GLFWgammaramp {
+ std.debug.assert(self.red.len == self.green.len);
+ std.debug.assert(self.red.len == self.blue.len);
+ return c.GLFWgammaramp{
+ .red = &self.red[0],
+ .green = &self.green[0],
+ .blue = &self.blue[0],
+ .size = @as(c_uint, @intCast(self.red.len)),
+ };
+}
+
+/// Deinitializes the memory using the allocator iff `.owned = true`.
+pub inline fn deinit(self: GammaRamp, allocator: mem.Allocator) void {
+ if (self.owned) |buf| allocator.free(buf);
+}
+
+test "conversion" {
+ const allocator = testing.allocator;
+
+ const ramp = try GammaRamp.init(allocator, 256);
+ defer ramp.deinit(allocator);
+
+ const glfw = ramp.toC();
+ _ = GammaRamp.fromC(glfw);
+}
diff --git a/pkg/glfw/Image.zig b/pkg/glfw/Image.zig
new file mode 100644
index 000000000..d32e5c310
--- /dev/null
+++ b/pkg/glfw/Image.zig
@@ -0,0 +1,82 @@
+//! Image data
+//!
+//!
+//! This describes a single 2D image. See the documentation for each related function what the
+//! expected pixel format is.
+//!
+//! see also: cursor_custom, window_icon
+//!
+//! It may be .owned (e.g. in the case of an image initialized by you for passing into glfw) or not
+//! .owned (e.g. in the case of one gotten via glfw) If it is .owned, deinit should be called to
+//! free the memory. It is safe to call deinit even if not .owned.
+
+const std = @import("std");
+const testing = std.testing;
+const mem = std.mem;
+const c = @import("c.zig").c;
+
+const Image = @This();
+
+/// The width of this image, in pixels.
+width: u32,
+
+/// The height of this image, in pixels.
+height: u32,
+
+/// The pixel data of this image, arranged left-to-right, top-to-bottom.
+pixels: []u8,
+
+/// Whether or not the pixels data is owned by you (true) or GLFW (false).
+owned: bool,
+
+/// Initializes a new owned image with the given size and pixel_data_len of undefined .pixel values.
+pub inline fn init(allocator: mem.Allocator, width: u32, height: u32, pixel_data_len: usize) !Image {
+ const buf = try allocator.alloc(u8, pixel_data_len);
+ return Image{
+ .width = width,
+ .height = height,
+ .pixels = buf,
+ .owned = true,
+ };
+}
+
+/// Turns a GLFW / C image into the nicer Zig type, and sets `.owned = false`.
+///
+/// The length of pixel data must be supplied, as GLFW's image type does not itself describe the
+/// number of bytes required per pixel / the length of the pixel data array.
+///
+/// The returned memory is valid for as long as the GLFW C memory is valid.
+pub inline fn fromC(native: c.GLFWimage, pixel_data_len: usize) Image {
+ return Image{
+ .width = @as(u32, @intCast(native.width)),
+ .height = @as(u32, @intCast(native.height)),
+ .pixels = native.pixels[0..pixel_data_len],
+ .owned = false,
+ };
+}
+
+/// Turns the nicer Zig type into a GLFW / C image, for passing into GLFW C functions.
+///
+/// The returned memory is valid for as long as the Zig memory is valid.
+pub inline fn toC(self: Image) c.GLFWimage {
+ return c.GLFWimage{
+ .width = @as(c_int, @intCast(self.width)),
+ .height = @as(c_int, @intCast(self.height)),
+ .pixels = &self.pixels[0],
+ };
+}
+
+/// Deinitializes the memory using the allocator iff `.owned = true`.
+pub inline fn deinit(self: Image, allocator: mem.Allocator) void {
+ if (self.owned) allocator.free(self.pixels);
+}
+
+test "conversion" {
+ const allocator = testing.allocator;
+
+ const image = try Image.init(allocator, 256, 256, 256 * 256 * 4);
+ defer image.deinit(allocator);
+
+ const glfw = image.toC();
+ _ = Image.fromC(glfw, image.width * image.height * 4);
+}
diff --git a/pkg/glfw/Joystick.zig b/pkg/glfw/Joystick.zig
new file mode 100644
index 000000000..dd55c731d
--- /dev/null
+++ b/pkg/glfw/Joystick.zig
@@ -0,0 +1,642 @@
+//! Represents a Joystick or gamepad
+//!
+//! It can be manually crafted via e.g. `glfw.Joystick{.jid = .one}`, but more
+//! typically you'll want to discover the joystick using `glfw.Joystick.setCallback`.
+
+const std = @import("std");
+
+const c = @import("c.zig").c;
+const Window = @import("Window.zig");
+const Action = @import("action.zig").Action;
+const GamepadAxis = @import("gamepad_axis.zig").GamepadAxis;
+const GamepadButton = @import("gamepad_button.zig").GamepadButton;
+const Hat = @import("hat.zig").Hat;
+
+const internal_debug = @import("internal_debug.zig");
+
+const Joystick = @This();
+
+/// The GLFW joystick ID.
+jid: Id,
+
+/// Joystick IDs.
+///
+/// See glfw.Joystick.setCallback for how these are used.
+pub const Id = enum(c_int) {
+ one = c.GLFW_JOYSTICK_1,
+ two = c.GLFW_JOYSTICK_2,
+ three = c.GLFW_JOYSTICK_3,
+ four = c.GLFW_JOYSTICK_4,
+ five = c.GLFW_JOYSTICK_5,
+ six = c.GLFW_JOYSTICK_6,
+ seven = c.GLFW_JOYSTICK_7,
+ eight = c.GLFW_JOYSTICK_8,
+ nine = c.GLFW_JOYSTICK_9,
+ ten = c.GLFW_JOYSTICK_10,
+ eleven = c.GLFW_JOYSTICK_11,
+ twelve = c.GLFW_JOYSTICK_12,
+ thirteen = c.GLFW_JOYSTICK_13,
+ fourteen = c.GLFW_JOYSTICK_14,
+ fifteen = c.GLFW_JOYSTICK_15,
+ sixteen = c.GLFW_JOYSTICK_16,
+ pub const last = @as(@This(), @enumFromInt(c.GLFW_JOYSTICK_LAST));
+};
+
+/// Gamepad input state
+///
+/// This describes the input state of a gamepad.
+///
+/// see also: gamepad, glfwGetGamepadState
+const GamepadState = extern struct {
+ /// The states of each gamepad button (see gamepad_buttons), `glfw.Action.press` or `glfw.Action.release`.
+ ///
+ /// Use the enumeration helper e.g. `.getButton(.dpad_up)` to access these indices.
+ buttons: [15]u8,
+
+ /// The states of each gamepad axis (see gamepad_axes), in the range -1.0 to 1.0 inclusive.
+ ///
+ /// Use the enumeration helper e.g. `.getAxis(.left_x)` to access these indices.
+ axes: [6]f32,
+
+ /// Returns the state of the specified gamepad button.
+ pub fn getButton(self: @This(), which: GamepadButton) Action {
+ return @as(Action, @enumFromInt(self.buttons[@as(u32, @intCast(@intFromEnum(which)))]));
+ }
+
+ /// Returns the status of the specified gamepad axis, in the range -1.0 to 1.0 inclusive.
+ pub fn getAxis(self: @This(), which: GamepadAxis) f32 {
+ return self.axes[@as(u32, @intCast(@intFromEnum(which)))];
+ }
+};
+
+/// 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.
+///
+/// @return `true` if the joystick is present, or `false` otherwise.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: joystick
+pub inline fn present(self: Joystick) bool {
+ internal_debug.assertInitialized();
+ const is_present = c.glfwJoystickPresent(@intFromEnum(self.jid));
+ return is_present == c.GLFW_TRUE;
+}
+
+/// 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 glfw.Joystick.present.
+///
+/// @return An array of axis values, or null if the joystick is not present.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
+/// null is additionally returned in the event of an 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.
+///
+/// see also: joystick_axis
+/// Replaces `glfwGetJoystickPos`.
+pub inline fn getAxes(self: Joystick) ?[]const f32 {
+ internal_debug.assertInitialized();
+ var count: c_int = undefined;
+ const axes = c.glfwGetJoystickAxes(@intFromEnum(self.jid), &count);
+ if (axes == null) return null;
+ return axes[0..@as(u32, @intCast(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.Action.press` or `glfw.Action.release`.
+///
+/// For backward compatibility with earlier versions that did not have glfw.Joystick.getHats, the
+/// button array also includes all hats, each represented as four buttons. The hats are in the same
+/// order as returned by glfw.Joystick.getHats and are in the order _up_, _right_, _down_ and
+/// _left_. To disable these extra buttons, set the 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 glfw.Joystick.present.
+///
+/// @return An array of button states, or null if the joystick is not present.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
+/// null is additionally returned in the event of an 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.
+///
+/// see also: joystick_button
+pub inline fn getButtons(self: Joystick) ?[]const u8 {
+ internal_debug.assertInitialized();
+ var count: c_int = undefined;
+ const buttons = c.glfwGetJoystickButtons(@intFromEnum(self.jid), &count);
+ if (buttons == null) return null;
+ return buttons[0..@as(u32, @intCast(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.RawHats.centered` | 0 |
+/// | `glfw.RawHats.up` | 1 |
+/// | `glfw.RawHats.right` | 2 |
+/// | `glfw.RawHats.down` | 4 |
+/// | `glfw.RawHats.left` | 8 |
+/// | `glfw.RawHats.right_up` | `glfw.RawHats.right` \| `glfw.RawHats.up` |
+/// | `glfw.RawHats.right_down` | `glfw.RawHats.right` \| `glfw.RawHats.down` |
+/// | `glfw.RawHats.left_up` | `glfw.RawHats.left` \| `glfw.RawHats.up` |
+/// | `glfw.RawHats.left_down` | `glfw.RawHats.left` \| `glfw.RawHats.down` |
+///
+/// The diagonal directions are bitwise combinations of the primary (up, right, down and left)
+/// directions, since the Zig GLFW wrapper returns a packed struct it is trivial to test for these:
+///
+/// ```
+/// if (hats.up and hats.right) {
+/// // up-right!
+/// }
+/// ```
+///
+/// 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 glfw.Joystick.present.
+///
+/// @return An array of hat states, or null if the joystick is not present.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
+/// null is additionally returned in the event of an 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.
+///
+/// see also: joystick_hat
+pub inline fn getHats(self: Joystick) ?[]const Hat {
+ internal_debug.assertInitialized();
+ var count: c_int = undefined;
+ const hats = c.glfwGetJoystickHats(@intFromEnum(self.jid), &count);
+ if (hats == null) return null;
+ const slice = hats[0..@as(u32, @intCast(count))];
+ return @as(*const []const Hat, @ptrCast(&slice)).*;
+}
+
+/// 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 glfw.Joystick.present.
+///
+/// @return The UTF-8 encoded name of the joystick, or null if the joystick is not present or an
+/// error occurred.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
+/// null is additionally returned in the event of an 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.
+///
+/// see also: joystick_name
+pub inline fn getName(self: Joystick) ?[:0]const u8 {
+ internal_debug.assertInitialized();
+ const name_opt = c.glfwGetJoystickName(@intFromEnum(self.jid));
+ return if (name_opt) |name|
+ std.mem.span(@as([*:0]const u8, @ptrCast(name)))
+ else
+ null;
+}
+
+/// 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 glfw.Joystick.present.
+///
+/// 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.
+///
+/// @return The UTF-8 encoded GUID of the joystick, or null if the joystick is not present.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
+/// null is additionally returned in the event of an 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.
+///
+/// see also: gamepad
+pub inline fn getGUID(self: Joystick) ?[:0]const u8 {
+ internal_debug.assertInitialized();
+ const guid_opt = c.glfwGetJoystickGUID(@intFromEnum(self.jid));
+ return if (guid_opt) |guid|
+ std.mem.span(@as([*:0]const u8, @ptrCast(guid)))
+ else
+ null;
+}
+
+/// 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.
+///
+/// @thread_safety This function may be called from any thread. Access is not synchronized.
+///
+/// see also: joystick_userptr, glfw.Joystick.getUserPointer
+pub inline fn setUserPointer(self: Joystick, comptime T: type, pointer: *T) void {
+ internal_debug.assertInitialized();
+ c.glfwSetJoystickUserPointer(@intFromEnum(self.jid), @as(*anyopaque, @ptrCast(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.
+///
+/// @thread_safety This function may be called from any thread. Access is not synchronized.
+///
+/// see also: joystick_userptr, glfw.Joystick.setUserPointer
+pub inline fn getUserPointer(self: Joystick, comptime PointerType: type) ?PointerType {
+ internal_debug.assertInitialized();
+ const ptr = c.glfwGetJoystickUserPointer(@intFromEnum(self.jid));
+ if (ptr) |p| return @as(PointerType, @ptrCast(@alignCast(p)));
+ return null;
+}
+
+/// Describes an event relating to a joystick.
+pub const Event = enum(c_int) {
+ /// The device was connected.
+ connected = c.GLFW_CONNECTED,
+
+ /// The device was disconnected.
+ disconnected = c.GLFW_DISCONNECTED,
+};
+
+/// 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 (see 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.
+///
+/// @param[in] callback The new callback, or null to remove the currently set callback.
+///
+/// @callback_param `jid` The joystick that was connected or disconnected.
+/// @callback_param `event` One of `.connected` or `.disconnected`. Future releases may add
+/// more events.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: joystick_event
+pub inline fn setCallback(comptime callback: ?fn (joystick: Joystick, event: Event) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn joystickCallbackWrapper(jid: c_int, event: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ Joystick{ .jid = @as(Joystick.Id, @enumFromInt(jid)) },
+ @as(Event, @enumFromInt(event)),
+ });
+ }
+ };
+
+ if (c.glfwSetJoystickCallback(CWrapper.joystickCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetJoystickCallback(null) != null) return;
+ }
+}
+
+/// 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 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.
+///
+/// @param[in] string The string containing the gamepad mappings.
+///
+/// Possible errors include glfw.ErrorCode.InvalidValue.
+/// Returns a boolean indicating success.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: gamepad, glfw.Joystick.isGamepad, glfwGetGamepadName
+///
+///
+/// @ingroup input
+pub inline fn updateGamepadMappings(gamepad_mappings: [*:0]const u8) bool {
+ internal_debug.assertInitialized();
+ return c.glfwUpdateGamepadMappings(gamepad_mappings) == c.GLFW_TRUE;
+}
+
+/// 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 `false` but will not generate an error. Call glfw.Joystick.present to check if a
+/// joystick is present regardless of whether it has a mapping.
+///
+/// @return `true` if a joystick is both present and has a gamepad mapping, or `false` otherwise.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum.
+/// Additionally returns false in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: gamepad, glfw.Joystick.getGamepadState
+pub inline fn isGamepad(self: Joystick) bool {
+ internal_debug.assertInitialized();
+ const is_gamepad = c.glfwJoystickIsGamepad(@intFromEnum(self.jid));
+ return is_gamepad == c.GLFW_TRUE;
+}
+
+/// 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, not an error. Call glfw.Joystick.present to check whether it is
+/// present regardless of whether it has a mapping.
+///
+/// @return The UTF-8 encoded name of the gamepad, or null if the joystick is not present or does
+/// not have a mapping.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum.
+/// Additionally returns null in the event of an 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, the gamepad mappings are
+/// updated or the library is terminated.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: gamepad, glfw.Joystick.isGamepad
+pub inline fn getGamepadName(self: Joystick) ?[:0]const u8 {
+ internal_debug.assertInitialized();
+ const name_opt = c.glfwGetGamepadName(@intFromEnum(self.jid));
+ return if (name_opt) |name|
+ std.mem.span(@as([*:0]const u8, @ptrCast(name)))
+ else
+ null;
+}
+
+/// Retrieves the state of the joystick remapped as a gamepad.
+///
+/// This function retrieves the state of the 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 `false`. Call glfw.joystickPresent 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 GamepadState. Unavailable buttons
+/// and axes will always report `glfw.Action.release` and 0.0 respectively.
+///
+/// @param[in] jid The joystick (see joysticks) to query.
+/// @param[out] state The gamepad input state of the joystick.
+/// @return the gamepad input state if successful, or null if no joystick is connected or it has no
+/// gamepad mapping.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum.
+/// Returns null in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: gamepad, glfw.UpdateGamepadMappings, glfw.Joystick.isGamepad
+pub inline fn getGamepadState(self: Joystick) ?GamepadState {
+ internal_debug.assertInitialized();
+ var state: GamepadState = undefined;
+ const success = c.glfwGetGamepadState(@intFromEnum(self.jid), @as(*c.GLFWgamepadstate, @ptrCast(&state)));
+ return if (success == c.GLFW_TRUE) state else null;
+}
+
+test "present" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+ _ = joystick.present();
+}
+
+test "getAxes" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+ _ = joystick.getAxes();
+}
+
+test "getButtons" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+ _ = joystick.getButtons();
+}
+
+test "getHats" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+
+ if (joystick.getHats()) |hats| {
+ for (hats) |hat| {
+ if (hat.down and hat.up) {
+ // down-up!
+ }
+ }
+ }
+}
+
+test "getName" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+ _ = joystick.getName();
+}
+
+test "getGUID" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+ _ = joystick.getGUID();
+}
+
+test "setUserPointer_syntax" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+
+ // Must be called from joystick callback, we cannot test it.
+ _ = joystick;
+ _ = setUserPointer;
+}
+
+test "getUserPointer_syntax" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+
+ // Must be called from joystick callback, we cannot test it.
+ _ = joystick;
+ _ = getUserPointer;
+}
+
+test "setCallback" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ glfw.Joystick.setCallback((struct {
+ pub fn callback(joystick: Joystick, event: Event) void {
+ _ = joystick;
+ _ = event;
+ }
+ }).callback);
+}
+
+test "updateGamepadMappings_syntax" {
+ // We don't have a gamepad mapping to test with, just confirm the syntax is good.
+ _ = updateGamepadMappings;
+}
+
+test "isGamepad" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+ _ = joystick.isGamepad();
+}
+
+test "getGamepadName" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+ _ = joystick.getGamepadName();
+}
+
+test "getGamepadState" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const joystick = glfw.Joystick{ .jid = .one };
+ _ = joystick.getGamepadState();
+ _ = (std.mem.zeroes(GamepadState)).getAxis(.left_x);
+ _ = (std.mem.zeroes(GamepadState)).getButton(.dpad_up);
+}
diff --git a/pkg/glfw/LICENSE b/pkg/glfw/LICENSE
new file mode 100644
index 000000000..eeeb852fe
--- /dev/null
+++ b/pkg/glfw/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2021 Hexops Contributors (given via the Git commit history).
+Copyright (c) 2025 Mitchell Hashimoto
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/pkg/glfw/Monitor.zig b/pkg/glfw/Monitor.zig
new file mode 100644
index 000000000..868872e19
--- /dev/null
+++ b/pkg/glfw/Monitor.zig
@@ -0,0 +1,599 @@
+//! Monitor type and related functions
+
+const std = @import("std");
+const mem = std.mem;
+const testing = std.testing;
+const c = @import("c.zig").c;
+
+const GammaRamp = @import("GammaRamp.zig");
+const VideoMode = @import("VideoMode.zig");
+
+const internal_debug = @import("internal_debug.zig");
+
+const Monitor = @This();
+
+handle: *c.GLFWmonitor,
+
+/// A monitor position, in screen coordinates, of the upper left corner of the monitor on the
+/// virtual screen.
+const Pos = struct {
+ /// The x coordinate.
+ x: u32,
+ /// The y coordinate.
+ y: u32,
+};
+
+/// Returns the position of the monitor's viewport on the virtual screen.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_properties
+pub inline fn getPos(self: Monitor) Pos {
+ internal_debug.assertInitialized();
+ var xpos: c_int = 0;
+ var ypos: c_int = 0;
+ c.glfwGetMonitorPos(self.handle, &xpos, &ypos);
+ return Pos{ .x = @as(u32, @intCast(xpos)), .y = @as(u32, @intCast(ypos)) };
+}
+
+/// The monitor workarea, in screen coordinates.
+///
+/// This is the position of the upper-left corner of the work area of the monitor, along with the
+/// work area size. The work area is defined as the area of the monitor not occluded by the
+/// window system task bar where present. If no task bar exists then the work area is the
+/// monitor resolution in screen coordinates.
+const Workarea = struct {
+ x: u32,
+ y: u32,
+ width: u32,
+ height: u32,
+};
+
+/// Retrieves the work area of the monitor.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// A zero value is returned in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_workarea
+pub inline fn getWorkarea(self: Monitor) Workarea {
+ internal_debug.assertInitialized();
+ var xpos: c_int = 0;
+ var ypos: c_int = 0;
+ var width: c_int = 0;
+ var height: c_int = 0;
+ c.glfwGetMonitorWorkarea(self.handle, &xpos, &ypos, &width, &height);
+ return Workarea{ .x = @as(u32, @intCast(xpos)), .y = @as(u32, @intCast(ypos)), .width = @as(u32, @intCast(width)), .height = @as(u32, @intCast(height)) };
+}
+
+/// The physical size, in millimetres, of the display area of a monitor.
+const PhysicalSize = struct {
+ width_mm: u32,
+ height_mm: u32,
+};
+
+/// Returns the physical size of the monitor.
+///
+/// Some platforms 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.
+///
+/// win32: On Windows 8 and earlier the physical size is calculated 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.
+///
+/// see also: monitor_properties
+pub inline fn getPhysicalSize(self: Monitor) PhysicalSize {
+ internal_debug.assertInitialized();
+ var width_mm: c_int = 0;
+ var height_mm: c_int = 0;
+ c.glfwGetMonitorPhysicalSize(self.handle, &width_mm, &height_mm);
+ return PhysicalSize{ .width_mm = @as(u32, @intCast(width_mm)), .height_mm = @as(u32, @intCast(height_mm)) };
+}
+
+/// The content scale for a monitor.
+///
+/// This 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 users
+/// settings. It may be very different from the raw DPI calculated from the physical size and
+/// current resolution.
+const ContentScale = struct {
+ x_scale: f32,
+ y_scale: f32,
+};
+
+/// Returns the content scale for the monitor.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// A zero value is returned in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_scale, glfw.Window.getContentScale
+pub inline fn getContentScale(self: Monitor) ContentScale {
+ internal_debug.assertInitialized();
+ var x_scale: f32 = 0;
+ var y_scale: f32 = 0;
+ c.glfwGetMonitorContentScale(self.handle, &x_scale, &y_scale);
+ return ContentScale{ .x_scale = @as(f32, @floatCast(x_scale)), .y_scale = @as(f32, @floatCast(y_scale)) };
+}
+
+/// 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.
+///
+/// @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.
+///
+/// see also: monitor_properties
+pub inline fn getName(self: Monitor) [*:0]const u8 {
+ internal_debug.assertInitialized();
+ if (c.glfwGetMonitorName(self.handle)) |name| return @as([*:0]const u8, @ptrCast(name));
+ // `glfwGetMonitorName` returns `null` only for errors, but the only error is unreachable
+ // (NotInitialized)
+ unreachable;
+}
+
+/// 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.
+///
+/// This function may be called from the monitor callback, even for a monitor that is being
+/// disconnected.
+///
+/// @thread_safety This function may be called from any thread. Access is not synchronized.
+///
+/// see also: monitor_userptr, glfw.Monitor.getUserPointer
+pub inline fn setUserPointer(self: Monitor, comptime T: type, ptr: *T) void {
+ internal_debug.assertInitialized();
+ c.glfwSetMonitorUserPointer(self.handle, ptr);
+}
+
+/// Returns the user pointer of the specified monitor.
+///
+/// This function returns the current value of the user-defined pointer of the specified monitor.
+///
+/// This function may be called from the monitor callback, even for a monitor that is being
+/// disconnected.
+///
+/// @thread_safety This function may be called from any thread. Access is not synchronized.
+///
+/// see also: monitor_userptr, glfw.Monitor.setUserPointer
+pub inline fn getUserPointer(self: Monitor, comptime T: type) ?*T {
+ internal_debug.assertInitialized();
+ const ptr = c.glfwGetMonitorUserPointer(self.handle);
+ if (ptr == null) return null;
+ return @as(*T, @ptrCast(@alignCast(ptr.?)));
+}
+
+/// Returns the available video modes for the specified monitor.
+///
+/// This function returns an array of all video modes supported by the monitor. The returned slice
+/// 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), then resolution width and finally
+/// by refresh rate.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError, glfw.ErrorCode.FeatureUnavailable.
+/// Returns null in the event of an error.
+///
+/// The returned slice memory is owned by the caller.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_modes, glfw.Monitor.getVideoMode
+///
+/// wayland: Gamma handling is privileged protocol, this function will thus never be implemented and
+/// emits glfw.ErrorCode.FeatureUnavailable
+///
+/// TODO(glfw): rewrite this to not require any allocation.
+pub inline fn getVideoModes(self: Monitor, allocator: mem.Allocator) mem.Allocator.Error!?[]VideoMode {
+ internal_debug.assertInitialized();
+ var count: c_int = 0;
+ if (c.glfwGetVideoModes(self.handle, &count)) |modes| {
+ const slice = try allocator.alloc(VideoMode, @as(u32, @intCast(count)));
+ var i: u32 = 0;
+ while (i < count) : (i += 1) {
+ slice[i] = VideoMode{ .handle = @as([*c]const c.GLFWvidmode, @ptrCast(modes))[i] };
+ }
+ return slice;
+ }
+ return null;
+}
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError, glfw.ErrorCode.FeatureUnavailable.
+/// Additionally returns null in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
+/// and will thus never be implemented and emits glfw.ErrorCode.FeatureUnavailable
+///
+/// see also: monitor_modes, glfw.Monitor.getVideoModes
+pub inline fn getVideoMode(self: Monitor) ?VideoMode {
+ internal_debug.assertInitialized();
+ if (c.glfwGetVideoMode(self.handle)) |mode| return VideoMode{ .handle = mode.* };
+ return null;
+}
+
+/// 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 glfw.Monitor.setGammaRamp 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 glfw.srgb_capable hint.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError, glfw.ErrorCode.FeatureUnavailable.
+///
+/// wayland: Gamma handling is privileged protocol, this function will thus never be implemented and
+/// emits glfw.ErrorCode.FeatureUnavailable
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_gamma
+pub inline fn setGamma(self: Monitor, gamma: f32) void {
+ internal_debug.assertInitialized();
+
+ std.debug.assert(!std.math.isNan(gamma));
+ std.debug.assert(gamma >= 0);
+ std.debug.assert(gamma <= std.math.f32_max);
+
+ c.glfwSetGamma(self.handle, gamma);
+}
+
+/// Returns the current gamma ramp for the specified monitor.
+///
+/// This function returns the current gamma ramp of the specified monitor.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// Additionally returns null in the event of an error.
+///
+/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
+/// and returns glfw.ErrorCode.FeatureUnavailable.
+///
+/// The returned gamma ramp is `.owned = true` by GLFW, and is valid until the monitor is
+/// disconnected, this function is called again, or `glfw.terminate()` is called.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_gamma
+pub inline fn getGammaRamp(self: Monitor) ?GammaRamp {
+ internal_debug.assertInitialized();
+ if (c.glfwGetGammaRamp(self.handle)) |ramp| return GammaRamp.fromC(ramp.*);
+ return null;
+}
+
+/// 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
+/// `glfw.terminate()`.
+///
+/// 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 glfw.srgb_capable hint.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError, glfw.ErrorCode.FeatureUnavailable.
+///
+/// The size of the specified gamma ramp should match the size of the current ramp for that
+/// monitor. On win32, the gamma ramp size must be 256.
+///
+/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
+/// and returns glfw.ErrorCode.FeatureUnavailable.
+///
+/// @pointer_lifetime The specified gamma ramp is copied before this function returns.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_gamma
+pub inline fn setGammaRamp(self: Monitor, ramp: GammaRamp) void {
+ internal_debug.assertInitialized();
+ c.glfwSetGammaRamp(self.handle, &ramp.toC());
+}
+
+/// Returns the currently connected monitors.
+///
+/// This function returns a slice of all currently connected monitors. The primary monitor is
+/// always first. If no monitors were found, this function returns an empty slice.
+///
+/// The returned slice memory is owned by the caller. The underlying handles are owned by GLFW, and
+/// are valid until the monitor configuration changes or `glfw.terminate` is called.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_monitors, monitor_event, glfw.monitor.getPrimary
+pub inline fn getAll(allocator: mem.Allocator) mem.Allocator.Error![]Monitor {
+ internal_debug.assertInitialized();
+ var count: c_int = 0;
+ if (c.glfwGetMonitors(&count)) |monitors| {
+ const slice = try allocator.alloc(Monitor, @as(u32, @intCast(count)));
+ var i: u32 = 0;
+ while (i < count) : (i += 1) {
+ slice[i] = Monitor{ .handle = @as([*c]const ?*c.GLFWmonitor, @ptrCast(monitors))[i].? };
+ }
+ return slice;
+ }
+ // `glfwGetMonitors` returning null can be either an error or no monitors, but the only error is
+ // unreachable (NotInitialized)
+ return &[_]Monitor{};
+}
+
+/// 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.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_monitors, glfw.monitors.getAll
+pub inline fn getPrimary() ?Monitor {
+ internal_debug.assertInitialized();
+ if (c.glfwGetPrimaryMonitor()) |handle| return Monitor{ .handle = handle };
+ return null;
+}
+
+/// Describes an event relating to a monitor.
+pub const Event = enum(c_int) {
+ /// The device was connected.
+ connected = c.GLFW_CONNECTED,
+
+ /// The device was disconnected.
+ disconnected = c.GLFW_DISCONNECTED,
+};
+
+/// 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. Example:
+///
+/// ```
+/// fn monitorCallback(monitor: glfw.Monitor, event: glfw.Monitor.Event, data: *MyData) void {
+/// // data is the pointer you passed into setCallback.
+/// // event is one of .connected or .disconnected
+/// }
+/// ...
+/// glfw.Monitor.setCallback(MyData, &myData, monitorCallback)
+/// ```
+///
+/// `event` may be one of .connected or .disconnected. More events may be added in the future.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: monitor_event
+pub inline fn setCallback(comptime callback: ?fn (monitor: Monitor, event: Event) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn monitorCallbackWrapper(monitor: ?*c.GLFWmonitor, event: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ Monitor{ .handle = monitor.? },
+ @as(Event, @enumFromInt(event)),
+ });
+ }
+ };
+
+ if (c.glfwSetMonitorCallback(CWrapper.monitorCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetMonitorCallback(null) != null) return;
+ }
+}
+
+test "getAll" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const allocator = testing.allocator;
+ const monitors = try getAll(allocator);
+ defer allocator.free(monitors);
+}
+
+test "getPrimary" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = getPrimary();
+}
+
+test "getPos" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ _ = m.getPos();
+ }
+}
+
+test "getWorkarea" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ _ = m.getWorkarea();
+ }
+}
+
+test "getPhysicalSize" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ _ = m.getPhysicalSize();
+ }
+}
+
+test "getContentScale" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ _ = m.getContentScale();
+ }
+}
+
+test "getName" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ _ = m.getName();
+ }
+}
+
+test "userPointer" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ var p = m.getUserPointer(u32);
+ try testing.expect(p == null);
+ var x: u32 = 5;
+ m.setUserPointer(u32, &x);
+ p = m.getUserPointer(u32);
+ try testing.expectEqual(p.?.*, 5);
+ }
+}
+
+test "setCallback" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ setCallback(struct {
+ fn callback(monitor: Monitor, event: Event) void {
+ _ = monitor;
+ _ = event;
+ }
+ }.callback);
+}
+
+test "getVideoModes" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ const allocator = testing.allocator;
+ const modes_maybe = try m.getVideoModes(allocator);
+ if (modes_maybe) |modes| {
+ defer allocator.free(modes);
+ }
+ }
+}
+
+test "getVideoMode" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ _ = m.getVideoMode();
+ }
+}
+
+test "set_getGammaRamp" {
+ const allocator = testing.allocator;
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const monitor = getPrimary();
+ if (monitor) |m| {
+ if (m.getGammaRamp()) |ramp| {
+ // Set it to the exact same value; if we do otherwise an our tests fail it wouldn't call
+ // terminate and our made-up gamma ramp would get stuck.
+ m.setGammaRamp(ramp);
+
+ // technically not needed here / noop because GLFW owns this gamma ramp.
+ defer ramp.deinit(allocator);
+ }
+ }
+}
diff --git a/pkg/glfw/VideoMode.zig b/pkg/glfw/VideoMode.zig
new file mode 100644
index 000000000..f433b8d05
--- /dev/null
+++ b/pkg/glfw/VideoMode.zig
@@ -0,0 +1,50 @@
+//! Monitor video modes and related functions
+//!
+//! see also: glfw.Monitor.getVideoMode
+
+const std = @import("std");
+const c = @import("c.zig").c;
+
+const VideoMode = @This();
+
+handle: c.GLFWvidmode,
+
+/// Returns the width of the video mode, in screen coordinates.
+pub inline fn getWidth(self: VideoMode) u32 {
+ return @as(u32, @intCast(self.handle.width));
+}
+
+/// Returns the height of the video mode, in screen coordinates.
+pub inline fn getHeight(self: VideoMode) u32 {
+ return @as(u32, @intCast(self.handle.height));
+}
+
+/// Returns the bit depth of the red channel of the video mode.
+pub inline fn getRedBits(self: VideoMode) u32 {
+ return @as(u32, @intCast(self.handle.redBits));
+}
+
+/// Returns the bit depth of the green channel of the video mode.
+pub inline fn getGreenBits(self: VideoMode) u32 {
+ return @as(u32, @intCast(self.handle.greenBits));
+}
+
+/// Returns the bit depth of the blue channel of the video mode.
+pub inline fn getBlueBits(self: VideoMode) u32 {
+ return @as(u32, @intCast(self.handle.blueBits));
+}
+
+/// Returns the refresh rate of the video mode, in Hz.
+pub inline fn getRefreshRate(self: VideoMode) u32 {
+ return @as(u32, @intCast(self.handle.refreshRate));
+}
+
+test "getters" {
+ const x = std.mem.zeroes(VideoMode);
+ _ = x.getWidth();
+ _ = x.getHeight();
+ _ = x.getRedBits();
+ _ = x.getGreenBits();
+ _ = x.getBlueBits();
+ _ = x.getRefreshRate();
+}
diff --git a/pkg/glfw/Window.zig b/pkg/glfw/Window.zig
new file mode 100644
index 000000000..29dcac23e
--- /dev/null
+++ b/pkg/glfw/Window.zig
@@ -0,0 +1,3551 @@
+//! Window type and related functions
+
+const std = @import("std");
+const testing = std.testing;
+const mem = std.mem;
+const c = @import("c.zig").c;
+
+const glfw = @import("main.zig");
+const Image = @import("Image.zig");
+const Monitor = @import("Monitor.zig");
+const Cursor = @import("Cursor.zig");
+const Key = @import("key.zig").Key;
+const Action = @import("action.zig").Action;
+const Mods = @import("mod.zig").Mods;
+const MouseButton = @import("mouse_button.zig").MouseButton;
+
+const internal_debug = @import("internal_debug.zig");
+
+const Window = @This();
+
+handle: *c.GLFWwindow,
+
+/// Returns a Zig GLFW window from an underlying C GLFW window handle.
+pub inline fn from(handle: *anyopaque) Window {
+ return Window{ .handle = @as(*c.GLFWwindow, @ptrCast(@alignCast(handle))) };
+}
+
+/// Resets all window hints to their default values.
+///
+/// This function resets all window hints to their default values.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_hints, glfw.Window.hint, glfw.Window.hintString
+pub inline fn defaultHints() void {
+ internal_debug.assertInitialized();
+ c.glfwDefaultWindowHints();
+}
+
+/// Window hints
+const Hint = enum(c_int) {
+ resizable = c.GLFW_RESIZABLE,
+ visible = c.GLFW_VISIBLE,
+ decorated = c.GLFW_DECORATED,
+ focused = c.GLFW_FOCUSED,
+ auto_iconify = c.GLFW_AUTO_ICONIFY,
+ floating = c.GLFW_FLOATING,
+ maximized = c.GLFW_MAXIMIZED,
+ center_cursor = c.GLFW_CENTER_CURSOR,
+ transparent_framebuffer = c.GLFW_TRANSPARENT_FRAMEBUFFER,
+ focus_on_show = c.GLFW_FOCUS_ON_SHOW,
+ mouse_passthrough = c.GLFW_MOUSE_PASSTHROUGH,
+ position_x = c.GLFW_POSITION_X,
+ position_y = c.GLFW_POSITION_Y,
+ scale_to_monitor = c.GLFW_SCALE_TO_MONITOR,
+
+ /// Framebuffer hints
+ red_bits = c.GLFW_RED_BITS,
+ green_bits = c.GLFW_GREEN_BITS,
+ blue_bits = c.GLFW_BLUE_BITS,
+ alpha_bits = c.GLFW_ALPHA_BITS,
+ depth_bits = c.GLFW_DEPTH_BITS,
+ stencil_bits = c.GLFW_STENCIL_BITS,
+ accum_red_bits = c.GLFW_ACCUM_RED_BITS,
+ accum_green_bits = c.GLFW_ACCUM_GREEN_BITS,
+ accum_blue_bits = c.GLFW_ACCUM_BLUE_BITS,
+ accum_alpha_bits = c.GLFW_ACCUM_ALPHA_BITS,
+ aux_buffers = c.GLFW_AUX_BUFFERS,
+
+ /// Framebuffer MSAA samples
+ samples = c.GLFW_SAMPLES,
+
+ /// Monitor refresh rate
+ refresh_rate = c.GLFW_REFRESH_RATE,
+
+ /// OpenGL stereoscopic rendering
+ stereo = c.GLFW_STEREO,
+
+ /// Framebuffer sRGB
+ srgb_capable = c.GLFW_SRGB_CAPABLE,
+
+ /// Framebuffer double buffering
+ doublebuffer = c.GLFW_DOUBLEBUFFER,
+
+ client_api = c.GLFW_CLIENT_API,
+ context_creation_api = c.GLFW_CONTEXT_CREATION_API,
+
+ context_version_major = c.GLFW_CONTEXT_VERSION_MAJOR,
+ context_version_minor = c.GLFW_CONTEXT_VERSION_MINOR,
+
+ context_robustness = c.GLFW_CONTEXT_ROBUSTNESS,
+ context_release_behavior = c.GLFW_CONTEXT_RELEASE_BEHAVIOR,
+ context_no_error = c.GLFW_CONTEXT_NO_ERROR,
+ // NOTE: This supersedes opengl_debug_context / GLFW_OPENGL_DEBUG_CONTEXT
+ context_debug = c.GLFW_CONTEXT_DEBUG,
+
+ opengl_forward_compat = c.GLFW_OPENGL_FORWARD_COMPAT,
+ opengl_profile = c.GLFW_OPENGL_PROFILE,
+
+ /// macOS specific
+ cocoa_retina_framebuffer = c.GLFW_COCOA_RETINA_FRAMEBUFFER,
+
+ /// macOS specific
+ cocoa_frame_name = c.GLFW_COCOA_FRAME_NAME,
+
+ /// macOS specific
+ cocoa_graphics_switching = c.GLFW_COCOA_GRAPHICS_SWITCHING,
+
+ /// X11 specific
+ x11_class_name = c.GLFW_X11_CLASS_NAME,
+
+ /// X11 specific
+ x11_instance_name = c.GLFW_X11_INSTANCE_NAME,
+
+ /// Windows specific
+ win32_keyboard_menu = c.GLFW_WIN32_KEYBOARD_MENU,
+
+ /// Allows specification of the Wayland app_id.
+ wayland_app_id = c.GLFW_WAYLAND_APP_ID,
+};
+
+/// Window hints
+pub const Hints = struct {
+ // Note: The defaults here are directly from the GLFW source of the glfwDefaultWindowHints function
+ resizable: bool = true,
+ visible: bool = true,
+ decorated: bool = true,
+ focused: bool = true,
+ auto_iconify: bool = true,
+ floating: bool = false,
+ maximized: bool = false,
+ center_cursor: bool = true,
+ transparent_framebuffer: bool = false,
+ focus_on_show: bool = true,
+ mouse_passthrough: bool = false,
+ position_x: c_int = @intFromEnum(Position.any),
+ position_y: c_int = @intFromEnum(Position.any),
+
+ scale_to_monitor: bool = false,
+
+ /// Framebuffer hints
+ red_bits: ?PositiveCInt = 8,
+ green_bits: ?PositiveCInt = 8,
+ blue_bits: ?PositiveCInt = 8,
+ alpha_bits: ?PositiveCInt = 8,
+ depth_bits: ?PositiveCInt = 24,
+ stencil_bits: ?PositiveCInt = 8,
+ accum_red_bits: ?PositiveCInt = 0,
+ accum_green_bits: ?PositiveCInt = 0,
+ accum_blue_bits: ?PositiveCInt = 0,
+ accum_alpha_bits: ?PositiveCInt = 0,
+ aux_buffers: ?PositiveCInt = 0,
+
+ /// Framebuffer MSAA samples
+ samples: ?PositiveCInt = 0,
+
+ /// Monitor refresh rate
+ refresh_rate: ?PositiveCInt = null,
+
+ /// OpenGL stereoscopic rendering
+ stereo: bool = false,
+
+ /// Framebuffer sRGB
+ srgb_capable: bool = false,
+
+ /// Framebuffer double buffering
+ doublebuffer: bool = true,
+
+ client_api: ClientAPI = .opengl_api,
+ context_creation_api: ContextCreationAPI = .native_context_api,
+
+ context_version_major: c_int = 1,
+ context_version_minor: c_int = 0,
+
+ context_robustness: ContextRobustness = .no_robustness,
+ context_release_behavior: ContextReleaseBehavior = .any_release_behavior,
+
+ /// Note: disables the context creating errors,
+ /// instead turning them into undefined behavior.
+ context_no_error: bool = false,
+ context_debug: bool = false,
+
+ opengl_forward_compat: bool = false,
+
+ opengl_profile: OpenGLProfile = .opengl_any_profile,
+
+ /// macOS specific
+ cocoa_retina_framebuffer: bool = true,
+
+ /// macOS specific
+ cocoa_frame_name: [:0]const u8 = "",
+
+ /// macOS specific
+ cocoa_graphics_switching: bool = false,
+
+ /// X11 specific
+ x11_class_name: [:0]const u8 = "",
+
+ /// X11 specific
+ x11_instance_name: [:0]const u8 = "",
+
+ /// Windows specific
+ win32_keyboard_menu: bool = false,
+
+ /// Allows specification of the Wayland app_id.
+ wayland_app_id: [:0]const u8 = "",
+
+ pub const PositiveCInt = std.math.IntFittingRange(0, std.math.maxInt(c_int));
+
+ pub const ClientAPI = enum(c_int) {
+ opengl_api = c.GLFW_OPENGL_API,
+ opengl_es_api = c.GLFW_OPENGL_ES_API,
+ no_api = c.GLFW_NO_API,
+ };
+
+ pub const ContextCreationAPI = enum(c_int) {
+ native_context_api = c.GLFW_NATIVE_CONTEXT_API,
+ egl_context_api = c.GLFW_EGL_CONTEXT_API,
+ osmesa_context_api = c.GLFW_OSMESA_CONTEXT_API,
+ };
+
+ pub const ContextRobustness = enum(c_int) {
+ no_robustness = c.GLFW_NO_ROBUSTNESS,
+ no_reset_notification = c.GLFW_NO_RESET_NOTIFICATION,
+ lose_context_on_reset = c.GLFW_LOSE_CONTEXT_ON_RESET,
+ };
+
+ pub const ContextReleaseBehavior = enum(c_int) {
+ any_release_behavior = c.GLFW_ANY_RELEASE_BEHAVIOR,
+ release_behavior_flush = c.GLFW_RELEASE_BEHAVIOR_FLUSH,
+ release_behavior_none = c.GLFW_RELEASE_BEHAVIOR_NONE,
+ };
+
+ pub const OpenGLProfile = enum(c_int) {
+ opengl_any_profile = c.GLFW_OPENGL_ANY_PROFILE,
+ opengl_compat_profile = c.GLFW_OPENGL_COMPAT_PROFILE,
+ opengl_core_profile = c.GLFW_OPENGL_CORE_PROFILE,
+ };
+
+ pub const Position = enum(c_int) {
+ /// 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
+ /// Window.Hint.visible hint, set its Window.Hint.position and then Window.hide() it.
+ ///
+ /// To create the window at a specific position, set the Window.Hint.position_x and
+ /// Window.Hint.position_y hints before creation. To restore the default behavior, set
+ /// either or both hints back to Window.Hints.Position.any
+ any = @bitCast(c.GLFW_ANY_POSITION),
+ };
+
+ fn set(hints: Hints) void {
+ internal_debug.assertInitialized();
+ inline for (comptime std.meta.fieldNames(Hint)) |field_name| {
+ const hint_tag = @intFromEnum(@field(Hint, field_name));
+ const hint_value = @field(hints, field_name);
+ switch (@TypeOf(hint_value)) {
+ bool => c.glfwWindowHint(hint_tag, @intFromBool(hint_value)),
+ ?PositiveCInt => c.glfwWindowHint(hint_tag, if (hint_value) |unwrapped| unwrapped else glfw.dont_care),
+ c_int => c.glfwWindowHint(hint_tag, hint_value),
+
+ ClientAPI,
+ ContextCreationAPI,
+ ContextRobustness,
+ ContextReleaseBehavior,
+ OpenGLProfile,
+ Position,
+ => c.glfwWindowHint(hint_tag, @intFromEnum(hint_value)),
+
+ [:0]const u8 => c.glfwWindowHintString(hint_tag, hint_value.ptr),
+
+ else => unreachable,
+ }
+ }
+ }
+};
+
+/// 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 using `glfw.Window.hint`.
+///
+/// Successful creation does not change which context is current. Before you can use the newly
+/// created context, you need to make it current using `glfw.makeContextCurrent`. For
+/// information about the `share` parameter, see context_sharing.
+///
+/// The created window, framebuffer and context may differ from what you requested, as not all
+/// parameters and hints are hard constraints. 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 glfw.Window.getAttrib, glfw.Window.getSize and glfw.window.getFramebufferSize.
+///
+/// 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 window_windowed_full_screen.
+///
+/// Once you have created the window, you can switch it between windowed and full screen mode with
+/// glfw.Window.setMonitor. 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 `visible` window
+/// hint, set its position and then show 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 after creation.
+///
+/// The swap interval is not set during window creation and the initial value may vary depending on
+/// driver settings and defaults.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum, glfw.ErrorCode.InvalidValue,
+/// glfw.ErrorCode.APIUnavailable, glfw.ErrorCode.VersionUnavailable, glfw.ErrorCode.FormatUnavailable and
+/// glfw.ErrorCode.PlatformError.
+/// Returns null in the event of an error.
+///
+/// Parameters are as follows:
+///
+/// * `width` The desired width, in screen coordinates, of the window.
+/// * `height` The desired height, in screen coordinates, of the window.
+/// * `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.
+///
+/// win32: Window creation will fail if the Microsoft GDI software OpenGL implementation is the
+/// only one available.
+///
+/// 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 glfw.Window.setIcon.
+///
+/// win32: The context to share resources with must not be current on any other thread.
+///
+/// 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` and `glfw.opengl_profile` hints accordingly. OpenGL 3.0 and 3.1
+/// contexts are not supported at all on macOS.
+///
+/// macos: The OS only supports 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_profile` hint
+/// accordingly. OpenGL 3.0 and 3.1 contexts are not supported at all on macOS.
+///
+/// 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.
+///
+/// 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 hint is true (1) 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/Info.plist.in` in the source tree.
+///
+/// macos: When activating frame autosaving with glfw.cocoa_frame_name, the specified window size
+/// and position may be overridden by previously saved values.
+///
+/// x11: Some window managers will not respect the placement of initially hidden windows.
+///
+/// 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.
+///
+/// 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
+/// and glfw.x11_instance_name window hints to override this.
+///
+/// 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.
+///
+/// wayland: A full screen window will not attempt to change the mode, no matter what the
+/// requested size or refresh rate.
+///
+/// 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.
+///
+/// see also: window_creation, glfw.Window.destroy
+pub inline fn create(
+ width: u32,
+ height: u32,
+ title: [*:0]const u8,
+ monitor: ?Monitor,
+ share: ?Window,
+ hints: Hints,
+) ?Window {
+ internal_debug.assertInitialized();
+ const ignore_hints_struct = if (comptime @import("builtin").is_test) testing_ignore_window_hints_struct else false;
+ if (!ignore_hints_struct) hints.set();
+
+ if (c.glfwCreateWindow(
+ @as(c_int, @intCast(width)),
+ @as(c_int, @intCast(height)),
+ &title[0],
+ if (monitor) |m| m.handle else null,
+ if (share) |w| w.handle else null,
+ )) |handle| return from(handle);
+ return null;
+}
+
+var testing_ignore_window_hints_struct = if (@import("builtin").is_test) false else @as(void, {});
+
+/// 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.
+///
+/// note: The context of the specified window must not be current on any other thread when this
+/// function is called.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @reentrancy This function must not be called from a callback.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_creation, glfw.Window.create
+pub inline fn destroy(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwDestroyWindow(self.handle);
+}
+
+/// Checks the close flag of the specified window.
+///
+/// This function returns the value of the close flag of the specified window.
+///
+/// @thread_safety This function may be called from any thread. Access is not synchronized.
+///
+/// see also: window_close
+pub inline fn shouldClose(self: Window) bool {
+ internal_debug.assertInitialized();
+ return c.glfwWindowShouldClose(self.handle) == c.GLFW_TRUE;
+}
+
+/// 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.
+///
+/// @thread_safety This function may be called from any thread. Access is not
+/// synchronized.
+///
+/// see also: window_close
+pub inline fn setShouldClose(self: Window, value: bool) void {
+ internal_debug.assertInitialized();
+ const boolean = if (value) c.GLFW_TRUE else c.GLFW_FALSE;
+ c.glfwSetWindowShouldClose(self.handle, boolean);
+}
+
+/// Sets the UTF-8 encoded title of the specified window.
+///
+/// This function sets the window title, encoded as UTF-8, of the specified window.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// 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.
+///
+/// see also: window_title
+pub inline fn setTitle(self: Window, title: [*:0]const u8) void {
+ internal_debug.assertInitialized();
+ c.glfwSetWindowTitle(self.handle, 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.
+///
+/// @pointer_lifetime The specified image data is copied before this function returns.
+///
+/// macos: Regular windows do not have icons on macOS. This function will emit FeatureUnavailable.
+/// 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.
+///
+/// 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 will emit glfw.ErrorCode.FeatureUnavailable.
+///
+/// Possible errors include glfw.ErrorCode.InvalidValue, glfw.ErrorCode.FeatureUnavailable
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_icon
+pub inline fn setIcon(self: Window, allocator: mem.Allocator, images: ?[]const Image) mem.Allocator.Error!void {
+ internal_debug.assertInitialized();
+ if (images) |im| {
+ const tmp = try allocator.alloc(c.GLFWimage, im.len);
+ defer allocator.free(tmp);
+ for (im, 0..) |img, index| tmp[index] = img.toC();
+ c.glfwSetWindowIcon(self.handle, @as(c_int, @intCast(im.len)), &tmp[0]);
+ } else c.glfwSetWindowIcon(self.handle, 0, null);
+}
+
+pub const Pos = struct {
+ x: i64,
+ y: i64,
+};
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.FeatureUnavailable.
+/// Additionally returns a zero value in the event of an error.
+///
+/// wayland: There is no way for an application to retrieve the global position of its windows,
+/// this function will always emit glfw.ErrorCode.FeatureUnavailable.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_pos glfw.Window.setPos
+pub inline fn getPos(self: Window) Pos {
+ internal_debug.assertInitialized();
+ var x: c_int = 0;
+ var y: c_int = 0;
+ c.glfwGetWindowPos(self.handle, &x, &y);
+ return Pos{ .x = @as(i64, @intCast(x)), .y = @as(i64, @intCast(y)) };
+}
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.FeatureUnavailable.
+///
+/// wayland: There is no way for an application to set the global position of its windows, this
+/// function will always emit glfw.ErrorCode.FeatureUnavailable.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_pos, glfw.Window.getPos
+pub inline fn setPos(self: Window, pos: Pos) void {
+ internal_debug.assertInitialized();
+ c.glfwSetWindowPos(self.handle, @as(c_int, @intCast(pos.x)), @as(c_int, @intCast(pos.y)));
+}
+
+pub const Size = struct {
+ width: u32,
+ height: u32,
+};
+
+/// 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
+/// glfw.Window.getFramebufferSize.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// Additionally returns a zero value in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_size, glfw.Window.setSize
+pub inline fn getSize(self: Window) Size {
+ internal_debug.assertInitialized();
+ var width: c_int = 0;
+ var height: c_int = 0;
+ c.glfwGetWindowSize(self.handle, &width, &height);
+ return Size{ .width = @as(u32, @intCast(width)), .height = @as(u32, @intCast(height)) };
+}
+
+/// 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 glfw.Window.setMonitor.
+///
+/// The window manager may put limits on what sizes are allowed. GLFW cannot and should not
+/// override these limits.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// 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.
+///
+/// see also: window_size, glfw.Window.getSize, glfw.Window.SetMonitor
+pub inline fn setSize(self: Window, size: Size) void {
+ internal_debug.assertInitialized();
+ c.glfwSetWindowSize(self.handle, @as(c_int, @intCast(size.width)), @as(c_int, @intCast(size.height)));
+}
+
+/// A size with option width/height, used to represent e.g. constraints on a windows size while
+/// allowing specific axis to be unconstrained (null) if desired.
+pub const SizeOptional = struct {
+ width: ?u32 = null,
+ height: ?u32 = null,
+};
+
+/// Sets the size limits of the specified window's content area.
+///
+/// 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. glfw.dont_care
+/// may be used for any width/height parameter.
+///
+/// Possible errors include glfw.ErrorCode.InvalidValue and glfw.ErrorCode.PlatformError.
+///
+/// If you set size limits and an aspect ratio that conflict, the results are undefined.
+///
+/// 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.
+///
+/// see also: window_sizelimits, glfw.Window.setAspectRatio
+pub inline fn setSizeLimits(self: Window, min: SizeOptional, max: SizeOptional) void {
+ internal_debug.assertInitialized();
+
+ if (min.width != null and max.width != null) {
+ std.debug.assert(min.width.? <= max.width.?);
+ }
+ if (min.height != null and max.height != null) {
+ std.debug.assert(min.height.? <= max.height.?);
+ }
+
+ c.glfwSetWindowSizeLimits(
+ self.handle,
+ if (min.width) |min_width| @as(c_int, @intCast(min_width)) else glfw.dont_care,
+ if (min.height) |min_height| @as(c_int, @intCast(min_height)) else glfw.dont_care,
+ if (max.width) |max_width| @as(c_int, @intCast(max_width)) else glfw.dont_care,
+ if (max.height) |max_height| @as(c_int, @intCast(max_height)) else glfw.dont_care,
+ );
+}
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.InvalidValue and glfw.ErrorCode.PlatformError.
+///
+/// If you set size limits and an aspect ratio that conflict, the results are undefined.
+///
+/// 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.
+///
+/// see also: window_sizelimits, glfw.Window.setSizeLimits
+///
+/// WARNING: on wayland it will return glfw.ErrorCode.FeatureUnimplemented
+pub inline fn setAspectRatio(self: Window, numerator: ?u32, denominator: ?u32) void {
+ internal_debug.assertInitialized();
+
+ if (numerator != null and denominator != null) {
+ std.debug.assert(numerator.? > 0);
+ std.debug.assert(denominator.? > 0);
+ }
+
+ c.glfwSetWindowAspectRatio(
+ self.handle,
+ if (numerator) |numerator_unwrapped| @as(c_int, @intCast(numerator_unwrapped)) else glfw.dont_care,
+ if (denominator) |denominator_unwrapped| @as(c_int, @intCast(denominator_unwrapped)) else glfw.dont_care,
+ );
+}
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// Additionally returns a zero value in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_fbsize, glfwWindow.setFramebufferSizeCallback
+pub inline fn getFramebufferSize(self: Window) Size {
+ internal_debug.assertInitialized();
+ var width: c_int = 0;
+ var height: c_int = 0;
+ c.glfwGetFramebufferSize(self.handle, &width, &height);
+ return Size{ .width = @as(u32, @intCast(width)), .height = @as(u32, @intCast(height)) };
+}
+
+pub const FrameSize = struct {
+ left: u32,
+ top: u32,
+ right: u32,
+ bottom: u32,
+};
+
+/// 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 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// Additionally returns a zero value in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_size
+pub inline fn getFrameSize(self: Window) FrameSize {
+ internal_debug.assertInitialized();
+ var left: c_int = 0;
+ var top: c_int = 0;
+ var right: c_int = 0;
+ var bottom: c_int = 0;
+ c.glfwGetWindowFrameSize(self.handle, &left, &top, &right, &bottom);
+ return FrameSize{
+ .left = @as(u32, @intCast(left)),
+ .top = @as(u32, @intCast(top)),
+ .right = @as(u32, @intCast(right)),
+ .bottom = @as(u32, @intCast(bottom)),
+ };
+}
+
+pub const ContentScale = struct {
+ x_scale: f32,
+ y_scale: f32,
+};
+
+/// 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 platforms 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// Additionally returns a zero value in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_scale, glfwSetWindowContentScaleCallback, glfwGetMonitorContentScale
+pub inline fn getContentScale(self: Window) ContentScale {
+ internal_debug.assertInitialized();
+ var x_scale: f32 = 0;
+ var y_scale: f32 = 0;
+ c.glfwGetWindowContentScale(self.handle, &x_scale, &y_scale);
+ return ContentScale{ .x_scale = x_scale, .y_scale = y_scale };
+}
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// Additionally returns a zero value in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_transparency, glfw.Window.setOpacity
+pub inline fn getOpacity(self: Window) f32 {
+ internal_debug.assertInitialized();
+ const opacity = c.glfwGetWindowOpacity(self.handle);
+ return opacity;
+}
+
+/// 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.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_transparency, glfw.Window.getOpacity
+pub inline fn setOpacity(self: Window, opacity: f32) void {
+ internal_debug.assertInitialized();
+ c.glfwSetWindowOpacity(self.handle, 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, GLFW restores the original video mode of the
+/// monitor. The window's desired video mode is set again when the window is restored.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// wayland: Once a window is iconified, glfw.Window.restorebe able to restore it. This is a design
+/// decision of the xdg-shell protocol.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_iconify, glfw.Window.restore, glfw.Window.maximize
+pub inline fn iconify(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwIconifyWindow(self.handle);
+}
+
+/// 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 an iconified full screen window, its desired video mode is set
+/// again for its monitor when the window is restored.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_iconify, glfw.Window.iconify, glfw.Window.maximize
+pub inline fn restore(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwRestoreWindow(self.handle);
+}
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_iconify, glfw.Window.iconify, glfw.Window.restore
+pub inline fn maximize(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwMaximizeWindow(self.handle);
+}
+
+/// 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 window hint
+/// to change this behavior for all newly created windows, or change the
+/// behavior for an existing window with glfw.Window.setAttrib.
+///
+/// wayland: Because Wayland wants every frame of the desktop to be complete, this function does
+/// not immediately make the window visible. Instead it will become visible the next time the window
+/// framebuffer is updated after this call.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_hide, glfw.Window.hide
+///
+/// WARNING: on wayland it will return glfw.ErrorCode.FeatureUnavailable
+pub inline fn show(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwShowWindow(self.handle);
+}
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_hide, glfw.Window.show
+pub inline fn hide(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwHideWindow(self.handle);
+}
+
+/// 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 to disable this behavior.
+///
+/// Also by default, windowed mode windows are focused when shown with glfw.Window.show. Set the
+/// glfw.focus_on_show 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 (window_attention).
+///
+/// wayland It is not possible for an application to set the input focus. This function will emit
+/// glfw.ErrorCode.FeatureUnavailable.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_focus, window_attention
+pub inline fn focus(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwFocusWindow(self.handle);
+}
+
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// 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.
+///
+/// see also: window_attention
+///
+/// WARNING: on wayland it will return glfw.ErrorCode.FeatureUnimplemented
+pub inline fn requestAttention(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwRequestWindowAttention(self.handle);
+}
+
+/// 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 glfw.ErrorCode.NoWindowContext.
+///
+/// This function does not apply to Vulkan. If you are rendering with Vulkan, see `vkQueuePresentKHR`
+/// instead.
+///
+/// @param[in] window The window whose buffers to swap.
+///
+/// Possible errors include glfw.ErrorCode.NoWindowContext and glfw.ErrorCode.PlatformError.
+///
+/// __EGL:__ The context of the specified window must be current on the calling thread.
+///
+/// @thread_safety This function may be called from any thread.
+///
+/// see also: buffer_swap, glfwSwapInterval
+pub inline fn swapBuffers(self: Window) void {
+ internal_debug.assertInitialized();
+ c.glfwSwapBuffers(self.handle);
+}
+
+/// 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.
+///
+/// @return The monitor, or null if the window is in windowed mode.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_monitor, glfw.Window.setMonitor
+pub inline fn getMonitor(self: Window) ?Monitor {
+ internal_debug.assertInitialized();
+ if (c.glfwGetWindowMonitor(self.handle)) |monitor| return Monitor{ .handle = monitor };
+ return null;
+}
+
+/// 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.
+///
+/// @param[in] window The window whose monitor, size or video mode to set.
+/// @param[in] monitor The desired monitor, or null to set windowed mode.
+/// @param[in] xpos The desired x-coordinate of the upper-left corner of the content area.
+/// @param[in] ypos The desired y-coordinate of the upper-left corner of the content area.
+/// @param[in] width The desired with, in screen coordinates, of the content area or video mode.
+/// @param[in] height The desired height, in screen coordinates, of the content area or video mode.
+/// @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, or `glfw.dont_care`.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// 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.
+///
+/// wayland: The desired window position is ignored, as there is no way for an application to set
+/// this property.
+///
+/// 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.
+///
+/// see also: window_monitor, window_full_screen, glfw.Window.getMonitor, glfw.Window.setSize
+pub inline fn setMonitor(self: Window, monitor: ?Monitor, xpos: i32, ypos: i32, width: u32, height: u32, refresh_rate: ?u32) void {
+ internal_debug.assertInitialized();
+ c.glfwSetWindowMonitor(
+ self.handle,
+ if (monitor) |m| m.handle else null,
+ @as(c_int, @intCast(xpos)),
+ @as(c_int, @intCast(ypos)),
+ @as(c_int, @intCast(width)),
+ @as(c_int, @intCast(height)),
+ if (refresh_rate) |refresh_rate_unwrapped| @as(c_int, @intCast(refresh_rate_unwrapped)) else glfw.dont_care,
+ );
+}
+
+/// Window attributes
+pub const Attrib = enum(c_int) {
+ iconified = c.GLFW_ICONIFIED,
+ resizable = c.GLFW_RESIZABLE,
+ visible = c.GLFW_VISIBLE,
+ decorated = c.GLFW_DECORATED,
+ focused = c.GLFW_FOCUSED,
+ auto_iconify = c.GLFW_AUTO_ICONIFY,
+ floating = c.GLFW_FLOATING,
+ maximized = c.GLFW_MAXIMIZED,
+ transparent_framebuffer = c.GLFW_TRANSPARENT_FRAMEBUFFER,
+ hovered = c.GLFW_HOVERED,
+ focus_on_show = c.GLFW_FOCUS_ON_SHOW,
+ mouse_passthrough = c.GLFW_MOUSE_PASSTHROUGH,
+ doublebuffer = c.GLFW_DOUBLEBUFFER,
+
+ client_api = c.GLFW_CLIENT_API,
+ context_creation_api = c.GLFW_CONTEXT_CREATION_API,
+ context_version_major = c.GLFW_CONTEXT_VERSION_MAJOR,
+ context_version_minor = c.GLFW_CONTEXT_VERSION_MINOR,
+ context_revision = c.GLFW_CONTEXT_REVISION,
+
+ context_robustness = c.GLFW_CONTEXT_ROBUSTNESS,
+ context_release_behavior = c.GLFW_CONTEXT_RELEASE_BEHAVIOR,
+ context_no_error = c.GLFW_CONTEXT_NO_ERROR,
+ context_debug = c.GLFW_CONTEXT_DEBUG,
+
+ opengl_forward_compat = c.GLFW_OPENGL_FORWARD_COMPAT,
+ opengl_profile = c.GLFW_OPENGL_PROFILE,
+};
+
+/// 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.
+///
+/// @param[in] attrib The window attribute (see window_attribs) whose value to return.
+/// @return The value of the attribute, or zero if an error occurred.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
+/// Additionally returns a zero value in the event of an error.
+///
+/// Framebuffer related hints are not window attributes. See window_attribs_fb for more information.
+///
+/// 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.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// wayland: The Wayland protocol provides no way to check whether a window is iconified, so
+/// glfw.Window.Attrib.iconified always returns `false`.
+///
+/// see also: window_attribs, glfw.Window.setAttrib
+pub inline fn getAttrib(self: Window, attrib: Attrib) i32 {
+ internal_debug.assertInitialized();
+ return c.glfwGetWindowAttrib(self.handle, @intFromEnum(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, glfw.resizable, glfw.floating, glfw.auto_iconify,
+/// glfw.focus_on_show.
+///
+/// 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.
+///
+/// @param[in] attrib A supported window attribute.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum, glfw.ErrorCode.InvalidValue,
+/// glfw.ErrorCode.PlatformError, glfw.ErrorCode.FeatureUnavailable
+///
+/// Calling glfw.Window.getAttrib 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.
+///
+/// see also: window_attribs, glfw.Window.getAttrib
+///
+pub inline fn setAttrib(self: Window, attrib: Attrib, value: bool) void {
+ internal_debug.assertInitialized();
+ std.debug.assert(switch (attrib) {
+ .decorated,
+ .resizable,
+ .floating,
+ .auto_iconify,
+ .focus_on_show,
+ .mouse_passthrough,
+ .doublebuffer,
+ => true,
+ else => false,
+ });
+ c.glfwSetWindowAttrib(self.handle, @intFromEnum(attrib), if (value) c.GLFW_TRUE else c.GLFW_FALSE);
+}
+
+/// 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.
+///
+/// @thread_safety This function may be called from any thread. Access is not synchronized.
+///
+/// see also: window_userptr, glfw.Window.getUserPointer
+pub inline fn setUserPointer(self: Window, pointer: ?*anyopaque) void {
+ internal_debug.assertInitialized();
+ c.glfwSetWindowUserPointer(self.handle, 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.
+///
+/// @thread_safety This function may be called from any thread. Access is not synchronized.
+///
+/// see also: window_userptr, glfw.Window.setUserPointer
+pub inline fn getUserPointer(self: Window, comptime T: type) ?*T {
+ internal_debug.assertInitialized();
+ if (c.glfwGetWindowUserPointer(self.handle)) |user_pointer| return @as(?*T, @ptrCast(@alignCast(user_pointer)));
+ return null;
+}
+
+/// 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.
+///
+/// @param[in] callback The new callback, or null to remove the currently set callback.
+///
+/// @callback_param `window` the window that moved.
+/// @callback_param `xpos` the new x-coordinate, in screen coordinates, of the upper-left corner of
+/// the content area of the window.
+/// @callback_param `ypos` the new y-coordinate, in screen coordinates, of the upper-left corner of
+/// the content area of the window.
+///
+/// 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.
+///
+/// see also: window_pos
+pub inline fn setPosCallback(self: Window, comptime callback: ?fn (window: Window, xpos: i32, ypos: i32) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn posCallbackWrapper(handle: ?*c.GLFWwindow, xpos: c_int, ypos: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ @as(i32, @intCast(xpos)),
+ @as(i32, @intCast(ypos)),
+ });
+ }
+ };
+
+ if (c.glfwSetWindowPosCallback(self.handle, CWrapper.posCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetWindowPosCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @callback_param `window` the window that was resized.
+/// @callback_param `width` the new width, in screen coordinates, of the window.
+/// @callback_param `height` the new height, in screen coordinates, of the window.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_size
+pub inline fn setSizeCallback(self: Window, comptime callback: ?fn (window: Window, width: i32, height: i32) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn sizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ @as(i32, @intCast(width)),
+ @as(i32, @intCast(height)),
+ });
+ }
+ };
+
+ if (c.glfwSetWindowSizeCallback(self.handle, CWrapper.sizeCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetWindowSizeCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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
+/// glfw.Window.setShouldClose.
+///
+/// The close callback is not triggered by glfw.Window.destroy.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set callback.
+///
+/// @callback_param `window` the window that the user attempted to close.
+///
+/// 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.
+///
+/// see also: window_close
+pub inline fn setCloseCallback(self: Window, comptime callback: ?fn (window: Window) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn closeCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ });
+ }
+ };
+
+ if (c.glfwSetWindowCloseCallback(self.handle, CWrapper.closeCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetWindowCloseCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set
+/// callback.
+///
+/// @callback_param `window` the window whose content needs to be refreshed.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_refresh
+pub inline fn setRefreshCallback(self: Window, comptime callback: ?fn (window: Window) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn refreshCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ });
+ }
+ };
+
+ if (c.glfwSetWindowRefreshCallback(self.handle, CWrapper.refreshCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetWindowRefreshCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set
+/// callback.
+///
+/// @callback_param `window` the window whose input focus has changed.
+/// @callback_param `focused` `true` if the window was given input focus, or `false` if it lost it.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_focus
+pub inline fn setFocusCallback(self: Window, comptime callback: ?fn (window: Window, focused: bool) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn focusCallbackWrapper(handle: ?*c.GLFWwindow, focused: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ focused == c.GLFW_TRUE,
+ });
+ }
+ };
+
+ if (c.glfwSetWindowFocusCallback(self.handle, CWrapper.focusCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetWindowFocusCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set
+/// callback.
+///
+/// @callback_param `window` the window which was iconified or restored.
+/// @callback_param `iconified` `true` if the window was iconified, or `false` if it was restored.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_iconify
+pub inline fn setIconifyCallback(self: Window, comptime callback: ?fn (window: Window, iconified: bool) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn iconifyCallbackWrapper(handle: ?*c.GLFWwindow, iconified: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ iconified == c.GLFW_TRUE,
+ });
+ }
+ };
+
+ if (c.glfwSetWindowIconifyCallback(self.handle, CWrapper.iconifyCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetWindowIconifyCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set
+/// callback.
+///
+/// @callback_param `window` the window which was maximized or restored.
+/// @callback_param `maximized` `true` if the window was maximized, or `false` if it was restored.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_maximize
+// GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun callback);
+pub inline fn setMaximizeCallback(self: Window, comptime callback: ?fn (window: Window, maximized: bool) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn maximizeCallbackWrapper(handle: ?*c.GLFWwindow, maximized: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ maximized == c.GLFW_TRUE,
+ });
+ }
+ };
+
+ if (c.glfwSetWindowMaximizeCallback(self.handle, CWrapper.maximizeCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetWindowMaximizeCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set
+/// callback.
+///
+/// @callback_param `window` the window whose framebuffer was resized.
+/// @callback_param `width` the new width, in pixels, of the framebuffer.
+/// @callback_param `height` the new height, in pixels, of the framebuffer.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_fbsize
+pub inline fn setFramebufferSizeCallback(self: Window, comptime callback: ?fn (window: Window, width: u32, height: u32) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn framebufferSizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ @as(u32, @intCast(width)),
+ @as(u32, @intCast(height)),
+ });
+ }
+ };
+
+ if (c.glfwSetFramebufferSizeCallback(self.handle, CWrapper.framebufferSizeCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetFramebufferSizeCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set
+/// callback.
+///
+/// @callback_param `window` the window whose content scale changed.
+/// @callback_param `xscale` the new x-axis content scale of the window.
+/// @callback_param `yscale` the new y-axis content scale of the window.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_scale, glfw.Window.getContentScale
+pub inline fn setContentScaleCallback(self: Window, comptime callback: ?fn (window: Window, xscale: f32, yscale: f32) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn windowScaleCallbackWrapper(handle: ?*c.GLFWwindow, xscale: f32, yscale: f32) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ xscale,
+ yscale,
+ });
+ }
+ };
+
+ if (c.glfwSetWindowContentScaleCallback(self.handle, CWrapper.windowScaleCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetWindowContentScaleCallback(self.handle, null) != null) return;
+ }
+}
+
+pub const InputMode = enum(c_int) {
+ cursor = c.GLFW_CURSOR,
+ sticky_keys = c.GLFW_STICKY_KEYS,
+ sticky_mouse_buttons = c.GLFW_STICKY_MOUSE_BUTTONS,
+ lock_key_mods = c.GLFW_LOCK_KEY_MODS,
+ raw_mouse_motion = c.GLFW_RAW_MOUSE_MOTION,
+};
+
+/// A cursor input mode to be supplied to `glfw.Window.setInputModeCursor`
+pub const InputModeCursor = enum(c_int) {
+ /// Makes the cursor visible and behaving normally.
+ normal = c.GLFW_CURSOR_NORMAL,
+
+ /// Makes the cursor invisible when it is over the content area of the window but does not
+ /// restrict it from leaving.
+ hidden = c.GLFW_CURSOR_HIDDEN,
+
+ /// Hides and grabs the cursor, providing virtual and unlimited cursor movement. This is useful
+ /// for implementing for example 3D camera controls.
+ disabled = c.GLFW_CURSOR_DISABLED,
+
+ /// Makes the cursor visible but confines it to the content area of the window.
+ captured = c.GLFW_CURSOR_CAPTURED,
+};
+
+/// Sets the input mode of the cursor, whether it should behave normally, be hidden, or grabbed.
+pub inline fn setInputModeCursor(self: Window, value: InputModeCursor) void {
+ return self.setInputMode(InputMode.cursor, value);
+}
+
+/// Gets the current input mode of the cursor.
+pub inline fn getInputModeCursor(self: Window) InputModeCursor {
+ return @as(InputModeCursor, @enumFromInt(self.getInputMode(InputMode.cursor)));
+}
+
+/// Sets the input mode of sticky keys, if enabled a key press will ensure that `glfw.Window.getKey`
+/// return `.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.
+pub inline fn setInputModeStickyKeys(self: Window, enabled: bool) void {
+ return self.setInputMode(InputMode.sticky_keys, enabled);
+}
+
+/// Tells if the sticky keys input mode is enabled.
+pub inline fn getInputModeStickyKeys(self: Window) bool {
+ return self.getInputMode(InputMode.sticky_keys) == 1;
+}
+
+/// Sets the input mode of sticky mouse buttons, if enabled a mouse button press will ensure that
+/// `glfw.Window.getMouseButton` return `.press` the next time it is called even if the button had
+/// been released before the call.
+///
+/// This is useful when you are only interested in whether buttons have been pressed but not when
+/// or in which order.
+pub inline fn setInputModeStickyMouseButtons(self: Window, enabled: bool) void {
+ return self.setInputMode(InputMode.sticky_mouse_buttons, enabled);
+}
+
+/// Tells if the sticky mouse buttons input mode is enabled.
+pub inline fn getInputModeStickyMouseButtons(self: Window) bool {
+ return self.getInputMode(InputMode.sticky_mouse_buttons) == 1;
+}
+
+/// Sets the input mode of locking key modifiers, if enabled callbacks that receive modifier bits
+/// will also have the glfw.mod.caps_lock bit set when the event was generated with Caps Lock on,
+/// and the glfw.mod.num_lock bit when Num Lock was on.
+pub inline fn setInputModeLockKeyMods(self: Window, enabled: bool) void {
+ return self.setInputMode(InputMode.lock_key_mods, enabled);
+}
+
+/// Tells if the locking key modifiers input mode is enabled.
+pub inline fn getInputModeLockKeyMods(self: Window) bool {
+ return self.getInputMode(InputMode.lock_key_mods) == 1;
+}
+
+/// Sets whether the raw mouse motion input mode is enabled, if enabled unscaled and unaccelerated
+/// mouse motion events will be sent, otherwise standard mouse motion events respecting the user's
+/// OS settings will be sent.
+///
+/// If raw motion is not supported, attempting to set this will emit glfw.ErrorCode.FeatureUnavailable.
+/// Call glfw.rawMouseMotionSupported to check for support.
+pub inline fn setInputModeRawMouseMotion(self: Window, enabled: bool) void {
+ return self.setInputMode(InputMode.raw_mouse_motion, enabled);
+}
+
+/// Tells if the raw mouse motion input mode is enabled.
+pub inline fn getInputModeRawMouseMotion(self: Window) bool {
+ return self.getInputMode(InputMode.raw_mouse_motion) == 1;
+}
+
+/// Returns the value of an input option for the specified window.
+///
+/// Consider using one of the following variants instead, if applicable, as they'll give you a
+/// typed return value:
+///
+/// * `glfw.Window.getInputModeCursor`
+/// * `glfw.Window.getInputModeStickyKeys`
+/// * `glfw.Window.getInputModeStickyMouseButtons`
+/// * `glfw.Window.getInputModeLockKeyMods`
+/// * `glfw.Window.getInputModeRawMouseMotion`
+///
+/// This function returns the value of an input option for the specified window. The mode must be
+/// one of the `glfw.Window.InputMode` enumerations.
+///
+/// Boolean values, such as for `glfw.Window.InputMode.raw_mouse_motion`, are returned as integers.
+/// You may convert to a boolean using `== 1`.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: glfw.Window.setInputMode
+pub inline fn getInputMode(self: Window, mode: InputMode) i32 {
+ internal_debug.assertInitialized();
+ const value = c.glfwGetInputMode(self.handle, @intFromEnum(mode));
+ return @as(i32, @intCast(value));
+}
+
+/// Sets an input option for the specified window.
+///
+/// Consider using one of the following variants instead, if applicable, as they'll guide you to
+/// the right input value via enumerations:
+///
+/// * `glfw.Window.setInputModeCursor`
+/// * `glfw.Window.setInputModeStickyKeys`
+/// * `glfw.Window.setInputModeStickyMouseButtons`
+/// * `glfw.Window.setInputModeLockKeyMods`
+/// * `glfw.Window.setInputModeRawMouseMotion`
+///
+/// @param[in] mode One of the `glfw.Window.InputMode` enumerations.
+/// @param[in] value The new value of the specified input mode.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: glfw.Window.getInputMode
+pub inline fn setInputMode(self: Window, mode: InputMode, value: anytype) void {
+ internal_debug.assertInitialized();
+ const T = @TypeOf(value);
+ std.debug.assert(switch (mode) {
+ .cursor => switch (@import("shims.zig").typeInfo(T)) {
+ .@"enum" => T == InputModeCursor,
+ .enum_literal => @hasField(InputModeCursor, @tagName(value)),
+ else => false,
+ },
+ .sticky_keys => T == bool,
+ .sticky_mouse_buttons => T == bool,
+ .lock_key_mods => T == bool,
+ .raw_mouse_motion => T == bool,
+ });
+ const int_value: c_int = switch (@import("shims.zig").typeInfo(T)) {
+ .@"enum",
+ .enum_literal,
+ => @intFromEnum(@as(InputModeCursor, value)),
+ else => @intFromBool(value),
+ };
+ c.glfwSetInputMode(self.handle, @intFromEnum(mode), int_value);
+}
+
+/// Returns the last reported press state of a keyboard key for the specified window.
+///
+/// This function returns the last press state reported for the specified key to the specified
+/// window. The returned state is one of `true` (pressed) or `false` (released).
+///
+/// * `glfw.Action.repeat` is only reported to the key callback.
+///
+/// If the `glfw.sticky_keys` input mode is enabled, this function returns `glfw.Action.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 (see 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 (see mods) are not key tokens and cannot be used with this function.
+///
+/// __Do not use this function__ to implement text input, use glfw.Window.setCharCallback instead.
+///
+/// @param[in] window The desired window.
+/// @param[in] key The desired keyboard key (see keys). `glfw.key.unknown` is not a valid key for
+/// this function.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: input_key
+pub inline fn getKey(self: Window, key: Key) Action {
+ internal_debug.assertInitialized();
+ const state = c.glfwGetKey(self.handle, @intFromEnum(key));
+ return @as(Action, @enumFromInt(state));
+}
+
+/// Returns the last reported state of a mouse button for the specified window.
+///
+/// This function returns whether the specified mouse button is pressed or not.
+///
+/// If the glfw.sticky_mouse_buttons input mode is enabled, this function returns `true` the first
+/// time you call it for a mouse button that was pressed, even if that mouse button has already been
+/// released.
+///
+/// @param[in] button The desired mouse button.
+/// @return One of `true` (if pressed) or `false` (if released)
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: input_mouse_button
+pub inline fn getMouseButton(self: Window, button: MouseButton) Action {
+ internal_debug.assertInitialized();
+ const state = c.glfwGetMouseButton(self.handle, @intFromEnum(button));
+ return @as(Action, @enumFromInt(state));
+}
+
+pub const CursorPos = struct {
+ xpos: f64,
+ ypos: f64,
+};
+
+/// 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 `f64`.
+///
+/// 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.
+///
+/// @param[in] window The desired window.
+/// @param[out] xpos Where to store the cursor x-coordinate, relative to the left edge of the
+/// content area, or null.
+/// @param[out] ypos Where to store the cursor y-coordinate, relative to the to top edge of the
+/// content area, or null.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+/// Additionally returns a zero value in the event of an error.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: cursor_pos, glfw.Window.setCursorPos
+pub inline fn getCursorPos(self: Window) CursorPos {
+ internal_debug.assertInitialized();
+ var pos: CursorPos = undefined;
+ c.glfwGetCursorPos(self.handle, &pos.xpos, &pos.ypos);
+ return pos;
+}
+
+/// 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 glfw.Window.setInputMode 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`.
+///
+/// @param[in] window The desired window.
+/// @param[in] xpos The desired x-coordinate, relative to the left edge of the content area.
+/// @param[in] ypos The desired y-coordinate, relative to the top edge of the content area.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError, glfw.ErrorCode.FeatureUnavailable.
+///
+/// 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.
+///
+/// see also: cursor_pos, glfw.Window.getCursorPos
+pub inline fn setCursorPos(self: Window, xpos: f64, ypos: f64) void {
+ internal_debug.assertInitialized();
+ c.glfwSetCursorPos(self.handle, xpos, ypos);
+}
+
+/// 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 (see 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.
+///
+/// @param[in] cursor The cursor to set, or null to switch back to the default arrow cursor.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: cursor_object
+pub inline fn setCursor(self: Window, cursor: ?Cursor) void {
+ internal_debug.assertInitialized();
+ c.glfwSetCursor(self.handle, if (cursor) |cs| cs.ptr else null);
+}
+
+/// 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 (see keys) named
+/// after their values in the standard US keyboard layout. If you want to input text, use the
+/// character callback (see glfw.Window.setCharCallback) 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 (see glfw.Window.setFocusCallback) 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
+/// glfw.Window.getKey.
+///
+/// Sometimes GLFW needs to generate synthetic key events, in which case the scancode may be zero.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new key callback, or null to remove the currently set callback.
+///
+/// @callback_param[in] window The window that received the event.
+/// @callback_param[in] key The keyboard key (see keys) that was pressed or released.
+/// @callback_param[in] scancode The platform-specific scancode of the key.
+/// @callback_param[in] action `glfw.Action.press`, `glfw.Action.release` or `glfw.Action.repeat`.
+/// Future releases may add more actions.
+/// @callback_param[in] mods Bit field describing which modifier keys (see mods) were held down.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: input_key
+pub inline fn setKeyCallback(self: Window, comptime callback: ?fn (window: Window, key: Key, scancode: i32, action: Action, mods: Mods) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn keyCallbackWrapper(handle: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ @as(Key, @enumFromInt(key)),
+ @as(i32, @intCast(scancode)),
+ @as(Action, @enumFromInt(action)),
+ Mods.fromInt(mods),
+ });
+ }
+ };
+
+ if (c.glfwSetKeyCallback(self.handle, CWrapper.keyCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetKeyCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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 (see glfw.Window.setKeyCallback) 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.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set callback.
+///
+/// @callback_param[in] window The window that received the event.
+/// @callback_param[in] codepoint The Unicode code point of the character.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: input_char
+pub inline fn setCharCallback(self: Window, comptime callback: ?fn (window: Window, codepoint: u21) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn charCallbackWrapper(handle: ?*c.GLFWwindow, codepoint: c_uint) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ @as(u21, @intCast(codepoint)),
+ });
+ }
+ };
+
+ if (c.glfwSetCharCallback(self.handle, CWrapper.charCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetCharCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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 (see glfw.Window.setFocusCallback) has been called.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new callback, or null to remove the currently set callback.
+///
+/// @callback_param[in] window The window that received the event.
+/// @callback_param[in] button The mouse button that was pressed or released.
+/// @callback_param[in] action One of `glfw.Action.press` or `glfw.Action.release`. Future releases
+/// may add more actions.
+/// @callback_param[in] mods Bit field describing which modifier keys (see mods) were held down.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: input_mouse_button
+pub inline fn setMouseButtonCallback(self: Window, comptime callback: ?fn (window: Window, button: MouseButton, action: Action, mods: Mods) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn mouseButtonCallbackWrapper(handle: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ @as(MouseButton, @enumFromInt(button)),
+ @as(Action, @enumFromInt(action)),
+ Mods.fromInt(mods),
+ });
+ }
+ };
+
+ if (c.glfwSetMouseButtonCallback(self.handle, CWrapper.mouseButtonCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetMouseButtonCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] callback The new callback, or null to remove the currently set callback.
+///
+/// @callback_param[in] window The window that received the event.
+/// @callback_param[in] xpos The new cursor x-coordinate, relative to the left edge of the content
+/// area.
+/// callback_@param[in] ypos The new cursor y-coordinate, relative to the top edge of the content
+/// area.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: cursor_pos
+pub inline fn setCursorPosCallback(self: Window, comptime callback: ?fn (window: Window, xpos: f64, ypos: f64) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn cursorPosCallbackWrapper(handle: ?*c.GLFWwindow, xpos: f64, ypos: f64) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ xpos,
+ ypos,
+ });
+ }
+ };
+
+ if (c.glfwSetCursorPosCallback(self.handle, CWrapper.cursorPosCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetCursorPosCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] callback The new callback, or null to remove the currently set callback.
+///
+/// @callback_param[in] window The window that received the event.
+/// @callback_param[in] entered `true` if the cursor entered the window's content area, or `false`
+/// if it left it.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: cursor_enter
+pub inline fn setCursorEnterCallback(self: Window, comptime callback: ?fn (window: Window, entered: bool) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn cursorEnterCallbackWrapper(handle: ?*c.GLFWwindow, entered: c_int) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ entered == c.GLFW_TRUE,
+ });
+ }
+ };
+
+ if (c.glfwSetCursorEnterCallback(self.handle, CWrapper.cursorEnterCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetCursorEnterCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] window The window whose callback to set.
+/// @param[in] callback The new scroll callback, or null to remove the currently set callback.
+///
+/// @callback_param[in] window The window that received the event.
+/// @callback_param[in] xoffset The scroll offset along the x-axis.
+/// @callback_param[in] yoffset The scroll offset along the y-axis.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: scrolling
+pub inline fn setScrollCallback(self: Window, comptime callback: ?fn (window: Window, xoffset: f64, yoffset: f64) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn scrollCallbackWrapper(handle: ?*c.GLFWwindow, xoffset: f64, yoffset: f64) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ xoffset,
+ yoffset,
+ });
+ }
+ };
+
+ if (c.glfwSetScrollCallback(self.handle, CWrapper.scrollCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetScrollCallback(self.handle, null) != null) return;
+ }
+}
+
+/// 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.
+///
+/// @param[in] callback The new file drop callback, or null to remove the currently set callback.
+///
+/// @callback_param[in] window The window that received the event.
+/// @callback_param[in] path_count The number of dropped paths.
+/// @callback_param[in] paths The UTF-8 encoded file and/or directory path names.
+///
+/// @callback_pointer_lifetime The path array and its strings are valid until the callback function
+/// returns.
+///
+/// wayland: File drop is currently unimplemented.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: path_drop
+pub inline fn setDropCallback(self: Window, comptime callback: ?fn (window: Window, paths: [][*:0]const u8) void) void {
+ internal_debug.assertInitialized();
+
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn dropCallbackWrapper(handle: ?*c.GLFWwindow, path_count: c_int, paths: [*c][*c]const u8) callconv(.C) void {
+ @call(.always_inline, user_callback, .{
+ from(handle.?),
+ @as([*][*:0]const u8, @ptrCast(paths))[0..@as(u32, @intCast(path_count))],
+ });
+ }
+ };
+
+ if (c.glfwSetDropCallback(self.handle, CWrapper.dropCallbackWrapper) != null) return;
+ } else {
+ if (c.glfwSetDropCallback(self.handle, null) != null) return;
+ }
+}
+
+/// For testing purposes only; see glfw.Window.Hints and glfw.Window.create for the public API.
+/// Sets the specified window hint to the desired value.
+///
+/// This function sets hints for the next call to glfw.Window.create. The hints, once set, retain
+/// their values until changed by a call to this function or glfw.window.defaultHints, or until the
+/// library is terminated.
+///
+/// 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 glfw.createWindow.
+///
+/// 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.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum.
+///
+/// @pointer_lifetime in the event that value is of a str type, the specified string is copied before this function returns.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: window_hints, glfw.Window.defaultHints
+inline fn hint(h: Hint, value: anytype) void {
+ internal_debug.assertInitialized();
+ const value_type = @TypeOf(value);
+ const value_type_info: @import("shims.zig").std.builtin.Type = @import("shims.zig").typeInfo(value_type);
+
+ switch (value_type_info) {
+ .int, .comptime_int => {
+ c.glfwWindowHint(@intFromEnum(h), @as(c_int, @intCast(value)));
+ },
+ .bool => {
+ const int_value = @intFromBool(value);
+ c.glfwWindowHint(@intFromEnum(h), @as(c_int, @intCast(int_value)));
+ },
+ .@"enum" => {
+ const int_value = @intFromEnum(value);
+ c.glfwWindowHint(@intFromEnum(h), @as(c_int, @intCast(int_value)));
+ },
+ .array => |arr_type| {
+ if (arr_type.child != u8) {
+ @compileError("expected array of u8, got " ++ @typeName(arr_type));
+ }
+ c.glfwWindowHintString(@intFromEnum(h), &value[0]);
+ },
+ .pointer => |pointer_info| {
+ const pointed_type = @import("shims.zig").typeInfo(pointer_info.child);
+ switch (pointed_type) {
+ .array => |arr_type| {
+ if (arr_type.child != u8) {
+ @compileError("expected pointer to array of u8, got " ++ @typeName(arr_type));
+ }
+ },
+ else => @compileError("expected pointer to array, got " ++ @typeName(pointed_type)),
+ }
+
+ c.glfwWindowHintString(@intFromEnum(h), &value[0]);
+ },
+ else => {
+ @compileError("expected a int, bool, enum, array, or pointer, got " ++ @typeName(value_type));
+ },
+ }
+}
+
+test "defaultHints" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ defaultHints();
+}
+
+test "hint comptime int" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ hint(.focused, 1);
+ defaultHints();
+}
+
+test "hint int" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const focused: i32 = 1;
+
+ hint(.focused, focused);
+ defaultHints();
+}
+
+test "hint bool" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ hint(.focused, true);
+ defaultHints();
+}
+
+test "hint enum(u1)" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const MyEnum = enum(u1) {
+ true = 1,
+ false = 0,
+ };
+
+ hint(.focused, MyEnum.true);
+ defaultHints();
+}
+
+test "hint enum(i32)" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const MyEnum = enum(i32) {
+ true = 1,
+ false = 0,
+ };
+
+ hint(.focused, MyEnum.true);
+ defaultHints();
+}
+
+test "hint array str" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const str_arr = [_]u8{ 'm', 'y', 'c', 'l', 'a', 's', 's' };
+
+ hint(.x11_class_name, str_arr);
+ defaultHints();
+}
+
+test "hint pointer str" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ hint(.x11_class_name, "myclass");
+}
+
+test "createWindow" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+}
+
+test "setShouldClose" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ window.setShouldClose(true);
+ defer window.destroy();
+}
+
+test "setTitle" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setTitle("Updated title!");
+}
+
+test "setIcon" {
+ const allocator = testing.allocator;
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ // Create an all-red icon image.
+ const width: u32 = 48;
+ const height: u32 = 48;
+ const icon = try Image.init(allocator, width, height, width * height * 4);
+ var x: u32 = 0;
+ var y: u32 = 0;
+ while (y <= height) : (y += 1) {
+ while (x <= width) : (x += 1) {
+ icon.pixels[(x * y * 4) + 0] = 255; // red
+ icon.pixels[(x * y * 4) + 1] = 0; // green
+ icon.pixels[(x * y * 4) + 2] = 0; // blue
+ icon.pixels[(x * y * 4) + 3] = 255; // alpha
+ }
+ }
+ try window.setIcon(allocator, &[_]Image{icon});
+
+ icon.deinit(allocator); // glfw copies it.
+}
+
+test "getPos" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getPos();
+}
+
+test "setPos" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.setPos(.{ .x = 0, .y = 0 });
+}
+
+test "getSize" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getSize();
+}
+
+test "setSize" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.setSize(.{ .width = 640, .height = 480 });
+}
+
+test "setSizeLimits" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setSizeLimits(
+ .{ .width = 720, .height = 480 },
+ .{ .width = 1080, .height = 1920 },
+ );
+}
+
+test "setAspectRatio" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setAspectRatio(4, 3);
+}
+
+test "getFramebufferSize" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getFramebufferSize();
+}
+
+test "getFrameSize" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getFrameSize();
+}
+
+test "getContentScale" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getContentScale();
+}
+
+test "getOpacity" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getOpacity();
+}
+
+test "iconify" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.iconify();
+}
+
+test "restore" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.restore();
+}
+
+test "maximize" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.maximize();
+}
+
+test "show" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.show();
+}
+
+test "hide" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.hide();
+}
+
+test "focus" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.focus();
+}
+
+test "requestAttention" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.requestAttention();
+}
+
+test "swapBuffers" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.swapBuffers();
+}
+
+test "getMonitor" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getMonitor();
+}
+
+test "setMonitor" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setMonitor(null, 10, 10, 640, 480, 60);
+}
+
+test "getAttrib" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getAttrib(.focused);
+}
+
+test "setAttrib" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setAttrib(.decorated, false);
+}
+
+test "setUserPointer" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ const T = struct { name: []const u8 };
+ var my_value = T{ .name = "my window!" };
+
+ window.setUserPointer(&my_value);
+}
+
+test "getUserPointer" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ const T = struct { name: []const u8 };
+ var my_value = T{ .name = "my window!" };
+
+ window.setUserPointer(&my_value);
+ const got = window.getUserPointer(T);
+ std.debug.assert(&my_value == got);
+}
+
+test "setPosCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setPosCallback((struct {
+ fn callback(_window: Window, xpos: i32, ypos: i32) void {
+ _ = _window;
+ _ = xpos;
+ _ = ypos;
+ }
+ }).callback);
+}
+
+test "setSizeCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setSizeCallback((struct {
+ fn callback(_window: Window, width: i32, height: i32) void {
+ _ = _window;
+ _ = width;
+ _ = height;
+ }
+ }).callback);
+}
+
+test "setCloseCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setCloseCallback((struct {
+ fn callback(_window: Window) void {
+ _ = _window;
+ }
+ }).callback);
+}
+
+test "setRefreshCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setRefreshCallback((struct {
+ fn callback(_window: Window) void {
+ _ = _window;
+ }
+ }).callback);
+}
+
+test "setFocusCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setFocusCallback((struct {
+ fn callback(_window: Window, focused: bool) void {
+ _ = _window;
+ _ = focused;
+ }
+ }).callback);
+}
+
+test "setIconifyCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setIconifyCallback((struct {
+ fn callback(_window: Window, iconified: bool) void {
+ _ = _window;
+ _ = iconified;
+ }
+ }).callback);
+}
+
+test "setMaximizeCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setMaximizeCallback((struct {
+ fn callback(_window: Window, maximized: bool) void {
+ _ = _window;
+ _ = maximized;
+ }
+ }).callback);
+}
+
+test "setFramebufferSizeCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setFramebufferSizeCallback((struct {
+ fn callback(_window: Window, width: u32, height: u32) void {
+ _ = _window;
+ _ = width;
+ _ = height;
+ }
+ }).callback);
+}
+
+test "setContentScaleCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setContentScaleCallback((struct {
+ fn callback(_window: Window, xscale: f32, yscale: f32) void {
+ _ = _window;
+ _ = xscale;
+ _ = yscale;
+ }
+ }).callback);
+}
+
+test "setDropCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setDropCallback((struct {
+ fn callback(_window: Window, paths: [][*:0]const u8) void {
+ _ = _window;
+ _ = paths;
+ }
+ }).callback);
+}
+
+test "getInputModeCursor" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getInputModeCursor();
+}
+
+test "setInputModeCursor" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setInputModeCursor(.hidden);
+}
+
+test "getInputModeStickyKeys" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getInputModeStickyKeys();
+}
+
+test "setInputModeStickyKeys" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setInputModeStickyKeys(false);
+}
+
+test "getInputModeStickyMouseButtons" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getInputModeStickyMouseButtons();
+}
+
+test "setInputModeStickyMouseButtons" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setInputModeStickyMouseButtons(false);
+}
+
+test "getInputModeLockKeyMods" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getInputModeLockKeyMods();
+}
+
+test "setInputModeLockKeyMods" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setInputModeLockKeyMods(false);
+}
+
+test "getInputModeRawMouseMotion" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getInputModeRawMouseMotion();
+}
+
+test "setInputModeRawMouseMotion" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setInputModeRawMouseMotion(false);
+}
+
+test "getInputMode" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getInputMode(glfw.Window.InputMode.raw_mouse_motion) == 1;
+}
+
+test "setInputMode" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ // Boolean values.
+ window.setInputMode(glfw.Window.InputMode.sticky_mouse_buttons, true);
+
+ // Integer values.
+ window.setInputMode(glfw.Window.InputMode.cursor, glfw.Window.InputModeCursor.hidden);
+}
+
+test "getKey" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getKey(glfw.Key.escape);
+}
+
+test "getMouseButton" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getMouseButton(.left);
+}
+
+test "getCursorPos" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ _ = window.getCursorPos();
+}
+
+test "setCursorPos" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setCursorPos(0, 0);
+}
+
+test "setCursor" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ const cursor = glfw.Cursor.createStandard(.ibeam);
+ if (cursor) |cur| {
+ window.setCursor(cur);
+ defer cur.destroy();
+ }
+}
+
+test "setKeyCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setKeyCallback((struct {
+ fn callback(_window: Window, key: Key, scancode: i32, action: Action, mods: Mods) void {
+ _ = _window;
+ _ = key;
+ _ = scancode;
+ _ = action;
+ _ = mods;
+ }
+ }).callback);
+}
+
+test "setCharCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setCharCallback((struct {
+ fn callback(_window: Window, codepoint: u21) void {
+ _ = _window;
+ _ = codepoint;
+ }
+ }).callback);
+}
+
+test "setMouseButtonCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setMouseButtonCallback((struct {
+ fn callback(_window: Window, button: MouseButton, action: Action, mods: Mods) void {
+ _ = _window;
+ _ = button;
+ _ = action;
+ _ = mods;
+ }
+ }).callback);
+}
+
+test "setCursorPosCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setCursorPosCallback((struct {
+ fn callback(_window: Window, xpos: f64, ypos: f64) void {
+ _ = _window;
+ _ = xpos;
+ _ = ypos;
+ }
+ }).callback);
+}
+
+test "setCursorEnterCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setCursorEnterCallback((struct {
+ fn callback(_window: Window, entered: bool) void {
+ _ = _window;
+ _ = entered;
+ }
+ }).callback);
+}
+
+test "setScrollCallback" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ window.setScrollCallback((struct {
+ fn callback(_window: Window, xoffset: f64, yoffset: f64) void {
+ _ = _window;
+ _ = xoffset;
+ _ = yoffset;
+ }
+ }).callback);
+}
+
+test "hint-attribute default value parity" {
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ testing_ignore_window_hints_struct = true;
+ const window_a = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window_a: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window_a.destroy();
+
+ testing_ignore_window_hints_struct = false;
+ const window_b = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window_b: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window_b.destroy();
+
+ inline for (comptime std.enums.values(Window.Hint)) |hint_tag| {
+ if (@hasField(Window.Attrib, @tagName(hint_tag))) {
+ const attrib_tag = @field(Window.Attrib, @tagName(hint_tag));
+ switch (attrib_tag) {
+ .resizable,
+ .visible,
+ .decorated,
+ .auto_iconify,
+ .floating,
+ .maximized,
+ .transparent_framebuffer,
+ .focus_on_show,
+ .mouse_passthrough,
+ .doublebuffer,
+ .client_api,
+ .context_creation_api,
+ .context_version_major,
+ .context_version_minor,
+ .context_robustness,
+ .context_release_behavior,
+ .context_no_error, // Note: at the time of writing this, GLFW does not list the default value for this hint in the documentation
+ .context_debug,
+ .opengl_forward_compat,
+ .opengl_profile,
+ => {
+ const expected = window_a.getAttrib(attrib_tag);
+ const actual = window_b.getAttrib(attrib_tag);
+
+ testing.expectEqual(expected, actual) catch |err| {
+ std.debug.print("On attribute '{}'.\n", .{hint_tag});
+ return err;
+ };
+ },
+
+ // This attribute is based on a check for which window is currently in focus,
+ // and the default value, as of writing this comment, is 'true', which means
+ // that first window_a takes focus, and then window_b takes focus, meaning
+ // that we can't actually test for the default value.
+ .focused => continue,
+
+ .iconified,
+ .hovered,
+ .context_revision,
+ => unreachable,
+ }
+ }
+ // Future: we could consider hint values that can't be retrieved via attributes:
+ // center_cursor
+ // mouse_passthrough
+ // scale_to_monitor
+ // red_bits
+ // green_bits
+ // blue_bits
+ // alpha_bits
+ // depth_bits
+ // stencil_bits
+ // accum_red_bits
+ // accum_green_bits
+ // accum_blue_bits
+ // accum_alpha_bits
+ // aux_buffers
+ // samples
+
+ // refresh_rate
+ // stereo
+ // srgb_capable
+ // doublebuffer
+
+ // platform specific, and thus not considered:
+ // cocoa_retina_framebuffer
+ // cocoa_frame_name
+ // cocoa_graphics_switching
+ }
+}
diff --git a/pkg/glfw/action.zig b/pkg/glfw/action.zig
new file mode 100644
index 000000000..59314709f
--- /dev/null
+++ b/pkg/glfw/action.zig
@@ -0,0 +1,13 @@
+const c = @import("c.zig").c;
+
+/// Key and button actions
+pub const Action = enum(c_int) {
+ /// The key or mouse button was released.
+ release = c.GLFW_RELEASE,
+
+ /// The key or mouse button was pressed.
+ press = c.GLFW_PRESS,
+
+ /// The key was held down until it repeated.
+ repeat = c.GLFW_REPEAT,
+};
diff --git a/pkg/glfw/allocator.zig b/pkg/glfw/allocator.zig
new file mode 100644
index 000000000..d6517cf3e
--- /dev/null
+++ b/pkg/glfw/allocator.zig
@@ -0,0 +1,143 @@
+// TODO: implement custom allocator support
+
+// /*! @brief
+// *
+// * @sa @ref init_allocator
+// * @sa @ref glfwInitAllocator
+// *
+// * @since Added in version 3.4.
+// *
+// * @ingroup init
+// */
+// typedef struct GLFWallocator
+// {
+// GLFWallocatefun allocate;
+// GLFWreallocatefun reallocate;
+// GLFWdeallocatefun deallocate;
+// void* user;
+// } GLFWallocator;
+
+// /*! @brief The function pointer type for memory allocation callbacks.
+// *
+// * This is the function pointer type for memory allocation callbacks. A memory
+// * allocation callback function has the following signature:
+// * @code
+// * void* function_name(size_t size, void* user)
+// * @endcode
+// *
+// * This function must return either a memory block at least `size` bytes long,
+// * or `NULL` if allocation failed. Note that not all parts of GLFW handle allocation
+// * failures gracefully yet.
+// *
+// * This function may be called during @ref glfwInit but before the library is
+// * flagged as initialized, as well as during @ref glfwTerminate after the
+// * library is no longer flagged as initialized.
+// *
+// * Any memory allocated by this function will be deallocated during library
+// * termination or earlier.
+// *
+// * The size will always be greater than zero. Allocations of size zero are filtered out
+// * before reaching the custom allocator.
+// *
+// * @param[in] size The minimum size, in bytes, of the memory block.
+// * @param[in] user The user-defined pointer from the allocator.
+// * @return The address of the newly allocated memory block, or `NULL` if an
+// * error occurred.
+// *
+// * @pointer_lifetime The returned memory block must be valid at least until it
+// * is deallocated.
+// *
+// * @reentrancy This function should not call any GLFW function.
+// *
+// * @thread_safety This function may be called from any thread that calls GLFW functions.
+// *
+// * @sa @ref init_allocator
+// * @sa @ref GLFWallocator
+// *
+// * @since Added in version 3.4.
+// *
+// * @ingroup init
+// */
+// typedef void* (* GLFWallocatefun)(size_t size, void* user);
+
+// /*! @brief The function pointer type for memory reallocation callbacks.
+// *
+// * This is the function pointer type for memory reallocation callbacks.
+// * A memory reallocation callback function has the following signature:
+// * @code
+// * void* function_name(void* block, size_t size, void* user)
+// * @endcode
+// *
+// * This function must return a memory block at least `size` bytes long, or
+// * `NULL` if allocation failed. Note that not all parts of GLFW handle allocation
+// * failures gracefully yet.
+// *
+// * This function may be called during @ref glfwInit but before the library is
+// * flagged as initialized, as well as during @ref glfwTerminate after the
+// * library is no longer flagged as initialized.
+// *
+// * Any memory allocated by this function will be deallocated during library
+// * termination or earlier.
+// *
+// * The block address will never be `NULL` and the size will always be greater than zero.
+// * Reallocations of a block to size zero are converted into deallocations. Reallocations
+// * of `NULL` to a non-zero size are converted into regular allocations.
+// *
+// * @param[in] block The address of the memory block to reallocate.
+// * @param[in] size The new minimum size, in bytes, of the memory block.
+// * @param[in] user The user-defined pointer from the allocator.
+// * @return The address of the newly allocated or resized memory block, or
+// * `NULL` if an error occurred.
+// *
+// * @pointer_lifetime The returned memory block must be valid at least until it
+// * is deallocated.
+// *
+// * @reentrancy This function should not call any GLFW function.
+// *
+// * @thread_safety This function may be called from any thread that calls GLFW functions.
+// *
+// * @sa @ref init_allocator
+// * @sa @ref GLFWallocator
+// *
+// * @since Added in version 3.4.
+// *
+// * @ingroup init
+// */
+// typedef void* (* GLFWreallocatefun)(void* block, size_t size, void* user);
+
+// /*! @brief The function pointer type for memory deallocation callbacks.
+// *
+// * This is the function pointer type for memory deallocation callbacks.
+// * A memory deallocation callback function has the following signature:
+// * @code
+// * void function_name(void* block, void* user)
+// * @endcode
+// *
+// * This function may deallocate the specified memory block. This memory block
+// * will have been allocated with the same allocator.
+// *
+// * This function may be called during @ref glfwInit but before the library is
+// * flagged as initialized, as well as during @ref glfwTerminate after the
+// * library is no longer flagged as initialized.
+// *
+// * The block address will never be `NULL`. Deallocations of `NULL` are filtered out
+// * before reaching the custom allocator.
+// *
+// * @param[in] block The address of the memory block to deallocate.
+// * @param[in] user The user-defined pointer from the allocator.
+// *
+// * @pointer_lifetime The specified memory block will not be accessed by GLFW
+// * after this function is called.
+// *
+// * @reentrancy This function should not call any GLFW function.
+// *
+// * @thread_safety This function may be called from any thread that calls GLFW functions.
+// *
+// * @sa @ref init_allocator
+// * @sa @ref GLFWallocator
+// *
+// * @since Added in version 3.4.
+// *
+// * @ingroup init
+// */
+// typedef void (* GLFWdeallocatefun)(void* block, void* user);
diff --git a/pkg/glfw/build.zig b/pkg/glfw/build.zig
new file mode 100644
index 000000000..cc61f18b2
--- /dev/null
+++ b/pkg/glfw/build.zig
@@ -0,0 +1,272 @@
+const std = @import("std");
+const apple_sdk = @import("apple_sdk");
+
+pub fn build(b: *std.Build) !void {
+ const target = b.standardTargetOptions(.{});
+ const optimize = b.standardOptimizeOption(.{});
+
+ const module = b.addModule("glfw", .{
+ .root_source_file = b.path("main.zig"),
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const lib = try buildLib(b, module, .{
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const test_exe: ?*std.Build.Step.Compile = if (target.query.isNative()) exe: {
+ const exe = b.addTest(.{
+ .name = "test",
+ .root_source_file = b.path("main.zig"),
+ .target = target,
+ .optimize = optimize,
+ });
+ if (target.result.os.tag.isDarwin()) {
+ try apple_sdk.addPaths(b, exe.root_module);
+ }
+
+ const tests_run = b.addRunArtifact(exe);
+ const test_step = b.step("test", "Run tests");
+ test_step.dependOn(&tests_run.step);
+
+ // Uncomment this if we're debugging tests
+ b.installArtifact(exe);
+
+ break :exe exe;
+ } else null;
+
+ if (b.systemIntegrationOption("glfw3", .{})) {
+ module.linkSystemLibrary("glfw3", dynamic_link_opts);
+ if (test_exe) |exe| exe.linkSystemLibrary2("glfw3", dynamic_link_opts);
+ } else {
+ module.linkLibrary(lib);
+ b.installArtifact(lib);
+ if (test_exe) |exe| exe.linkLibrary(lib);
+ }
+}
+
+fn buildLib(
+ b: *std.Build,
+ module: *std.Build.Module,
+ options: anytype,
+) !*std.Build.Step.Compile {
+ const target = options.target;
+ const optimize = options.optimize;
+
+ const use_x11 = b.option(
+ bool,
+ "x11",
+ "Build with X11. Only useful on Linux",
+ ) orelse true;
+ const use_wl = b.option(
+ bool,
+ "wayland",
+ "Build with Wayland. Only useful on Linux",
+ ) orelse true;
+
+ const use_opengl = b.option(
+ bool,
+ "opengl",
+ "Build with OpenGL; deprecated on MacOS",
+ ) orelse false;
+ const use_gles = b.option(
+ bool,
+ "gles",
+ "Build with GLES; not supported on MacOS",
+ ) orelse false;
+ const use_metal = b.option(
+ bool,
+ "metal",
+ "Build with Metal; only supported on MacOS",
+ ) orelse true;
+
+ const lib = b.addStaticLibrary(.{
+ .name = "glfw",
+ .target = target,
+ .optimize = optimize,
+ });
+ lib.linkLibC();
+
+ const upstream = b.lazyDependency("glfw", .{}) orelse return lib;
+ lib.addIncludePath(upstream.path("include"));
+ module.addIncludePath(upstream.path("include"));
+ lib.installHeadersDirectory(upstream.path("include/GLFW"), "GLFW", .{});
+
+ switch (target.result.os.tag) {
+ .windows => {
+ lib.linkSystemLibrary("gdi32");
+ lib.linkSystemLibrary("user32");
+ lib.linkSystemLibrary("shell32");
+
+ if (use_opengl) {
+ lib.linkSystemLibrary("opengl32");
+ }
+
+ if (use_gles) {
+ lib.linkSystemLibrary("GLESv3");
+ }
+
+ const flags = [_][]const u8{"-D_GLFW_WIN32"};
+ lib.addCSourceFiles(.{
+ .root = upstream.path(""),
+ .files = &base_sources,
+ .flags = &flags,
+ });
+ lib.addCSourceFiles(.{
+ .root = upstream.path(""),
+ .files = &windows_sources,
+ .flags = &flags,
+ });
+ },
+
+ .macos => {
+ try apple_sdk.addPaths(b, lib.root_module);
+ try apple_sdk.addPaths(b, module);
+
+ // Transitive dependencies, explicit linkage of these works around
+ // ziglang/zig#17130
+ lib.linkFramework("CFNetwork");
+ lib.linkFramework("ApplicationServices");
+ lib.linkFramework("ColorSync");
+ lib.linkFramework("CoreText");
+ lib.linkFramework("ImageIO");
+
+ // Direct dependencies
+ lib.linkSystemLibrary("objc");
+ lib.linkFramework("IOKit");
+ lib.linkFramework("CoreFoundation");
+ lib.linkFramework("AppKit");
+ lib.linkFramework("CoreServices");
+ lib.linkFramework("CoreGraphics");
+ lib.linkFramework("Foundation");
+
+ if (use_metal) {
+ lib.linkFramework("Metal");
+ }
+
+ if (use_opengl) {
+ lib.linkFramework("OpenGL");
+ }
+
+ const flags = [_][]const u8{"-D_GLFW_COCOA"};
+ lib.addCSourceFiles(.{
+ .root = upstream.path(""),
+ .files = &base_sources,
+ .flags = &flags,
+ });
+ lib.addCSourceFiles(.{
+ .root = upstream.path(""),
+ .files = &macos_sources,
+ .flags = &flags,
+ });
+ },
+
+ // everything that isn't windows or mac is linux :P
+ else => {
+ var sources = std.BoundedArray([]const u8, 64).init(0) catch unreachable;
+ var flags = std.BoundedArray([]const u8, 16).init(0) catch unreachable;
+
+ sources.appendSlice(&base_sources) catch unreachable;
+ sources.appendSlice(&linux_sources) catch unreachable;
+
+ if (use_x11) {
+ lib.linkSystemLibrary2("X11", dynamic_link_opts);
+ lib.linkSystemLibrary2("xkbcommon", dynamic_link_opts);
+ sources.appendSlice(&linux_x11_sources) catch unreachable;
+ flags.append("-D_GLFW_X11") catch unreachable;
+ }
+
+ if (use_wl) {
+ lib.linkSystemLibrary2("wayland-client", dynamic_link_opts);
+
+ lib.root_module.addCMacro("WL_MARSHAL_FLAG_DESTROY", "1");
+ lib.addIncludePath(b.path("wayland-headers"));
+
+ sources.appendSlice(&linux_wl_sources) catch unreachable;
+ flags.append("-D_GLFW_WAYLAND") catch unreachable;
+ flags.append("-Wno-implicit-function-declaration") catch unreachable;
+ }
+
+ lib.addCSourceFiles(.{
+ .root = upstream.path(""),
+ .files = sources.slice(),
+ .flags = flags.slice(),
+ });
+ },
+ }
+
+ return lib;
+}
+
+// For dynamic linking, we prefer dynamic linking and to search by
+// mode first. Mode first will search all paths for a dynamic library
+// before falling back to static.
+const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{
+ .preferred_link_mode = .dynamic,
+ .search_strategy = .mode_first,
+};
+
+const base_sources = [_][]const u8{
+ "src/context.c",
+ "src/egl_context.c",
+ "src/init.c",
+ "src/input.c",
+ "src/monitor.c",
+ "src/null_init.c",
+ "src/null_joystick.c",
+ "src/null_monitor.c",
+ "src/null_window.c",
+ "src/osmesa_context.c",
+ "src/platform.c",
+ "src/vulkan.c",
+ "src/window.c",
+};
+
+const linux_sources = [_][]const u8{
+ "src/linux_joystick.c",
+ "src/posix_module.c",
+ "src/posix_poll.c",
+ "src/posix_thread.c",
+ "src/posix_time.c",
+ "src/xkb_unicode.c",
+};
+
+const linux_wl_sources = [_][]const u8{
+ "src/wl_init.c",
+ "src/wl_monitor.c",
+ "src/wl_window.c",
+};
+
+const linux_x11_sources = [_][]const u8{
+ "src/glx_context.c",
+ "src/x11_init.c",
+ "src/x11_monitor.c",
+ "src/x11_window.c",
+};
+
+const windows_sources = [_][]const u8{
+ "src/wgl_context.c",
+ "src/win32_init.c",
+ "src/win32_joystick.c",
+ "src/win32_module.c",
+ "src/win32_monitor.c",
+ "src/win32_thread.c",
+ "src/win32_time.c",
+ "src/win32_window.c",
+};
+
+const macos_sources = [_][]const u8{
+ // C sources
+ "src/cocoa_time.c",
+ "src/posix_module.c",
+ "src/posix_thread.c",
+
+ // ObjC sources
+ "src/cocoa_init.m",
+ "src/cocoa_joystick.m",
+ "src/cocoa_monitor.m",
+ "src/cocoa_window.m",
+ "src/nsgl_context.m",
+};
diff --git a/pkg/glfw/build.zig.zon b/pkg/glfw/build.zig.zon
new file mode 100644
index 000000000..6fd6c81a8
--- /dev/null
+++ b/pkg/glfw/build.zig.zon
@@ -0,0 +1,15 @@
+.{
+ .name = .glfw,
+ .version = "3.4.0",
+ .fingerprint = 0x3bbe0a5c667e2c62,
+ .paths = .{""},
+ .dependencies = .{
+ .glfw = .{
+ .url = "https://github.com/glfw/glfw/archive/73948e6c0f15b1053cf74b7c4e6b04fd36e97e29.zip",
+ .hash = "N-V-__8AADTkRwBjUvVwTLOnV96QhN0J5Nyg7YzvnISe-Eax",
+ .lazy = true,
+ },
+
+ .apple_sdk = .{ .path = "../apple-sdk" },
+ },
+}
diff --git a/pkg/glfw/c.zig b/pkg/glfw/c.zig
new file mode 100644
index 000000000..58599025b
--- /dev/null
+++ b/pkg/glfw/c.zig
@@ -0,0 +1,6 @@
+pub const c = @cImport({
+ // Must be uncommented for vulkan.zig to work
+ // @cDefine("GLFW_INCLUDE_VULKAN", "1");
+ @cDefine("GLFW_INCLUDE_NONE", "1");
+ @cInclude("GLFW/glfw3.h");
+});
diff --git a/pkg/glfw/clipboard.zig b/pkg/glfw/clipboard.zig
new file mode 100644
index 000000000..a7e2d0e2f
--- /dev/null
+++ b/pkg/glfw/clipboard.zig
@@ -0,0 +1,71 @@
+const std = @import("std");
+
+const c = @import("c.zig").c;
+
+const internal_debug = @import("internal_debug.zig");
+
+/// Sets the clipboard to the specified string.
+///
+/// This function sets the system clipboard to the specified, UTF-8 encoded string.
+///
+/// @param[in] string A UTF-8 encoded string.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @pointer_lifetime The specified string is copied before this function returns.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: clipboard, glfwGetClipboardString
+pub inline fn setClipboardString(value: [*:0]const u8) void {
+ internal_debug.assertInitialized();
+ c.glfwSetClipboardString(null, value);
+}
+
+/// 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,
+/// glfw.ErrorCode.FormatUnavailable is returned.
+///
+/// @return The contents of the clipboard as a UTF-8 encoded string.
+///
+/// Possible errors include glfw.ErrorCode.FormatUnavailable and glfw.ErrorCode.PlatformError.
+/// null is returned in the event of an 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 glfw.getClipboardString or glfw.setClipboardString
+/// or until the library is terminated.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: clipboard, glfwSetClipboardString
+pub inline fn getClipboardString() ?[:0]const u8 {
+ internal_debug.assertInitialized();
+ if (c.glfwGetClipboardString(null)) |c_str| return std.mem.span(@as([*:0]const u8, @ptrCast(c_str)));
+ return null;
+}
+
+test "setClipboardString" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ glfw.setClipboardString("hello mach");
+}
+
+test "getClipboardString" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = glfw.getClipboardString();
+}
diff --git a/pkg/glfw/errors.zig b/pkg/glfw/errors.zig
new file mode 100644
index 000000000..ce98ec5cd
--- /dev/null
+++ b/pkg/glfw/errors.zig
@@ -0,0 +1,338 @@
+//! Errors
+
+const testing = @import("std").testing;
+const mem = @import("std").mem;
+const c = @import("c.zig").c;
+
+/// Errors that GLFW can produce.
+pub const ErrorCode = error{
+ /// GLFW has not been initialized.
+ ///
+ /// This occurs if a GLFW function was called that must not be called unless the library is
+ /// initialized.
+ NotInitialized,
+
+ /// 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
+ /// glfw.SwapInterval.
+ NoCurrentContext,
+
+ /// 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
+ /// glfw.red_bits with glfw.getWindowAttrib.
+ InvalidEnum,
+
+ /// 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
+ /// glfw.ErrorCode.VersionUnavailable error.
+ InvalidValue,
+
+ /// A memory allocation failed.
+ OutOfMemory,
+
+ /// GLFW could not find support for the requested API on the system.
+ ///
+ /// The installed graphics driver does not support the requested API, or does not support it
+ /// via the chosen context creation API. Below are a few examples.
+ ///
+ /// 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.
+ APIUnavailable,
+
+ /// The requested OpenGL or OpenGL ES version (including any requested context or framebuffer
+ /// hints) is not available on this machine.
+ ///
+ /// 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.
+ ///
+ /// 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 glfw.ErrorCode.InvalidValue,
+ /// because GLFW cannot know what future versions will exist.
+ VersionUnavailable,
+
+ /// A platform-specific error occurred that does not match any of the more specific categories.
+ ///
+ /// 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).
+ PlatformError,
+
+ /// 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.
+ ///
+ /// If emitted during window creation, one or more hard constraints 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.
+ ///
+ /// If emitted when querying the clipboard, ignore the error or report it to the user, as
+ /// appropriate.
+ FormatUnavailable,
+
+ /// 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.
+ NoWindowContext,
+
+ /// The specified cursor shape is not available.
+ ///
+ /// The specified standard cursor shape is not available, either because the
+ /// current platform cursor theme does not provide it or because it is not
+ /// available on the platform.
+ ///
+ /// analysis: Platform or system settings limitation. Pick another standard cursor shape or
+ /// create a custom cursor.
+ CursorUnavailable,
+
+ /// The requested feature is not provided by the platform.
+ ///
+ /// The requested feature is not provided by the platform, so GLFW is unable to
+ /// implement it. The documentation for each function notes if it could emit
+ /// this error.
+ ///
+ /// analysis: Platform or platform version limitation. The error can be ignored
+ /// unless the feature is critical to the application.
+ ///
+ /// A function call that emits this error has no effect other than the error and
+ /// updating any existing out parameters.
+ ///
+ FeatureUnavailable,
+
+ /// The requested feature is not implemented for the platform.
+ ///
+ /// The requested feature has not yet been implemented in GLFW for this platform.
+ ///
+ /// analysis: An incomplete implementation of GLFW for this platform, hopefully
+ /// fixed in a future release. The error can be ignored unless the feature is
+ /// critical to the application.
+ ///
+ /// A function call that emits this error has no effect other than the error and
+ /// updating any existing out parameters.
+ ///
+ FeatureUnimplemented,
+
+ /// Platform unavailable or no matching platform was found.
+ ///
+ /// If emitted during initialization, no matching platform was found. If glfw.InitHint.platform
+ /// is set to `.any_platform`, GLFW could not detect any of the platforms supported by this
+ /// library binary, except for the Null platform. If set to a specific platform, it is either
+ /// not supported by this library binary or GLFW was not able to detect it.
+ ///
+ /// If emitted by a native access function, GLFW was initialized for a different platform
+ /// than the function is for.
+ ///
+ /// analysis: Failure to detect any platform usually only happens on non-macOS Unix
+ /// systems, either when no window system is running or the program was run from
+ /// a terminal that does not have the necessary environment variables. Fall back to
+ /// a different platform if possible or notify the user that no usable platform was
+ /// detected.
+ ///
+ /// Failure to detect a specific platform may have the same cause as above or be because
+ /// support for that platform was not compiled in. Call glfw.platformSupported to
+ /// check whether a specific platform is supported by a library binary.
+ ///
+ PlatformUnavailable,
+};
+
+/// An error produced by GLFW and the description associated with it.
+pub const Error = struct {
+ error_code: ErrorCode,
+ description: [:0]const u8,
+};
+
+fn convertError(e: c_int) ErrorCode!void {
+ return switch (e) {
+ c.GLFW_NO_ERROR => {},
+ c.GLFW_NOT_INITIALIZED => ErrorCode.NotInitialized,
+ c.GLFW_NO_CURRENT_CONTEXT => ErrorCode.NoCurrentContext,
+ c.GLFW_INVALID_ENUM => ErrorCode.InvalidEnum,
+ c.GLFW_INVALID_VALUE => ErrorCode.InvalidValue,
+ c.GLFW_OUT_OF_MEMORY => ErrorCode.OutOfMemory,
+ c.GLFW_API_UNAVAILABLE => ErrorCode.APIUnavailable,
+ c.GLFW_VERSION_UNAVAILABLE => ErrorCode.VersionUnavailable,
+ c.GLFW_PLATFORM_ERROR => ErrorCode.PlatformError,
+ c.GLFW_FORMAT_UNAVAILABLE => ErrorCode.FormatUnavailable,
+ c.GLFW_NO_WINDOW_CONTEXT => ErrorCode.NoWindowContext,
+ c.GLFW_CURSOR_UNAVAILABLE => ErrorCode.CursorUnavailable,
+ c.GLFW_FEATURE_UNAVAILABLE => ErrorCode.FeatureUnavailable,
+ c.GLFW_FEATURE_UNIMPLEMENTED => ErrorCode.FeatureUnimplemented,
+ c.GLFW_PLATFORM_UNAVAILABLE => ErrorCode.PlatformUnavailable,
+ else => unreachable,
+ };
+}
+
+/// Clears the last error and the error description pointer for the calling thread. Does nothing if
+/// no error has occurred since the last call.
+///
+/// @remark This function may be called before @ref glfwInit.
+///
+/// @thread_safety This function may be called from any thread.
+pub inline fn clearError() void {
+ _ = c.glfwGetError(null);
+}
+
+/// Returns and clears the last error for the calling thread.
+///
+/// This function returns and clears the error code of the last error that occurred on the calling
+/// thread, along with a UTF-8 encoded human-readable description of it. If no error has occurred
+/// since the last call, it returns GLFW_NO_ERROR (zero) and the description pointer is set to
+/// `NULL`.
+///
+/// @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.
+pub inline fn getError() ?Error {
+ var desc: [*c]const u8 = null;
+ convertError(c.glfwGetError(&desc)) catch |error_code| {
+ return .{
+ .error_code = error_code,
+ .description = mem.sliceTo(desc, 0),
+ };
+ };
+ return null;
+}
+
+pub inline fn mustGetError() Error {
+ return getError() orelse {
+ @panic("glfw: mustGetError called but no error is present");
+ };
+}
+
+/// Returns and clears the last error for the calling thread.
+///
+/// This function returns and clears the error code of the last error that occurred on the calling
+/// thread. If no error has occurred since the last call, it returns GLFW_NO_ERROR (zero).
+///
+/// @return The last error code for the calling thread, or @ref GLFW_NO_ERROR (zero).
+///
+/// @remark This function may be called before @ref glfwInit.
+///
+/// @thread_safety This function may be called from any thread.
+pub inline fn getErrorCode() ErrorCode!void {
+ return convertError(c.glfwGetError(null));
+}
+
+/// Returns and clears the last error code for the calling thread. If no error is present, this
+/// function panics.
+pub inline fn mustGetErrorCode() ErrorCode {
+ try getErrorCode();
+ @panic("glfw: mustGetErrorCode called but no error is present");
+}
+
+/// Returns and clears the last error description for the calling thread.
+///
+/// This function returns a UTF-8 encoded human-readable description of the last error that occured
+/// on the calling thread. If no error has occurred since the last call, it returns null.
+///
+/// @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.
+pub inline fn getErrorString() ?[:0]const u8 {
+ var desc: [*c]const u8 = null;
+ const error_code = c.glfwGetError(&desc);
+ if (error_code != c.GLFW_NO_ERROR) {
+ return mem.sliceTo(desc, 0);
+ }
+ return null;
+}
+
+/// Returns and clears the last error description for the calling thread. If no error is present,
+/// this function panics.
+pub inline fn mustGetErrorString() [:0]const u8 {
+ return getErrorString() orelse {
+ @panic("glfw: mustGetErrorString called but no error is present");
+ };
+}
+
+/// 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.
+///
+/// @param[in] callback The new callback, or `NULL` to remove the currently set
+/// callback.
+///
+/// @callback_param `error_code` An error code. Future releases may add more error codes.
+/// @callback_param `description` A UTF-8 encoded string describing the error.
+///
+/// @errors None.
+///
+/// @remark This function may be called before @ref glfwInit.
+///
+/// @thread_safety This function must only be called from the main thread.
+pub fn setErrorCallback(comptime callback: ?fn (error_code: ErrorCode, description: [:0]const u8) void) void {
+ if (callback) |user_callback| {
+ const CWrapper = struct {
+ pub fn errorCallbackWrapper(err_int: c_int, c_description: [*c]const u8) callconv(.C) void {
+ convertError(err_int) catch |error_code| {
+ user_callback(error_code, mem.sliceTo(c_description, 0));
+ };
+ }
+ };
+
+ _ = c.glfwSetErrorCallback(CWrapper.errorCallbackWrapper);
+ return;
+ }
+
+ _ = c.glfwSetErrorCallback(null);
+}
+
+test "set error callback" {
+ const TestStruct = struct {
+ pub fn callback(_: ErrorCode, _: [:0]const u8) void {}
+ };
+ setErrorCallback(TestStruct.callback);
+}
+
+test "error string" {
+ try testing.expect(getErrorString() == null);
+}
+
+test "error code" {
+ try getErrorCode();
+}
+
+test "error code and string" {
+ try testing.expect(getError() == null);
+}
+
+test "clear error" {
+ clearError();
+}
diff --git a/pkg/glfw/gamepad_axis.zig b/pkg/glfw/gamepad_axis.zig
new file mode 100644
index 000000000..97fdf3748
--- /dev/null
+++ b/pkg/glfw/gamepad_axis.zig
@@ -0,0 +1,16 @@
+const c = @import("c.zig").c;
+
+/// Gamepad axes.
+///
+/// See glfw.getGamepadState for how these are used.
+pub const GamepadAxis = enum(c_int) {
+ left_x = c.GLFW_GAMEPAD_AXIS_LEFT_X,
+ left_y = c.GLFW_GAMEPAD_AXIS_LEFT_Y,
+ right_x = c.GLFW_GAMEPAD_AXIS_RIGHT_X,
+ right_y = c.GLFW_GAMEPAD_AXIS_RIGHT_Y,
+ left_trigger = c.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER,
+ right_trigger = c.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER,
+};
+
+/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
+pub const last = GamepadAxis.right_trigger;
diff --git a/pkg/glfw/gamepad_button.zig b/pkg/glfw/gamepad_button.zig
new file mode 100644
index 000000000..ac47ebea0
--- /dev/null
+++ b/pkg/glfw/gamepad_button.zig
@@ -0,0 +1,37 @@
+const c = @import("c.zig").c;
+
+/// Gamepad buttons.
+///
+/// See glfw.getGamepadState for how these are used.
+pub const GamepadButton = enum(c_int) {
+ a = c.GLFW_GAMEPAD_BUTTON_A,
+ b = c.GLFW_GAMEPAD_BUTTON_B,
+ x = c.GLFW_GAMEPAD_BUTTON_X,
+ y = c.GLFW_GAMEPAD_BUTTON_Y,
+ left_bumper = c.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER,
+ right_bumper = c.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER,
+ back = c.GLFW_GAMEPAD_BUTTON_BACK,
+ start = c.GLFW_GAMEPAD_BUTTON_START,
+ guide = c.GLFW_GAMEPAD_BUTTON_GUIDE,
+ left_thumb = c.GLFW_GAMEPAD_BUTTON_LEFT_THUMB,
+ right_thumb = c.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB,
+ dpad_up = c.GLFW_GAMEPAD_BUTTON_DPAD_UP,
+ dpad_right = c.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT,
+ dpad_down = c.GLFW_GAMEPAD_BUTTON_DPAD_DOWN,
+ dpad_left = c.GLFW_GAMEPAD_BUTTON_DPAD_LEFT,
+};
+
+/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
+pub const last = GamepadButton.dpad_left;
+
+/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
+pub const cross = GamepadButton.a;
+
+/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
+pub const circle = GamepadButton.b;
+
+/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
+pub const square = GamepadButton.x;
+
+/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
+pub const triangle = GamepadButton.y;
diff --git a/pkg/glfw/hat.zig b/pkg/glfw/hat.zig
new file mode 100644
index 000000000..ffbb4a1c8
--- /dev/null
+++ b/pkg/glfw/hat.zig
@@ -0,0 +1,100 @@
+const c = @import("c.zig").c;
+
+// must be in sync with GLFW C constants in hat state group, search for "@defgroup hat_state Joystick hat states"
+/// A bitmask of all Joystick hat states
+///
+/// See glfw.Joystick.getHats for how these are used.
+pub const Hat = packed struct(u8) {
+ up: bool = false,
+ right: bool = false,
+ down: bool = false,
+ left: bool = false,
+ _padding: u4 = 0,
+
+ pub inline fn centered(self: Hat) bool {
+ return self.up == false and self.right == false and self.down == false and self.left == false;
+ }
+
+ inline fn verifyIntType(comptime IntType: type) void {
+ comptime {
+ switch (@import("shims.zig").typeInfo(IntType)) {
+ .int => {},
+ else => @compileError("Int was not of int type"),
+ }
+ }
+ }
+
+ pub inline fn toInt(self: Hat, comptime IntType: type) IntType {
+ verifyIntType(IntType);
+ return @as(IntType, @intCast(@as(u8, @bitCast(self))));
+ }
+
+ pub inline fn fromInt(flags: anytype) Hat {
+ verifyIntType(@TypeOf(flags));
+ return @as(Hat, @bitCast(@as(u8, @intCast(flags))));
+ }
+};
+
+/// Holds all GLFW hat values in their raw form.
+pub const RawHat = struct {
+ pub const centered = c.GLFW_HAT_CENTERED;
+ pub const up = c.GLFW_HAT_UP;
+ pub const right = c.GLFW_HAT_RIGHT;
+ pub const down = c.GLFW_HAT_DOWN;
+ pub const left = c.GLFW_HAT_LEFT;
+
+ pub const right_up = right | up;
+ pub const right_down = right | down;
+ pub const left_up = left | up;
+ pub const left_down = left | down;
+};
+
+test "from int, single" {
+ const std = @import("std");
+
+ try std.testing.expectEqual(Hat{
+ .up = true,
+ .right = false,
+ .down = false,
+ .left = false,
+ ._padding = 0,
+ }, Hat.fromInt(RawHat.up));
+}
+
+test "from int, multi" {
+ const std = @import("std");
+
+ try std.testing.expectEqual(Hat{
+ .up = true,
+ .right = false,
+ .down = true,
+ .left = true,
+ ._padding = 0,
+ }, Hat.fromInt(RawHat.up | RawHat.down | RawHat.left));
+}
+
+test "to int, single" {
+ const std = @import("std");
+
+ var v = Hat{
+ .up = true,
+ .right = false,
+ .down = false,
+ .left = false,
+ ._padding = 0,
+ };
+ try std.testing.expectEqual(v.toInt(c_int), RawHat.up);
+}
+
+test "to int, multi" {
+ const std = @import("std");
+
+ var v = Hat{
+ .up = true,
+ .right = false,
+ .down = true,
+ .left = true,
+ ._padding = 0,
+ };
+ try std.testing.expectEqual(v.toInt(c_int), RawHat.up | RawHat.down | RawHat.left);
+}
diff --git a/pkg/glfw/internal_debug.zig b/pkg/glfw/internal_debug.zig
new file mode 100644
index 000000000..6e0ab4f1e
--- /dev/null
+++ b/pkg/glfw/internal_debug.zig
@@ -0,0 +1,14 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+const is_debug = builtin.mode == .Debug;
+var glfw_initialized = if (is_debug) false else @as(void, {});
+pub inline fn toggleInitialized() void {
+ if (is_debug) glfw_initialized = !glfw_initialized;
+}
+pub inline fn assertInitialized() void {
+ if (is_debug) std.debug.assert(glfw_initialized);
+}
+pub inline fn assumeInitialized() void {
+ if (is_debug) glfw_initialized = true;
+}
diff --git a/pkg/glfw/key.zig b/pkg/glfw/key.zig
new file mode 100644
index 000000000..27b13119c
--- /dev/null
+++ b/pkg/glfw/key.zig
@@ -0,0 +1,266 @@
+//! Keyboard key IDs.
+//!
+//! See glfw.setKeyCallback 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 alphanumeric characters are used (e.g. "a", "r", "three", etc.)
+//! - For non-alphanumeric characters, Unicode:ish names are used (e.g. "comma", "left_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.)
+
+const std = @import("std");
+
+const cc = @import("c.zig").c;
+
+const internal_debug = @import("internal_debug.zig");
+
+/// enum containing all glfw keys
+pub const Key = enum(c_int) {
+ /// The unknown key
+ unknown = cc.GLFW_KEY_UNKNOWN,
+
+ /// Printable keys
+ space = cc.GLFW_KEY_SPACE,
+ apostrophe = cc.GLFW_KEY_APOSTROPHE,
+ comma = cc.GLFW_KEY_COMMA,
+ minus = cc.GLFW_KEY_MINUS,
+ period = cc.GLFW_KEY_PERIOD,
+ slash = cc.GLFW_KEY_SLASH,
+ zero = cc.GLFW_KEY_0,
+ one = cc.GLFW_KEY_1,
+ two = cc.GLFW_KEY_2,
+ three = cc.GLFW_KEY_3,
+ four = cc.GLFW_KEY_4,
+ five = cc.GLFW_KEY_5,
+ six = cc.GLFW_KEY_6,
+ seven = cc.GLFW_KEY_7,
+ eight = cc.GLFW_KEY_8,
+ nine = cc.GLFW_KEY_9,
+ semicolon = cc.GLFW_KEY_SEMICOLON,
+ equal = cc.GLFW_KEY_EQUAL,
+ a = cc.GLFW_KEY_A,
+ b = cc.GLFW_KEY_B,
+ c = cc.GLFW_KEY_C,
+ d = cc.GLFW_KEY_D,
+ e = cc.GLFW_KEY_E,
+ f = cc.GLFW_KEY_F,
+ g = cc.GLFW_KEY_G,
+ h = cc.GLFW_KEY_H,
+ i = cc.GLFW_KEY_I,
+ j = cc.GLFW_KEY_J,
+ k = cc.GLFW_KEY_K,
+ l = cc.GLFW_KEY_L,
+ m = cc.GLFW_KEY_M,
+ n = cc.GLFW_KEY_N,
+ o = cc.GLFW_KEY_O,
+ p = cc.GLFW_KEY_P,
+ q = cc.GLFW_KEY_Q,
+ r = cc.GLFW_KEY_R,
+ s = cc.GLFW_KEY_S,
+ t = cc.GLFW_KEY_T,
+ u = cc.GLFW_KEY_U,
+ v = cc.GLFW_KEY_V,
+ w = cc.GLFW_KEY_W,
+ x = cc.GLFW_KEY_X,
+ y = cc.GLFW_KEY_Y,
+ z = cc.GLFW_KEY_Z,
+ left_bracket = cc.GLFW_KEY_LEFT_BRACKET,
+ backslash = cc.GLFW_KEY_BACKSLASH,
+ right_bracket = cc.GLFW_KEY_RIGHT_BRACKET,
+ grave_accent = cc.GLFW_KEY_GRAVE_ACCENT,
+ world_1 = cc.GLFW_KEY_WORLD_1, // non-US #1
+ world_2 = cc.GLFW_KEY_WORLD_2, // non-US #2
+
+ // Function keys
+ escape = cc.GLFW_KEY_ESCAPE,
+ enter = cc.GLFW_KEY_ENTER,
+ tab = cc.GLFW_KEY_TAB,
+ backspace = cc.GLFW_KEY_BACKSPACE,
+ insert = cc.GLFW_KEY_INSERT,
+ delete = cc.GLFW_KEY_DELETE,
+ right = cc.GLFW_KEY_RIGHT,
+ left = cc.GLFW_KEY_LEFT,
+ down = cc.GLFW_KEY_DOWN,
+ up = cc.GLFW_KEY_UP,
+ page_up = cc.GLFW_KEY_PAGE_UP,
+ page_down = cc.GLFW_KEY_PAGE_DOWN,
+ home = cc.GLFW_KEY_HOME,
+ end = cc.GLFW_KEY_END,
+ caps_lock = cc.GLFW_KEY_CAPS_LOCK,
+ scroll_lock = cc.GLFW_KEY_SCROLL_LOCK,
+ num_lock = cc.GLFW_KEY_NUM_LOCK,
+ print_screen = cc.GLFW_KEY_PRINT_SCREEN,
+ pause = cc.GLFW_KEY_PAUSE,
+ F1 = cc.GLFW_KEY_F1,
+ F2 = cc.GLFW_KEY_F2,
+ F3 = cc.GLFW_KEY_F3,
+ F4 = cc.GLFW_KEY_F4,
+ F5 = cc.GLFW_KEY_F5,
+ F6 = cc.GLFW_KEY_F6,
+ F7 = cc.GLFW_KEY_F7,
+ F8 = cc.GLFW_KEY_F8,
+ F9 = cc.GLFW_KEY_F9,
+ F10 = cc.GLFW_KEY_F10,
+ F11 = cc.GLFW_KEY_F11,
+ F12 = cc.GLFW_KEY_F12,
+ F13 = cc.GLFW_KEY_F13,
+ F14 = cc.GLFW_KEY_F14,
+ F15 = cc.GLFW_KEY_F15,
+ F16 = cc.GLFW_KEY_F16,
+ F17 = cc.GLFW_KEY_F17,
+ F18 = cc.GLFW_KEY_F18,
+ F19 = cc.GLFW_KEY_F19,
+ F20 = cc.GLFW_KEY_F20,
+ F21 = cc.GLFW_KEY_F21,
+ F22 = cc.GLFW_KEY_F22,
+ F23 = cc.GLFW_KEY_F23,
+ F24 = cc.GLFW_KEY_F24,
+ F25 = cc.GLFW_KEY_F25,
+ kp_0 = cc.GLFW_KEY_KP_0,
+ kp_1 = cc.GLFW_KEY_KP_1,
+ kp_2 = cc.GLFW_KEY_KP_2,
+ kp_3 = cc.GLFW_KEY_KP_3,
+ kp_4 = cc.GLFW_KEY_KP_4,
+ kp_5 = cc.GLFW_KEY_KP_5,
+ kp_6 = cc.GLFW_KEY_KP_6,
+ kp_7 = cc.GLFW_KEY_KP_7,
+ kp_8 = cc.GLFW_KEY_KP_8,
+ kp_9 = cc.GLFW_KEY_KP_9,
+ kp_decimal = cc.GLFW_KEY_KP_DECIMAL,
+ kp_divide = cc.GLFW_KEY_KP_DIVIDE,
+ kp_multiply = cc.GLFW_KEY_KP_MULTIPLY,
+ kp_subtract = cc.GLFW_KEY_KP_SUBTRACT,
+ kp_add = cc.GLFW_KEY_KP_ADD,
+ kp_enter = cc.GLFW_KEY_KP_ENTER,
+ kp_equal = cc.GLFW_KEY_KP_EQUAL,
+ left_shift = cc.GLFW_KEY_LEFT_SHIFT,
+ left_control = cc.GLFW_KEY_LEFT_CONTROL,
+ left_alt = cc.GLFW_KEY_LEFT_ALT,
+ left_super = cc.GLFW_KEY_LEFT_SUPER,
+ right_shift = cc.GLFW_KEY_RIGHT_SHIFT,
+ right_control = cc.GLFW_KEY_RIGHT_CONTROL,
+ right_alt = cc.GLFW_KEY_RIGHT_ALT,
+ right_super = cc.GLFW_KEY_RIGHT_SUPER,
+ menu = cc.GLFW_KEY_MENU,
+
+ pub inline fn last() Key {
+ return @as(Key, @enumFromInt(cc.GLFW_KEY_LAST));
+ }
+
+ /// 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 (see 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 (see 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.
+ ///
+ /// @param[in] key The key to query, or `glfw.key.unknown`.
+ /// @param[in] scancode The scancode of the key to query.
+ /// @return The UTF-8 encoded, layout-specific name of the key, or null.
+ ///
+ /// Possible errors include glfw.ErrorCode.PlatformError.
+ /// Also returns null in the event of an error.
+ ///
+ /// 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.
+ ///
+ /// see also: input_key_name
+ pub inline fn getName(self: Key, scancode: i32) ?[:0]const u8 {
+ internal_debug.assertInitialized();
+ const name_opt = cc.glfwGetKeyName(@intFromEnum(self), @as(c_int, @intCast(scancode)));
+ return if (name_opt) |name|
+ std.mem.span(@as([*:0]const u8, @ptrCast(name)))
+ else
+ null;
+ }
+
+ /// 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`.
+ ///
+ /// @param[in] key Any named key (see keys).
+ /// @return The platform-specific scancode for the key.
+ ///
+ /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
+ /// Additionally returns -1 in the event of an error.
+ ///
+ /// @thread_safety This function may be called from any thread.
+ pub inline fn getScancode(self: Key) i32 {
+ internal_debug.assertInitialized();
+ return cc.glfwGetKeyScancode(@intFromEnum(self));
+ }
+};
+
+test "getName" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = glfw.Key.a.getName(0);
+}
+
+test "getScancode" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = glfw.Key.a.getScancode();
+}
diff --git a/pkg/glfw/main.zig b/pkg/glfw/main.zig
new file mode 100644
index 000000000..329f17ed2
--- /dev/null
+++ b/pkg/glfw/main.zig
@@ -0,0 +1,586 @@
+const std = @import("std");
+const testing = std.testing;
+
+const c = @import("c.zig").c;
+
+const key = @import("key.zig");
+const errors = @import("errors.zig");
+
+/// Possible value for various window hints, etc.
+pub const dont_care = c.GLFW_DONT_CARE;
+
+pub const getError = errors.getError;
+pub const mustGetError = errors.mustGetError;
+pub const getErrorCode = errors.getErrorCode;
+pub const mustGetErrorCode = errors.mustGetErrorCode;
+pub const getErrorString = errors.getErrorString;
+pub const mustGetErrorString = errors.mustGetErrorString;
+pub const setErrorCallback = errors.setErrorCallback;
+pub const clearError = errors.clearError;
+pub const ErrorCode = errors.ErrorCode;
+pub const Error = errors.Error;
+
+pub const Action = @import("action.zig").Action;
+pub const GamepadAxis = @import("gamepad_axis.zig").GamepadAxis;
+pub const GamepadButton = @import("gamepad_button.zig").GamepadButton;
+pub const gamepad_axis = @import("gamepad_axis.zig");
+pub const gamepad_button = @import("gamepad_button.zig");
+pub const GammaRamp = @import("GammaRamp.zig");
+pub const Image = @import("Image.zig");
+pub const Joystick = @import("Joystick.zig");
+pub const Monitor = @import("Monitor.zig");
+pub const mouse_button = @import("mouse_button.zig");
+pub const MouseButton = mouse_button.MouseButton;
+pub const version = @import("version.zig");
+pub const VideoMode = @import("VideoMode.zig");
+pub const Window = @import("Window.zig");
+pub const Cursor = @import("Cursor.zig");
+pub const Native = @import("native.zig").Native;
+pub const BackendOptions = @import("native.zig").BackendOptions;
+pub const Key = key.Key;
+pub const setClipboardString = @import("clipboard.zig").setClipboardString;
+pub const getClipboardString = @import("clipboard.zig").getClipboardString;
+pub const makeContextCurrent = @import("opengl.zig").makeContextCurrent;
+pub const getCurrentContext = @import("opengl.zig").getCurrentContext;
+pub const swapInterval = @import("opengl.zig").swapInterval;
+pub const extensionSupported = @import("opengl.zig").extensionSupported;
+pub const GLProc = @import("opengl.zig").GLProc;
+pub const getProcAddress = @import("opengl.zig").getProcAddress;
+pub const getTime = @import("time.zig").getTime;
+pub const setTime = @import("time.zig").setTime;
+pub const getTimerValue = @import("time.zig").getTimerValue;
+pub const getTimerFrequency = @import("time.zig").getTimerFrequency;
+pub const Hat = @import("hat.zig").Hat;
+pub const RawHat = @import("hat.zig").RawHat;
+pub const Mods = @import("mod.zig").Mods;
+pub const RawMods = @import("mod.zig").RawMods;
+
+const internal_debug = @import("internal_debug.zig");
+
+/// If GLFW was already initialized in your program, e.g. you are embedding Zig code into an existing
+/// program that has already called glfwInit via the C API for you - then you need to tell mach/glfw
+/// that it has in fact been initialized already, otherwise when you call other methods mach/glfw
+/// would panic thinking glfw.init has not been called yet.
+pub fn assumeInitialized() void {
+ internal_debug.assumeInitialized();
+}
+
+/// 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 glfw.Terminate before returning. If it succeeds, you should
+/// call glfw.Terminate before the application exits.
+///
+/// Additional calls to this function after successful initialization but before termination will
+/// return immediately with no error.
+///
+/// The glfw.InitHint.platform init hint controls which platforms are considered during
+/// initialization. This also depends on which platforms the library was compiled to support.
+///
+/// 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 `glfw.InitHint.cocoa_chdir_resources`.
+///
+/// macos: This function will create the main menu and dock icon for the application. 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. The menu bar and dock icon can be
+/// disabled entirely with `glfw.InitHint.cocoa_menubar`.
+///
+/// x11: This function will set the `LC_CTYPE` category of the application locale according to the
+/// current environment if that category is still "C". This is because the "C" locale breaks
+/// Unicode text input.
+///
+/// Possible errors include glfw.ErrorCode.PlatformUnavailable, glfw.ErrorCode.PlatformError.
+/// Returns a bool indicating success.
+///
+/// @thread_safety This function must only be called from the main thread.
+pub inline fn init(hints: InitHints) bool {
+ internal_debug.toggleInitialized();
+ internal_debug.assertInitialized();
+ errdefer {
+ internal_debug.assertInitialized();
+ internal_debug.toggleInitialized();
+ }
+
+ inline for (comptime std.meta.fieldNames(InitHints)) |field_name| {
+ const init_hint = @field(InitHint, field_name);
+ const init_value = @field(hints, field_name);
+ if (@TypeOf(init_value) == PlatformType) {
+ initHint(init_hint, @intFromEnum(init_value));
+ } else {
+ initHint(init_hint, init_value);
+ }
+ }
+
+ return c.glfwInit() == c.GLFW_TRUE;
+}
+
+// TODO: implement custom allocator support
+//
+// /*! @brief Sets the init allocator to the desired value.
+// *
+// * To use the default allocator, call this function with a `NULL` argument.
+// *
+// * If you specify an allocator struct, every member must be a valid function
+// * pointer. If any member is `NULL`, this function emits @ref
+// * GLFW_INVALID_VALUE and the init allocator is unchanged.
+// *
+// * @param[in] allocator The allocator to use at the next initialization, or
+// * `NULL` to use the default one.
+// *
+// * @errors Possible errors include @ref GLFW_INVALID_VALUE.
+// *
+// * @pointer_lifetime The specified allocator is copied before this function
+// * returns.
+// *
+// * @thread_safety This function must only be called from the main thread.
+// *
+// * @sa @ref init_allocator
+// * @sa @ref glfwInit
+// *
+// * @since Added in version 3.4.
+// *
+// * @ingroup init
+// */
+// GLFWAPI void glfwInitAllocator(const GLFWallocator* allocator);
+
+/// 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
+/// glfw.init 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 glfw.init before it returns failure.
+///
+/// This function has no effect if GLFW is not initialized.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// 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.
+pub inline fn terminate() void {
+ internal_debug.assertInitialized();
+ internal_debug.toggleInitialized();
+ c.glfwTerminate();
+}
+
+/// Initialization hints for passing into glfw.init
+pub const InitHints = struct {
+ /// Specifies whether to also expose joystick hats as buttons, for compatibility with earlier
+ /// versions of GLFW that did not have glfwGetJoystickHats.
+ joystick_hat_buttons: bool = true,
+
+ /// macOS specific init hint. Ignored on other platforms.
+ ///
+ /// Specifies whether to set the current directory to the application to the Contents/Resources
+ /// subdirectory of the application's bundle, if present.
+ cocoa_chdir_resources: bool = true,
+
+ /// macOS specific init hint. Ignored on other platforms.
+ ///
+ /// specifies whether to create a basic menu bar, either from a nib or manually, when the first
+ /// window is created, which is when AppKit is initialized.
+ cocoa_menubar: bool = true,
+
+ /// Platform selection init hint.
+ ///
+ /// Possible values are `PlatformType` enums.
+ platform: PlatformType = .any,
+};
+
+/// Initialization hints for passing into glfw.initHint
+const InitHint = enum(c_int) {
+ /// Specifies whether to also expose joystick hats as buttons, for compatibility with earlier
+ /// versions of GLFW that did not have glfwGetJoystickHats.
+ ///
+ /// Possible values are `true` and `false`.
+ joystick_hat_buttons = c.GLFW_JOYSTICK_HAT_BUTTONS,
+
+ /// ANGLE rendering backend init hint.
+ ///
+ /// Possible values are `AnglePlatformType` enums.
+ angle_platform_type = c.GLFW_ANGLE_PLATFORM_TYPE,
+
+ /// Platform selection init hint.
+ ///
+ /// Possible values are `PlatformType` enums.
+ platform = c.GLFW_PLATFORM,
+
+ /// macOS specific init hint. Ignored on other platforms.
+ ///
+ /// Specifies whether to set the current directory to the application to the Contents/Resources
+ /// subdirectory of the application's bundle, if present.
+ ///
+ /// Possible values are `true` and `false`.
+ cocoa_chdir_resources = c.GLFW_COCOA_CHDIR_RESOURCES,
+
+ /// macOS specific init hint. Ignored on other platforms.
+ ///
+ /// specifies whether to create a basic menu bar, either from a nib or manually, when the first
+ /// window is created, which is when AppKit is initialized.
+ ///
+ /// Possible values are `true` and `false`.
+ cocoa_menubar = c.GLFW_COCOA_MENUBAR,
+
+ /// X11 specific init hint.
+ x11_xcb_vulkan_surface = c.GLFW_X11_XCB_VULKAN_SURFACE,
+
+ /// Wayland specific init hint.
+ ///
+ /// Possible values are `WaylandLibdecorInitHint` enums.
+ wayland_libdecor = c.GLFW_WAYLAND_LIBDECOR,
+};
+
+/// Angle platform type hints for glfw.InitHint.angle_platform_type
+pub const AnglePlatformType = enum(c_int) {
+ none = c.GLFW_ANGLE_PLATFORM_TYPE_NONE,
+ opengl = c.GLFW_ANGLE_PLATFORM_TYPE_OPENGL,
+ opengles = c.GLFW_ANGLE_PLATFORM_TYPE_OPENGLES,
+ d3d9 = c.GLFW_ANGLE_PLATFORM_TYPE_D3D9,
+ d3d11 = c.GLFW_ANGLE_PLATFORM_TYPE_D3D11,
+ vulkan = c.GLFW_ANGLE_PLATFORM_TYPE_VULKAN,
+ metal = c.GLFW_ANGLE_PLATFORM_TYPE_METAL,
+};
+
+/// Wayland libdecor hints for glfw.InitHint.wayland_libdecor
+///
+/// libdecor is important for GNOME, since GNOME does not implement server side decorations on
+/// wayland. libdecor is loaded dynamically at runtime, so in general enabling it is always
+/// safe to do. It is enabled by default.
+pub const WaylandLibdecorInitHint = enum(c_int) {
+ wayland_prefer_libdecor = c.GLFW_WAYLAND_PREFER_LIBDECOR,
+ wayland_disable_libdecor = c.GLFW_WAYLAND_DISABLE_LIBDECOR,
+};
+
+/// Platform type hints for glfw.InitHint.platform
+pub const PlatformType = enum(c_int) {
+ /// Enables automatic platform detection.
+ /// Will default to X11 on wayland.
+ any = c.GLFW_ANY_PLATFORM,
+ win32 = c.GLFW_PLATFORM_WIN32,
+ cocoa = c.GLFW_PLATFORM_COCOA,
+ wayland = c.GLFW_PLATFORM_WAYLAND,
+ x11 = c.GLFW_PLATFORM_X11,
+ null = c.GLFW_PLATFORM_NULL,
+};
+
+/// 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.
+///
+/// @param hint: The init hint to set.
+/// @param value: The new value of the init hint.
+///
+/// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.InvalidValue.
+///
+/// @remarks This function may be called before glfw.init.
+///
+/// @thread_safety This function must only be called from the main thread.
+fn initHint(hint: InitHint, value: anytype) void {
+ switch (@import("shims.zig").typeInfo(@TypeOf(value))) {
+ .int, .comptime_int => {
+ c.glfwInitHint(@intFromEnum(hint), @as(c_int, @intCast(value)));
+ },
+ .bool => c.glfwInitHint(@intFromEnum(hint), @as(c_int, @intCast(@intFromBool(value)))),
+ else => @compileError("expected a int or bool, got " ++ @typeName(@TypeOf(value))),
+ }
+}
+
+/// Returns a string describing the compile-time configuration.
+///
+/// This function returns the compile-time generated version string of the GLFW library binary. It
+/// describes the version, platform, compiler and any platform or operating system 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. Use the glfw.version
+/// constants instead.
+///
+/// __Do not use the version string__ to parse what platforms are supported. The
+/// `glfw.platformSupported` function lets you query platform support.
+///
+/// returns: The ASCII encoded GLFW version string.
+///
+/// remark: This function may be called before @ref glfw.Init.
+///
+/// pointer_lifetime: The returned string is static and compile-time generated.
+///
+/// thread_safety: This function may be called from any thread.
+pub inline fn getVersionString() [:0]const u8 {
+ return std.mem.span(@as([*:0]const u8, @ptrCast(c.glfwGetVersionString())));
+}
+
+/// Returns the currently selected platform.
+///
+/// This function returns the platform that was selected during initialization. The returned value
+/// will be one of `glfw.PlatformType.win32`, `glfw.PlatformType.cocoa`,
+/// `glfw.PlatformType.wayland`, `glfw.PlatformType.x11` or `glfw.PlatformType.null`.
+///
+/// thread_safety: This function may be called from any thread.
+pub fn getPlatform() PlatformType {
+ internal_debug.assertInitialized();
+ return @as(PlatformType, @enumFromInt(c.glfwGetPlatform()));
+}
+
+/// Returns whether the library includes support for the specified platform.
+///
+/// This function returns whether the library was compiled with support for the specified platform.
+/// The platform must be one of `glfw.PlatformType.win32`, `glfw.PlatformType.cocoa`,
+/// `glfw.PlatformType.wayland`, `glfw.PlatformType.x11` or `glfw.PlatformType.null`.
+///
+/// remark: This function may be called before glfw.Init.
+///
+/// thread_safety: This function may be called from any thread.
+pub fn platformSupported(platform: PlatformType) bool {
+ internal_debug.assertInitialized();
+ return c.glfwPlatformSupported(@intFromEnum(platform)) == c.GLFW_TRUE;
+}
+
+/// 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 (see 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @reentrancy This function must not be called from a callback.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: events, glfw.waitEvents, glfw.waitEventsTimeout
+pub inline fn pollEvents() void {
+ internal_debug.assertInitialized();
+ c.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 glfw.pollEvents,
+/// 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 (see 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.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @reentrancy This function must not be called from a callback.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: events, glfw.pollEvents, glfw.waitEventsTimeout
+pub inline fn waitEvents() void {
+ internal_debug.assertInitialized();
+ c.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 glfw.pollEvents, 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 (see 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.
+///
+/// @param[in] timeout The maximum amount of time, in seconds, to wait.
+///
+/// Possible errors include glfw.ErrorCode.InvalidValue and glfw.ErrorCode.PlatformError.
+///
+/// @reentrancy This function must not be called from a callback.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: events, glfw.pollEvents, glfw.waitEvents
+pub inline fn waitEventsTimeout(timeout: f64) void {
+ internal_debug.assertInitialized();
+ std.debug.assert(!std.math.isNan(timeout));
+ std.debug.assert(timeout >= 0);
+ std.debug.assert(timeout <= std.math.floatMax(f64));
+ c.glfwWaitEventsTimeout(timeout);
+}
+
+/// Posts an empty event to the event queue.
+///
+/// This function posts an empty event from the current thread to the event queue, causing
+/// glfw.waitEvents or glfw.waitEventsTimeout to return.
+///
+/// Possible errors include glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function may be called from any thread.
+///
+/// see also: events, glfw.waitEvents, glfw.waitEventsTimeout
+pub inline fn postEmptyEvent() void {
+ internal_debug.assertInitialized();
+ c.glfwPostEmptyEvent();
+}
+
+/// 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, glfw.ErrorCode.PlatformError
+/// 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.
+///
+/// @return `true` if raw mouse motion is supported on the current machine, or `false` otherwise.
+///
+/// @thread_safety This function must only be called from the main thread.
+///
+/// see also: raw_mouse_motion, glfw.setInputMode
+pub inline fn rawMouseMotionSupported() bool {
+ internal_debug.assertInitialized();
+ return c.glfwRawMouseMotionSupported() == c.GLFW_TRUE;
+}
+
+pub fn basicTest() !void {
+ defer clearError(); // clear any error we generate
+ if (!init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
+ std.process.exit(1);
+ }
+ defer terminate();
+
+ const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ const start = std.time.milliTimestamp();
+ while (std.time.milliTimestamp() < start + 1000 and !window.shouldClose()) {
+ c.glfwPollEvents();
+ }
+}
+
+test {
+ std.testing.refAllDeclsRecursive(@This());
+}
+
+test "getVersionString" {
+ std.debug.print("\nGLFW version v{}.{}.{}\n", .{ version.major, version.minor, version.revision });
+ std.debug.print("\nstring: {s}\n", .{getVersionString()});
+}
+
+test "init" {
+ _ = init(.{ .cocoa_chdir_resources = true });
+ if (getErrorString()) |err| {
+ std.log.err("failed to initialize GLFW: {?s}", .{err});
+ std.process.exit(1);
+ }
+ defer terminate();
+}
+
+test "pollEvents" {
+ defer clearError(); // clear any error we generate
+ if (!init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
+ std.process.exit(1);
+ }
+ defer terminate();
+
+ pollEvents();
+}
+
+test "waitEventsTimeout" {
+ defer clearError(); // clear any error we generate
+ if (!init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
+ std.process.exit(1);
+ }
+ defer terminate();
+
+ waitEventsTimeout(0.25);
+}
+
+test "postEmptyEvent_and_waitEvents" {
+ defer clearError(); // clear any error we generate
+ if (!init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
+ std.process.exit(1);
+ }
+ defer terminate();
+
+ postEmptyEvent();
+ waitEvents();
+}
+
+test "rawMouseMotionSupported" {
+ defer clearError(); // clear any error we generate
+ if (!init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
+ std.process.exit(1);
+ }
+ defer terminate();
+
+ _ = rawMouseMotionSupported();
+}
+
+test "basic" {
+ try basicTest();
+}
diff --git a/pkg/glfw/mod.zig b/pkg/glfw/mod.zig
new file mode 100644
index 000000000..aa9c9371f
--- /dev/null
+++ b/pkg/glfw/mod.zig
@@ -0,0 +1,167 @@
+//! Modifier key flags
+//!
+//! See glfw.setKeyCallback for how these are used.
+
+const c = @import("c.zig").c;
+
+// must be in sync with GLFW C constants in modifier group, search for "@defgroup mods Modifier key flags"
+/// A bitmask of all key modifiers
+pub const Mods = packed struct(u8) {
+ shift: bool = false,
+ control: bool = false,
+ alt: bool = false,
+ super: bool = false,
+ caps_lock: bool = false,
+ num_lock: bool = false,
+ _padding: u2 = 0,
+
+ inline fn verifyIntType(comptime IntType: type) void {
+ comptime {
+ switch (@import("shims.zig").typeInfo(IntType)) {
+ .int => {},
+ else => @compileError("Int was not of int type"),
+ }
+ }
+ }
+
+ pub inline fn toInt(self: Mods, comptime IntType: type) IntType {
+ verifyIntType(IntType);
+ return @as(IntType, @intCast(@as(u8, @bitCast(self))));
+ }
+
+ pub inline fn fromInt(flags: anytype) Mods {
+ verifyIntType(@TypeOf(flags));
+ return @as(Mods, @bitCast(@as(u8, @intCast(flags))));
+ }
+};
+
+/// Holds all GLFW mod values in their raw form.
+pub const RawMods = struct {
+ /// If this bit is set one or more Shift keys were held down.
+ pub const shift = c.GLFW_MOD_SHIFT;
+
+ /// If this bit is set one or more Control keys were held down.
+ pub const control = c.GLFW_MOD_CONTROL;
+
+ /// If this bit is set one or more Alt keys were held down.
+ pub const alt = c.GLFW_MOD_ALT;
+
+ /// If this bit is set one or more Super keys were held down.
+ pub const super = c.GLFW_MOD_SUPER;
+
+ /// If this bit is set the Caps Lock key is enabled and the glfw.lock_key_mods input mode is set.
+ pub const caps_lock = c.GLFW_MOD_CAPS_LOCK;
+
+ /// If this bit is set the Num Lock key is enabled and the glfw.lock_key_mods input mode is set.
+ pub const num_lock = c.GLFW_MOD_NUM_LOCK;
+};
+
+test "shift int to bitmask" {
+ const std = @import("std");
+
+ const int_mod = RawMods.shift;
+ const mod = Mods.fromInt(int_mod);
+
+ try std.testing.expect(mod.shift == true);
+ try std.testing.expect(mod.control == false);
+ try std.testing.expect(mod.alt == false);
+ try std.testing.expect(mod.super == false);
+ try std.testing.expect(mod.caps_lock == false);
+ try std.testing.expect(mod.num_lock == false);
+}
+
+test "shift int and alt to bitmask" {
+ const std = @import("std");
+
+ const int_mod = RawMods.shift | RawMods.alt;
+ const mod = Mods.fromInt(int_mod);
+
+ try std.testing.expect(mod.shift == true);
+ try std.testing.expect(mod.control == false);
+ try std.testing.expect(mod.alt == true);
+ try std.testing.expect(mod.super == false);
+ try std.testing.expect(mod.caps_lock == false);
+ try std.testing.expect(mod.num_lock == false);
+}
+
+test "super int to bitmask" {
+ const std = @import("std");
+
+ const int_mod = RawMods.super;
+ const mod = Mods.fromInt(int_mod);
+
+ try std.testing.expect(mod.shift == false);
+ try std.testing.expect(mod.control == false);
+ try std.testing.expect(mod.alt == false);
+ try std.testing.expect(mod.super == true);
+ try std.testing.expect(mod.caps_lock == false);
+ try std.testing.expect(mod.num_lock == false);
+}
+
+test "num lock int to bitmask" {
+ const std = @import("std");
+
+ const int_mod = RawMods.num_lock;
+ const mod = Mods.fromInt(int_mod);
+
+ try std.testing.expect(mod.shift == false);
+ try std.testing.expect(mod.control == false);
+ try std.testing.expect(mod.alt == false);
+ try std.testing.expect(mod.super == false);
+ try std.testing.expect(mod.caps_lock == false);
+ try std.testing.expect(mod.num_lock == true);
+}
+
+test "all int to bitmask" {
+ const std = @import("std");
+
+ const int_mod = RawMods.shift | RawMods.control |
+ RawMods.alt | RawMods.super |
+ RawMods.caps_lock | RawMods.num_lock;
+ const mod = Mods.fromInt(int_mod);
+
+ try std.testing.expect(mod.shift == true);
+ try std.testing.expect(mod.control == true);
+ try std.testing.expect(mod.alt == true);
+ try std.testing.expect(mod.super == true);
+ try std.testing.expect(mod.caps_lock == true);
+ try std.testing.expect(mod.num_lock == true);
+}
+
+test "shift bitmask to int" {
+ const std = @import("std");
+
+ const mod = Mods{ .shift = true };
+ const int_mod = mod.toInt(c_int);
+
+ try std.testing.expectEqual(int_mod, RawMods.shift);
+}
+
+test "shift and alt bitmask to int" {
+ const std = @import("std");
+
+ const mod = Mods{ .shift = true, .alt = true };
+ const int_mod = mod.toInt(c_int);
+
+ try std.testing.expectEqual(int_mod, RawMods.shift | RawMods.alt);
+}
+
+test "all bitmask to int" {
+ const std = @import("std");
+
+ const mod = Mods{
+ .shift = true,
+ .control = true,
+ .alt = true,
+ .super = true,
+ .caps_lock = true,
+ .num_lock = true,
+ };
+ const int_mod = mod.toInt(c_int);
+
+ const expected = RawMods.shift | RawMods.control |
+ RawMods.alt | RawMods.super |
+ RawMods.caps_lock | RawMods.num_lock;
+
+ try std.testing.expectEqual(int_mod, expected);
+}
diff --git a/pkg/glfw/mouse_button.zig b/pkg/glfw/mouse_button.zig
new file mode 100644
index 000000000..847049f5e
--- /dev/null
+++ b/pkg/glfw/mouse_button.zig
@@ -0,0 +1,23 @@
+const c = @import("c.zig").c;
+
+/// Mouse button IDs.
+///
+/// See glfw.setMouseButtonCallback for how these are used.
+pub const MouseButton = enum(c_int) {
+ // We use left/right/middle aliases here because those are more common and we cannot have
+ // duplicate values in a Zig enum.
+ left = c.GLFW_MOUSE_BUTTON_1,
+ right = c.GLFW_MOUSE_BUTTON_2,
+ middle = c.GLFW_MOUSE_BUTTON_3,
+ four = c.GLFW_MOUSE_BUTTON_4,
+ five = c.GLFW_MOUSE_BUTTON_5,
+ six = c.GLFW_MOUSE_BUTTON_6,
+ seven = c.GLFW_MOUSE_BUTTON_7,
+ eight = c.GLFW_MOUSE_BUTTON_8,
+};
+
+/// Not in the MouseButton enumeration as it is a duplicate value which is forbidden.
+pub const last = MouseButton.eight;
+pub const one = MouseButton.left;
+pub const two = MouseButton.right;
+pub const three = MouseButton.middle;
diff --git a/pkg/glfw/native.zig b/pkg/glfw/native.zig
new file mode 100644
index 000000000..6b8f1831a
--- /dev/null
+++ b/pkg/glfw/native.zig
@@ -0,0 +1,393 @@
+//! Native access functions
+const std = @import("std");
+
+const Window = @import("Window.zig");
+const Monitor = @import("Monitor.zig");
+
+const internal_debug = @import("internal_debug.zig");
+
+pub const BackendOptions = struct {
+ win32: bool = false,
+ wgl: bool = false,
+ cocoa: bool = false,
+ nsgl: bool = false,
+ x11: bool = false,
+ glx: bool = false,
+ wayland: bool = false,
+ egl: bool = false,
+ osmesa: bool = false,
+};
+
+/// This function returns a type which allows provides an interface to access
+/// the native handles based on backends selected.
+///
+/// The available window API options are:
+/// * win32
+/// * cocoa
+/// * x11
+/// * wayland
+///
+/// The available context API options are:
+///
+/// * wgl
+/// * nsgl
+/// * glx
+/// * egl
+/// * osmesa
+///
+/// The chosen backends must match those the library was compiled for. Failure to do so
+/// will cause a link-time error.
+pub fn Native(comptime options: BackendOptions) type {
+ const native = @cImport({
+ // @cDefine("GLFW_INCLUDE_VULKAN", "1");
+ @cDefine("GLFW_INCLUDE_NONE", "1");
+ if (options.win32) @cDefine("GLFW_EXPOSE_NATIVE_WIN32", "1");
+ if (options.wgl) @cDefine("GLFW_EXPOSE_NATIVE_WGL", "1");
+ if (options.cocoa) @cDefine("GLFW_EXPOSE_NATIVE_COCOA", "1");
+ if (options.nsgl) @cDefine("GLFW_EXPOSE_NATIVE_NGSL", "1");
+ if (options.x11) @cDefine("GLFW_EXPOSE_NATIVE_X11", "1");
+ if (options.glx) @cDefine("GLFW_EXPOSE_NATIVE_GLX", "1");
+ if (options.wayland) @cDefine("GLFW_EXPOSE_NATIVE_WAYLAND", "1");
+ if (options.egl) @cDefine("GLFW_EXPOSE_NATIVE_EGL", "1");
+ if (options.osmesa) @cDefine("GLFW_EXPOSE_NATIVE_OSMESA", "1");
+ @cDefine("__kernel_ptr_semantics", "");
+ @cInclude("GLFW/glfw3.h");
+ @cInclude("GLFW/glfw3native.h");
+ });
+
+ return struct {
+ /// Returns the adapter device name of the specified monitor.
+ ///
+ /// return: The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) of the
+ /// specified monitor.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getWin32Adapter(monitor: Monitor) [*:0]const u8 {
+ internal_debug.assertInitialized();
+ if (native.glfwGetWin32Adapter(@as(*native.GLFWmonitor, @ptrCast(monitor.handle)))) |adapter| return adapter;
+ // `glfwGetWin32Adapter` returns `null` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the display device name of the specified monitor.
+ ///
+ /// return: The UTF-8 encoded display device name (for example `\\.\DISPLAY1\Monitor0`)
+ /// of the specified monitor.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getWin32Monitor(monitor: Monitor) [*:0]const u8 {
+ internal_debug.assertInitialized();
+ if (native.glfwGetWin32Monitor(@as(*native.GLFWmonitor, @ptrCast(monitor.handle)))) |mon| return mon;
+ // `glfwGetWin32Monitor` returns `null` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `HWND` of the specified window.
+ ///
+ /// The `HDC` associated with the window can be queried with the
+ /// [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc)
+ /// function.
+ /// ```
+ /// const dc = std.os.windows.user32.GetDC(native.getWin32Window(window));
+ /// ```
+ /// This DC is private and does not need to be released.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getWin32Window(window: Window) std.os.windows.HWND {
+ internal_debug.assertInitialized();
+ if (native.glfwGetWin32Window(@as(*native.GLFWwindow, @ptrCast(window.handle)))) |win|
+ return @as(std.os.windows.HWND, @ptrCast(win));
+ // `glfwGetWin32Window` returns `null` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `HGLRC` of the specified window.
+ ///
+ /// The `HDC` associated with the window can be queried with the
+ /// [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc)
+ /// function.
+ /// ```
+ /// const dc = std.os.windows.user32.GetDC(native.getWin32Window(window));
+ /// ```
+ /// This DC is private and does not need to be released.
+ ///
+ /// Possible errors include glfw.ErrorCode.NoWindowContext
+ /// null is returned in the event of an error.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getWGLContext(window: Window) ?std.os.windows.HGLRC {
+ internal_debug.assertInitialized();
+ if (native.glfwGetWGLContext(@as(*native.GLFWwindow, @ptrCast(window.handle)))) |context| return context;
+ return null;
+ }
+
+ /// Returns the `CGDirectDisplayID` of the specified monitor.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getCocoaMonitor(monitor: Monitor) u32 {
+ internal_debug.assertInitialized();
+ const mon = native.glfwGetCocoaMonitor(@as(*native.GLFWmonitor, @ptrCast(monitor.handle)));
+ if (mon != native.kCGNullDirectDisplay) return mon;
+ // `glfwGetCocoaMonitor` returns `kCGNullDirectDisplay` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `NSWindow` of the specified window.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getCocoaWindow(window: Window) ?*anyopaque {
+ internal_debug.assertInitialized();
+ return native.glfwGetCocoaWindow(@as(*native.GLFWwindow, @ptrCast(window.handle)));
+ }
+
+ /// Returns the `NSWindow` of the specified window.
+ ///
+ /// Possible errors include glfw.ErrorCode.NoWindowContext.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getNSGLContext(window: Window) u32 {
+ internal_debug.assertInitialized();
+ return native.glfwGetNSGLContext(@as(*native.GLFWwindow, @ptrCast(window.handle)));
+ }
+
+ /// Returns the `Display` used by GLFW.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getX11Display() *anyopaque {
+ internal_debug.assertInitialized();
+ if (native.glfwGetX11Display()) |display| return @as(*anyopaque, @ptrCast(display));
+ // `glfwGetX11Display` returns `null` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `RRCrtc` of the specified monitor.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getX11Adapter(monitor: Monitor) u32 {
+ internal_debug.assertInitialized();
+ const adapter = native.glfwGetX11Adapter(@as(*native.GLFWMonitor, @ptrCast(monitor.handle)));
+ if (adapter != 0) return adapter;
+ // `glfwGetX11Adapter` returns `0` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `RROutput` of the specified monitor.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getX11Monitor(monitor: Monitor) u32 {
+ internal_debug.assertInitialized();
+ const mon = native.glfwGetX11Monitor(@as(*native.GLFWmonitor, @ptrCast(monitor.handle)));
+ if (mon != 0) return mon;
+ // `glfwGetX11Monitor` returns `0` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `Window` of the specified window.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getX11Window(window: Window) u32 {
+ internal_debug.assertInitialized();
+ const win = native.glfwGetX11Window(@as(*native.GLFWwindow, @ptrCast(window.handle)));
+ if (win != 0) return @as(u32, @intCast(win));
+ // `glfwGetX11Window` returns `0` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Sets the current primary selection to the specified string.
+ ///
+ /// Possible errors include glfw.ErrorCode.PlatformError.
+ ///
+ /// The specified string is copied before this function returns.
+ ///
+ /// thread_safety: This function must only be called from the main thread.
+ pub fn setX11SelectionString(string: [*:0]const u8) void {
+ internal_debug.assertInitialized();
+ native.glfwSetX11SelectionString(string);
+ }
+
+ /// Returns the contents of the current primary selection as a string.
+ ///
+ /// Possible errors include glfw.ErrorCode.PlatformError.
+ /// Returns null in the event of an error.
+ ///
+ /// The returned string is allocated and freed by GLFW. You should not free it
+ /// yourself. It is valid until the next call to getX11SelectionString or
+ /// setX11SelectionString, or until the library is terminated.
+ ///
+ /// thread_safety: This function must only be called from the main thread.
+ pub fn getX11SelectionString() ?[*:0]const u8 {
+ internal_debug.assertInitialized();
+ if (native.glfwGetX11SelectionString()) |str| return str;
+ return null;
+ }
+
+ /// Returns the `GLXContext` of the specified window.
+ ///
+ /// Possible errors include glfw.ErrorCode.NoWindowContext.
+ /// Returns null in the event of an error.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getGLXContext(window: Window) ?*anyopaque {
+ internal_debug.assertInitialized();
+ if (native.glfwGetGLXContext(@as(*native.GLFWwindow, @ptrCast(window.handle)))) |context| return @as(*anyopaque, @ptrCast(context));
+ return null;
+ }
+
+ /// Returns the `GLXWindow` of the specified window.
+ ///
+ /// Possible errors include glfw.ErrorCode.NoWindowContext.
+ /// Returns null in the event of an error.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getGLXWindow(window: Window) ?*anyopaque {
+ internal_debug.assertInitialized();
+ const win = native.glfwGetGLXWindow(@as(*native.GLFWwindow, @ptrCast(window.handle)));
+ if (win != 0) return @as(*anyopaque, @ptrCast(win));
+ return null;
+ }
+
+ /// Returns the `*wl_display` used by GLFW.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getWaylandDisplay() *anyopaque {
+ internal_debug.assertInitialized();
+ if (native.glfwGetWaylandDisplay()) |display| return @as(*anyopaque, @ptrCast(display));
+ // `glfwGetWaylandDisplay` returns `null` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `*wl_output` of the specified monitor.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getWaylandMonitor(monitor: Monitor) *anyopaque {
+ internal_debug.assertInitialized();
+ if (native.glfwGetWaylandMonitor(@as(*native.GLFWmonitor, @ptrCast(monitor.handle)))) |mon| return @as(*anyopaque, @ptrCast(mon));
+ // `glfwGetWaylandMonitor` returns `null` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `*wl_surface` of the specified window.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getWaylandWindow(window: Window) *anyopaque {
+ internal_debug.assertInitialized();
+ if (native.glfwGetWaylandWindow(@as(*native.GLFWwindow, @ptrCast(window.handle)))) |win| return @as(*anyopaque, @ptrCast(win));
+ // `glfwGetWaylandWindow` returns `null` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `EGLDisplay` used by GLFW.
+ ///
+ /// remark: Because EGL is initialized on demand, this function will return `EGL_NO_DISPLAY`
+ /// until the first context has been created via EGL.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getEGLDisplay() *anyopaque {
+ internal_debug.assertInitialized();
+ const display = native.glfwGetEGLDisplay();
+ if (display != native.EGL_NO_DISPLAY) return @as(*anyopaque, @ptrCast(display));
+ // `glfwGetEGLDisplay` returns `EGL_NO_DISPLAY` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+ }
+
+ /// Returns the `EGLContext` of the specified window.
+ ///
+ /// Possible errors include glfw.ErrorCode.NoWindowContext.
+ /// Returns null in the event of an error.
+ ///
+ /// thread_safety This function may be called from any thread. Access is not synchronized.
+ pub fn getEGLContext(window: Window) ?*anyopaque {
+ internal_debug.assertInitialized();
+ const context = native.glfwGetEGLContext(@as(*native.GLFWwindow, @ptrCast(window.handle)));
+ if (context != native.EGL_NO_CONTEXT) return @as(*anyopaque, @ptrCast(context));
+ return null;
+ }
+
+ /// Returns the `EGLSurface` of the specified window.
+ ///
+ /// Possible errors include glfw.ErrorCode.NotInitalized and glfw.ErrorCode.NoWindowContext.
+ ///
+ /// thread_safety This function may be called from any thread. Access is not synchronized.
+ pub fn getEGLSurface(window: Window) ?*anyopaque {
+ internal_debug.assertInitialized();
+ const surface = native.glfwGetEGLSurface(@as(*native.GLFWwindow, @ptrCast(window.handle)));
+ if (surface != native.EGL_NO_SURFACE) return @as(*anyopaque, @ptrCast(surface));
+ return null;
+ }
+
+ pub const OSMesaColorBuffer = struct {
+ width: c_int,
+ height: c_int,
+ format: c_int,
+ buffer: *anyopaque,
+ };
+
+ /// Retrieves the color buffer associated with the specified window.
+ ///
+ /// Possible errors include glfw.ErrorCode.NoWindowContext and glfw.ErrorCode.PlatformError.
+ /// Returns null in the event of an error.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getOSMesaColorBuffer(window: Window) ?OSMesaColorBuffer {
+ internal_debug.assertInitialized();
+ var buf: OSMesaColorBuffer = undefined;
+ if (native.glfwGetOSMesaColorBuffer(
+ @as(*native.GLFWwindow, @ptrCast(window.handle)),
+ &buf.width,
+ &buf.height,
+ &buf.format,
+ &buf.buffer,
+ ) == native.GLFW_TRUE) return buf;
+ return null;
+ }
+
+ pub const OSMesaDepthBuffer = struct {
+ width: c_int,
+ height: c_int,
+ bytes_per_value: c_int,
+ buffer: *anyopaque,
+ };
+
+ /// Retrieves the depth buffer associated with the specified window.
+ ///
+ /// Possible errors include glfw.ErrorCode.NoWindowContext and glfw.ErrorCode.PlatformError.
+ /// Returns null in the event of an error.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getOSMesaDepthBuffer(window: Window) ?OSMesaDepthBuffer {
+ internal_debug.assertInitialized();
+ var buf: OSMesaDepthBuffer = undefined;
+ if (native.glfwGetOSMesaDepthBuffer(
+ @as(*native.GLFWwindow, @ptrCast(window.handle)),
+ &buf.width,
+ &buf.height,
+ &buf.bytes_per_value,
+ &buf.buffer,
+ ) == native.GLFW_TRUE) return buf;
+ return null;
+ }
+
+ /// Returns the 'OSMesaContext' of the specified window.
+ ///
+ /// Possible errors include glfw.ErrorCode.NoWindowContext.
+ ///
+ /// thread_safety: This function may be called from any thread. Access is not synchronized.
+ pub fn getOSMesaContext(window: Window) ?*anyopaque {
+ internal_debug.assertInitialized();
+ if (native.glfwGetOSMesaContext(@as(*native.GLFWwindow, @ptrCast(window.handle)))) |context| return @as(*anyopaque, @ptrCast(context));
+ return null;
+ }
+ };
+}
diff --git a/pkg/glfw/opengl.zig b/pkg/glfw/opengl.zig
new file mode 100644
index 000000000..de99582c2
--- /dev/null
+++ b/pkg/glfw/opengl.zig
@@ -0,0 +1,256 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+const c = @import("c.zig").c;
+const Window = @import("Window.zig");
+
+const internal_debug = @import("internal_debug.zig");
+
+/// 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 hint.
+///
+/// The specified window must have an OpenGL or OpenGL ES context. Specifying a window without a
+/// context will generate glfw.ErrorCode.NoWindowContext.
+///
+/// @param[in] window The window whose context to make current, or null to
+/// detach the current context.
+///
+/// Possible errors include glfw.ErrorCode.NoWindowContext and glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function may be called from any thread.
+///
+/// see also: context_current, glfwGetCurrentContext
+pub inline fn makeContextCurrent(window: ?Window) void {
+ internal_debug.assertInitialized();
+ if (window) |w| c.glfwMakeContextCurrent(w.handle) else c.glfwMakeContextCurrent(null);
+}
+
+/// 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 he window whose context is current, or null if no window's context is current.
+///
+/// @thread_safety This function may be called from any thread.
+///
+/// see also: context_current, glfwMakeContextCurrent
+pub inline fn getCurrentContext() ?Window {
+ internal_debug.assertInitialized();
+ if (c.glfwGetCurrentContext()) |handle| return Window.from(handle);
+ return null;
+}
+
+/// 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 glfw.SwapBuffers 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 glfw.extensionSupported.
+///
+/// A context must be current on the calling thread. Calling this function without a current context
+/// will cause glfw.ErrorCode.NoCurrentContext.
+///
+/// This function does not apply to Vulkan. If you are rendering with Vulkan, see the present mode
+/// of your swapchain instead.
+///
+/// @param[in] interval The minimum number of screen updates to wait for until the buffers are
+/// swapped by glfw.swapBuffers.
+///
+/// Possible errors include glfw.ErrorCode.NoCurrentContext and glfw.ErrorCode.PlatformError.
+///
+/// This function is not called during context creation, leaving the swap interval set to whatever
+/// is the default for that API. 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.
+///
+/// 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.
+///
+/// see also: buffer_swap, glfwSwapBuffers
+pub inline fn swapInterval(interval: i32) void {
+ internal_debug.assertInitialized();
+ c.glfwSwapInterval(@as(c_int, @intCast(interval)));
+}
+
+/// Returns whether the specified extension is available.
+///
+/// This function returns whether the specified API extension (see 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 glfw.ErrorCode.NoCurrentContext.
+///
+/// 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 glfw.getRequiredInstanceExtensions,
+/// `vkEnumerateInstanceExtensionProperties` and `vkEnumerateDeviceExtensionProperties` instead.
+///
+/// @param[in] extension The ASCII encoded name of the extension.
+/// @return `true` if the extension is available, or `false` otherwise.
+///
+/// Possible errors include glfw.ErrorCode.NoCurrentContext, glfw.ErrorCode.InvalidValue
+/// and glfw.ErrorCode.PlatformError.
+///
+/// @thread_safety This function may be called from any thread.
+///
+/// see also: context_glext, glfw.getProcAddress
+pub inline fn extensionSupported(extension: [:0]const u8) bool {
+ internal_debug.assertInitialized();
+
+ std.debug.assert(extension.len != 0);
+ std.debug.assert(extension[0] != 0);
+
+ return c.glfwExtensionSupported(extension.ptr) == c.GLFW_TRUE;
+}
+
+/// Client API function pointer type.
+///
+/// Generic function pointer used for returning client API function pointers.
+///
+/// see also: context_glext, glfwGetProcAddress
+pub const GLProc = *const fn () callconv(if (builtin.os.tag == .windows and builtin.cpu.arch == .x86) .Stdcall else .C) void;
+
+/// 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 (see 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 glfw.ErrorCode.NoCurrentContext.
+///
+/// This function does not apply to Vulkan. If you are rendering with Vulkan, see glfw.getInstanceProcAddress,
+/// `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` instead.
+///
+/// @param[in] procname The ASCII encoded name of the function.
+/// @return The address of the function, or null if an error occurred.
+///
+/// To maintain ABI compatability with the C glfwGetProcAddress, as it is commonly passed into
+/// libraries expecting that exact ABI, this function does not return an error. Instead, if
+/// glfw.ErrorCode.NotInitialized, glfw.ErrorCode.NoCurrentContext, or glfw.ErrorCode.PlatformError
+/// would occur this function will panic. You should ensure a valid OpenGL context exists and the
+/// GLFW is initialized before calling this function.
+///
+/// The address of a given function is not guaranteed to be the same between contexts.
+///
+/// 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.
+///
+/// see also: context_glext, glfwExtensionSupported
+pub fn getProcAddress(proc_name: [*:0]const u8) callconv(.C) ?GLProc {
+ internal_debug.assertInitialized();
+ if (c.glfwGetProcAddress(proc_name)) |proc_address| return @ptrCast(proc_address);
+ return null;
+}
+
+test "makeContextCurrent" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ glfw.makeContextCurrent(window);
+}
+
+test "getCurrentContext" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const current_context = glfw.getCurrentContext();
+ std.debug.assert(current_context == null);
+}
+
+test "swapInterval" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ glfw.makeContextCurrent(window);
+ glfw.swapInterval(1);
+}
+
+test "getProcAddress" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ glfw.makeContextCurrent(window);
+ _ = glfw.getProcAddress("foobar");
+}
+
+test "extensionSupported" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
+ std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
+ return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
+ };
+ defer window.destroy();
+
+ glfw.makeContextCurrent(window);
+ _ = glfw.extensionSupported("foobar");
+}
diff --git a/pkg/glfw/shims.zig b/pkg/glfw/shims.zig
new file mode 100644
index 000000000..c731bb910
--- /dev/null
+++ b/pkg/glfw/shims.zig
@@ -0,0 +1,84 @@
+// Zig 0.14.0-dev changed the names of all 'std.builtin.Type' fields.
+const old_std_builtin_type_field_names = @hasField(@import("std").builtin.Type, "Type");
+
+pub const std = struct {
+ pub const builtin = struct {
+ pub const Type = if (old_std_builtin_type_field_names) union(enum) {
+ type: void,
+ void: void,
+ bool: void,
+ noreturn: void,
+ int: Int,
+ float: Float,
+ pointer: Pointer,
+ array: Array,
+ @"struct": Struct,
+ comptime_float: void,
+ comptime_int: void,
+ undefined: void,
+ null: void,
+ optional: Optional,
+ error_union: ErrorUnion,
+ error_set: ErrorSet,
+ @"enum": Enum,
+ @"union": Union,
+ @"fn": Fn,
+ @"opaque": Opaque,
+ frame: Frame,
+ @"anyframe": AnyFrame,
+ vector: Vector,
+ enum_literal: void,
+
+ pub const Int = @import("std").builtin.Type.Int;
+ pub const Float = @import("std").builtin.Type.Float;
+ pub const Pointer = @import("std").builtin.Type.Pointer;
+ pub const Array = @import("std").builtin.Type.Array;
+ pub const ContainerLayout = @import("std").builtin.Type.ContainerLayout;
+ pub const StructField = @import("std").builtin.Type.StructField;
+ pub const Struct = @import("std").builtin.Type.Struct;
+ pub const Optional = @import("std").builtin.Type.Optional;
+ pub const ErrorUnion = @import("std").builtin.Type.ErrorUnion;
+ pub const Error = @import("std").builtin.Type.Error;
+ pub const ErrorSet = @import("std").builtin.Type.ErrorSet;
+ pub const EnumField = @import("std").builtin.Type.EnumField;
+ pub const Enum = @import("std").builtin.Type.Enum;
+ pub const UnionField = @import("std").builtin.Type.UnionField;
+ pub const Union = @import("std").builtin.Type.Union;
+ pub const Fn = @import("std").builtin.Type.Fn;
+ pub const Opaque = @import("std").builtin.Type.Opaque;
+ pub const Frame = @import("std").builtin.Type.Frame;
+ pub const AnyFrame = @import("std").builtin.Type.AnyFrame;
+ pub const Vector = @import("std").builtin.Type.Vector;
+ pub const Declaration = @import("std").builtin.Type.Declaration;
+ } else @import("std").builtin.Type;
+ };
+};
+
+pub fn typeInfo(comptime T: type) std.builtin.Type {
+ return if (old_std_builtin_type_field_names) switch (@typeInfo(T)) {
+ .Type => .type,
+ .Void => .void,
+ .Bool => .bool,
+ .NoReturn => .noreturn,
+ .Int => |x| .{ .int = x },
+ .Float => |x| .{ .float = x },
+ .Pointer => |x| .{ .pointer = x },
+ .Array => |x| .{ .array = x },
+ .Struct => |x| .{ .@"struct" = x },
+ .ComptimeFloat => .comptime_float,
+ .ComptimeInt => .comptime_int,
+ .Undefined => .undefined,
+ .Null => .null,
+ .Optional => |x| .{ .optional = x },
+ .ErrorUnion => |x| .{ .error_union = x },
+ .ErrorSet => |x| .{ .error_set = x },
+ .Enum => |x| .{ .@"enum" = x },
+ .Union => |x| .{ .@"union" = x },
+ .Fn => |x| .{ .@"fn" = x },
+ .Opaque => |x| .{ .@"opaque" = x },
+ .Frame => |x| .{ .frame = x },
+ .AnyFrame => .@"anyframe",
+ .Vector => |x| .{ .vector = x },
+ .EnumLiteral => .enum_literal,
+ } else @typeInfo(T);
+}
diff --git a/pkg/glfw/time.zig b/pkg/glfw/time.zig
new file mode 100644
index 000000000..c3432b105
--- /dev/null
+++ b/pkg/glfw/time.zig
@@ -0,0 +1,153 @@
+const std = @import("std");
+
+const c = @import("c.zig").c;
+
+const internal_debug = @import("internal_debug.zig");
+
+/// 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 glfw.getTimerFrequency
+/// and glfw.getTimerValue.
+///
+/// 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 operating system.
+///
+/// @return The current time, in seconds, or zero if an
+/// error occurred.
+///
+/// @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.
+///
+/// see also: time
+pub inline fn getTime() f64 {
+ internal_debug.assertInitialized();
+ const time = c.glfwGetTime();
+ if (time != 0) return time;
+ // `glfwGetTime` returns `0` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+}
+
+/// 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 glfw.getTimerFrequency and
+/// glfw.getTimerValue.
+///
+/// @param[in] time The new value, in seconds.
+///
+/// Possible errors include glfw.ErrorCode.InvalidValue.
+///
+/// The upper limit of GLFW time is calculated as `floor((2^64 - 1) / 10^9)` 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 glfw.getTime.
+///
+/// see also: time
+pub inline fn setTime(time: f64) void {
+ internal_debug.assertInitialized();
+
+ std.debug.assert(!std.math.isNan(time));
+ std.debug.assert(time >= 0);
+ // assert time is lteq to largest number of seconds representable by u64 with nanosecond precision
+ std.debug.assert(time <= max_time: {
+ const @"2^64" = std.math.maxInt(u64);
+ break :max_time @divTrunc(@"2^64", std.time.ns_per_s);
+ });
+
+ c.glfwSetTime(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 glfw.getTimerFrequency.
+///
+/// @return The value of the timer, or zero if an error occurred.
+///
+/// @thread_safety This function may be called from any thread.
+///
+/// see also: time, glfw.getTimerFrequency
+pub inline fn getTimerValue() u64 {
+ internal_debug.assertInitialized();
+ const value = c.glfwGetTimerValue();
+ if (value != 0) return value;
+ // `glfwGetTimerValue` returns `0` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+}
+
+/// Returns the frequency, in Hz, of the raw timer.
+///
+/// This function returns the frequency, in Hz, of the raw timer.
+///
+/// @return The frequency of the timer, in Hz, or zero if an error occurred.
+///
+/// @thread_safety This function may be called from any thread.
+///
+/// see also: time, glfw.getTimerValue
+pub inline fn getTimerFrequency() u64 {
+ internal_debug.assertInitialized();
+ const frequency = c.glfwGetTimerFrequency();
+ if (frequency != 0) return frequency;
+ // `glfwGetTimerFrequency` returns `0` only for errors
+ // but the only potential error is unreachable (NotInitialized)
+ unreachable;
+}
+
+test "getTime" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = getTime();
+}
+
+test "setTime" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = glfw.setTime(1234);
+}
+
+test "getTimerValue" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = glfw.getTimerValue();
+}
+
+test "getTimerFrequency" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = glfw.getTimerFrequency();
+}
diff --git a/pkg/glfw/version.zig b/pkg/glfw/version.zig
new file mode 100644
index 000000000..e83a4d708
--- /dev/null
+++ b/pkg/glfw/version.zig
@@ -0,0 +1,18 @@
+//! GLFW version info
+
+const c = @import("c.zig").c;
+
+/// The major version number of the GLFW library.
+///
+/// This is incremented when the API is changed in non-compatible ways.
+pub const major = c.GLFW_VERSION_MAJOR;
+
+/// The minor version number of the GLFW library.
+///
+/// This is incremented when features are added to the API but it remains backward-compatible.
+pub const minor = c.GLFW_VERSION_MINOR;
+
+/// The revision number of the GLFW library.
+///
+/// This is incremented when a bug fix release is made that does not contain any API changes.
+pub const revision = c.GLFW_VERSION_REVISION;
diff --git a/pkg/glfw/vulkan.zig b/pkg/glfw/vulkan.zig
new file mode 100644
index 000000000..6c6021d02
--- /dev/null
+++ b/pkg/glfw/vulkan.zig
@@ -0,0 +1,290 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+const c = @import("c.zig").c;
+const Window = @import("Window.zig");
+
+const internal_debug = @import("internal_debug.zig");
+
+/// Sets the desired Vulkan `vkGetInstanceProcAddr` function.
+///
+/// This function sets the `vkGetInstanceProcAddr` function that GLFW will use for all
+/// Vulkan related entry point queries.
+///
+/// This feature is mostly useful on macOS, if your copy of the Vulkan loader is in
+/// a location where GLFW cannot find it through dynamic loading, or if you are still
+/// using the static library version of the loader.
+///
+/// If set to `NULL`, GLFW will try to load the Vulkan loader dynamically by its standard
+/// name and get this function from there. This is the default behavior.
+///
+/// The standard name of the loader is `vulkan-1.dll` on Windows, `libvulkan.so.1` on
+/// Linux and other Unix-like systems and `libvulkan.1.dylib` on macOS. If your code is
+/// also loading it via these names then you probably don't need to use this function.
+///
+/// The function address you set is never reset by GLFW, but it only takes effect during
+/// initialization. Once GLFW has been initialized, any updates will be ignored until the
+/// library is terminated and initialized again.
+///
+/// remark: This function may be called before glfw.Init.
+///
+/// thread_safety: This function must only be called from the main thread.
+pub fn initVulkanLoader(loader_function: ?VKGetInstanceProcAddr) void {
+ c.glfwInitVulkanLoader(loader_function orelse null);
+}
+
+pub const VKGetInstanceProcAddr = *const fn (vk_instance: c.VkInstance, name: [*c]const u8) callconv(.C) ?VKProc;
+
+/// 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. Call glfw.getRequiredInstanceExtensions
+/// to check whether the extensions necessary for Vulkan surface creation are available and
+/// glfw.getPhysicalDevicePresentationSupport to check whether a queue family of a physical device
+/// supports image presentation.
+///
+/// @return `true` if Vulkan is minimally available, or `false` otherwise.
+///
+/// @thread_safety This function may be called from any thread.
+pub inline fn vulkanSupported() bool {
+ internal_debug.assertInitialized();
+ const supported = c.glfwVulkanSupported();
+ return supported == c.GLFW_TRUE;
+}
+
+/// 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
+/// glfw.ErrorCode.APIUnavailable error. Call glfw.vulkanSupported 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.
+///
+/// Possible errors include glfw.ErrorCode.APIUnavailable.
+/// Returns null in the event of an error.
+///
+/// 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.
+///
+/// @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.
+///
+/// see also: vulkan_ext, glfwCreateWindowSurface
+pub inline fn getRequiredInstanceExtensions() ?[][*:0]const u8 {
+ internal_debug.assertInitialized();
+ var count: u32 = 0;
+ if (c.glfwGetRequiredInstanceExtensions(&count)) |extensions| return @as([*][*:0]const u8, @ptrCast(extensions))[0..count];
+ return null;
+}
+
+/// Vulkan API function pointer type.
+///
+/// Generic function pointer used for returning Vulkan API function pointers.
+///
+/// see also: vulkan_proc, glfw.getInstanceProcAddress
+pub const VKProc = *const fn () callconv(if (builtin.os.tag == .windows and builtin.cpu.arch == .x86) .Stdcall else .C) void;
+
+/// 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
+/// glfw.ErrorCode.APIUnavailable error. Call glfw.vulkanSupported 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.
+///
+/// @param[in] instance The Vulkan instance to query, or null to retrieve functions related to
+/// instance creation.
+/// @param[in] procname The ASCII encoded name of the function.
+/// @return The address of the function, or null if an error occurred.
+///
+/// To maintain ABI compatability with the C glfwGetInstanceProcAddress, as it is commonly passed
+/// into libraries expecting that exact ABI, this function does not return an error. Instead, if
+/// glfw.ErrorCode.NotInitialized or glfw.ErrorCode.APIUnavailable would occur this function will panic.
+/// You may check glfw.vulkanSupported prior to invoking this function.
+///
+/// @pointer_lifetime The returned function pointer is valid until the library is terminated.
+///
+/// @thread_safety This function may be called from any thread.
+pub fn getInstanceProcAddress(vk_instance: ?*anyopaque, proc_name: [*:0]const u8) callconv(.C) ?VKProc {
+ internal_debug.assertInitialized();
+ if (c.glfwGetInstanceProcAddress(if (vk_instance) |v| @as(c.VkInstance, @ptrCast(v)) else null, proc_name)) |proc_address| return proc_address;
+ return null;
+}
+
+/// 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 glfw.ErrorCode.APIUnavailable error. Call
+/// glfw.vulkanSupported to check whether Vulkan is at least minimally available and
+/// glfw.getRequiredInstanceExtensions to check what instance extensions are required.
+///
+/// @param[in] instance The instance that the physical device belongs to.
+/// @param[in] device The physical device that the queue family belongs to.
+/// @param[in] queuefamily The index of the queue family to query.
+/// @return `true` if the queue family supports presentation, or `false` otherwise.
+///
+/// Possible errors include glfw.ErrorCode.APIUnavailable and glfw.ErrorCode.PlatformError.
+/// Returns false in the event of an error.
+///
+/// macos: This function currently always returns `true`, as the `VK_MVK_macos_surface` and
+/// 'VK_EXT_metal_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.
+///
+/// see also: vulkan_present
+pub inline fn getPhysicalDevicePresentationSupport(
+ vk_instance: *anyopaque,
+ vk_physical_device: *anyopaque,
+ queue_family: u32,
+) bool {
+ internal_debug.assertInitialized();
+ return c.glfwGetPhysicalDevicePresentationSupport(
+ @as(c.VkInstance, @ptrCast(vk_instance)),
+ @as(c.VkPhysicalDevice, @ptrCast(vk_physical_device)),
+ queue_family,
+ ) == c.GLFW_TRUE;
+}
+
+/// 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 glfw.ErrorCode.APIUnavailable error. Call
+/// glfw.vulkanSupported 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 glfw.ErrorCode.APIUnavailable error. Call glfw.getRequiredInstanceExtensions 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 set to `GLFW_NO_API` otherwise it generates a glfw.ErrorCode.InvalidValue 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.
+///
+/// @param[in] vk_instance The Vulkan instance to create the surface in.
+/// @param[in] window The window to create the surface for.
+/// @param[in] vk_allocation_callbacks The allocator to use, or null to use the default
+/// allocator.
+/// @param[out] surface Where to store the handle of the surface. This is set
+/// to `VK_NULL_HANDLE` if an error occurred.
+/// @return `VkResult` type, `VK_SUCCESS` if successful, or a Vulkan error code if an
+/// error occurred.
+///
+/// Possible errors include glfw.ErrorCode.APIUnavailable, glfw.ErrorCode.PlatformError and glfw.ErrorCode.InvalidValue
+/// Returns a bool indicating success.
+///
+/// If an error occurs before the creation call is made, GLFW returns the Vulkan error code most
+/// appropriate for the error. Appropriate use of glfw.vulkanSupported and glfw.getRequiredInstanceExtensions
+/// should eliminate almost all occurrences of these errors.
+///
+/// macos: GLFW prefers the `VK_EXT_metal_surface` extension, with the `VK_MVK_macos_surface`
+/// extension as a fallback. The name of the selected extension, if any, is included in the array
+/// returned by glfw.getRequiredInstanceExtensions.
+///
+/// macos: This function currently only supports the `VK_MVK_macos_surface` extension from MoltenVK.
+///
+/// macos: This function creates and sets a `CAMetalLayer` instance for the window content view,
+/// which is required for MoltenVK to function.
+///
+/// x11: By default GLFW prefers the `VK_KHR_xcb_surface` extension, with the `VK_KHR_xlib_surface`
+/// extension as a fallback. You can make `VK_KHR_xlib_surface` the preferred extension by setting
+/// glfw.InitHints.x11_xcb_vulkan_surface. The name of the selected extension, if any, is included
+/// in the array returned by glfw.getRequiredInstanceExtensions.
+///
+/// @thread_safety This function may be called from any thread. For synchronization details of
+/// Vulkan objects, see the Vulkan specification.
+///
+/// see also: vulkan_surface, glfw.getRequiredInstanceExtensions
+pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_allocation_callbacks: anytype, vk_surface_khr: anytype) i32 {
+ internal_debug.assertInitialized();
+ // zig-vulkan uses enums to represent opaque pointers:
+ // pub const Instance = enum(usize) { null_handle = 0, _ };
+ const instance: c.VkInstance = switch (@import("shims.zig").typeInfo(@TypeOf(vk_instance))) {
+ .@"enum" => @as(c.VkInstance, @ptrFromInt(@intFromEnum(vk_instance))),
+ else => @as(c.VkInstance, @ptrCast(vk_instance)),
+ };
+
+ return c.glfwCreateWindowSurface(
+ instance,
+ window.handle,
+ if (vk_allocation_callbacks == null) null else @as(*const c.VkAllocationCallbacks, @ptrCast(@alignCast(vk_allocation_callbacks))),
+ @as(*c.VkSurfaceKHR, @ptrCast(@alignCast(vk_surface_khr))),
+ );
+}
+
+test "vulkanSupported" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = glfw.vulkanSupported();
+}
+
+test "getRequiredInstanceExtensions" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ _ = glfw.getRequiredInstanceExtensions();
+}
+
+test "getInstanceProcAddress" {
+ const glfw = @import("main.zig");
+ defer glfw.clearError(); // clear any error we generate
+ if (!glfw.init(.{})) {
+ std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
+ std.process.exit(1);
+ }
+ defer glfw.terminate();
+
+ // syntax check only, we don't have a real vulkan instance and so this function would panic.
+ _ = glfw.getInstanceProcAddress;
+}
+
+test "syntax" {
+ // Best we can do for these two functions in terms of testing in lieu of an actual Vulkan
+ // context.
+ _ = getPhysicalDevicePresentationSupport;
+ _ = createWindowSurface;
+ _ = initVulkanLoader;
+}
diff --git a/pkg/glfw/wayland-headers/wayland-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-client-protocol-code.h
new file mode 100755
index 000000000..68b0ecbc1
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-client-protocol-code.h
@@ -0,0 +1,524 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_buffer_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_data_device_interface;
+extern const struct wl_interface wl_data_offer_interface;
+extern const struct wl_interface wl_data_source_interface;
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_region_interface;
+extern const struct wl_interface wl_registry_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_shell_surface_interface;
+extern const struct wl_interface wl_shm_pool_interface;
+extern const struct wl_interface wl_subsurface_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wl_touch_interface;
+
+static const struct wl_interface *wayland_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &wl_callback_interface,
+ &wl_registry_interface,
+ &wl_surface_interface,
+ &wl_region_interface,
+ &wl_buffer_interface,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &wl_shm_pool_interface,
+ NULL,
+ NULL,
+ &wl_data_source_interface,
+ &wl_surface_interface,
+ &wl_surface_interface,
+ NULL,
+ &wl_data_source_interface,
+ NULL,
+ &wl_data_offer_interface,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ NULL,
+ &wl_data_offer_interface,
+ &wl_data_offer_interface,
+ &wl_data_source_interface,
+ &wl_data_device_interface,
+ &wl_seat_interface,
+ &wl_shell_surface_interface,
+ &wl_surface_interface,
+ &wl_seat_interface,
+ NULL,
+ &wl_seat_interface,
+ NULL,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &wl_output_interface,
+ &wl_seat_interface,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ NULL,
+ NULL,
+ &wl_output_interface,
+ &wl_buffer_interface,
+ NULL,
+ NULL,
+ &wl_callback_interface,
+ &wl_region_interface,
+ &wl_region_interface,
+ &wl_output_interface,
+ &wl_output_interface,
+ &wl_pointer_interface,
+ &wl_keyboard_interface,
+ &wl_touch_interface,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ NULL,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ NULL,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ NULL,
+ &wl_surface_interface,
+ NULL,
+ NULL,
+ NULL,
+ &wl_subsurface_interface,
+ &wl_surface_interface,
+ &wl_surface_interface,
+ &wl_surface_interface,
+ &wl_surface_interface,
+};
+
+static const struct wl_message wl_display_requests[] = {
+ { "sync", "n", wayland_types + 8 },
+ { "get_registry", "n", wayland_types + 9 },
+};
+
+static const struct wl_message wl_display_events[] = {
+ { "error", "ous", wayland_types + 0 },
+ { "delete_id", "u", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_display_interface = {
+ "wl_display", 1,
+ 2, wl_display_requests,
+ 2, wl_display_events,
+};
+
+static const struct wl_message wl_registry_requests[] = {
+ { "bind", "usun", wayland_types + 0 },
+};
+
+static const struct wl_message wl_registry_events[] = {
+ { "global", "usu", wayland_types + 0 },
+ { "global_remove", "u", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_registry_interface = {
+ "wl_registry", 1,
+ 1, wl_registry_requests,
+ 2, wl_registry_events,
+};
+
+static const struct wl_message wl_callback_events[] = {
+ { "done", "u", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_callback_interface = {
+ "wl_callback", 1,
+ 0, NULL,
+ 1, wl_callback_events,
+};
+
+static const struct wl_message wl_compositor_requests[] = {
+ { "create_surface", "n", wayland_types + 10 },
+ { "create_region", "n", wayland_types + 11 },
+};
+
+WL_PRIVATE const struct wl_interface wl_compositor_interface = {
+ "wl_compositor", 6,
+ 2, wl_compositor_requests,
+ 0, NULL,
+};
+
+static const struct wl_message wl_shm_pool_requests[] = {
+ { "create_buffer", "niiiiu", wayland_types + 12 },
+ { "destroy", "", wayland_types + 0 },
+ { "resize", "i", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_shm_pool_interface = {
+ "wl_shm_pool", 1,
+ 3, wl_shm_pool_requests,
+ 0, NULL,
+};
+
+static const struct wl_message wl_shm_requests[] = {
+ { "create_pool", "nhi", wayland_types + 18 },
+};
+
+static const struct wl_message wl_shm_events[] = {
+ { "format", "u", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_shm_interface = {
+ "wl_shm", 1,
+ 1, wl_shm_requests,
+ 1, wl_shm_events,
+};
+
+static const struct wl_message wl_buffer_requests[] = {
+ { "destroy", "", wayland_types + 0 },
+};
+
+static const struct wl_message wl_buffer_events[] = {
+ { "release", "", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_buffer_interface = {
+ "wl_buffer", 1,
+ 1, wl_buffer_requests,
+ 1, wl_buffer_events,
+};
+
+static const struct wl_message wl_data_offer_requests[] = {
+ { "accept", "u?s", wayland_types + 0 },
+ { "receive", "sh", wayland_types + 0 },
+ { "destroy", "", wayland_types + 0 },
+ { "finish", "3", wayland_types + 0 },
+ { "set_actions", "3uu", wayland_types + 0 },
+};
+
+static const struct wl_message wl_data_offer_events[] = {
+ { "offer", "s", wayland_types + 0 },
+ { "source_actions", "3u", wayland_types + 0 },
+ { "action", "3u", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_data_offer_interface = {
+ "wl_data_offer", 3,
+ 5, wl_data_offer_requests,
+ 3, wl_data_offer_events,
+};
+
+static const struct wl_message wl_data_source_requests[] = {
+ { "offer", "s", wayland_types + 0 },
+ { "destroy", "", wayland_types + 0 },
+ { "set_actions", "3u", wayland_types + 0 },
+};
+
+static const struct wl_message wl_data_source_events[] = {
+ { "target", "?s", wayland_types + 0 },
+ { "send", "sh", wayland_types + 0 },
+ { "cancelled", "", wayland_types + 0 },
+ { "dnd_drop_performed", "3", wayland_types + 0 },
+ { "dnd_finished", "3", wayland_types + 0 },
+ { "action", "3u", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_data_source_interface = {
+ "wl_data_source", 3,
+ 3, wl_data_source_requests,
+ 6, wl_data_source_events,
+};
+
+static const struct wl_message wl_data_device_requests[] = {
+ { "start_drag", "?oo?ou", wayland_types + 21 },
+ { "set_selection", "?ou", wayland_types + 25 },
+ { "release", "2", wayland_types + 0 },
+};
+
+static const struct wl_message wl_data_device_events[] = {
+ { "data_offer", "n", wayland_types + 27 },
+ { "enter", "uoff?o", wayland_types + 28 },
+ { "leave", "", wayland_types + 0 },
+ { "motion", "uff", wayland_types + 0 },
+ { "drop", "", wayland_types + 0 },
+ { "selection", "?o", wayland_types + 33 },
+};
+
+WL_PRIVATE const struct wl_interface wl_data_device_interface = {
+ "wl_data_device", 3,
+ 3, wl_data_device_requests,
+ 6, wl_data_device_events,
+};
+
+static const struct wl_message wl_data_device_manager_requests[] = {
+ { "create_data_source", "n", wayland_types + 34 },
+ { "get_data_device", "no", wayland_types + 35 },
+};
+
+WL_PRIVATE const struct wl_interface wl_data_device_manager_interface = {
+ "wl_data_device_manager", 3,
+ 2, wl_data_device_manager_requests,
+ 0, NULL,
+};
+
+static const struct wl_message wl_shell_requests[] = {
+ { "get_shell_surface", "no", wayland_types + 37 },
+};
+
+WL_PRIVATE const struct wl_interface wl_shell_interface = {
+ "wl_shell", 1,
+ 1, wl_shell_requests,
+ 0, NULL,
+};
+
+static const struct wl_message wl_shell_surface_requests[] = {
+ { "pong", "u", wayland_types + 0 },
+ { "move", "ou", wayland_types + 39 },
+ { "resize", "ouu", wayland_types + 41 },
+ { "set_toplevel", "", wayland_types + 0 },
+ { "set_transient", "oiiu", wayland_types + 44 },
+ { "set_fullscreen", "uu?o", wayland_types + 48 },
+ { "set_popup", "ouoiiu", wayland_types + 51 },
+ { "set_maximized", "?o", wayland_types + 57 },
+ { "set_title", "s", wayland_types + 0 },
+ { "set_class", "s", wayland_types + 0 },
+};
+
+static const struct wl_message wl_shell_surface_events[] = {
+ { "ping", "u", wayland_types + 0 },
+ { "configure", "uii", wayland_types + 0 },
+ { "popup_done", "", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_shell_surface_interface = {
+ "wl_shell_surface", 1,
+ 10, wl_shell_surface_requests,
+ 3, wl_shell_surface_events,
+};
+
+static const struct wl_message wl_surface_requests[] = {
+ { "destroy", "", wayland_types + 0 },
+ { "attach", "?oii", wayland_types + 58 },
+ { "damage", "iiii", wayland_types + 0 },
+ { "frame", "n", wayland_types + 61 },
+ { "set_opaque_region", "?o", wayland_types + 62 },
+ { "set_input_region", "?o", wayland_types + 63 },
+ { "commit", "", wayland_types + 0 },
+ { "set_buffer_transform", "2i", wayland_types + 0 },
+ { "set_buffer_scale", "3i", wayland_types + 0 },
+ { "damage_buffer", "4iiii", wayland_types + 0 },
+ { "offset", "5ii", wayland_types + 0 },
+};
+
+static const struct wl_message wl_surface_events[] = {
+ { "enter", "o", wayland_types + 64 },
+ { "leave", "o", wayland_types + 65 },
+ { "preferred_buffer_scale", "6i", wayland_types + 0 },
+ { "preferred_buffer_transform", "6u", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_surface_interface = {
+ "wl_surface", 6,
+ 11, wl_surface_requests,
+ 4, wl_surface_events,
+};
+
+static const struct wl_message wl_seat_requests[] = {
+ { "get_pointer", "n", wayland_types + 66 },
+ { "get_keyboard", "n", wayland_types + 67 },
+ { "get_touch", "n", wayland_types + 68 },
+ { "release", "5", wayland_types + 0 },
+};
+
+static const struct wl_message wl_seat_events[] = {
+ { "capabilities", "u", wayland_types + 0 },
+ { "name", "2s", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_seat_interface = {
+ "wl_seat", 9,
+ 4, wl_seat_requests,
+ 2, wl_seat_events,
+};
+
+static const struct wl_message wl_pointer_requests[] = {
+ { "set_cursor", "u?oii", wayland_types + 69 },
+ { "release", "3", wayland_types + 0 },
+};
+
+static const struct wl_message wl_pointer_events[] = {
+ { "enter", "uoff", wayland_types + 73 },
+ { "leave", "uo", wayland_types + 77 },
+ { "motion", "uff", wayland_types + 0 },
+ { "button", "uuuu", wayland_types + 0 },
+ { "axis", "uuf", wayland_types + 0 },
+ { "frame", "5", wayland_types + 0 },
+ { "axis_source", "5u", wayland_types + 0 },
+ { "axis_stop", "5uu", wayland_types + 0 },
+ { "axis_discrete", "5ui", wayland_types + 0 },
+ { "axis_value120", "8ui", wayland_types + 0 },
+ { "axis_relative_direction", "9uu", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_pointer_interface = {
+ "wl_pointer", 9,
+ 2, wl_pointer_requests,
+ 11, wl_pointer_events,
+};
+
+static const struct wl_message wl_keyboard_requests[] = {
+ { "release", "3", wayland_types + 0 },
+};
+
+static const struct wl_message wl_keyboard_events[] = {
+ { "keymap", "uhu", wayland_types + 0 },
+ { "enter", "uoa", wayland_types + 79 },
+ { "leave", "uo", wayland_types + 82 },
+ { "key", "uuuu", wayland_types + 0 },
+ { "modifiers", "uuuuu", wayland_types + 0 },
+ { "repeat_info", "4ii", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_keyboard_interface = {
+ "wl_keyboard", 9,
+ 1, wl_keyboard_requests,
+ 6, wl_keyboard_events,
+};
+
+static const struct wl_message wl_touch_requests[] = {
+ { "release", "3", wayland_types + 0 },
+};
+
+static const struct wl_message wl_touch_events[] = {
+ { "down", "uuoiff", wayland_types + 84 },
+ { "up", "uui", wayland_types + 0 },
+ { "motion", "uiff", wayland_types + 0 },
+ { "frame", "", wayland_types + 0 },
+ { "cancel", "", wayland_types + 0 },
+ { "shape", "6iff", wayland_types + 0 },
+ { "orientation", "6if", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_touch_interface = {
+ "wl_touch", 9,
+ 1, wl_touch_requests,
+ 7, wl_touch_events,
+};
+
+static const struct wl_message wl_output_requests[] = {
+ { "release", "3", wayland_types + 0 },
+};
+
+static const struct wl_message wl_output_events[] = {
+ { "geometry", "iiiiissi", wayland_types + 0 },
+ { "mode", "uiii", wayland_types + 0 },
+ { "done", "2", wayland_types + 0 },
+ { "scale", "2i", wayland_types + 0 },
+ { "name", "4s", wayland_types + 0 },
+ { "description", "4s", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_output_interface = {
+ "wl_output", 4,
+ 1, wl_output_requests,
+ 6, wl_output_events,
+};
+
+static const struct wl_message wl_region_requests[] = {
+ { "destroy", "", wayland_types + 0 },
+ { "add", "iiii", wayland_types + 0 },
+ { "subtract", "iiii", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_region_interface = {
+ "wl_region", 1,
+ 3, wl_region_requests,
+ 0, NULL,
+};
+
+static const struct wl_message wl_subcompositor_requests[] = {
+ { "destroy", "", wayland_types + 0 },
+ { "get_subsurface", "noo", wayland_types + 90 },
+};
+
+WL_PRIVATE const struct wl_interface wl_subcompositor_interface = {
+ "wl_subcompositor", 1,
+ 2, wl_subcompositor_requests,
+ 0, NULL,
+};
+
+static const struct wl_message wl_subsurface_requests[] = {
+ { "destroy", "", wayland_types + 0 },
+ { "set_position", "ii", wayland_types + 0 },
+ { "place_above", "o", wayland_types + 93 },
+ { "place_below", "o", wayland_types + 94 },
+ { "set_sync", "", wayland_types + 0 },
+ { "set_desync", "", wayland_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wl_subsurface_interface = {
+ "wl_subsurface", 1,
+ 6, wl_subsurface_requests,
+ 0, NULL,
+};
+
diff --git a/pkg/glfw/wayland-headers/wayland-idle-inhibit-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-idle-inhibit-unstable-v1-client-protocol-code.h
new file mode 100755
index 000000000..251a915ba
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-idle-inhibit-unstable-v1-client-protocol-code.h
@@ -0,0 +1,68 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+/*
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface zwp_idle_inhibitor_v1_interface;
+
+static const struct wl_interface *idle_inhibit_unstable_v1_types[] = {
+ &zwp_idle_inhibitor_v1_interface,
+ &wl_surface_interface,
+};
+
+static const struct wl_message zwp_idle_inhibit_manager_v1_requests[] = {
+ { "destroy", "", idle_inhibit_unstable_v1_types + 0 },
+ { "create_inhibitor", "no", idle_inhibit_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_idle_inhibit_manager_v1_interface = {
+ "zwp_idle_inhibit_manager_v1", 1,
+ 2, zwp_idle_inhibit_manager_v1_requests,
+ 0, NULL,
+};
+
+static const struct wl_message zwp_idle_inhibitor_v1_requests[] = {
+ { "destroy", "", idle_inhibit_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_idle_inhibitor_v1_interface = {
+ "zwp_idle_inhibitor_v1", 1,
+ 1, zwp_idle_inhibitor_v1_requests,
+ 0, NULL,
+};
+
diff --git a/pkg/glfw/wayland-headers/wayland-idle-inhibit-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/wayland-idle-inhibit-unstable-v1-client-protocol.h
new file mode 100755
index 000000000..1a8de3be6
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-idle-inhibit-unstable-v1-client-protocol.h
@@ -0,0 +1,232 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+#ifndef IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_idle_inhibit_unstable_v1 The idle_inhibit_unstable_v1 protocol
+ * @section page_ifaces_idle_inhibit_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_idle_inhibit_manager_v1 - control behavior when display idles
+ * - @subpage page_iface_zwp_idle_inhibitor_v1 - context object for inhibiting idle behavior
+ * @section page_copyright_idle_inhibit_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_surface;
+struct zwp_idle_inhibit_manager_v1;
+struct zwp_idle_inhibitor_v1;
+
+#ifndef ZWP_IDLE_INHIBIT_MANAGER_V1_INTERFACE
+#define ZWP_IDLE_INHIBIT_MANAGER_V1_INTERFACE
+/**
+ * @page page_iface_zwp_idle_inhibit_manager_v1 zwp_idle_inhibit_manager_v1
+ * @section page_iface_zwp_idle_inhibit_manager_v1_desc Description
+ *
+ * This interface permits inhibiting the idle behavior such as screen
+ * blanking, locking, and screensaving. The client binds the idle manager
+ * globally, then creates idle-inhibitor objects for each surface.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ * @section page_iface_zwp_idle_inhibit_manager_v1_api API
+ * See @ref iface_zwp_idle_inhibit_manager_v1.
+ */
+/**
+ * @defgroup iface_zwp_idle_inhibit_manager_v1 The zwp_idle_inhibit_manager_v1 interface
+ *
+ * This interface permits inhibiting the idle behavior such as screen
+ * blanking, locking, and screensaving. The client binds the idle manager
+ * globally, then creates idle-inhibitor objects for each surface.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ */
+extern const struct wl_interface zwp_idle_inhibit_manager_v1_interface;
+#endif
+#ifndef ZWP_IDLE_INHIBITOR_V1_INTERFACE
+#define ZWP_IDLE_INHIBITOR_V1_INTERFACE
+/**
+ * @page page_iface_zwp_idle_inhibitor_v1 zwp_idle_inhibitor_v1
+ * @section page_iface_zwp_idle_inhibitor_v1_desc Description
+ *
+ * An idle inhibitor prevents the output that the associated surface is
+ * visible on from being set to a state where it is not visually usable due
+ * to lack of user interaction (e.g. blanked, dimmed, locked, set to power
+ * save, etc.) Any screensaver processes are also blocked from displaying.
+ *
+ * If the surface is destroyed, unmapped, becomes occluded, loses
+ * visibility, or otherwise becomes not visually relevant for the user, the
+ * idle inhibitor will not be honored by the compositor; if the surface
+ * subsequently regains visibility the inhibitor takes effect once again.
+ * Likewise, the inhibitor isn't honored if the system was already idled at
+ * the time the inhibitor was established, although if the system later
+ * de-idles and re-idles the inhibitor will take effect.
+ * @section page_iface_zwp_idle_inhibitor_v1_api API
+ * See @ref iface_zwp_idle_inhibitor_v1.
+ */
+/**
+ * @defgroup iface_zwp_idle_inhibitor_v1 The zwp_idle_inhibitor_v1 interface
+ *
+ * An idle inhibitor prevents the output that the associated surface is
+ * visible on from being set to a state where it is not visually usable due
+ * to lack of user interaction (e.g. blanked, dimmed, locked, set to power
+ * save, etc.) Any screensaver processes are also blocked from displaying.
+ *
+ * If the surface is destroyed, unmapped, becomes occluded, loses
+ * visibility, or otherwise becomes not visually relevant for the user, the
+ * idle inhibitor will not be honored by the compositor; if the surface
+ * subsequently regains visibility the inhibitor takes effect once again.
+ * Likewise, the inhibitor isn't honored if the system was already idled at
+ * the time the inhibitor was established, although if the system later
+ * de-idles and re-idles the inhibitor will take effect.
+ */
+extern const struct wl_interface zwp_idle_inhibitor_v1_interface;
+#endif
+
+#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY 0
+#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR 1
+
+
+/**
+ * @ingroup iface_zwp_idle_inhibit_manager_v1
+ */
+#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_idle_inhibit_manager_v1
+ */
+#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_idle_inhibit_manager_v1 */
+static inline void
+zwp_idle_inhibit_manager_v1_set_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1, user_data);
+}
+
+/** @ingroup iface_zwp_idle_inhibit_manager_v1 */
+static inline void *
+zwp_idle_inhibit_manager_v1_get_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
+}
+
+static inline uint32_t
+zwp_idle_inhibit_manager_v1_get_version(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
+}
+
+/**
+ * @ingroup iface_zwp_idle_inhibit_manager_v1
+ *
+ * Destroy the inhibit manager.
+ */
+static inline void
+zwp_idle_inhibit_manager_v1_destroy(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibit_manager_v1,
+ ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zwp_idle_inhibit_manager_v1
+ *
+ * Create a new inhibitor object associated with the given surface.
+ */
+static inline struct zwp_idle_inhibitor_v1 *
+zwp_idle_inhibit_manager_v1_create_inhibitor(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, struct wl_surface *surface)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibit_manager_v1,
+ ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR, &zwp_idle_inhibitor_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1), 0, NULL, surface);
+
+ return (struct zwp_idle_inhibitor_v1 *) id;
+}
+
+#define ZWP_IDLE_INHIBITOR_V1_DESTROY 0
+
+
+/**
+ * @ingroup iface_zwp_idle_inhibitor_v1
+ */
+#define ZWP_IDLE_INHIBITOR_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_idle_inhibitor_v1 */
+static inline void
+zwp_idle_inhibitor_v1_set_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1, user_data);
+}
+
+/** @ingroup iface_zwp_idle_inhibitor_v1 */
+static inline void *
+zwp_idle_inhibitor_v1_get_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1);
+}
+
+static inline uint32_t
+zwp_idle_inhibitor_v1_get_version(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1);
+}
+
+/**
+ * @ingroup iface_zwp_idle_inhibitor_v1
+ *
+ * Remove the inhibitor effect from the associated wl_surface.
+ */
+static inline void
+zwp_idle_inhibitor_v1_destroy(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibitor_v1,
+ ZWP_IDLE_INHIBITOR_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pkg/glfw/wayland-headers/wayland-pointer-constraints-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-pointer-constraints-unstable-v1-client-protocol-code.h
new file mode 100755
index 000000000..9aa943fa6
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-pointer-constraints-unstable-v1-client-protocol-code.h
@@ -0,0 +1,108 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+/*
+ * Copyright © 2014 Jonas Ådahl
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_region_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface zwp_confined_pointer_v1_interface;
+extern const struct wl_interface zwp_locked_pointer_v1_interface;
+
+static const struct wl_interface *pointer_constraints_unstable_v1_types[] = {
+ NULL,
+ NULL,
+ &zwp_locked_pointer_v1_interface,
+ &wl_surface_interface,
+ &wl_pointer_interface,
+ &wl_region_interface,
+ NULL,
+ &zwp_confined_pointer_v1_interface,
+ &wl_surface_interface,
+ &wl_pointer_interface,
+ &wl_region_interface,
+ NULL,
+ &wl_region_interface,
+ &wl_region_interface,
+};
+
+static const struct wl_message zwp_pointer_constraints_v1_requests[] = {
+ { "destroy", "", pointer_constraints_unstable_v1_types + 0 },
+ { "lock_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 2 },
+ { "confine_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 7 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_pointer_constraints_v1_interface = {
+ "zwp_pointer_constraints_v1", 1,
+ 3, zwp_pointer_constraints_v1_requests,
+ 0, NULL,
+};
+
+static const struct wl_message zwp_locked_pointer_v1_requests[] = {
+ { "destroy", "", pointer_constraints_unstable_v1_types + 0 },
+ { "set_cursor_position_hint", "ff", pointer_constraints_unstable_v1_types + 0 },
+ { "set_region", "?o", pointer_constraints_unstable_v1_types + 12 },
+};
+
+static const struct wl_message zwp_locked_pointer_v1_events[] = {
+ { "locked", "", pointer_constraints_unstable_v1_types + 0 },
+ { "unlocked", "", pointer_constraints_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_locked_pointer_v1_interface = {
+ "zwp_locked_pointer_v1", 1,
+ 3, zwp_locked_pointer_v1_requests,
+ 2, zwp_locked_pointer_v1_events,
+};
+
+static const struct wl_message zwp_confined_pointer_v1_requests[] = {
+ { "destroy", "", pointer_constraints_unstable_v1_types + 0 },
+ { "set_region", "?o", pointer_constraints_unstable_v1_types + 13 },
+};
+
+static const struct wl_message zwp_confined_pointer_v1_events[] = {
+ { "confined", "", pointer_constraints_unstable_v1_types + 0 },
+ { "unconfined", "", pointer_constraints_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_confined_pointer_v1_interface = {
+ "zwp_confined_pointer_v1", 1,
+ 2, zwp_confined_pointer_v1_requests,
+ 2, zwp_confined_pointer_v1_events,
+};
+
diff --git a/pkg/glfw/wayland-headers/wayland-pointer-constraints-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/wayland-pointer-constraints-unstable-v1-client-protocol.h
new file mode 100755
index 000000000..dd84a3f8b
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-pointer-constraints-unstable-v1-client-protocol.h
@@ -0,0 +1,667 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+#ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_pointer_constraints_unstable_v1 The pointer_constraints_unstable_v1 protocol
+ * protocol for constraining pointer motions
+ *
+ * @section page_desc_pointer_constraints_unstable_v1 Description
+ *
+ * This protocol specifies a set of interfaces used for adding constraints to
+ * the motion of a pointer. Possible constraints include confining pointer
+ * motions to a given region, or locking it to its current position.
+ *
+ * In order to constrain the pointer, a client must first bind the global
+ * interface "wp_pointer_constraints" which, if a compositor supports pointer
+ * constraints, is exposed by the registry. Using the bound global object, the
+ * client uses the request that corresponds to the type of constraint it wants
+ * to make. See wp_pointer_constraints for more details.
+ *
+ * Warning! The protocol described in this file is experimental and backward
+ * incompatible changes may be made. Backward compatible changes may be added
+ * together with the corresponding interface version bump. Backward
+ * incompatible changes are done by bumping the version number in the protocol
+ * and interface names and resetting the interface version. Once the protocol
+ * is to be declared stable, the 'z' prefix and the version number in the
+ * protocol and interface names are removed and the interface version number is
+ * reset.
+ *
+ * @section page_ifaces_pointer_constraints_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_pointer_constraints_v1 - constrain the movement of a pointer
+ * - @subpage page_iface_zwp_locked_pointer_v1 - receive relative pointer motion events
+ * - @subpage page_iface_zwp_confined_pointer_v1 - confined pointer object
+ * @section page_copyright_pointer_constraints_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2014 Jonas Ådahl
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_pointer;
+struct wl_region;
+struct wl_surface;
+struct zwp_confined_pointer_v1;
+struct zwp_locked_pointer_v1;
+struct zwp_pointer_constraints_v1;
+
+#ifndef ZWP_POINTER_CONSTRAINTS_V1_INTERFACE
+#define ZWP_POINTER_CONSTRAINTS_V1_INTERFACE
+/**
+ * @page page_iface_zwp_pointer_constraints_v1 zwp_pointer_constraints_v1
+ * @section page_iface_zwp_pointer_constraints_v1_desc Description
+ *
+ * The global interface exposing pointer constraining functionality. It
+ * exposes two requests: lock_pointer for locking the pointer to its
+ * position, and confine_pointer for locking the pointer to a region.
+ *
+ * The lock_pointer and confine_pointer requests create the objects
+ * wp_locked_pointer and wp_confined_pointer respectively, and the client can
+ * use these objects to interact with the lock.
+ *
+ * For any surface, only one lock or confinement may be active across all
+ * wl_pointer objects of the same seat. If a lock or confinement is requested
+ * when another lock or confinement is active or requested on the same surface
+ * and with any of the wl_pointer objects of the same seat, an
+ * 'already_constrained' error will be raised.
+ * @section page_iface_zwp_pointer_constraints_v1_api API
+ * See @ref iface_zwp_pointer_constraints_v1.
+ */
+/**
+ * @defgroup iface_zwp_pointer_constraints_v1 The zwp_pointer_constraints_v1 interface
+ *
+ * The global interface exposing pointer constraining functionality. It
+ * exposes two requests: lock_pointer for locking the pointer to its
+ * position, and confine_pointer for locking the pointer to a region.
+ *
+ * The lock_pointer and confine_pointer requests create the objects
+ * wp_locked_pointer and wp_confined_pointer respectively, and the client can
+ * use these objects to interact with the lock.
+ *
+ * For any surface, only one lock or confinement may be active across all
+ * wl_pointer objects of the same seat. If a lock or confinement is requested
+ * when another lock or confinement is active or requested on the same surface
+ * and with any of the wl_pointer objects of the same seat, an
+ * 'already_constrained' error will be raised.
+ */
+extern const struct wl_interface zwp_pointer_constraints_v1_interface;
+#endif
+#ifndef ZWP_LOCKED_POINTER_V1_INTERFACE
+#define ZWP_LOCKED_POINTER_V1_INTERFACE
+/**
+ * @page page_iface_zwp_locked_pointer_v1 zwp_locked_pointer_v1
+ * @section page_iface_zwp_locked_pointer_v1_desc Description
+ *
+ * The wp_locked_pointer interface represents a locked pointer state.
+ *
+ * While the lock of this object is active, the wl_pointer objects of the
+ * associated seat will not emit any wl_pointer.motion events.
+ *
+ * This object will send the event 'locked' when the lock is activated.
+ * Whenever the lock is activated, it is guaranteed that the locked surface
+ * will already have received pointer focus and that the pointer will be
+ * within the region passed to the request creating this object.
+ *
+ * To unlock the pointer, send the destroy request. This will also destroy
+ * the wp_locked_pointer object.
+ *
+ * If the compositor decides to unlock the pointer the unlocked event is
+ * sent. See wp_locked_pointer.unlock for details.
+ *
+ * When unlocking, the compositor may warp the cursor position to the set
+ * cursor position hint. If it does, it will not result in any relative
+ * motion events emitted via wp_relative_pointer.
+ *
+ * If the surface the lock was requested on is destroyed and the lock is not
+ * yet activated, the wp_locked_pointer object is now defunct and must be
+ * destroyed.
+ * @section page_iface_zwp_locked_pointer_v1_api API
+ * See @ref iface_zwp_locked_pointer_v1.
+ */
+/**
+ * @defgroup iface_zwp_locked_pointer_v1 The zwp_locked_pointer_v1 interface
+ *
+ * The wp_locked_pointer interface represents a locked pointer state.
+ *
+ * While the lock of this object is active, the wl_pointer objects of the
+ * associated seat will not emit any wl_pointer.motion events.
+ *
+ * This object will send the event 'locked' when the lock is activated.
+ * Whenever the lock is activated, it is guaranteed that the locked surface
+ * will already have received pointer focus and that the pointer will be
+ * within the region passed to the request creating this object.
+ *
+ * To unlock the pointer, send the destroy request. This will also destroy
+ * the wp_locked_pointer object.
+ *
+ * If the compositor decides to unlock the pointer the unlocked event is
+ * sent. See wp_locked_pointer.unlock for details.
+ *
+ * When unlocking, the compositor may warp the cursor position to the set
+ * cursor position hint. If it does, it will not result in any relative
+ * motion events emitted via wp_relative_pointer.
+ *
+ * If the surface the lock was requested on is destroyed and the lock is not
+ * yet activated, the wp_locked_pointer object is now defunct and must be
+ * destroyed.
+ */
+extern const struct wl_interface zwp_locked_pointer_v1_interface;
+#endif
+#ifndef ZWP_CONFINED_POINTER_V1_INTERFACE
+#define ZWP_CONFINED_POINTER_V1_INTERFACE
+/**
+ * @page page_iface_zwp_confined_pointer_v1 zwp_confined_pointer_v1
+ * @section page_iface_zwp_confined_pointer_v1_desc Description
+ *
+ * The wp_confined_pointer interface represents a confined pointer state.
+ *
+ * This object will send the event 'confined' when the confinement is
+ * activated. Whenever the confinement is activated, it is guaranteed that
+ * the surface the pointer is confined to will already have received pointer
+ * focus and that the pointer will be within the region passed to the request
+ * creating this object. It is up to the compositor to decide whether this
+ * requires some user interaction and if the pointer will warp to within the
+ * passed region if outside.
+ *
+ * To unconfine the pointer, send the destroy request. This will also destroy
+ * the wp_confined_pointer object.
+ *
+ * If the compositor decides to unconfine the pointer the unconfined event is
+ * sent. The wp_confined_pointer object is at this point defunct and should
+ * be destroyed.
+ * @section page_iface_zwp_confined_pointer_v1_api API
+ * See @ref iface_zwp_confined_pointer_v1.
+ */
+/**
+ * @defgroup iface_zwp_confined_pointer_v1 The zwp_confined_pointer_v1 interface
+ *
+ * The wp_confined_pointer interface represents a confined pointer state.
+ *
+ * This object will send the event 'confined' when the confinement is
+ * activated. Whenever the confinement is activated, it is guaranteed that
+ * the surface the pointer is confined to will already have received pointer
+ * focus and that the pointer will be within the region passed to the request
+ * creating this object. It is up to the compositor to decide whether this
+ * requires some user interaction and if the pointer will warp to within the
+ * passed region if outside.
+ *
+ * To unconfine the pointer, send the destroy request. This will also destroy
+ * the wp_confined_pointer object.
+ *
+ * If the compositor decides to unconfine the pointer the unconfined event is
+ * sent. The wp_confined_pointer object is at this point defunct and should
+ * be destroyed.
+ */
+extern const struct wl_interface zwp_confined_pointer_v1_interface;
+#endif
+
+#ifndef ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
+#define ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ * wp_pointer_constraints error values
+ *
+ * These errors can be emitted in response to wp_pointer_constraints
+ * requests.
+ */
+enum zwp_pointer_constraints_v1_error {
+ /**
+ * pointer constraint already requested on that surface
+ */
+ ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED = 1,
+};
+#endif /* ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM */
+
+#ifndef ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
+#define ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ * constraint lifetime
+ *
+ * These values represent different lifetime semantics. They are passed
+ * as arguments to the factory requests to specify how the constraint
+ * lifetimes should be managed.
+ */
+enum zwp_pointer_constraints_v1_lifetime {
+ /**
+ * the pointer constraint is defunct once deactivated
+ *
+ * A oneshot pointer constraint will never reactivate once it has
+ * been deactivated. See the corresponding deactivation event
+ * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined)
+ * for details.
+ */
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT = 1,
+ /**
+ * the pointer constraint may reactivate
+ *
+ * A persistent pointer constraint may again reactivate once it
+ * has been deactivated. See the corresponding deactivation event
+ * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined)
+ * for details.
+ */
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT = 2,
+};
+#endif /* ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM */
+
+#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY 0
+#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER 1
+#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER 2
+
+
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ */
+#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ */
+#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ */
+#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_pointer_constraints_v1 */
+static inline void
+zwp_pointer_constraints_v1_set_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_pointer_constraints_v1, user_data);
+}
+
+/** @ingroup iface_zwp_pointer_constraints_v1 */
+static inline void *
+zwp_pointer_constraints_v1_get_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_pointer_constraints_v1);
+}
+
+static inline uint32_t
+zwp_pointer_constraints_v1_get_version(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1);
+}
+
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ *
+ * Used by the client to notify the server that it will no longer use this
+ * pointer constraints object.
+ */
+static inline void
+zwp_pointer_constraints_v1_destroy(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
+ ZWP_POINTER_CONSTRAINTS_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ *
+ * The lock_pointer request lets the client request to disable movements of
+ * the virtual pointer (i.e. the cursor), effectively locking the pointer
+ * to a position. This request may not take effect immediately; in the
+ * future, when the compositor deems implementation-specific constraints
+ * are satisfied, the pointer lock will be activated and the compositor
+ * sends a locked event.
+ *
+ * The protocol provides no guarantee that the constraints are ever
+ * satisfied, and does not require the compositor to send an error if the
+ * constraints cannot ever be satisfied. It is thus possible to request a
+ * lock that will never activate.
+ *
+ * There may not be another pointer constraint of any kind requested or
+ * active on the surface for any of the wl_pointer objects of the seat of
+ * the passed pointer when requesting a lock. If there is, an error will be
+ * raised. See general pointer lock documentation for more details.
+ *
+ * The intersection of the region passed with this request and the input
+ * region of the surface is used to determine where the pointer must be
+ * in order for the lock to activate. It is up to the compositor whether to
+ * warp the pointer or require some kind of user interaction for the lock
+ * to activate. If the region is null the surface input region is used.
+ *
+ * A surface may receive pointer focus without the lock being activated.
+ *
+ * The request creates a new object wp_locked_pointer which is used to
+ * interact with the lock as well as receive updates about its state. See
+ * the the description of wp_locked_pointer for further information.
+ *
+ * Note that while a pointer is locked, the wl_pointer objects of the
+ * corresponding seat will not emit any wl_pointer.motion events, but
+ * relative motion events will still be emitted via wp_relative_pointer
+ * objects of the same seat. wl_pointer.axis and wl_pointer.button events
+ * are unaffected.
+ */
+static inline struct zwp_locked_pointer_v1 *
+zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
+ ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER, &zwp_locked_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), 0, NULL, surface, pointer, region, lifetime);
+
+ return (struct zwp_locked_pointer_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ *
+ * The confine_pointer request lets the client request to confine the
+ * pointer cursor to a given region. This request may not take effect
+ * immediately; in the future, when the compositor deems implementation-
+ * specific constraints are satisfied, the pointer confinement will be
+ * activated and the compositor sends a confined event.
+ *
+ * The intersection of the region passed with this request and the input
+ * region of the surface is used to determine where the pointer must be
+ * in order for the confinement to activate. It is up to the compositor
+ * whether to warp the pointer or require some kind of user interaction for
+ * the confinement to activate. If the region is null the surface input
+ * region is used.
+ *
+ * The request will create a new object wp_confined_pointer which is used
+ * to interact with the confinement as well as receive updates about its
+ * state. See the the description of wp_confined_pointer for further
+ * information.
+ */
+static inline struct zwp_confined_pointer_v1 *
+zwp_pointer_constraints_v1_confine_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
+ ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER, &zwp_confined_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), 0, NULL, surface, pointer, region, lifetime);
+
+ return (struct zwp_confined_pointer_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ * @struct zwp_locked_pointer_v1_listener
+ */
+struct zwp_locked_pointer_v1_listener {
+ /**
+ * lock activation event
+ *
+ * Notification that the pointer lock of the seat's pointer is
+ * activated.
+ */
+ void (*locked)(void *data,
+ struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
+ /**
+ * lock deactivation event
+ *
+ * Notification that the pointer lock of the seat's pointer is no
+ * longer active. If this is a oneshot pointer lock (see
+ * wp_pointer_constraints.lifetime) this object is now defunct and
+ * should be destroyed. If this is a persistent pointer lock (see
+ * wp_pointer_constraints.lifetime) this pointer lock may again
+ * reactivate in the future.
+ */
+ void (*unlocked)(void *data,
+ struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
+};
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+static inline int
+zwp_locked_pointer_v1_add_listener(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1,
+ const struct zwp_locked_pointer_v1_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zwp_locked_pointer_v1,
+ (void (**)(void)) listener, data);
+}
+
+#define ZWP_LOCKED_POINTER_V1_DESTROY 0
+#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT 1
+#define ZWP_LOCKED_POINTER_V1_SET_REGION 2
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_LOCKED_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_UNLOCKED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_SET_REGION_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_locked_pointer_v1 */
+static inline void
+zwp_locked_pointer_v1_set_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_locked_pointer_v1, user_data);
+}
+
+/** @ingroup iface_zwp_locked_pointer_v1 */
+static inline void *
+zwp_locked_pointer_v1_get_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_locked_pointer_v1);
+}
+
+static inline uint32_t
+zwp_locked_pointer_v1_get_version(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1);
+}
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ *
+ * Destroy the locked pointer object. If applicable, the compositor will
+ * unlock the pointer.
+ */
+static inline void
+zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
+ ZWP_LOCKED_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ *
+ * Set the cursor position hint relative to the top left corner of the
+ * surface.
+ *
+ * If the client is drawing its own cursor, it should update the position
+ * hint to the position of its own cursor. A compositor may use this
+ * information to warp the pointer upon unlock in order to avoid pointer
+ * jumps.
+ *
+ * The cursor position hint is double buffered. The new hint will only take
+ * effect when the associated surface gets it pending state applied. See
+ * wl_surface.commit for details.
+ */
+static inline void
+zwp_locked_pointer_v1_set_cursor_position_hint(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
+ ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), 0, surface_x, surface_y);
+}
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ *
+ * Set a new region used to lock the pointer.
+ *
+ * The new lock region is double-buffered. The new lock region will
+ * only take effect when the associated surface gets its pending state
+ * applied. See wl_surface.commit for details.
+ *
+ * For details about the lock region, see wp_locked_pointer.
+ */
+static inline void
+zwp_locked_pointer_v1_set_region(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, struct wl_region *region)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
+ ZWP_LOCKED_POINTER_V1_SET_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), 0, region);
+}
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ * @struct zwp_confined_pointer_v1_listener
+ */
+struct zwp_confined_pointer_v1_listener {
+ /**
+ * pointer confined
+ *
+ * Notification that the pointer confinement of the seat's
+ * pointer is activated.
+ */
+ void (*confined)(void *data,
+ struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
+ /**
+ * pointer unconfined
+ *
+ * Notification that the pointer confinement of the seat's
+ * pointer is no longer active. If this is a oneshot pointer
+ * confinement (see wp_pointer_constraints.lifetime) this object is
+ * now defunct and should be destroyed. If this is a persistent
+ * pointer confinement (see wp_pointer_constraints.lifetime) this
+ * pointer confinement may again reactivate in the future.
+ */
+ void (*unconfined)(void *data,
+ struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
+};
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+static inline int
+zwp_confined_pointer_v1_add_listener(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1,
+ const struct zwp_confined_pointer_v1_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zwp_confined_pointer_v1,
+ (void (**)(void)) listener, data);
+}
+
+#define ZWP_CONFINED_POINTER_V1_DESTROY 0
+#define ZWP_CONFINED_POINTER_V1_SET_REGION 1
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+#define ZWP_CONFINED_POINTER_V1_CONFINED_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+#define ZWP_CONFINED_POINTER_V1_UNCONFINED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+#define ZWP_CONFINED_POINTER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+#define ZWP_CONFINED_POINTER_V1_SET_REGION_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_confined_pointer_v1 */
+static inline void
+zwp_confined_pointer_v1_set_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_confined_pointer_v1, user_data);
+}
+
+/** @ingroup iface_zwp_confined_pointer_v1 */
+static inline void *
+zwp_confined_pointer_v1_get_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_confined_pointer_v1);
+}
+
+static inline uint32_t
+zwp_confined_pointer_v1_get_version(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1);
+}
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ *
+ * Destroy the confined pointer object. If applicable, the compositor will
+ * unconfine the pointer.
+ */
+static inline void
+zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_confined_pointer_v1,
+ ZWP_CONFINED_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ *
+ * Set a new region used to confine the pointer.
+ *
+ * The new confine region is double-buffered. The new confine region will
+ * only take effect when the associated surface gets its pending state
+ * applied. See wl_surface.commit for details.
+ *
+ * If the confinement is active when the new confinement region is applied
+ * and the pointer ends up outside of newly applied region, the pointer may
+ * warped to a position within the new confinement region. If warped, a
+ * wl_pointer.motion event will be emitted, but no
+ * wp_relative_pointer.relative_motion event.
+ *
+ * The compositor may also, instead of using the new region, unconfine the
+ * pointer.
+ *
+ * For details about the confine region, see wp_confined_pointer.
+ */
+static inline void
+zwp_confined_pointer_v1_set_region(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, struct wl_region *region)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_confined_pointer_v1,
+ ZWP_CONFINED_POINTER_V1_SET_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1), 0, region);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pkg/glfw/wayland-headers/wayland-relative-pointer-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-relative-pointer-unstable-v1-client-protocol-code.h
new file mode 100755
index 000000000..4707c7860
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-relative-pointer-unstable-v1-client-protocol-code.h
@@ -0,0 +1,79 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+/*
+ * Copyright © 2014 Jonas Ådahl
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface zwp_relative_pointer_v1_interface;
+
+static const struct wl_interface *relative_pointer_unstable_v1_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &zwp_relative_pointer_v1_interface,
+ &wl_pointer_interface,
+};
+
+static const struct wl_message zwp_relative_pointer_manager_v1_requests[] = {
+ { "destroy", "", relative_pointer_unstable_v1_types + 0 },
+ { "get_relative_pointer", "no", relative_pointer_unstable_v1_types + 6 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_relative_pointer_manager_v1_interface = {
+ "zwp_relative_pointer_manager_v1", 1,
+ 2, zwp_relative_pointer_manager_v1_requests,
+ 0, NULL,
+};
+
+static const struct wl_message zwp_relative_pointer_v1_requests[] = {
+ { "destroy", "", relative_pointer_unstable_v1_types + 0 },
+};
+
+static const struct wl_message zwp_relative_pointer_v1_events[] = {
+ { "relative_motion", "uuffff", relative_pointer_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_relative_pointer_v1_interface = {
+ "zwp_relative_pointer_v1", 1,
+ 1, zwp_relative_pointer_v1_requests,
+ 1, zwp_relative_pointer_v1_events,
+};
+
diff --git a/pkg/glfw/wayland-headers/wayland-relative-pointer-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/wayland-relative-pointer-unstable-v1-client-protocol.h
new file mode 100755
index 000000000..bbcb0e568
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-relative-pointer-unstable-v1-client-protocol.h
@@ -0,0 +1,297 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+#ifndef RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_relative_pointer_unstable_v1 The relative_pointer_unstable_v1 protocol
+ * protocol for relative pointer motion events
+ *
+ * @section page_desc_relative_pointer_unstable_v1 Description
+ *
+ * This protocol specifies a set of interfaces used for making clients able to
+ * receive relative pointer events not obstructed by barriers (such as the
+ * monitor edge or other pointer barriers).
+ *
+ * To start receiving relative pointer events, a client must first bind the
+ * global interface "wp_relative_pointer_manager" which, if a compositor
+ * supports relative pointer motion events, is exposed by the registry. After
+ * having created the relative pointer manager proxy object, the client uses
+ * it to create the actual relative pointer object using the
+ * "get_relative_pointer" request given a wl_pointer. The relative pointer
+ * motion events will then, when applicable, be transmitted via the proxy of
+ * the newly created relative pointer object. See the documentation of the
+ * relative pointer interface for more details.
+ *
+ * Warning! The protocol described in this file is experimental and backward
+ * incompatible changes may be made. Backward compatible changes may be added
+ * together with the corresponding interface version bump. Backward
+ * incompatible changes are done by bumping the version number in the protocol
+ * and interface names and resetting the interface version. Once the protocol
+ * is to be declared stable, the 'z' prefix and the version number in the
+ * protocol and interface names are removed and the interface version number is
+ * reset.
+ *
+ * @section page_ifaces_relative_pointer_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_relative_pointer_manager_v1 - get relative pointer objects
+ * - @subpage page_iface_zwp_relative_pointer_v1 - relative pointer object
+ * @section page_copyright_relative_pointer_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2014 Jonas Ådahl
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_pointer;
+struct zwp_relative_pointer_manager_v1;
+struct zwp_relative_pointer_v1;
+
+#ifndef ZWP_RELATIVE_POINTER_MANAGER_V1_INTERFACE
+#define ZWP_RELATIVE_POINTER_MANAGER_V1_INTERFACE
+/**
+ * @page page_iface_zwp_relative_pointer_manager_v1 zwp_relative_pointer_manager_v1
+ * @section page_iface_zwp_relative_pointer_manager_v1_desc Description
+ *
+ * A global interface used for getting the relative pointer object for a
+ * given pointer.
+ * @section page_iface_zwp_relative_pointer_manager_v1_api API
+ * See @ref iface_zwp_relative_pointer_manager_v1.
+ */
+/**
+ * @defgroup iface_zwp_relative_pointer_manager_v1 The zwp_relative_pointer_manager_v1 interface
+ *
+ * A global interface used for getting the relative pointer object for a
+ * given pointer.
+ */
+extern const struct wl_interface zwp_relative_pointer_manager_v1_interface;
+#endif
+#ifndef ZWP_RELATIVE_POINTER_V1_INTERFACE
+#define ZWP_RELATIVE_POINTER_V1_INTERFACE
+/**
+ * @page page_iface_zwp_relative_pointer_v1 zwp_relative_pointer_v1
+ * @section page_iface_zwp_relative_pointer_v1_desc Description
+ *
+ * A wp_relative_pointer object is an extension to the wl_pointer interface
+ * used for emitting relative pointer events. It shares the same focus as
+ * wl_pointer objects of the same seat and will only emit events when it has
+ * focus.
+ * @section page_iface_zwp_relative_pointer_v1_api API
+ * See @ref iface_zwp_relative_pointer_v1.
+ */
+/**
+ * @defgroup iface_zwp_relative_pointer_v1 The zwp_relative_pointer_v1 interface
+ *
+ * A wp_relative_pointer object is an extension to the wl_pointer interface
+ * used for emitting relative pointer events. It shares the same focus as
+ * wl_pointer objects of the same seat and will only emit events when it has
+ * focus.
+ */
+extern const struct wl_interface zwp_relative_pointer_v1_interface;
+#endif
+
+#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY 0
+#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER 1
+
+
+/**
+ * @ingroup iface_zwp_relative_pointer_manager_v1
+ */
+#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_relative_pointer_manager_v1
+ */
+#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_relative_pointer_manager_v1 */
+static inline void
+zwp_relative_pointer_manager_v1_set_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1, user_data);
+}
+
+/** @ingroup iface_zwp_relative_pointer_manager_v1 */
+static inline void *
+zwp_relative_pointer_manager_v1_get_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1);
+}
+
+static inline uint32_t
+zwp_relative_pointer_manager_v1_get_version(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1);
+}
+
+/**
+ * @ingroup iface_zwp_relative_pointer_manager_v1
+ *
+ * Used by the client to notify the server that it will no longer use this
+ * relative pointer manager object.
+ */
+static inline void
+zwp_relative_pointer_manager_v1_destroy(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_manager_v1,
+ ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zwp_relative_pointer_manager_v1
+ *
+ * Create a relative pointer interface given a wl_pointer object. See the
+ * wp_relative_pointer interface for more details.
+ */
+static inline struct zwp_relative_pointer_v1 *
+zwp_relative_pointer_manager_v1_get_relative_pointer(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, struct wl_pointer *pointer)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_manager_v1,
+ ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER, &zwp_relative_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1), 0, NULL, pointer);
+
+ return (struct zwp_relative_pointer_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwp_relative_pointer_v1
+ * @struct zwp_relative_pointer_v1_listener
+ */
+struct zwp_relative_pointer_v1_listener {
+ /**
+ * relative pointer motion
+ *
+ * Relative x/y pointer motion from the pointer of the seat
+ * associated with this object.
+ *
+ * A relative motion is in the same dimension as regular wl_pointer
+ * motion events, except they do not represent an absolute
+ * position. For example, moving a pointer from (x, y) to (x', y')
+ * would have the equivalent relative motion (x' - x, y' - y). If a
+ * pointer motion caused the absolute pointer position to be
+ * clipped by for example the edge of the monitor, the relative
+ * motion is unaffected by the clipping and will represent the
+ * unclipped motion.
+ *
+ * This event also contains non-accelerated motion deltas. The
+ * non-accelerated delta is, when applicable, the regular pointer
+ * motion delta as it was before having applied motion acceleration
+ * and other transformations such as normalization.
+ *
+ * Note that the non-accelerated delta does not represent 'raw'
+ * events as they were read from some device. Pointer motion
+ * acceleration is device- and configuration-specific and
+ * non-accelerated deltas and accelerated deltas may have the same
+ * value on some devices.
+ *
+ * Relative motions are not coupled to wl_pointer.motion events,
+ * and can be sent in combination with such events, but also
+ * independently. There may also be scenarios where
+ * wl_pointer.motion is sent, but there is no relative motion. The
+ * order of an absolute and relative motion event originating from
+ * the same physical motion is not guaranteed.
+ *
+ * If the client needs button events or focus state, it can receive
+ * them from a wl_pointer object of the same seat that the
+ * wp_relative_pointer object is associated with.
+ * @param utime_hi high 32 bits of a 64 bit timestamp with microsecond granularity
+ * @param utime_lo low 32 bits of a 64 bit timestamp with microsecond granularity
+ * @param dx the x component of the motion vector
+ * @param dy the y component of the motion vector
+ * @param dx_unaccel the x component of the unaccelerated motion vector
+ * @param dy_unaccel the y component of the unaccelerated motion vector
+ */
+ void (*relative_motion)(void *data,
+ struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
+ uint32_t utime_hi,
+ uint32_t utime_lo,
+ wl_fixed_t dx,
+ wl_fixed_t dy,
+ wl_fixed_t dx_unaccel,
+ wl_fixed_t dy_unaccel);
+};
+
+/**
+ * @ingroup iface_zwp_relative_pointer_v1
+ */
+static inline int
+zwp_relative_pointer_v1_add_listener(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
+ const struct zwp_relative_pointer_v1_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zwp_relative_pointer_v1,
+ (void (**)(void)) listener, data);
+}
+
+#define ZWP_RELATIVE_POINTER_V1_DESTROY 0
+
+/**
+ * @ingroup iface_zwp_relative_pointer_v1
+ */
+#define ZWP_RELATIVE_POINTER_V1_RELATIVE_MOTION_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_relative_pointer_v1
+ */
+#define ZWP_RELATIVE_POINTER_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_relative_pointer_v1 */
+static inline void
+zwp_relative_pointer_v1_set_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_v1, user_data);
+}
+
+/** @ingroup iface_zwp_relative_pointer_v1 */
+static inline void *
+zwp_relative_pointer_v1_get_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_v1);
+}
+
+static inline uint32_t
+zwp_relative_pointer_v1_get_version(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1);
+}
+
+/**
+ * @ingroup iface_zwp_relative_pointer_v1
+ */
+static inline void
+zwp_relative_pointer_v1_destroy(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_v1,
+ ZWP_RELATIVE_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pkg/glfw/wayland-headers/wayland-viewporter-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-viewporter-client-protocol-code.h
new file mode 100755
index 000000000..225938653
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-viewporter-client-protocol-code.h
@@ -0,0 +1,74 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+/*
+ * Copyright © 2013-2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wp_viewport_interface;
+
+static const struct wl_interface *viewporter_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &wp_viewport_interface,
+ &wl_surface_interface,
+};
+
+static const struct wl_message wp_viewporter_requests[] = {
+ { "destroy", "", viewporter_types + 0 },
+ { "get_viewport", "no", viewporter_types + 4 },
+};
+
+WL_PRIVATE const struct wl_interface wp_viewporter_interface = {
+ "wp_viewporter", 1,
+ 2, wp_viewporter_requests,
+ 0, NULL,
+};
+
+static const struct wl_message wp_viewport_requests[] = {
+ { "destroy", "", viewporter_types + 0 },
+ { "set_source", "ffff", viewporter_types + 0 },
+ { "set_destination", "ii", viewporter_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface wp_viewport_interface = {
+ "wp_viewport", 1,
+ 3, wp_viewport_requests,
+ 0, NULL,
+};
+
diff --git a/pkg/glfw/wayland-headers/wayland-viewporter-client-protocol.h b/pkg/glfw/wayland-headers/wayland-viewporter-client-protocol.h
new file mode 100755
index 000000000..b09cb200f
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-viewporter-client-protocol.h
@@ -0,0 +1,398 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+#ifndef VIEWPORTER_CLIENT_PROTOCOL_H
+#define VIEWPORTER_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_viewporter The viewporter protocol
+ * @section page_ifaces_viewporter Interfaces
+ * - @subpage page_iface_wp_viewporter - surface cropping and scaling
+ * - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface
+ * @section page_copyright_viewporter Copyright
+ * <pre>
+ *
+ * Copyright © 2013-2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_surface;
+struct wp_viewport;
+struct wp_viewporter;
+
+#ifndef WP_VIEWPORTER_INTERFACE
+#define WP_VIEWPORTER_INTERFACE
+/**
+ * @page page_iface_wp_viewporter wp_viewporter
+ * @section page_iface_wp_viewporter_desc Description
+ *
+ * The global interface exposing surface cropping and scaling
+ * capabilities is used to instantiate an interface extension for a
+ * wl_surface object. This extended interface will then allow
+ * cropping and scaling the surface contents, effectively
+ * disconnecting the direct relationship between the buffer and the
+ * surface size.
+ * @section page_iface_wp_viewporter_api API
+ * See @ref iface_wp_viewporter.
+ */
+/**
+ * @defgroup iface_wp_viewporter The wp_viewporter interface
+ *
+ * The global interface exposing surface cropping and scaling
+ * capabilities is used to instantiate an interface extension for a
+ * wl_surface object. This extended interface will then allow
+ * cropping and scaling the surface contents, effectively
+ * disconnecting the direct relationship between the buffer and the
+ * surface size.
+ */
+extern const struct wl_interface wp_viewporter_interface;
+#endif
+#ifndef WP_VIEWPORT_INTERFACE
+#define WP_VIEWPORT_INTERFACE
+/**
+ * @page page_iface_wp_viewport wp_viewport
+ * @section page_iface_wp_viewport_desc Description
+ *
+ * An additional interface to a wl_surface object, which allows the
+ * client to specify the cropping and scaling of the surface
+ * contents.
+ *
+ * This interface works with two concepts: the source rectangle (src_x,
+ * src_y, src_width, src_height), and the destination size (dst_width,
+ * dst_height). The contents of the source rectangle are scaled to the
+ * destination size, and content outside the source rectangle is ignored.
+ * This state is double-buffered, and is applied on the next
+ * wl_surface.commit.
+ *
+ * The two parts of crop and scale state are independent: the source
+ * rectangle, and the destination size. Initially both are unset, that
+ * is, no scaling is applied. The whole of the current wl_buffer is
+ * used as the source, and the surface size is as defined in
+ * wl_surface.attach.
+ *
+ * If the destination size is set, it causes the surface size to become
+ * dst_width, dst_height. The source (rectangle) is scaled to exactly
+ * this size. This overrides whatever the attached wl_buffer size is,
+ * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
+ * has no content and therefore no size. Otherwise, the size is always
+ * at least 1x1 in surface local coordinates.
+ *
+ * If the source rectangle is set, it defines what area of the wl_buffer is
+ * taken as the source. If the source rectangle is set and the destination
+ * size is not set, then src_width and src_height must be integers, and the
+ * surface size becomes the source rectangle size. This results in cropping
+ * without scaling. If src_width or src_height are not integers and
+ * destination size is not set, the bad_size protocol error is raised when
+ * the surface state is applied.
+ *
+ * The coordinate transformations from buffer pixel coordinates up to
+ * the surface-local coordinates happen in the following order:
+ * 1. buffer_transform (wl_surface.set_buffer_transform)
+ * 2. buffer_scale (wl_surface.set_buffer_scale)
+ * 3. crop and scale (wp_viewport.set*)
+ * This means, that the source rectangle coordinates of crop and scale
+ * are given in the coordinates after the buffer transform and scale,
+ * i.e. in the coordinates that would be the surface-local coordinates
+ * if the crop and scale was not applied.
+ *
+ * If src_x or src_y are negative, the bad_value protocol error is raised.
+ * Otherwise, if the source rectangle is partially or completely outside of
+ * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
+ * when the surface state is applied. A NULL wl_buffer does not raise the
+ * out_of_buffer error.
+ *
+ * If the wl_surface associated with the wp_viewport is destroyed,
+ * all wp_viewport requests except 'destroy' raise the protocol error
+ * no_surface.
+ *
+ * If the wp_viewport object is destroyed, the crop and scale
+ * state is removed from the wl_surface. The change will be applied
+ * on the next wl_surface.commit.
+ * @section page_iface_wp_viewport_api API
+ * See @ref iface_wp_viewport.
+ */
+/**
+ * @defgroup iface_wp_viewport The wp_viewport interface
+ *
+ * An additional interface to a wl_surface object, which allows the
+ * client to specify the cropping and scaling of the surface
+ * contents.
+ *
+ * This interface works with two concepts: the source rectangle (src_x,
+ * src_y, src_width, src_height), and the destination size (dst_width,
+ * dst_height). The contents of the source rectangle are scaled to the
+ * destination size, and content outside the source rectangle is ignored.
+ * This state is double-buffered, and is applied on the next
+ * wl_surface.commit.
+ *
+ * The two parts of crop and scale state are independent: the source
+ * rectangle, and the destination size. Initially both are unset, that
+ * is, no scaling is applied. The whole of the current wl_buffer is
+ * used as the source, and the surface size is as defined in
+ * wl_surface.attach.
+ *
+ * If the destination size is set, it causes the surface size to become
+ * dst_width, dst_height. The source (rectangle) is scaled to exactly
+ * this size. This overrides whatever the attached wl_buffer size is,
+ * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
+ * has no content and therefore no size. Otherwise, the size is always
+ * at least 1x1 in surface local coordinates.
+ *
+ * If the source rectangle is set, it defines what area of the wl_buffer is
+ * taken as the source. If the source rectangle is set and the destination
+ * size is not set, then src_width and src_height must be integers, and the
+ * surface size becomes the source rectangle size. This results in cropping
+ * without scaling. If src_width or src_height are not integers and
+ * destination size is not set, the bad_size protocol error is raised when
+ * the surface state is applied.
+ *
+ * The coordinate transformations from buffer pixel coordinates up to
+ * the surface-local coordinates happen in the following order:
+ * 1. buffer_transform (wl_surface.set_buffer_transform)
+ * 2. buffer_scale (wl_surface.set_buffer_scale)
+ * 3. crop and scale (wp_viewport.set*)
+ * This means, that the source rectangle coordinates of crop and scale
+ * are given in the coordinates after the buffer transform and scale,
+ * i.e. in the coordinates that would be the surface-local coordinates
+ * if the crop and scale was not applied.
+ *
+ * If src_x or src_y are negative, the bad_value protocol error is raised.
+ * Otherwise, if the source rectangle is partially or completely outside of
+ * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
+ * when the surface state is applied. A NULL wl_buffer does not raise the
+ * out_of_buffer error.
+ *
+ * If the wl_surface associated with the wp_viewport is destroyed,
+ * all wp_viewport requests except 'destroy' raise the protocol error
+ * no_surface.
+ *
+ * If the wp_viewport object is destroyed, the crop and scale
+ * state is removed from the wl_surface. The change will be applied
+ * on the next wl_surface.commit.
+ */
+extern const struct wl_interface wp_viewport_interface;
+#endif
+
+#ifndef WP_VIEWPORTER_ERROR_ENUM
+#define WP_VIEWPORTER_ERROR_ENUM
+enum wp_viewporter_error {
+ /**
+ * the surface already has a viewport object associated
+ */
+ WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0,
+};
+#endif /* WP_VIEWPORTER_ERROR_ENUM */
+
+#define WP_VIEWPORTER_DESTROY 0
+#define WP_VIEWPORTER_GET_VIEWPORT 1
+
+
+/**
+ * @ingroup iface_wp_viewporter
+ */
+#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wp_viewporter
+ */
+#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1
+
+/** @ingroup iface_wp_viewporter */
+static inline void
+wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data);
+}
+
+/** @ingroup iface_wp_viewporter */
+static inline void *
+wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter);
+}
+
+static inline uint32_t
+wp_viewporter_get_version(struct wp_viewporter *wp_viewporter)
+{
+ return wl_proxy_get_version((struct wl_proxy *) wp_viewporter);
+}
+
+/**
+ * @ingroup iface_wp_viewporter
+ *
+ * Informs the server that the client will not be using this
+ * protocol object anymore. This does not affect any other objects,
+ * wp_viewport objects included.
+ */
+static inline void
+wp_viewporter_destroy(struct wp_viewporter *wp_viewporter)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter,
+ WP_VIEWPORTER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wp_viewporter
+ *
+ * Instantiate an interface extension for the given wl_surface to
+ * crop and scale its content. If the given wl_surface already has
+ * a wp_viewport object associated, the viewport_exists
+ * protocol error is raised.
+ */
+static inline struct wp_viewport *
+wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter,
+ WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), 0, NULL, surface);
+
+ return (struct wp_viewport *) id;
+}
+
+#ifndef WP_VIEWPORT_ERROR_ENUM
+#define WP_VIEWPORT_ERROR_ENUM
+enum wp_viewport_error {
+ /**
+ * negative or zero values in width or height
+ */
+ WP_VIEWPORT_ERROR_BAD_VALUE = 0,
+ /**
+ * destination size is not integer
+ */
+ WP_VIEWPORT_ERROR_BAD_SIZE = 1,
+ /**
+ * source rectangle extends outside of the content area
+ */
+ WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2,
+ /**
+ * the wl_surface was destroyed
+ */
+ WP_VIEWPORT_ERROR_NO_SURFACE = 3,
+};
+#endif /* WP_VIEWPORT_ERROR_ENUM */
+
+#define WP_VIEWPORT_DESTROY 0
+#define WP_VIEWPORT_SET_SOURCE 1
+#define WP_VIEWPORT_SET_DESTINATION 2
+
+
+/**
+ * @ingroup iface_wp_viewport
+ */
+#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wp_viewport
+ */
+#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wp_viewport
+ */
+#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1
+
+/** @ingroup iface_wp_viewport */
+static inline void
+wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data);
+}
+
+/** @ingroup iface_wp_viewport */
+static inline void *
+wp_viewport_get_user_data(struct wp_viewport *wp_viewport)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport);
+}
+
+static inline uint32_t
+wp_viewport_get_version(struct wp_viewport *wp_viewport)
+{
+ return wl_proxy_get_version((struct wl_proxy *) wp_viewport);
+}
+
+/**
+ * @ingroup iface_wp_viewport
+ *
+ * The associated wl_surface's crop and scale state is removed.
+ * The change is applied on the next wl_surface.commit.
+ */
+static inline void
+wp_viewport_destroy(struct wp_viewport *wp_viewport)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
+ WP_VIEWPORT_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wp_viewport
+ *
+ * Set the source rectangle of the associated wl_surface. See
+ * wp_viewport for the description, and relation to the wl_buffer
+ * size.
+ *
+ * If all of x, y, width and height are -1.0, the source rectangle is
+ * unset instead. Any other set of values where width or height are zero
+ * or negative, or x or y are negative, raise the bad_value protocol
+ * error.
+ *
+ * The crop and scale state is double-buffered state, and will be
+ * applied on the next wl_surface.commit.
+ */
+static inline void
+wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
+ WP_VIEWPORT_SET_SOURCE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, x, y, width, height);
+}
+
+/**
+ * @ingroup iface_wp_viewport
+ *
+ * Set the destination size of the associated wl_surface. See
+ * wp_viewport for the description, and relation to the wl_buffer
+ * size.
+ *
+ * If width is -1 and height is -1, the destination size is unset
+ * instead. Any other pair of values for width and height that
+ * contains zero or negative values raises the bad_value protocol
+ * error.
+ *
+ * The crop and scale state is double-buffered state, and will be
+ * applied on the next wl_surface.commit.
+ */
+static inline void
+wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
+ WP_VIEWPORT_SET_DESTINATION, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, width, height);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pkg/glfw/wayland-headers/wayland-xdg-decoration-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-xdg-decoration-client-protocol-code.h
new file mode 100755
index 000000000..9c2d471c8
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-xdg-decoration-client-protocol-code.h
@@ -0,0 +1,75 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+/*
+ * Copyright © 2018 Simon Ser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface xdg_toplevel_interface;
+extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
+
+static const struct wl_interface *xdg_decoration_unstable_v1_types[] = {
+ NULL,
+ &zxdg_toplevel_decoration_v1_interface,
+ &xdg_toplevel_interface,
+};
+
+static const struct wl_message zxdg_decoration_manager_v1_requests[] = {
+ { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
+ { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 },
+};
+
+WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = {
+ "zxdg_decoration_manager_v1", 1,
+ 2, zxdg_decoration_manager_v1_requests,
+ 0, NULL,
+};
+
+static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = {
+ { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
+ { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 },
+ { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 },
+};
+
+static const struct wl_message zxdg_toplevel_decoration_v1_events[] = {
+ { "configure", "u", xdg_decoration_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = {
+ "zxdg_toplevel_decoration_v1", 1,
+ 3, zxdg_toplevel_decoration_v1_requests,
+ 1, zxdg_toplevel_decoration_v1_events,
+};
+
diff --git a/pkg/glfw/wayland-headers/wayland-xdg-decoration-client-protocol.h b/pkg/glfw/wayland-headers/wayland-xdg-decoration-client-protocol.h
new file mode 100755
index 000000000..be8879fe0
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-xdg-decoration-client-protocol.h
@@ -0,0 +1,378 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol
+ * @section page_ifaces_xdg_decoration_unstable_v1 Interfaces
+ * - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager
+ * - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface
+ * @section page_copyright_xdg_decoration_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2018 Simon Ser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct xdg_toplevel;
+struct zxdg_decoration_manager_v1;
+struct zxdg_toplevel_decoration_v1;
+
+#ifndef ZXDG_DECORATION_MANAGER_V1_INTERFACE
+#define ZXDG_DECORATION_MANAGER_V1_INTERFACE
+/**
+ * @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1
+ * @section page_iface_zxdg_decoration_manager_v1_desc Description
+ *
+ * This interface allows a compositor to announce support for server-side
+ * decorations.
+ *
+ * A window decoration is a set of window controls as deemed appropriate by
+ * the party managing them, such as user interface components used to move,
+ * resize and change a window's state.
+ *
+ * A client can use this protocol to request being decorated by a supporting
+ * compositor.
+ *
+ * If compositor and client do not negotiate the use of a server-side
+ * decoration using this protocol, clients continue to self-decorate as they
+ * see fit.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ * @section page_iface_zxdg_decoration_manager_v1_api API
+ * See @ref iface_zxdg_decoration_manager_v1.
+ */
+/**
+ * @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface
+ *
+ * This interface allows a compositor to announce support for server-side
+ * decorations.
+ *
+ * A window decoration is a set of window controls as deemed appropriate by
+ * the party managing them, such as user interface components used to move,
+ * resize and change a window's state.
+ *
+ * A client can use this protocol to request being decorated by a supporting
+ * compositor.
+ *
+ * If compositor and client do not negotiate the use of a server-side
+ * decoration using this protocol, clients continue to self-decorate as they
+ * see fit.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ */
+extern const struct wl_interface zxdg_decoration_manager_v1_interface;
+#endif
+#ifndef ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE
+#define ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE
+/**
+ * @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1
+ * @section page_iface_zxdg_toplevel_decoration_v1_desc Description
+ *
+ * The decoration object allows the compositor to toggle server-side window
+ * decorations for a toplevel surface. The client can request to switch to
+ * another mode.
+ *
+ * The xdg_toplevel_decoration object must be destroyed before its
+ * xdg_toplevel.
+ * @section page_iface_zxdg_toplevel_decoration_v1_api API
+ * See @ref iface_zxdg_toplevel_decoration_v1.
+ */
+/**
+ * @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface
+ *
+ * The decoration object allows the compositor to toggle server-side window
+ * decorations for a toplevel surface. The client can request to switch to
+ * another mode.
+ *
+ * The xdg_toplevel_decoration object must be destroyed before its
+ * xdg_toplevel.
+ */
+extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
+#endif
+
+#define ZXDG_DECORATION_MANAGER_V1_DESTROY 0
+#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1
+
+
+/**
+ * @ingroup iface_zxdg_decoration_manager_v1
+ */
+#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zxdg_decoration_manager_v1
+ */
+#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1
+
+/** @ingroup iface_zxdg_decoration_manager_v1 */
+static inline void
+zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data);
+}
+
+/** @ingroup iface_zxdg_decoration_manager_v1 */
+static inline void *
+zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1);
+}
+
+static inline uint32_t
+zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1);
+}
+
+/**
+ * @ingroup iface_zxdg_decoration_manager_v1
+ *
+ * Destroy the decoration manager. This doesn't destroy objects created
+ * with the manager.
+ */
+static inline void
+zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1,
+ ZXDG_DECORATION_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zxdg_decoration_manager_v1
+ *
+ * Create a new decoration object associated with the given toplevel.
+ *
+ * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
+ * buffer attached or committed is a client error, and any attempts by a
+ * client to attach or manipulate a buffer prior to the first
+ * xdg_toplevel_decoration.configure event must also be treated as
+ * errors.
+ */
+static inline struct zxdg_toplevel_decoration_v1 *
+zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1,
+ ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), 0, NULL, toplevel);
+
+ return (struct zxdg_toplevel_decoration_v1 *) id;
+}
+
+#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM
+#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM
+enum zxdg_toplevel_decoration_v1_error {
+ /**
+ * xdg_toplevel has a buffer attached before configure
+ */
+ ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0,
+ /**
+ * xdg_toplevel already has a decoration object
+ */
+ ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1,
+ /**
+ * xdg_toplevel destroyed before the decoration object
+ */
+ ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2,
+};
+#endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */
+
+#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM
+#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ * window decoration modes
+ *
+ * These values describe window decoration modes.
+ */
+enum zxdg_toplevel_decoration_v1_mode {
+ /**
+ * no server-side window decoration
+ */
+ ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1,
+ /**
+ * server-side window decoration
+ */
+ ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2,
+};
+#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */
+
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ * @struct zxdg_toplevel_decoration_v1_listener
+ */
+struct zxdg_toplevel_decoration_v1_listener {
+ /**
+ * suggest a surface change
+ *
+ * The configure event asks the client to change its decoration
+ * mode. The configured state should not be applied immediately.
+ * Clients must send an ack_configure in response to this event.
+ * See xdg_surface.configure and xdg_surface.ack_configure for
+ * details.
+ *
+ * A configure event can be sent at any time. The specified mode
+ * must be obeyed by the client.
+ * @param mode the decoration mode
+ */
+ void (*configure)(void *data,
+ struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
+ uint32_t mode);
+};
+
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ */
+static inline int
+zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
+ const struct zxdg_toplevel_decoration_v1_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1,
+ (void (**)(void)) listener, data);
+}
+
+#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0
+#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1
+#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2
+
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ */
+#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ */
+#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ */
+#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ */
+#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1
+
+/** @ingroup iface_zxdg_toplevel_decoration_v1 */
+static inline void
+zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data);
+}
+
+/** @ingroup iface_zxdg_toplevel_decoration_v1 */
+static inline void *
+zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1);
+}
+
+static inline uint32_t
+zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1);
+}
+
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ *
+ * Switch back to a mode without any server-side decorations at the next
+ * commit.
+ */
+static inline void
+zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
+ ZXDG_TOPLEVEL_DECORATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ *
+ * Set the toplevel surface decoration mode. This informs the compositor
+ * that the client prefers the provided decoration mode.
+ *
+ * After requesting a decoration mode, the compositor will respond by
+ * emitting an xdg_surface.configure event. The client should then update
+ * its content, drawing it without decorations if the received mode is
+ * server-side decorations. The client must also acknowledge the configure
+ * when committing the new content (see xdg_surface.ack_configure).
+ *
+ * The compositor can decide not to use the client's mode and enforce a
+ * different mode instead.
+ *
+ * Clients whose decoration mode depend on the xdg_toplevel state may send
+ * a set_mode request in response to an xdg_surface.configure event and wait
+ * for the next xdg_surface.configure event to prevent unwanted state.
+ * Such clients are responsible for preventing configure loops and must
+ * make sure not to send multiple successive set_mode requests with the
+ * same decoration mode.
+ */
+static inline void
+zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
+ ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0, mode);
+}
+
+/**
+ * @ingroup iface_zxdg_toplevel_decoration_v1
+ *
+ * Unset the toplevel surface decoration mode. This informs the compositor
+ * that the client doesn't prefer a particular decoration mode.
+ *
+ * This request has the same semantics as set_mode.
+ */
+static inline void
+zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
+ ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pkg/glfw/wayland-headers/wayland-xdg-shell-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-xdg-shell-client-protocol-code.h
new file mode 100755
index 000000000..da289269d
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-xdg-shell-client-protocol-code.h
@@ -0,0 +1,183 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+/*
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013 Rafael Antognolli
+ * Copyright © 2013 Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface xdg_popup_interface;
+extern const struct wl_interface xdg_positioner_interface;
+extern const struct wl_interface xdg_surface_interface;
+extern const struct wl_interface xdg_toplevel_interface;
+
+static const struct wl_interface *xdg_shell_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &xdg_positioner_interface,
+ &xdg_surface_interface,
+ &wl_surface_interface,
+ &xdg_toplevel_interface,
+ &xdg_popup_interface,
+ &xdg_surface_interface,
+ &xdg_positioner_interface,
+ &xdg_toplevel_interface,
+ &wl_seat_interface,
+ NULL,
+ NULL,
+ NULL,
+ &wl_seat_interface,
+ NULL,
+ &wl_seat_interface,
+ NULL,
+ NULL,
+ &wl_output_interface,
+ &wl_seat_interface,
+ NULL,
+ &xdg_positioner_interface,
+ NULL,
+};
+
+static const struct wl_message xdg_wm_base_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "create_positioner", "n", xdg_shell_types + 4 },
+ { "get_xdg_surface", "no", xdg_shell_types + 5 },
+ { "pong", "u", xdg_shell_types + 0 },
+};
+
+static const struct wl_message xdg_wm_base_events[] = {
+ { "ping", "u", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
+ "xdg_wm_base", 6,
+ 4, xdg_wm_base_requests,
+ 1, xdg_wm_base_events,
+};
+
+static const struct wl_message xdg_positioner_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "set_size", "ii", xdg_shell_types + 0 },
+ { "set_anchor_rect", "iiii", xdg_shell_types + 0 },
+ { "set_anchor", "u", xdg_shell_types + 0 },
+ { "set_gravity", "u", xdg_shell_types + 0 },
+ { "set_constraint_adjustment", "u", xdg_shell_types + 0 },
+ { "set_offset", "ii", xdg_shell_types + 0 },
+ { "set_reactive", "3", xdg_shell_types + 0 },
+ { "set_parent_size", "3ii", xdg_shell_types + 0 },
+ { "set_parent_configure", "3u", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
+ "xdg_positioner", 6,
+ 10, xdg_positioner_requests,
+ 0, NULL,
+};
+
+static const struct wl_message xdg_surface_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "get_toplevel", "n", xdg_shell_types + 7 },
+ { "get_popup", "n?oo", xdg_shell_types + 8 },
+ { "set_window_geometry", "iiii", xdg_shell_types + 0 },
+ { "ack_configure", "u", xdg_shell_types + 0 },
+};
+
+static const struct wl_message xdg_surface_events[] = {
+ { "configure", "u", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_surface_interface = {
+ "xdg_surface", 6,
+ 5, xdg_surface_requests,
+ 1, xdg_surface_events,
+};
+
+static const struct wl_message xdg_toplevel_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "set_parent", "?o", xdg_shell_types + 11 },
+ { "set_title", "s", xdg_shell_types + 0 },
+ { "set_app_id", "s", xdg_shell_types + 0 },
+ { "show_window_menu", "ouii", xdg_shell_types + 12 },
+ { "move", "ou", xdg_shell_types + 16 },
+ { "resize", "ouu", xdg_shell_types + 18 },
+ { "set_max_size", "ii", xdg_shell_types + 0 },
+ { "set_min_size", "ii", xdg_shell_types + 0 },
+ { "set_maximized", "", xdg_shell_types + 0 },
+ { "unset_maximized", "", xdg_shell_types + 0 },
+ { "set_fullscreen", "?o", xdg_shell_types + 21 },
+ { "unset_fullscreen", "", xdg_shell_types + 0 },
+ { "set_minimized", "", xdg_shell_types + 0 },
+};
+
+static const struct wl_message xdg_toplevel_events[] = {
+ { "configure", "iia", xdg_shell_types + 0 },
+ { "close", "", xdg_shell_types + 0 },
+ { "configure_bounds", "4ii", xdg_shell_types + 0 },
+ { "wm_capabilities", "5a", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
+ "xdg_toplevel", 6,
+ 14, xdg_toplevel_requests,
+ 4, xdg_toplevel_events,
+};
+
+static const struct wl_message xdg_popup_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "grab", "ou", xdg_shell_types + 22 },
+ { "reposition", "3ou", xdg_shell_types + 24 },
+};
+
+static const struct wl_message xdg_popup_events[] = {
+ { "configure", "iiii", xdg_shell_types + 0 },
+ { "popup_done", "", xdg_shell_types + 0 },
+ { "repositioned", "3u", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_popup_interface = {
+ "xdg_popup", 6,
+ 3, xdg_popup_requests,
+ 3, xdg_popup_events,
+};
+
diff --git a/pkg/glfw/wayland-headers/wayland-xdg-shell-client-protocol.h b/pkg/glfw/wayland-headers/wayland-xdg-shell-client-protocol.h
new file mode 100755
index 000000000..575159628
--- /dev/null
+++ b/pkg/glfw/wayland-headers/wayland-xdg-shell-client-protocol.h
@@ -0,0 +1,2307 @@
+/* Generated by wayland-scanner 1.20.0 */
+
+#ifndef XDG_SHELL_CLIENT_PROTOCOL_H
+#define XDG_SHELL_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_xdg_shell The xdg_shell protocol
+ * @section page_ifaces_xdg_shell Interfaces
+ * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces
+ * - @subpage page_iface_xdg_positioner - child surface positioner
+ * - @subpage page_iface_xdg_surface - desktop user interface surface base interface
+ * - @subpage page_iface_xdg_toplevel - toplevel surface
+ * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus
+ * @section page_copyright_xdg_shell Copyright
+ * <pre>
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013 Rafael Antognolli
+ * Copyright © 2013 Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_output;
+struct wl_seat;
+struct wl_surface;
+struct xdg_popup;
+struct xdg_positioner;
+struct xdg_surface;
+struct xdg_toplevel;
+struct xdg_wm_base;
+
+#ifndef XDG_WM_BASE_INTERFACE
+#define XDG_WM_BASE_INTERFACE
+/**
+ * @page page_iface_xdg_wm_base xdg_wm_base
+ * @section page_iface_xdg_wm_base_desc Description
+ *
+ * The xdg_wm_base interface is exposed as a global object enabling clients
+ * to turn their wl_surfaces into windows in a desktop environment. It
+ * defines the basic functionality needed for clients and the compositor to
+ * create windows that can be dragged, resized, maximized, etc, as well as
+ * creating transient windows such as popup menus.
+ * @section page_iface_xdg_wm_base_api API
+ * See @ref iface_xdg_wm_base.
+ */
+/**
+ * @defgroup iface_xdg_wm_base The xdg_wm_base interface
+ *
+ * The xdg_wm_base interface is exposed as a global object enabling clients
+ * to turn their wl_surfaces into windows in a desktop environment. It
+ * defines the basic functionality needed for clients and the compositor to
+ * create windows that can be dragged, resized, maximized, etc, as well as
+ * creating transient windows such as popup menus.
+ */
+extern const struct wl_interface xdg_wm_base_interface;
+#endif
+#ifndef XDG_POSITIONER_INTERFACE
+#define XDG_POSITIONER_INTERFACE
+/**
+ * @page page_iface_xdg_positioner xdg_positioner
+ * @section page_iface_xdg_positioner_desc Description
+ *
+ * The xdg_positioner provides a collection of rules for the placement of a
+ * child surface relative to a parent surface. Rules can be defined to ensure
+ * the child surface remains within the visible area's borders, and to
+ * specify how the child surface changes its position, such as sliding along
+ * an axis, or flipping around a rectangle. These positioner-created rules are
+ * constrained by the requirement that a child surface must intersect with or
+ * be at least partially adjacent to its parent surface.
+ *
+ * See the various requests for details about possible rules.
+ *
+ * At the time of the request, the compositor makes a copy of the rules
+ * specified by the xdg_positioner. Thus, after the request is complete the
+ * xdg_positioner object can be destroyed or reused; further changes to the
+ * object will have no effect on previous usages.
+ *
+ * For an xdg_positioner object to be considered complete, it must have a
+ * non-zero size set by set_size, and a non-zero anchor rectangle set by
+ * set_anchor_rect. Passing an incomplete xdg_positioner object when
+ * positioning a surface raises an invalid_positioner error.
+ * @section page_iface_xdg_positioner_api API
+ * See @ref iface_xdg_positioner.
+ */
+/**
+ * @defgroup iface_xdg_positioner The xdg_positioner interface
+ *
+ * The xdg_positioner provides a collection of rules for the placement of a
+ * child surface relative to a parent surface. Rules can be defined to ensure
+ * the child surface remains within the visible area's borders, and to
+ * specify how the child surface changes its position, such as sliding along
+ * an axis, or flipping around a rectangle. These positioner-created rules are
+ * constrained by the requirement that a child surface must intersect with or
+ * be at least partially adjacent to its parent surface.
+ *
+ * See the various requests for details about possible rules.
+ *
+ * At the time of the request, the compositor makes a copy of the rules
+ * specified by the xdg_positioner. Thus, after the request is complete the
+ * xdg_positioner object can be destroyed or reused; further changes to the
+ * object will have no effect on previous usages.
+ *
+ * For an xdg_positioner object to be considered complete, it must have a
+ * non-zero size set by set_size, and a non-zero anchor rectangle set by
+ * set_anchor_rect. Passing an incomplete xdg_positioner object when
+ * positioning a surface raises an invalid_positioner error.
+ */
+extern const struct wl_interface xdg_positioner_interface;
+#endif
+#ifndef XDG_SURFACE_INTERFACE
+#define XDG_SURFACE_INTERFACE
+/**
+ * @page page_iface_xdg_surface xdg_surface
+ * @section page_iface_xdg_surface_desc Description
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides a base set of functionality required to construct user
+ * interface elements requiring management by the compositor, such as
+ * toplevel windows, menus, etc. The types of functionality are split into
+ * xdg_surface roles.
+ *
+ * Creating an xdg_surface does not set the role for a wl_surface. In order
+ * to map an xdg_surface, the client must create a role-specific object
+ * using, e.g., get_toplevel, get_popup. The wl_surface for any given
+ * xdg_surface can have at most one role, and may not be assigned any role
+ * not based on xdg_surface.
+ *
+ * A role must be assigned before any other requests are made to the
+ * xdg_surface object.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_surface state to take effect.
+ *
+ * Creating an xdg_surface from a wl_surface which has a buffer attached or
+ * committed is a client error, and any attempts by a client to attach or
+ * manipulate a buffer prior to the first xdg_surface.configure call must
+ * also be treated as errors.
+ *
+ * After creating a role-specific object and setting it up, the client must
+ * perform an initial commit without any buffer attached. The compositor
+ * will reply with initial wl_surface state such as
+ * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
+ * event. The client must acknowledge it and is then allowed to attach a
+ * buffer to map the surface.
+ *
+ * Mapping an xdg_surface-based role surface is defined as making it
+ * possible for the surface to be shown by the compositor. Note that
+ * a mapped surface is not guaranteed to be visible once it is mapped.
+ *
+ * For an xdg_surface to be mapped by the compositor, the following
+ * conditions must be met:
+ * (1) the client has assigned an xdg_surface-based role to the surface
+ * (2) the client has set and committed the xdg_surface state and the
+ * role-dependent state to the surface
+ * (3) the client has committed a buffer to the surface
+ *
+ * A newly-unmapped surface is considered to have met condition (1) out
+ * of the 3 required conditions for mapping a surface if its role surface
+ * has not been destroyed, i.e. the client must perform the initial commit
+ * again before attaching a buffer.
+ * @section page_iface_xdg_surface_api API
+ * See @ref iface_xdg_surface.
+ */
+/**
+ * @defgroup iface_xdg_surface The xdg_surface interface
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides a base set of functionality required to construct user
+ * interface elements requiring management by the compositor, such as
+ * toplevel windows, menus, etc. The types of functionality are split into
+ * xdg_surface roles.
+ *
+ * Creating an xdg_surface does not set the role for a wl_surface. In order
+ * to map an xdg_surface, the client must create a role-specific object
+ * using, e.g., get_toplevel, get_popup. The wl_surface for any given
+ * xdg_surface can have at most one role, and may not be assigned any role
+ * not based on xdg_surface.
+ *
+ * A role must be assigned before any other requests are made to the
+ * xdg_surface object.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_surface state to take effect.
+ *
+ * Creating an xdg_surface from a wl_surface which has a buffer attached or
+ * committed is a client error, and any attempts by a client to attach or
+ * manipulate a buffer prior to the first xdg_surface.configure call must
+ * also be treated as errors.
+ *
+ * After creating a role-specific object and setting it up, the client must
+ * perform an initial commit without any buffer attached. The compositor
+ * will reply with initial wl_surface state such as
+ * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
+ * event. The client must acknowledge it and is then allowed to attach a
+ * buffer to map the surface.
+ *
+ * Mapping an xdg_surface-based role surface is defined as making it
+ * possible for the surface to be shown by the compositor. Note that
+ * a mapped surface is not guaranteed to be visible once it is mapped.
+ *
+ * For an xdg_surface to be mapped by the compositor, the following
+ * conditions must be met:
+ * (1) the client has assigned an xdg_surface-based role to the surface
+ * (2) the client has set and committed the xdg_surface state and the
+ * role-dependent state to the surface
+ * (3) the client has committed a buffer to the surface
+ *
+ * A newly-unmapped surface is considered to have met condition (1) out
+ * of the 3 required conditions for mapping a surface if its role surface
+ * has not been destroyed, i.e. the client must perform the initial commit
+ * again before attaching a buffer.
+ */
+extern const struct wl_interface xdg_surface_interface;
+#endif
+#ifndef XDG_TOPLEVEL_INTERFACE
+#define XDG_TOPLEVEL_INTERFACE
+/**
+ * @page page_iface_xdg_toplevel xdg_toplevel
+ * @section page_iface_xdg_toplevel_desc Description
+ *
+ * This interface defines an xdg_surface role which allows a surface to,
+ * among other things, set window-like properties such as maximize,
+ * fullscreen, and minimize, set application-specific metadata like title and
+ * id, and well as trigger user interactive operations such as interactive
+ * resize and move.
+ *
+ * Unmapping an xdg_toplevel means that the surface cannot be shown
+ * by the compositor until it is explicitly mapped again.
+ * All active operations (e.g., move, resize) are canceled and all
+ * attributes (e.g. title, state, stacking, ...) are discarded for
+ * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
+ * the state it had right after xdg_surface.get_toplevel. The client
+ * can re-map the toplevel by perfoming a commit without any buffer
+ * attached, waiting for a configure event and handling it as usual (see
+ * xdg_surface description).
+ *
+ * Attaching a null buffer to a toplevel unmaps the surface.
+ * @section page_iface_xdg_toplevel_api API
+ * See @ref iface_xdg_toplevel.
+ */
+/**
+ * @defgroup iface_xdg_toplevel The xdg_toplevel interface
+ *
+ * This interface defines an xdg_surface role which allows a surface to,
+ * among other things, set window-like properties such as maximize,
+ * fullscreen, and minimize, set application-specific metadata like title and
+ * id, and well as trigger user interactive operations such as interactive
+ * resize and move.
+ *
+ * Unmapping an xdg_toplevel means that the surface cannot be shown
+ * by the compositor until it is explicitly mapped again.
+ * All active operations (e.g., move, resize) are canceled and all
+ * attributes (e.g. title, state, stacking, ...) are discarded for
+ * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
+ * the state it had right after xdg_surface.get_toplevel. The client
+ * can re-map the toplevel by perfoming a commit without any buffer
+ * attached, waiting for a configure event and handling it as usual (see
+ * xdg_surface description).
+ *
+ * Attaching a null buffer to a toplevel unmaps the surface.
+ */
+extern const struct wl_interface xdg_toplevel_interface;
+#endif
+#ifndef XDG_POPUP_INTERFACE
+#define XDG_POPUP_INTERFACE
+/**
+ * @page page_iface_xdg_popup xdg_popup
+ * @section page_iface_xdg_popup_desc Description
+ *
+ * A popup surface is a short-lived, temporary surface. It can be used to
+ * implement for example menus, popovers, tooltips and other similar user
+ * interface concepts.
+ *
+ * A popup can be made to take an explicit grab. See xdg_popup.grab for
+ * details.
+ *
+ * When the popup is dismissed, a popup_done event will be sent out, and at
+ * the same time the surface will be unmapped. See the xdg_popup.popup_done
+ * event for details.
+ *
+ * Explicitly destroying the xdg_popup object will also dismiss the popup and
+ * unmap the surface. Clients that want to dismiss the popup when another
+ * surface of their own is clicked should dismiss the popup using the destroy
+ * request.
+ *
+ * A newly created xdg_popup will be stacked on top of all previously created
+ * xdg_popup surfaces associated with the same xdg_toplevel.
+ *
+ * The parent of an xdg_popup must be mapped (see the xdg_surface
+ * description) before the xdg_popup itself.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_popup state to take effect.
+ * @section page_iface_xdg_popup_api API
+ * See @ref iface_xdg_popup.
+ */
+/**
+ * @defgroup iface_xdg_popup The xdg_popup interface
+ *
+ * A popup surface is a short-lived, temporary surface. It can be used to
+ * implement for example menus, popovers, tooltips and other similar user
+ * interface concepts.
+ *
+ * A popup can be made to take an explicit grab. See xdg_popup.grab for
+ * details.
+ *
+ * When the popup is dismissed, a popup_done event will be sent out, and at
+ * the same time the surface will be unmapped. See the xdg_popup.popup_done
+ * event for details.
+ *
+ * Explicitly destroying the xdg_popup object will also dismiss the popup and
+ * unmap the surface. Clients that want to dismiss the popup when another
+ * surface of their own is clicked should dismiss the popup using the destroy
+ * request.
+ *
+ * A newly created xdg_popup will be stacked on top of all previously created
+ * xdg_popup surfaces associated with the same xdg_toplevel.
+ *
+ * The parent of an xdg_popup must be mapped (see the xdg_surface
+ * description) before the xdg_popup itself.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_popup state to take effect.
+ */
+extern const struct wl_interface xdg_popup_interface;
+#endif
+
+#ifndef XDG_WM_BASE_ERROR_ENUM
+#define XDG_WM_BASE_ERROR_ENUM
+enum xdg_wm_base_error {
+ /**
+ * given wl_surface has another role
+ */
+ XDG_WM_BASE_ERROR_ROLE = 0,
+ /**
+ * xdg_wm_base was destroyed before children
+ */
+ XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1,
+ /**
+ * the client tried to map or destroy a non-topmost popup
+ */
+ XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2,
+ /**
+ * the client specified an invalid popup parent surface
+ */
+ XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3,
+ /**
+ * the client provided an invalid surface state
+ */
+ XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4,
+ /**
+ * the client provided an invalid positioner
+ */
+ XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5,
+ /**
+ * the client didn’t respond to a ping event in time
+ */
+ XDG_WM_BASE_ERROR_UNRESPONSIVE = 6,
+};
+#endif /* XDG_WM_BASE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_wm_base
+ * @struct xdg_wm_base_listener
+ */
+struct xdg_wm_base_listener {
+ /**
+ * check if the client is alive
+ *
+ * The ping event asks the client if it's still alive. Pass the
+ * serial specified in the event back to the compositor by sending
+ * a "pong" request back with the specified serial. See
+ * xdg_wm_base.pong.
+ *
+ * Compositors can use this to determine if the client is still
+ * alive. It's unspecified what will happen if the client doesn't
+ * respond to the ping request, or in what timeframe. Clients
+ * should try to respond in a reasonable amount of time. The
+ * “unresponsive” error is provided for compositors that wish
+ * to disconnect unresponsive clients.
+ *
+ * A compositor is free to ping in any way it wants, but a client
+ * must always respond to any xdg_wm_base object it created.
+ * @param serial pass this to the pong request
+ */
+ void (*ping)(void *data,
+ struct xdg_wm_base *xdg_wm_base,
+ uint32_t serial);
+};
+
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+static inline int
+xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base,
+ const struct xdg_wm_base_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base,
+ (void (**)(void)) listener, data);
+}
+
+#define XDG_WM_BASE_DESTROY 0
+#define XDG_WM_BASE_CREATE_POSITIONER 1
+#define XDG_WM_BASE_GET_XDG_SURFACE 2
+#define XDG_WM_BASE_PONG 3
+
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_PING_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_PONG_SINCE_VERSION 1
+
+/** @ingroup iface_xdg_wm_base */
+static inline void
+xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data);
+}
+
+/** @ingroup iface_xdg_wm_base */
+static inline void *
+xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base);
+}
+
+static inline uint32_t
+xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base);
+}
+
+/**
+ * @ingroup iface_xdg_wm_base
+ *
+ * Destroy this xdg_wm_base object.
+ *
+ * Destroying a bound xdg_wm_base object while there are surfaces
+ * still alive created by this xdg_wm_base object instance is illegal
+ * and will result in a defunct_surfaces error.
+ */
+static inline void
+xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
+ XDG_WM_BASE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_wm_base
+ *
+ * Create a positioner object. A positioner object is used to position
+ * surfaces relative to some parent surface. See the interface description
+ * and xdg_surface.get_popup for details.
+ */
+static inline struct xdg_positioner *
+xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
+ XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL);
+
+ return (struct xdg_positioner *) id;
+}
+
+/**
+ * @ingroup iface_xdg_wm_base
+ *
+ * This creates an xdg_surface for the given surface. While xdg_surface
+ * itself is not a role, the corresponding surface may only be assigned
+ * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is
+ * illegal to create an xdg_surface for a wl_surface which already has an
+ * assigned role and this will result in a role error.
+ *
+ * This creates an xdg_surface for the given surface. An xdg_surface is
+ * used as basis to define a role to a given surface, such as xdg_toplevel
+ * or xdg_popup. It also manages functionality shared between xdg_surface
+ * based surface roles.
+ *
+ * See the documentation of xdg_surface for more details about what an
+ * xdg_surface is and how it is used.
+ */
+static inline struct xdg_surface *
+xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
+ XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL, surface);
+
+ return (struct xdg_surface *) id;
+}
+
+/**
+ * @ingroup iface_xdg_wm_base
+ *
+ * A client must respond to a ping event with a pong request or
+ * the client may be deemed unresponsive. See xdg_wm_base.ping
+ * and xdg_wm_base.error.unresponsive.
+ */
+static inline void
+xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
+ XDG_WM_BASE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, serial);
+}
+
+#ifndef XDG_POSITIONER_ERROR_ENUM
+#define XDG_POSITIONER_ERROR_ENUM
+enum xdg_positioner_error {
+ /**
+ * invalid input provided
+ */
+ XDG_POSITIONER_ERROR_INVALID_INPUT = 0,
+};
+#endif /* XDG_POSITIONER_ERROR_ENUM */
+
+#ifndef XDG_POSITIONER_ANCHOR_ENUM
+#define XDG_POSITIONER_ANCHOR_ENUM
+enum xdg_positioner_anchor {
+ XDG_POSITIONER_ANCHOR_NONE = 0,
+ XDG_POSITIONER_ANCHOR_TOP = 1,
+ XDG_POSITIONER_ANCHOR_BOTTOM = 2,
+ XDG_POSITIONER_ANCHOR_LEFT = 3,
+ XDG_POSITIONER_ANCHOR_RIGHT = 4,
+ XDG_POSITIONER_ANCHOR_TOP_LEFT = 5,
+ XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6,
+ XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7,
+ XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8,
+};
+#endif /* XDG_POSITIONER_ANCHOR_ENUM */
+
+#ifndef XDG_POSITIONER_GRAVITY_ENUM
+#define XDG_POSITIONER_GRAVITY_ENUM
+enum xdg_positioner_gravity {
+ XDG_POSITIONER_GRAVITY_NONE = 0,
+ XDG_POSITIONER_GRAVITY_TOP = 1,
+ XDG_POSITIONER_GRAVITY_BOTTOM = 2,
+ XDG_POSITIONER_GRAVITY_LEFT = 3,
+ XDG_POSITIONER_GRAVITY_RIGHT = 4,
+ XDG_POSITIONER_GRAVITY_TOP_LEFT = 5,
+ XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6,
+ XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7,
+ XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8,
+};
+#endif /* XDG_POSITIONER_GRAVITY_ENUM */
+
+#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM
+#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM
+/**
+ * @ingroup iface_xdg_positioner
+ * constraint adjustments
+ *
+ * The constraint adjustment value define ways the compositor will adjust
+ * the position of the surface, if the unadjusted position would result
+ * in the surface being partly constrained.
+ *
+ * Whether a surface is considered 'constrained' is left to the compositor
+ * to determine. For example, the surface may be partly outside the
+ * compositor's defined 'work area', thus necessitating the child surface's
+ * position be adjusted until it is entirely inside the work area.
+ *
+ * The adjustments can be combined, according to a defined precedence: 1)
+ * Flip, 2) Slide, 3) Resize.
+ */
+enum xdg_positioner_constraint_adjustment {
+ /**
+ * don't move the child surface when constrained
+ *
+ * Don't alter the surface position even if it is constrained on
+ * some axis, for example partially outside the edge of an output.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0,
+ /**
+ * move along the x axis until unconstrained
+ *
+ * Slide the surface along the x axis until it is no longer
+ * constrained.
+ *
+ * First try to slide towards the direction of the gravity on the x
+ * axis until either the edge in the opposite direction of the
+ * gravity is unconstrained or the edge in the direction of the
+ * gravity is constrained.
+ *
+ * Then try to slide towards the opposite direction of the gravity
+ * on the x axis until either the edge in the direction of the
+ * gravity is unconstrained or the edge in the opposite direction
+ * of the gravity is constrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1,
+ /**
+ * move along the y axis until unconstrained
+ *
+ * Slide the surface along the y axis until it is no longer
+ * constrained.
+ *
+ * First try to slide towards the direction of the gravity on the y
+ * axis until either the edge in the opposite direction of the
+ * gravity is unconstrained or the edge in the direction of the
+ * gravity is constrained.
+ *
+ * Then try to slide towards the opposite direction of the gravity
+ * on the y axis until either the edge in the direction of the
+ * gravity is unconstrained or the edge in the opposite direction
+ * of the gravity is constrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2,
+ /**
+ * invert the anchor and gravity on the x axis
+ *
+ * Invert the anchor and gravity on the x axis if the surface is
+ * constrained on the x axis. For example, if the left edge of the
+ * surface is constrained, the gravity is 'left' and the anchor is
+ * 'left', change the gravity to 'right' and the anchor to 'right'.
+ *
+ * If the adjusted position also ends up being constrained, the
+ * resulting position of the flip_x adjustment will be the one
+ * before the adjustment.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4,
+ /**
+ * invert the anchor and gravity on the y axis
+ *
+ * Invert the anchor and gravity on the y axis if the surface is
+ * constrained on the y axis. For example, if the bottom edge of
+ * the surface is constrained, the gravity is 'bottom' and the
+ * anchor is 'bottom', change the gravity to 'top' and the anchor
+ * to 'top'.
+ *
+ * The adjusted position is calculated given the original anchor
+ * rectangle and offset, but with the new flipped anchor and
+ * gravity values.
+ *
+ * If the adjusted position also ends up being constrained, the
+ * resulting position of the flip_y adjustment will be the one
+ * before the adjustment.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8,
+ /**
+ * horizontally resize the surface
+ *
+ * Resize the surface horizontally so that it is completely
+ * unconstrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16,
+ /**
+ * vertically resize the surface
+ *
+ * Resize the surface vertically so that it is completely
+ * unconstrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32,
+};
+#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */
+
+#define XDG_POSITIONER_DESTROY 0
+#define XDG_POSITIONER_SET_SIZE 1
+#define XDG_POSITIONER_SET_ANCHOR_RECT 2
+#define XDG_POSITIONER_SET_ANCHOR 3
+#define XDG_POSITIONER_SET_GRAVITY 4
+#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5
+#define XDG_POSITIONER_SET_OFFSET 6
+#define XDG_POSITIONER_SET_REACTIVE 7
+#define XDG_POSITIONER_SET_PARENT_SIZE 8
+#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9
+
+
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3
+
+/** @ingroup iface_xdg_positioner */
+static inline void
+xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data);
+}
+
+/** @ingroup iface_xdg_positioner */
+static inline void *
+xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner);
+}
+
+static inline uint32_t
+xdg_positioner_get_version(struct xdg_positioner *xdg_positioner)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_positioner);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Notify the compositor that the xdg_positioner will no longer be used.
+ */
+static inline void
+xdg_positioner_destroy(struct xdg_positioner *xdg_positioner)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Set the size of the surface that is to be positioned with the positioner
+ * object. The size is in surface-local coordinates and corresponds to the
+ * window geometry. See xdg_surface.set_window_geometry.
+ *
+ * If a zero or negative size is set the invalid_input error is raised.
+ */
+static inline void
+xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Specify the anchor rectangle within the parent surface that the child
+ * surface will be placed relative to. The rectangle is relative to the
+ * window geometry as defined by xdg_surface.set_window_geometry of the
+ * parent surface.
+ *
+ * When the xdg_positioner object is used to position a child surface, the
+ * anchor rectangle may not extend outside the window geometry of the
+ * positioned child's parent surface.
+ *
+ * If a negative size is set the invalid_input error is raised.
+ */
+static inline void
+xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Defines the anchor point for the anchor rectangle. The specified anchor
+ * is used derive an anchor point that the child surface will be
+ * positioned relative to. If a corner anchor is set (e.g. 'top_left' or
+ * 'bottom_right'), the anchor point will be at the specified corner;
+ * otherwise, the derived anchor point will be centered on the specified
+ * edge, or in the center of the anchor rectangle if no edge is specified.
+ */
+static inline void
+xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, anchor);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Defines in what direction a surface should be positioned, relative to
+ * the anchor point of the parent surface. If a corner gravity is
+ * specified (e.g. 'bottom_right' or 'top_left'), then the child surface
+ * will be placed towards the specified gravity; otherwise, the child
+ * surface will be centered over the anchor point on any axis that had no
+ * gravity specified. If the gravity is not in the ‘gravity’ enum, an
+ * invalid_input error is raised.
+ */
+static inline void
+xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, gravity);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Specify how the window should be positioned if the originally intended
+ * position caused the surface to be constrained, meaning at least
+ * partially outside positioning boundaries set by the compositor. The
+ * adjustment is set by constructing a bitmask describing the adjustment to
+ * be made when the surface is constrained on that axis.
+ *
+ * If no bit for one axis is set, the compositor will assume that the child
+ * surface should not change its position on that axis when constrained.
+ *
+ * If more than one bit for one axis is set, the order of how adjustments
+ * are applied is specified in the corresponding adjustment descriptions.
+ *
+ * The default adjustment is none.
+ */
+static inline void
+xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, constraint_adjustment);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Specify the surface position offset relative to the position of the
+ * anchor on the anchor rectangle and the anchor on the surface. For
+ * example if the anchor of the anchor rectangle is at (x, y), the surface
+ * has the gravity bottom|right, and the offset is (ox, oy), the calculated
+ * surface position will be (x + ox, y + oy). The offset position of the
+ * surface is the one used for constraint testing. See
+ * set_constraint_adjustment.
+ *
+ * An example use case is placing a popup menu on top of a user interface
+ * element, while aligning the user interface element of the parent surface
+ * with some user interface element placed somewhere in the popup surface.
+ */
+static inline void
+xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * When set reactive, the surface is reconstrained if the conditions used
+ * for constraining changed, e.g. the parent window moved.
+ *
+ * If the conditions changed and the popup was reconstrained, an
+ * xdg_popup.configure event is sent with updated geometry, followed by an
+ * xdg_surface.configure event.
+ */
+static inline void
+xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_REACTIVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Set the parent window geometry the compositor should use when
+ * positioning the popup. The compositor may use this information to
+ * determine the future state the popup should be constrained using. If
+ * this doesn't match the dimension of the parent the popup is eventually
+ * positioned against, the behavior is undefined.
+ *
+ * The arguments are given in the surface-local coordinate space.
+ */
+static inline void
+xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_PARENT_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, parent_width, parent_height);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Set the serial of an xdg_surface.configure event this positioner will be
+ * used in response to. The compositor may use this information together
+ * with set_parent_size to determine what future state the popup should be
+ * constrained using.
+ */
+static inline void
+xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_PARENT_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, serial);
+}
+
+#ifndef XDG_SURFACE_ERROR_ENUM
+#define XDG_SURFACE_ERROR_ENUM
+enum xdg_surface_error {
+ /**
+ * Surface was not fully constructed
+ */
+ XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1,
+ /**
+ * Surface was already constructed
+ */
+ XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2,
+ /**
+ * Attaching a buffer to an unconfigured surface
+ */
+ XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3,
+ /**
+ * Invalid serial number when acking a configure event
+ */
+ XDG_SURFACE_ERROR_INVALID_SERIAL = 4,
+ /**
+ * Width or height was zero or negative
+ */
+ XDG_SURFACE_ERROR_INVALID_SIZE = 5,
+ /**
+ * Surface was destroyed before its role object
+ */
+ XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6,
+};
+#endif /* XDG_SURFACE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_surface
+ * @struct xdg_surface_listener
+ */
+struct xdg_surface_listener {
+ /**
+ * suggest a surface change
+ *
+ * The configure event marks the end of a configure sequence. A
+ * configure sequence is a set of one or more events configuring
+ * the state of the xdg_surface, including the final
+ * xdg_surface.configure event.
+ *
+ * Where applicable, xdg_surface surface roles will during a
+ * configure sequence extend this event as a latched state sent as
+ * events before the xdg_surface.configure event. Such events
+ * should be considered to make up a set of atomically applied
+ * configuration states, where the xdg_surface.configure commits
+ * the accumulated state.
+ *
+ * Clients should arrange their surface for the new states, and
+ * then send an ack_configure request with the serial sent in this
+ * configure event at some point before committing the new surface.
+ *
+ * If the client receives multiple configure events before it can
+ * respond to one, it is free to discard all but the last event it
+ * received.
+ * @param serial serial of the configure event
+ */
+ void (*configure)(void *data,
+ struct xdg_surface *xdg_surface,
+ uint32_t serial);
+};
+
+/**
+ * @ingroup iface_xdg_surface
+ */
+static inline int
+xdg_surface_add_listener(struct xdg_surface *xdg_surface,
+ const struct xdg_surface_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) xdg_surface,
+ (void (**)(void)) listener, data);
+}
+
+#define XDG_SURFACE_DESTROY 0
+#define XDG_SURFACE_GET_TOPLEVEL 1
+#define XDG_SURFACE_GET_POPUP 2
+#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3
+#define XDG_SURFACE_ACK_CONFIGURE 4
+
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1
+
+/** @ingroup iface_xdg_surface */
+static inline void
+xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);
+}
+
+/** @ingroup iface_xdg_surface */
+static inline void *
+xdg_surface_get_user_data(struct xdg_surface *xdg_surface)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);
+}
+
+static inline uint32_t
+xdg_surface_get_version(struct xdg_surface *xdg_surface)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_surface);
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * Destroy the xdg_surface object. An xdg_surface must only be destroyed
+ * after its role object has been destroyed, otherwise
+ * a defunct_role_object error is raised.
+ */
+static inline void
+xdg_surface_destroy(struct xdg_surface *xdg_surface)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * This creates an xdg_toplevel object for the given xdg_surface and gives
+ * the associated wl_surface the xdg_toplevel role.
+ *
+ * See the documentation of xdg_toplevel for more details about what an
+ * xdg_toplevel is and how it is used.
+ */
+static inline struct xdg_toplevel *
+xdg_surface_get_toplevel(struct xdg_surface *xdg_surface)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL);
+
+ return (struct xdg_toplevel *) id;
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * This creates an xdg_popup object for the given xdg_surface and gives
+ * the associated wl_surface the xdg_popup role.
+ *
+ * If null is passed as a parent, a parent surface must be specified using
+ * some other protocol, before committing the initial state.
+ *
+ * See the documentation of xdg_popup for more details about what an
+ * xdg_popup is and how it is used.
+ */
+static inline struct xdg_popup *
+xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_GET_POPUP, &xdg_popup_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL, parent, positioner);
+
+ return (struct xdg_popup *) id;
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * The window geometry of a surface is its "visible bounds" from the
+ * user's perspective. Client-side decorations often have invisible
+ * portions like drop-shadows which should be ignored for the
+ * purposes of aligning, placing and constraining windows.
+ *
+ * The window geometry is double buffered, and will be applied at the
+ * time wl_surface.commit of the corresponding wl_surface is called.
+ *
+ * When maintaining a position, the compositor should treat the (x, y)
+ * coordinate of the window geometry as the top left corner of the window.
+ * A client changing the (x, y) window geometry coordinate should in
+ * general not alter the position of the window.
+ *
+ * Once the window geometry of the surface is set, it is not possible to
+ * unset it, and it will remain the same until set_window_geometry is
+ * called again, even if a new subsurface or buffer is attached.
+ *
+ * If never set, the value is the full bounds of the surface,
+ * including any subsurfaces. This updates dynamically on every
+ * commit. This unset is meant for extremely simple clients.
+ *
+ * The arguments are given in the surface-local coordinate space of
+ * the wl_surface associated with this xdg_surface, and may extend outside
+ * of the wl_surface itself to mark parts of the subsurface tree as part of
+ * the window geometry.
+ *
+ * When applied, the effective window geometry will be the set window
+ * geometry clamped to the bounding rectangle of the combined
+ * geometry of the surface of the xdg_surface and the associated
+ * subsurfaces.
+ *
+ * The effective geometry will not be recalculated unless a new call to
+ * set_window_geometry is done and the new pending surface state is
+ * subsequently applied.
+ *
+ * The width and height of the effective window geometry must be
+ * greater than zero. Setting an invalid size will raise an
+ * invalid_size error.
+ */
+static inline void
+xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, x, y, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * When a configure event is received, if a client commits the
+ * surface in response to the configure event, then the client
+ * must make an ack_configure request sometime before the commit
+ * request, passing along the serial of the configure event.
+ *
+ * For instance, for toplevel surfaces the compositor might use this
+ * information to move a surface to the top left only when the client has
+ * drawn itself for the maximized or fullscreen state.
+ *
+ * If the client receives multiple configure events before it
+ * can respond to one, it only has to ack the last configure event.
+ * Acking a configure event that was never sent raises an invalid_serial
+ * error.
+ *
+ * A client is not required to commit immediately after sending
+ * an ack_configure request - it may even ack_configure several times
+ * before its next surface commit.
+ *
+ * A client may send multiple ack_configure requests before committing, but
+ * only the last request sent before a commit indicates which configure
+ * event the client really is responding to.
+ *
+ * Sending an ack_configure request consumes the serial number sent with
+ * the request, as well as serial numbers sent by all configure events
+ * sent on this xdg_surface prior to the configure event referenced by
+ * the committed serial.
+ *
+ * It is an error to issue multiple ack_configure requests referencing a
+ * serial from the same configure event, or to issue an ack_configure
+ * request referencing a serial from a configure event issued before the
+ * event identified by the last ack_configure request for the same
+ * xdg_surface. Doing so will raise an invalid_serial error.
+ */
+static inline void
+xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, serial);
+}
+
+#ifndef XDG_TOPLEVEL_ERROR_ENUM
+#define XDG_TOPLEVEL_ERROR_ENUM
+enum xdg_toplevel_error {
+ /**
+ * provided value is not a valid variant of the resize_edge enum
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0,
+ /**
+ * invalid parent toplevel
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1,
+ /**
+ * client provided an invalid min or max size
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2,
+};
+#endif /* XDG_TOPLEVEL_ERROR_ENUM */
+
+#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM
+#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM
+/**
+ * @ingroup iface_xdg_toplevel
+ * edge values for resizing
+ *
+ * These values are used to indicate which edge of a surface
+ * is being dragged in a resize operation.
+ */
+enum xdg_toplevel_resize_edge {
+ XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2,
+ XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6,
+ XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10,
+};
+#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */
+
+#ifndef XDG_TOPLEVEL_STATE_ENUM
+#define XDG_TOPLEVEL_STATE_ENUM
+/**
+ * @ingroup iface_xdg_toplevel
+ * types of state on the surface
+ *
+ * The different state values used on the surface. This is designed for
+ * state values like maximized, fullscreen. It is paired with the
+ * configure event to ensure that both the client and the compositor
+ * setting the state can be synchronized.
+ *
+ * States set in this way are double-buffered. They will get applied on
+ * the next commit.
+ */
+enum xdg_toplevel_state {
+ /**
+ * the surface is maximized
+ * the surface is maximized
+ *
+ * The surface is maximized. The window geometry specified in the
+ * configure event must be obeyed by the client, or the
+ * xdg_wm_base.invalid_surface_state error is raised.
+ *
+ * The client should draw without shadow or other decoration
+ * outside of the window geometry.
+ */
+ XDG_TOPLEVEL_STATE_MAXIMIZED = 1,
+ /**
+ * the surface is fullscreen
+ * the surface is fullscreen
+ *
+ * The surface is fullscreen. The window geometry specified in
+ * the configure event is a maximum; the client cannot resize
+ * beyond it. For a surface to cover the whole fullscreened area,
+ * the geometry dimensions must be obeyed by the client. For more
+ * details, see xdg_toplevel.set_fullscreen.
+ */
+ XDG_TOPLEVEL_STATE_FULLSCREEN = 2,
+ /**
+ * the surface is being resized
+ * the surface is being resized
+ *
+ * The surface is being resized. The window geometry specified in
+ * the configure event is a maximum; the client cannot resize
+ * beyond it. Clients that have aspect ratio or cell sizing
+ * configuration can use a smaller size, however.
+ */
+ XDG_TOPLEVEL_STATE_RESIZING = 3,
+ /**
+ * the surface is now activated
+ * the surface is now activated
+ *
+ * Client window decorations should be painted as if the window
+ * is active. Do not assume this means that the window actually has
+ * keyboard or pointer focus.
+ */
+ XDG_TOPLEVEL_STATE_ACTIVATED = 4,
+ /**
+ * the surface’s left edge is tiled
+ *
+ * The window is currently in a tiled layout and the left edge is
+ * considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_LEFT = 5,
+ /**
+ * the surface’s right edge is tiled
+ *
+ * The window is currently in a tiled layout and the right edge
+ * is considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_RIGHT = 6,
+ /**
+ * the surface’s top edge is tiled
+ *
+ * The window is currently in a tiled layout and the top edge is
+ * considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_TOP = 7,
+ /**
+ * the surface’s bottom edge is tiled
+ *
+ * The window is currently in a tiled layout and the bottom edge
+ * is considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8,
+ /**
+ * surface repaint is suspended
+ *
+ * The surface is currently not ordinarily being repainted; for
+ * example because its content is occluded by another window, or
+ * its outputs are switched off due to screen locking.
+ * @since 6
+ */
+ XDG_TOPLEVEL_STATE_SUSPENDED = 9,
+};
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6
+#endif /* XDG_TOPLEVEL_STATE_ENUM */
+
+#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM
+#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM
+enum xdg_toplevel_wm_capabilities {
+ /**
+ * show_window_menu is available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1,
+ /**
+ * set_maximized and unset_maximized are available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2,
+ /**
+ * set_fullscreen and unset_fullscreen are available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3,
+ /**
+ * set_minimized is available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4,
+};
+#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */
+
+/**
+ * @ingroup iface_xdg_toplevel
+ * @struct xdg_toplevel_listener
+ */
+struct xdg_toplevel_listener {
+ /**
+ * suggest a surface change
+ *
+ * This configure event asks the client to resize its toplevel
+ * surface or to change its state. The configured state should not
+ * be applied immediately. See xdg_surface.configure for details.
+ *
+ * The width and height arguments specify a hint to the window
+ * about how its surface should be resized in window geometry
+ * coordinates. See set_window_geometry.
+ *
+ * If the width or height arguments are zero, it means the client
+ * should decide its own window dimension. This may happen when the
+ * compositor needs to configure the state of the surface but
+ * doesn't have any information about any previous or expected
+ * dimension.
+ *
+ * The states listed in the event specify how the width/height
+ * arguments should be interpreted, and possibly how it should be
+ * drawn.
+ *
+ * Clients must send an ack_configure in response to this event.
+ * See xdg_surface.configure and xdg_surface.ack_configure for
+ * details.
+ */
+ void (*configure)(void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array *states);
+ /**
+ * surface wants to be closed
+ *
+ * The close event is sent by the compositor when the user wants
+ * the surface to be closed. This should be equivalent to the user
+ * clicking the close button in client-side decorations, if your
+ * application has any.
+ *
+ * This is only a request that the user intends to close the
+ * window. The client may choose to ignore this request, or show a
+ * dialog to ask the user to save their data, etc.
+ */
+ void (*close)(void *data,
+ struct xdg_toplevel *xdg_toplevel);
+ /**
+ * recommended window geometry bounds
+ *
+ * The configure_bounds event may be sent prior to a
+ * xdg_toplevel.configure event to communicate the bounds a window
+ * geometry size is recommended to constrain to.
+ *
+ * The passed width and height are in surface coordinate space. If
+ * width and height are 0, it means bounds is unknown and
+ * equivalent to as if no configure_bounds event was ever sent for
+ * this surface.
+ *
+ * The bounds can for example correspond to the size of a monitor
+ * excluding any panels or other shell components, so that a
+ * surface isn't created in a way that it cannot fit.
+ *
+ * The bounds may change at any point, and in such a case, a new
+ * xdg_toplevel.configure_bounds will be sent, followed by
+ * xdg_toplevel.configure and xdg_surface.configure.
+ * @since 4
+ */
+ void (*configure_bounds)(void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t width,
+ int32_t height);
+ /**
+ * compositor capabilities
+ *
+ * This event advertises the capabilities supported by the
+ * compositor. If a capability isn't supported, clients should hide
+ * or disable the UI elements that expose this functionality. For
+ * instance, if the compositor doesn't advertise support for
+ * minimized toplevels, a button triggering the set_minimized
+ * request should not be displayed.
+ *
+ * The compositor will ignore requests it doesn't support. For
+ * instance, a compositor which doesn't advertise support for
+ * minimized will ignore set_minimized requests.
+ *
+ * Compositors must send this event once before the first
+ * xdg_surface.configure event. When the capabilities change,
+ * compositors must send this event again and then send an
+ * xdg_surface.configure event.
+ *
+ * The configured state should not be applied immediately. See
+ * xdg_surface.configure for details.
+ *
+ * The capabilities are sent as an array of 32-bit unsigned
+ * integers in native endianness.
+ * @param capabilities array of 32-bit capabilities
+ * @since 5
+ */
+ void (*wm_capabilities)(void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ struct wl_array *capabilities);
+};
+
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+static inline int
+xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel,
+ const struct xdg_toplevel_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel,
+ (void (**)(void)) listener, data);
+}
+
+#define XDG_TOPLEVEL_DESTROY 0
+#define XDG_TOPLEVEL_SET_PARENT 1
+#define XDG_TOPLEVEL_SET_TITLE 2
+#define XDG_TOPLEVEL_SET_APP_ID 3
+#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4
+#define XDG_TOPLEVEL_MOVE 5
+#define XDG_TOPLEVEL_RESIZE 6
+#define XDG_TOPLEVEL_SET_MAX_SIZE 7
+#define XDG_TOPLEVEL_SET_MIN_SIZE 8
+#define XDG_TOPLEVEL_SET_MAXIMIZED 9
+#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10
+#define XDG_TOPLEVEL_SET_FULLSCREEN 11
+#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12
+#define XDG_TOPLEVEL_SET_MINIMIZED 13
+
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5
+
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1
+
+/** @ingroup iface_xdg_toplevel */
+static inline void
+xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data);
+}
+
+/** @ingroup iface_xdg_toplevel */
+static inline void *
+xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel);
+}
+
+static inline uint32_t
+xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * This request destroys the role surface and unmaps the surface;
+ * see "Unmapping" behavior in interface section for details.
+ */
+static inline void
+xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set the "parent" of this surface. This surface should be stacked
+ * above the parent surface and all other ancestor surfaces.
+ *
+ * Parent surfaces should be set on dialogs, toolboxes, or other
+ * "auxiliary" surfaces, so that the parent is raised when the dialog
+ * is raised.
+ *
+ * Setting a null parent for a child surface unsets its parent. Setting
+ * a null parent for a surface which currently has no parent is a no-op.
+ *
+ * Only mapped surfaces can have child surfaces. Setting a parent which
+ * is not mapped is equivalent to setting a null parent. If a surface
+ * becomes unmapped, its children's parent is set to the parent of
+ * the now-unmapped surface. If the now-unmapped surface has no parent,
+ * its children's parent is unset. If the now-unmapped surface becomes
+ * mapped again, its parent-child relationship is not restored.
+ *
+ * The parent toplevel must not be one of the child toplevel's
+ * descendants, and the parent must be different from the child toplevel,
+ * otherwise the invalid_parent protocol error is raised.
+ */
+static inline void
+xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, parent);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set a short title for the surface.
+ *
+ * This string may be used to identify the surface in a task bar,
+ * window list, or other user interface elements provided by the
+ * compositor.
+ *
+ * The string must be encoded in UTF-8.
+ */
+static inline void
+xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, title);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set an application identifier for the surface.
+ *
+ * The app ID identifies the general class of applications to which
+ * the surface belongs. The compositor can use this to group multiple
+ * surfaces together, or to determine how to launch a new application.
+ *
+ * For D-Bus activatable applications, the app ID is used as the D-Bus
+ * service name.
+ *
+ * The compositor shell will try to group application surfaces together
+ * by their app ID. As a best practice, it is suggested to select app
+ * ID's that match the basename of the application's .desktop file.
+ * For example, "org.freedesktop.FooViewer" where the .desktop file is
+ * "org.freedesktop.FooViewer.desktop".
+ *
+ * Like other properties, a set_app_id request can be sent after the
+ * xdg_toplevel has been mapped to update the property.
+ *
+ * See the desktop-entry specification [0] for more details on
+ * application identifiers and how they relate to well-known D-Bus
+ * names and .desktop files.
+ *
+ * [0] https://standards.freedesktop.org/desktop-entry-spec/
+ */
+static inline void
+xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, app_id);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Clients implementing client-side decorations might want to show
+ * a context menu when right-clicking on the decorations, giving the
+ * user a menu that they can use to maximize or minimize the window.
+ *
+ * This request asks the compositor to pop up such a window menu at
+ * the given position, relative to the local surface coordinates of
+ * the parent surface. There are no guarantees as to what menu items
+ * the window menu contains, or even if a window menu will be drawn
+ * at all.
+ *
+ * This request must be used in response to some sort of user action
+ * like a button press, key press, or touch down event.
+ */
+static inline void
+xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, x, y);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Start an interactive, user-driven move of the surface.
+ *
+ * This request must be used in response to some sort of user action
+ * like a button press, key press, or touch down event. The passed
+ * serial is used to determine the type of interactive move (touch,
+ * pointer, etc).
+ *
+ * The server may ignore move requests depending on the state of
+ * the surface (e.g. fullscreen or maximized), or if the passed serial
+ * is no longer valid.
+ *
+ * If triggered, the surface will lose the focus of the device
+ * (wl_pointer, wl_touch, etc) used for the move. It is up to the
+ * compositor to visually indicate that the move is taking place, such as
+ * updating a pointer cursor, during the move. There is no guarantee
+ * that the device focus will return when the move is completed.
+ */
+static inline void
+xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Start a user-driven, interactive resize of the surface.
+ *
+ * This request must be used in response to some sort of user action
+ * like a button press, key press, or touch down event. The passed
+ * serial is used to determine the type of interactive resize (touch,
+ * pointer, etc).
+ *
+ * The server may ignore resize requests depending on the state of
+ * the surface (e.g. fullscreen or maximized).
+ *
+ * If triggered, the client will receive configure events with the
+ * "resize" state enum value and the expected sizes. See the "resize"
+ * enum value for more details about what is required. The client
+ * must also acknowledge configure events using "ack_configure". After
+ * the resize is completed, the client will receive another "configure"
+ * event without the resize state.
+ *
+ * If triggered, the surface also will lose the focus of the device
+ * (wl_pointer, wl_touch, etc) used for the resize. It is up to the
+ * compositor to visually indicate that the resize is taking place,
+ * such as updating a pointer cursor, during the resize. There is no
+ * guarantee that the device focus will return when the resize is
+ * completed.
+ *
+ * The edges parameter specifies how the surface should be resized, and
+ * is one of the values of the resize_edge enum. Values not matching
+ * a variant of the enum will cause the invalid_resize_edge protocol error.
+ * The compositor may use this information to update the surface position
+ * for example when dragging the top left corner. The compositor may also
+ * use this information to adapt its behavior, e.g. choose an appropriate
+ * cursor image.
+ */
+static inline void
+xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, edges);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set a maximum size for the window.
+ *
+ * The client can specify a maximum size so that the compositor does
+ * not try to configure the window beyond this size.
+ *
+ * The width and height arguments are in window geometry coordinates.
+ * See xdg_surface.set_window_geometry.
+ *
+ * Values set in this way are double-buffered. They will get applied
+ * on the next commit.
+ *
+ * The compositor can use this information to allow or disallow
+ * different states like maximize or fullscreen and draw accurate
+ * animations.
+ *
+ * Similarly, a tiling window manager may use this information to
+ * place and resize client windows in a more effective way.
+ *
+ * The client should not rely on the compositor to obey the maximum
+ * size. The compositor may decide to ignore the values set by the
+ * client and request a larger size.
+ *
+ * If never set, or a value of zero in the request, means that the
+ * client has no expected maximum size in the given dimension.
+ * As a result, a client wishing to reset the maximum size
+ * to an unspecified state can use zero for width and height in the
+ * request.
+ *
+ * Requesting a maximum size to be smaller than the minimum size of
+ * a surface is illegal and will result in an invalid_size error.
+ *
+ * The width and height must be greater than or equal to zero. Using
+ * strictly negative values for width or height will result in a
+ * invalid_size error.
+ */
+static inline void
+xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set a minimum size for the window.
+ *
+ * The client can specify a minimum size so that the compositor does
+ * not try to configure the window below this size.
+ *
+ * The width and height arguments are in window geometry coordinates.
+ * See xdg_surface.set_window_geometry.
+ *
+ * Values set in this way are double-buffered. They will get applied
+ * on the next commit.
+ *
+ * The compositor can use this information to allow or disallow
+ * different states like maximize or fullscreen and draw accurate
+ * animations.
+ *
+ * Similarly, a tiling window manager may use this information to
+ * place and resize client windows in a more effective way.
+ *
+ * The client should not rely on the compositor to obey the minimum
+ * size. The compositor may decide to ignore the values set by the
+ * client and request a smaller size.
+ *
+ * If never set, or a value of zero in the request, means that the
+ * client has no expected minimum size in the given dimension.
+ * As a result, a client wishing to reset the minimum size
+ * to an unspecified state can use zero for width and height in the
+ * request.
+ *
+ * Requesting a minimum size to be larger than the maximum size of
+ * a surface is illegal and will result in an invalid_size error.
+ *
+ * The width and height must be greater than or equal to zero. Using
+ * strictly negative values for width and height will result in a
+ * invalid_size error.
+ */
+static inline void
+xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Maximize the surface.
+ *
+ * After requesting that the surface should be maximized, the compositor
+ * will respond by emitting a configure event. Whether this configure
+ * actually sets the window maximized is subject to compositor policies.
+ * The client must then update its content, drawing in the configured
+ * state. The client must also acknowledge the configure when committing
+ * the new content (see ack_configure).
+ *
+ * It is up to the compositor to decide how and where to maximize the
+ * surface, for example which output and what region of the screen should
+ * be used.
+ *
+ * If the surface was already maximized, the compositor will still emit
+ * a configure event with the "maximized" state.
+ *
+ * If the surface is in a fullscreen state, this request has no direct
+ * effect. It may alter the state the surface is returned to when
+ * unmaximized unless overridden by the compositor.
+ */
+static inline void
+xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Unmaximize the surface.
+ *
+ * After requesting that the surface should be unmaximized, the compositor
+ * will respond by emitting a configure event. Whether this actually
+ * un-maximizes the window is subject to compositor policies.
+ * If available and applicable, the compositor will include the window
+ * geometry dimensions the window had prior to being maximized in the
+ * configure event. The client must then update its content, drawing it in
+ * the configured state. The client must also acknowledge the configure
+ * when committing the new content (see ack_configure).
+ *
+ * It is up to the compositor to position the surface after it was
+ * unmaximized; usually the position the surface had before maximizing, if
+ * applicable.
+ *
+ * If the surface was already not maximized, the compositor will still
+ * emit a configure event without the "maximized" state.
+ *
+ * If the surface is in a fullscreen state, this request has no direct
+ * effect. It may alter the state the surface is returned to when
+ * unmaximized unless overridden by the compositor.
+ */
+static inline void
+xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Make the surface fullscreen.
+ *
+ * After requesting that the surface should be fullscreened, the
+ * compositor will respond by emitting a configure event. Whether the
+ * client is actually put into a fullscreen state is subject to compositor
+ * policies. The client must also acknowledge the configure when
+ * committing the new content (see ack_configure).
+ *
+ * The output passed by the request indicates the client's preference as
+ * to which display it should be set fullscreen on. If this value is NULL,
+ * it's up to the compositor to choose which display will be used to map
+ * this surface.
+ *
+ * If the surface doesn't cover the whole output, the compositor will
+ * position the surface in the center of the output and compensate with
+ * with border fill covering the rest of the output. The content of the
+ * border fill is undefined, but should be assumed to be in some way that
+ * attempts to blend into the surrounding area (e.g. solid black).
+ *
+ * If the fullscreened surface is not opaque, the compositor must make
+ * sure that other screen content not part of the same surface tree (made
+ * up of subsurfaces, popups or similarly coupled surfaces) are not
+ * visible below the fullscreened surface.
+ */
+static inline void
+xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, output);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Make the surface no longer fullscreen.
+ *
+ * After requesting that the surface should be unfullscreened, the
+ * compositor will respond by emitting a configure event.
+ * Whether this actually removes the fullscreen state of the client is
+ * subject to compositor policies.
+ *
+ * Making a surface unfullscreen sets states for the surface based on the following:
+ * * the state(s) it may have had before becoming fullscreen
+ * * any state(s) decided by the compositor
+ * * any state(s) requested by the client while the surface was fullscreen
+ *
+ * The compositor may include the previous window geometry dimensions in
+ * the configure event, if applicable.
+ *
+ * The client must also acknowledge the configure when committing the new
+ * content (see ack_configure).
+ */
+static inline void
+xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Request that the compositor minimize your surface. There is no
+ * way to know if the surface is currently minimized, nor is there
+ * any way to unset minimization on this surface.
+ *
+ * If you are looking to throttle redrawing when minimized, please
+ * instead use the wl_surface.frame event for this, as this will
+ * also work with live previews on windows in Alt-Tab, Expose or
+ * similar compositor features.
+ */
+static inline void
+xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
+}
+
+#ifndef XDG_POPUP_ERROR_ENUM
+#define XDG_POPUP_ERROR_ENUM
+enum xdg_popup_error {
+ /**
+ * tried to grab after being mapped
+ */
+ XDG_POPUP_ERROR_INVALID_GRAB = 0,
+};
+#endif /* XDG_POPUP_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_popup
+ * @struct xdg_popup_listener
+ */
+struct xdg_popup_listener {
+ /**
+ * configure the popup surface
+ *
+ * This event asks the popup surface to configure itself given
+ * the configuration. The configured state should not be applied
+ * immediately. See xdg_surface.configure for details.
+ *
+ * The x and y arguments represent the position the popup was
+ * placed at given the xdg_positioner rule, relative to the upper
+ * left corner of the window geometry of the parent surface.
+ *
+ * For version 2 or older, the configure event for an xdg_popup is
+ * only ever sent once for the initial configuration. Starting with
+ * version 3, it may be sent again if the popup is setup with an
+ * xdg_positioner with set_reactive requested, or in response to
+ * xdg_popup.reposition requests.
+ * @param x x position relative to parent surface window geometry
+ * @param y y position relative to parent surface window geometry
+ * @param width window geometry width
+ * @param height window geometry height
+ */
+ void (*configure)(void *data,
+ struct xdg_popup *xdg_popup,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height);
+ /**
+ * popup interaction is done
+ *
+ * The popup_done event is sent out when a popup is dismissed by
+ * the compositor. The client should destroy the xdg_popup object
+ * at this point.
+ */
+ void (*popup_done)(void *data,
+ struct xdg_popup *xdg_popup);
+ /**
+ * signal the completion of a repositioned request
+ *
+ * The repositioned event is sent as part of a popup
+ * configuration sequence, together with xdg_popup.configure and
+ * lastly xdg_surface.configure to notify the completion of a
+ * reposition request.
+ *
+ * The repositioned event is to notify about the completion of a
+ * xdg_popup.reposition request. The token argument is the token
+ * passed in the xdg_popup.reposition request.
+ *
+ * Immediately after this event is emitted, xdg_popup.configure and
+ * xdg_surface.configure will be sent with the updated size and
+ * position, as well as a new configure serial.
+ *
+ * The client should optionally update the content of the popup,
+ * but must acknowledge the new popup configuration for the new
+ * position to take effect. See xdg_surface.ack_configure for
+ * details.
+ * @param token reposition request token
+ * @since 3
+ */
+ void (*repositioned)(void *data,
+ struct xdg_popup *xdg_popup,
+ uint32_t token);
+};
+
+/**
+ * @ingroup iface_xdg_popup
+ */
+static inline int
+xdg_popup_add_listener(struct xdg_popup *xdg_popup,
+ const struct xdg_popup_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) xdg_popup,
+ (void (**)(void)) listener, data);
+}
+
+#define XDG_POPUP_DESTROY 0
+#define XDG_POPUP_GRAB 1
+#define XDG_POPUP_REPOSITION 2
+
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_GRAB_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_REPOSITION_SINCE_VERSION 3
+
+/** @ingroup iface_xdg_popup */
+static inline void
+xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);
+}
+
+/** @ingroup iface_xdg_popup */
+static inline void *
+xdg_popup_get_user_data(struct xdg_popup *xdg_popup)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);
+}
+
+static inline uint32_t
+xdg_popup_get_version(struct xdg_popup *xdg_popup)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_popup);
+}
+
+/**
+ * @ingroup iface_xdg_popup
+ *
+ * This destroys the popup. Explicitly destroying the xdg_popup
+ * object will also dismiss the popup, and unmap the surface.
+ *
+ * If this xdg_popup is not the "topmost" popup, the
+ * xdg_wm_base.not_the_topmost_popup protocol error will be sent.
+ */
+static inline void
+xdg_popup_destroy(struct xdg_popup *xdg_popup)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
+ XDG_POPUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_popup
+ *
+ * This request makes the created popup take an explicit grab. An explicit
+ * grab will be dismissed when the user dismisses the popup, or when the
+ * client destroys the xdg_popup. This can be done by the user clicking
+ * outside the surface, using the keyboard, or even locking the screen
+ * through closing the lid or a timeout.
+ *
+ * If the compositor denies the grab, the popup will be immediately
+ * dismissed.
+ *
+ * This request must be used in response to some sort of user action like a
+ * button press, key press, or touch down event. The serial number of the
+ * event should be passed as 'serial'.
+ *
+ * The parent of a grabbing popup must either be an xdg_toplevel surface or
+ * another xdg_popup with an explicit grab. If the parent is another
+ * xdg_popup it means that the popups are nested, with this popup now being
+ * the topmost popup.
+ *
+ * Nested popups must be destroyed in the reverse order they were created
+ * in, e.g. the only popup you are allowed to destroy at all times is the
+ * topmost one.
+ *
+ * When compositors choose to dismiss a popup, they may dismiss every
+ * nested grabbing popup as well. When a compositor dismisses popups, it
+ * will follow the same dismissing order as required from the client.
+ *
+ * If the topmost grabbing popup is destroyed, the grab will be returned to
+ * the parent of the popup, if that parent previously had an explicit grab.
+ *
+ * If the parent is a grabbing popup which has already been dismissed, this
+ * popup will be immediately dismissed. If the parent is a popup that did
+ * not take an explicit grab, an error will be raised.
+ *
+ * During a popup grab, the client owning the grab will receive pointer
+ * and touch events for all their surfaces as normal (similar to an
+ * "owner-events" grab in X11 parlance), while the top most grabbing popup
+ * will always have keyboard focus.
+ */
+static inline void
+xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
+ XDG_POPUP_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, seat, serial);
+}
+
+/**
+ * @ingroup iface_xdg_popup
+ *
+ * Reposition an already-mapped popup. The popup will be placed given the
+ * details in the passed xdg_positioner object, and a
+ * xdg_popup.repositioned followed by xdg_popup.configure and
+ * xdg_surface.configure will be emitted in response. Any parameters set
+ * by the previous positioner will be discarded.
+ *
+ * The passed token will be sent in the corresponding
+ * xdg_popup.repositioned event. The new popup position will not take
+ * effect until the corresponding configure event is acknowledged by the
+ * client. See xdg_popup.repositioned for details. The token itself is
+ * opaque, and has no other special meaning.
+ *
+ * If multiple reposition requests are sent, the compositor may skip all
+ * but the last one.
+ *
+ * If the popup is repositioned in response to a configure event for its
+ * parent, the client should send an xdg_positioner.set_parent_configure
+ * and possibly an xdg_positioner.set_parent_size request to allow the
+ * compositor to properly constrain the popup.
+ *
+ * If the popup is repositioned together with a parent that is being
+ * resized, but not in response to a configure event, the client should
+ * send an xdg_positioner.set_parent_size request.
+ */
+static inline void
+xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
+ XDG_POPUP_REPOSITION, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, positioner, token);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/build/Config.zig b/src/build/Config.zig
index 562e1777c..e0c7ed2be 100644
--- a/src/build/Config.zig
+++ b/src/build/Config.zig
@@ -337,8 +337,8 @@ pub fn init(b: *std.Build) !Config {
target.result.os.tag == .macos and
config.app_runtime == .none and
(!config.emit_bench and
- !config.emit_test_exe and
- !config.emit_helpgen);
+ !config.emit_test_exe and
+ !config.emit_helpgen);
//---------------------------------------------------------------
// System Packages
@@ -379,6 +379,11 @@ pub fn init(b: *std.Build) !Config {
"glslang",
"spirv-cross",
"simdutf",
+
+ // This is default false because it is used for testing
+ // primarily and not official packaging. The packaging
+ // guide advises against building the GLFW backend.
+ "glfw3",
}) |dep| {
_ = b.systemIntegrationOption(dep, .{ .default = false });
}
diff --git a/src/build/SharedDeps.zig b/src/build/SharedDeps.zig
index ae9f09afe..4e39c0b39 100644
--- a/src/build/SharedDeps.zig
+++ b/src/build/SharedDeps.zig
@@ -438,12 +438,15 @@ pub fn add(
switch (self.config.app_runtime) {
.none => {},
- .glfw => glfw: {
- const mach_glfw_dep = b.lazyDependency("mach_glfw", .{
+ .glfw => {
+ const glfw_dep = b.dependency("glfw", .{
.target = target,
.optimize = optimize,
- }) orelse break :glfw;
- step.root_module.addImport("glfw", mach_glfw_dep.module("mach-glfw"));
+ });
+ step.root_module.addImport(
+ "glfw",
+ glfw_dep.module("glfw"),
+ );
},
.gtk => {