diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index a1cc2af19..37d5ba79b 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -86,7 +86,7 @@ jobs: # GhosttyKit is the framework that is built from Zig for our native # Mac app to access. Build this in release mode. - name: Build GhosttyKit - run: nix develop -c zig build -Doptimize=ReleaseSafe + run: nix develop -c zig build -Doptimize=ReleaseSafe -Demit-macos-app=false # The native app is built with native XCode tooling. This also does # codesigning. IMPORTANT: this must NOT run in a Nix environment. @@ -238,7 +238,7 @@ jobs: # GhosttyKit is the framework that is built from Zig for our native # Mac app to access. Build this in release mode. - name: Build GhosttyKit - run: nix develop -c zig build -Doptimize=Debug + run: nix develop -c zig build -Doptimize=Debug -Demit-macos-app=false # The native app is built with native XCode tooling. This also does # codesigning. IMPORTANT: this must NOT run in a Nix environment. diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 3deafd066..33cf9f3a8 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -158,6 +158,7 @@ jobs: nix develop -c \ zig build \ -Doptimize=ReleaseFast \ + -Demit-macos-app=false \ -Dversion-string=${GHOSTTY_VERSION} # The native app is built with native XCode tooling. This also does diff --git a/.github/workflows/release-tip.yml b/.github/workflows/release-tip.yml index 2a3277ea6..4d009ab7b 100644 --- a/.github/workflows/release-tip.yml +++ b/.github/workflows/release-tip.yml @@ -196,7 +196,7 @@ jobs: # GhosttyKit is the framework that is built from Zig for our native # Mac app to access. Build this in release mode. - name: Build GhosttyKit - run: nix develop -c zig build -Doptimize=ReleaseFast + run: nix develop -c zig build -Doptimize=ReleaseFast -Demit-macos-app=false # The native app is built with native XCode tooling. This also does # codesigning. IMPORTANT: this must NOT run in a Nix environment. @@ -411,7 +411,7 @@ jobs: # GhosttyKit is the framework that is built from Zig for our native # Mac app to access. Build this in release mode. - name: Build GhosttyKit - run: nix develop -c zig build -Doptimize=Debug + run: nix develop -c zig build -Doptimize=Debug -Demit-macos-app=false # The native app is built with native XCode tooling. This also does # codesigning. IMPORTANT: this must NOT run in a Nix environment. @@ -586,7 +586,7 @@ jobs: # GhosttyKit is the framework that is built from Zig for our native # Mac app to access. Build this in release mode. - name: Build GhosttyKit - run: nix develop -c zig build -Doptimize=ReleaseSafe + run: nix develop -c zig build -Doptimize=ReleaseSafe -Demit-macos-app=false # The native app is built with native XCode tooling. This also does # codesigning. IMPORTANT: this must NOT run in a Nix environment. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4d09603f4..b34327f7d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,6 @@ jobs: - build-macos-tahoe - build-macos-matrix - build-windows - - build-windows-cross - flatpak-check-zig-cache - flatpak - test @@ -84,7 +83,7 @@ jobs: authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - name: Build Benchmarks - run: nix develop -c zig build -Dapp-runtime=glfw -Demit-bench + run: nix develop -c zig build -Demit-bench build-flatpak: strategy: @@ -151,7 +150,7 @@ jobs: authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - name: Test Build - run: nix develop -c zig build -Dapp-runtime=glfw + run: nix develop -c zig build build-linux-libghostty: runs-on: namespace-profile-ghostty-md @@ -295,7 +294,7 @@ jobs: # GhosttyKit is the framework that is built from Zig for our native # Mac app to access. - name: Build GhosttyKit - run: nix develop -c zig build --system ${{ steps.deps.outputs.deps }} + run: nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Demit-macos-app=false # The native app is built with native Xcode tooling. This also does # codesigning. IMPORTANT: this must NOT run in a Nix environment. @@ -335,7 +334,7 @@ jobs: # GhosttyKit is the framework that is built from Zig for our native # Mac app to access. - name: Build GhosttyKit - run: nix develop -c zig build --system ${{ steps.deps.outputs.deps }} + run: nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Demit-macos-app=false # The native app is built with native Xcode tooling. This also does # codesigning. IMPORTANT: this must NOT run in a Nix environment. @@ -374,33 +373,19 @@ jobs: - name: Test All run: | - # OpenGL - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=freetype - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=coretext - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=coretext_freetype - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=coretext_harfbuzz - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=coretext_noshape - - # Metal - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=freetype - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=coretext - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=coretext_freetype - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=coretext_harfbuzz - nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=coretext_noshape + nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Drenderer=metal -Dfont-backend=freetype + nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Drenderer=metal -Dfont-backend=coretext + nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Drenderer=metal -Dfont-backend=coretext_freetype + nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Drenderer=metal -Dfont-backend=coretext_harfbuzz + nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} -Drenderer=metal -Dfont-backend=coretext_noshape - name: Build All run: | - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=freetype - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=coretext - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=coretext_freetype - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=coretext_harfbuzz - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=opengl -Dfont-backend=coretext_noshape - - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=freetype - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=coretext - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=coretext_freetype - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=coretext_harfbuzz - nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Dapp-runtime=glfw -Drenderer=metal -Dfont-backend=coretext_noshape + nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Demit-macos-app=false -Drenderer=metal -Dfont-backend=freetype + nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Demit-macos-app=false -Drenderer=metal -Dfont-backend=coretext + nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Demit-macos-app=false -Drenderer=metal -Dfont-backend=coretext_freetype + nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Demit-macos-app=false -Drenderer=metal -Dfont-backend=coretext_harfbuzz + nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Demit-macos-app=false -Drenderer=metal -Dfont-backend=coretext_noshape build-snap: strategy: @@ -507,52 +492,6 @@ 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.8 - with: - path: | - /nix - /zig - - # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@v31 - with: - nix_path: nixpkgs=channel:nixos-unstable - - uses: cachix/cachix-action@v16 - 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 @@ -585,9 +524,6 @@ jobs: - name: Test GTK Build run: nix develop -c zig build -Dapp-runtime=gtk -Demit-docs - - name: Test GLFW Build - run: nix develop -c zig build -Dapp-runtime=glfw - # This relies on the cache being populated by the commands above. - name: Test System Build run: nix develop -c zig build --system ${ZIG_GLOBAL_CACHE_DIR}/p diff --git a/PACKAGING.md b/PACKAGING.md index d85f55de7..1483b8591 100644 --- a/PACKAGING.md +++ b/PACKAGING.md @@ -122,11 +122,3 @@ relevant to package maintainers: often necessary for system packages to specify a specific minimum Linux version, glibc, etc. Run `zig targets` to a get a full list of available targets. - -> [!WARNING] -> -> **The GLFW runtime is not meant for distribution.** The GLFW runtime -> (`-Dapp-runtime=glfw`) is meant for development and testing only. It is -> missing many features, has known memory leak scenarios, known crashes, -> and more. Please do not package the GLFW-based Ghostty runtime for -> distribution. diff --git a/README.md b/README.md index b59964e61..a761e25ce 100644 --- a/README.md +++ b/README.md @@ -194,12 +194,6 @@ omit the `-Doptimize` flag to build a debug build, and you may require additional dependencies since the source tarball includes some processed files that are not in the Git repository. -On Linux or macOS, you can use `zig build -Dapp-runtime=glfw run` for a quick -GLFW-based app for a faster development cycle while developing core -terminal features. Note that this app is missing many features and is also -known to crash in certain scenarios, so it is only meant for development -tasks. - Other useful commands: - `zig build test` for running unit tests. diff --git a/build.zig b/build.zig index 80af88488..024e2db61 100644 --- a/build.zig +++ b/build.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const assert = std.debug.assert; const builtin = @import("builtin"); const buildpkg = @import("src/build/main.zig"); @@ -22,7 +23,14 @@ pub fn build(b: *std.Build) !void { // Ghostty docs const docs = try buildpkg.GhosttyDocs.init(b, &deps); - if (config.emit_docs) docs.install(); + if (config.emit_docs) { + docs.install(); + } else if (config.target.result.os.tag.isDarwin()) { + // If we aren't emitting docs we need to emit a placeholder so + // our macOS xcodeproject builds since it expects the `share/man` + // directory to exist to copy into the app bundle. + docs.installDummy(b.getInstallStep()); + } // Ghostty webdata const webdata = try buildpkg.GhosttyWebdata.init(b, &deps); @@ -42,65 +50,116 @@ pub fn build(b: *std.Build) !void { check_step.dependOn(dist.install_step); } - // If we're not building libghostty, then install the exe and resources. + // libghostty + const libghostty_shared = try buildpkg.GhosttyLib.initShared( + b, + &deps, + ); + const libghostty_static = try buildpkg.GhosttyLib.initStatic( + b, + &deps, + ); + + // Runtime "none" is libghostty, anything else is an executable. if (config.app_runtime != .none) { exe.install(); resources.install(); i18n.install(); - } + } else { + // Libghostty + // + // Note: libghostty is not stable for general purpose use. It is used + // heavily by Ghostty on macOS but it isn't built to be reusable yet. + // As such, these build steps are lacking. For example, the Darwin + // build only produces an xcframework. - // Libghostty - // - // Note: libghostty is not stable for general purpose use. It is used - // heavily by Ghostty on macOS but it isn't built to be reusable yet. - // As such, these build steps are lacking. For example, the Darwin - // build only produces an xcframework. - if (config.app_runtime == .none) { - if (config.target.result.os.tag.isDarwin()) darwin: { - if (!config.emit_xcframework) break :darwin; - - // Build the xcframework - const xcframework = try buildpkg.GhosttyXCFramework.init(b, &deps); - xcframework.install(); - - // The xcframework build always installs resources because our - // macOS xcode project contains references to them. - resources.install(); - i18n.install(); - - // If we aren't emitting docs we need to emit a placeholder so - // our macOS xcodeproject builds. - if (!config.emit_docs) { - var wf = b.addWriteFiles(); - const path = "share/man/.placeholder"; - const placeholder = wf.add(path, "emit-docs not true so no man pages"); - b.getInstallStep().dependOn(&b.addInstallFile(placeholder, path).step); - } - } else { - const libghostty_shared = try buildpkg.GhosttyLib.initShared(b, &deps); - const libghostty_static = try buildpkg.GhosttyLib.initStatic(b, &deps); + // We shouldn't have this guard but we don't currently + // build on macOS this way ironically so we need to fix that. + if (!config.target.result.os.tag.isDarwin()) { libghostty_shared.installHeader(); // Only need one header libghostty_shared.install("libghostty.so"); libghostty_static.install("libghostty.a"); } } - // Run runs the Ghostty exe - { - const run_cmd = b.addRunArtifact(exe.exe); - if (b.args) |args| run_cmd.addArgs(args); - - // Set the proper resources dir so things like shell integration - // work correctly. If we're running `zig build run` in Ghostty, - // this also ensures it overwrites the release one with our debug - // build. - run_cmd.setEnvironmentVariable( - "GHOSTTY_RESOURCES_DIR", - b.getInstallPath(.prefix, "share/ghostty"), + // macOS only artifacts. These will error if they're initialized for + // other targets. + if (config.target.result.os.tag.isDarwin()) { + // Ghostty xcframework + const xcframework = try buildpkg.GhosttyXCFramework.init( + b, + &deps, + config.xcframework_target, ); + if (config.emit_xcframework) { + xcframework.install(); - const run_step = b.step("run", "Run the app"); - run_step.dependOn(&run_cmd.step); + // The xcframework build always installs resources because our + // macOS xcode project contains references to them. + resources.install(); + i18n.install(); + } + + // Ghostty macOS app + const macos_app = try buildpkg.GhosttyXcodebuild.init( + b, + &config, + .{ + .xcframework = &xcframework, + .docs = &docs, + .i18n = &i18n, + .resources = &resources, + }, + ); + if (config.emit_macos_app) { + macos_app.install(); + } + } + + // Run step + run: { + if (config.app_runtime != .none) { + const run_cmd = b.addRunArtifact(exe.exe); + if (b.args) |args| run_cmd.addArgs(args); + + // Set the proper resources dir so things like shell integration + // work correctly. If we're running `zig build run` in Ghostty, + // this also ensures it overwrites the release one with our debug + // build. + run_cmd.setEnvironmentVariable( + "GHOSTTY_RESOURCES_DIR", + b.getInstallPath(.prefix, "share/ghostty"), + ); + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + break :run; + } + + assert(config.app_runtime == .none); + + // On macOS we can run the macOS app. For "run" we always force + // a native-only build so that we can run as quickly as possible. + if (config.target.result.os.tag.isDarwin()) { + const xcframework_native = try buildpkg.GhosttyXCFramework.init( + b, + &deps, + .native, + ); + const macos_app_native_only = try buildpkg.GhosttyXcodebuild.init( + b, + &config, + .{ + .xcframework = &xcframework_native, + .docs = &docs, + .i18n = &i18n, + .resources = &resources, + }, + ); + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&macos_app_native_only.open.step); + } } // Tests diff --git a/build.zig.zon b/build.zig.zon index 237720f35..e98d878f9 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -64,7 +64,6 @@ .cimgui = .{ .path = "./pkg/cimgui", .lazy = true }, .fontconfig = .{ .path = "./pkg/fontconfig", .lazy = true }, .freetype = .{ .path = "./pkg/freetype", .lazy = true }, - .glfw = .{ .path = "./pkg/glfw", .lazy = true }, .gtk4_layer_shell = .{ .path = "./pkg/gtk4-layer-shell", .lazy = true }, .harfbuzz = .{ .path = "./pkg/harfbuzz", .lazy = true }, .highway = .{ .path = "./pkg/highway", .lazy = true }, @@ -100,6 +99,16 @@ .lazy = true, }, + // Fonts + .jetbrains_mono = .{ + .url = "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz", + .hash = "N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x", + }, + .nerd_fonts_symbols_only = .{ + .url = "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz", + .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO26s", + }, + // Other .apple_sdk = .{ .path = "./pkg/apple-sdk" }, .iterm2_themes = .{ diff --git a/build.zig.zon.json b/build.zig.zon.json index 420893ef7..0b904de83 100644 --- a/build.zig.zon.json +++ b/build.zig.zon.json @@ -19,11 +19,6 @@ "url": "https://deps.files.ghostty.org/gettext-0.24.tar.gz", "hash": "sha256-yRhQPVk9cNr0hE0XWhPYFq+stmfAb7oeydzVACwVGLc=" }, - "N-V-__8AAMrJSwAUGb9-vTzkNR-5LXS81MR__ZRVfF3tWgG6": { - "name": "glfw", - "url": "https://github.com/glfw/glfw/archive/e7ea71be039836da3a98cea55ae5569cb5eb885c.tar.gz", - "hash": "sha256-M3N1XUAlMebBo5X1Py+9YxjKXgZ6eacqWRCbUmwLKQo=" - }, "N-V-__8AABzkUgISeKGgXAzgtutgJsZc0-kkeqBBscJgMkvy": { "name": "glslang", "url": "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz", @@ -59,6 +54,11 @@ "url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6fa671fdc1daf1fcfa025cb960ffa3e7373a2ed8.tar.gz", "hash": "sha256-g9o2CIc/TfWYoUS/l/HP5KZECD7qNsdQUlFruaKkVz4=" }, + "N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": { + "name": "jetbrains_mono", + "url": "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz", + "hash": "sha256-xXppHouCrQmLWWPzlZAy5AOPORCHr3cViFulkEYQXMQ=" + }, "N-V-__8AAJrvXQCqAT8Mg9o_tk6m0yf5Fz-gCNEOKLyTSerD": { "name": "libpng", "url": "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz", @@ -74,6 +74,11 @@ "url": "https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz", "hash": "sha256-bCgFni4+60K1tLFkieORamNGwQladP7jvGXNxdiaYhU=" }, + "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO26s": { + "name": "nerd_fonts_symbols_only", + "url": "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz", + "hash": "sha256-EWTRuVbUveJI17LwmYxDzJT1ICQxoVZKeTiVsec7DQQ=" + }, "N-V-__8AAHjwMQDBXnLq3Q2QhaivE0kE2aD138vtX2Bq1g7c": { "name": "oniguruma", "url": "https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz", diff --git a/build.zig.zon.nix b/build.zig.zon.nix index 6e4b86606..52260181e 100644 --- a/build.zig.zon.nix +++ b/build.zig.zon.nix @@ -113,14 +113,6 @@ in hash = "sha256-yRhQPVk9cNr0hE0XWhPYFq+stmfAb7oeydzVACwVGLc="; }; } - { - name = "N-V-__8AAMrJSwAUGb9-vTzkNR-5LXS81MR__ZRVfF3tWgG6"; - path = fetchZigArtifact { - name = "glfw"; - url = "https://github.com/glfw/glfw/archive/e7ea71be039836da3a98cea55ae5569cb5eb885c.tar.gz"; - hash = "sha256-M3N1XUAlMebBo5X1Py+9YxjKXgZ6eacqWRCbUmwLKQo="; - }; - } { name = "N-V-__8AABzkUgISeKGgXAzgtutgJsZc0-kkeqBBscJgMkvy"; path = fetchZigArtifact { @@ -177,6 +169,14 @@ in hash = "sha256-g9o2CIc/TfWYoUS/l/HP5KZECD7qNsdQUlFruaKkVz4="; }; } + { + name = "N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x"; + path = fetchZigArtifact { + name = "jetbrains_mono"; + url = "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz"; + hash = "sha256-xXppHouCrQmLWWPzlZAy5AOPORCHr3cViFulkEYQXMQ="; + }; + } { name = "N-V-__8AAJrvXQCqAT8Mg9o_tk6m0yf5Fz-gCNEOKLyTSerD"; path = fetchZigArtifact { @@ -201,6 +201,14 @@ in hash = "sha256-bCgFni4+60K1tLFkieORamNGwQladP7jvGXNxdiaYhU="; }; } + { + name = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO26s"; + path = fetchZigArtifact { + name = "nerd_fonts_symbols_only"; + url = "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz"; + hash = "sha256-EWTRuVbUveJI17LwmYxDzJT1ICQxoVZKeTiVsec7DQQ="; + }; + } { name = "N-V-__8AAHjwMQDBXnLq3Q2QhaivE0kE2aD138vtX2Bq1g7c"; path = fetchZigArtifact { diff --git a/build.zig.zon.txt b/build.zig.zon.txt index f05a789dd..4427763d8 100644 --- a/build.zig.zon.txt +++ b/build.zig.zon.txt @@ -2,6 +2,8 @@ git+https://codeberg.org/atman/zg#4a002763419a34d61dcbb1f415821b83b9bf8ddc git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23 https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz +https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz +https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz @@ -25,7 +27,6 @@ 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/e7ea71be039836da3a98cea55ae5569cb5eb885c.tar.gz https://github.com/jcollie/ghostty-gobject/releases/download/0.14.0-2025-03-18-21-1/ghostty-gobject-0.14.0-2025-03-18-21-1.tar.zst https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6fa671fdc1daf1fcfa025cb960ffa3e7373a2ed8.tar.gz https://github.com/mitchellh/libxev/archive/75a10d0fb374e8eb84948dcfc68d865e755e59c2.tar.gz diff --git a/flatpak/zig-packages.json b/flatpak/zig-packages.json index daf7e5cea..0848d72d4 100644 --- a/flatpak/zig-packages.json +++ b/flatpak/zig-packages.json @@ -23,12 +23,6 @@ "dest": "vendor/p/N-V-__8AADcZkgn4cMhTUpIz6mShCKyqqB-NBtf_S2bHaTC-", "sha256": "c918503d593d70daf4844d175a13d816afacb667c06fba1ec9dcd5002c1518b7" }, - { - "type": "archive", - "url": "https://github.com/glfw/glfw/archive/e7ea71be039836da3a98cea55ae5569cb5eb885c.tar.gz", - "dest": "vendor/p/N-V-__8AAMrJSwAUGb9-vTzkNR-5LXS81MR__ZRVfF3tWgG6", - "sha256": "3373755d402531e6c1a395f53f2fbd6318ca5e067a79a72a59109b526c0b290a" - }, { "type": "archive", "url": "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz", @@ -71,6 +65,12 @@ "dest": "vendor/p/N-V-__8AAGHcWgTaKLjwmFkxToNT4jgz5VXUHR7hz8TQ2_AS", "sha256": "83da3608873f4df598a144bf97f1cfe4a644083eea36c75052516bb9a2a4573e" }, + { + "type": "archive", + "url": "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz", + "dest": "vendor/p/N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x", + "sha256": "c57a691e8b82ad098b5963f3959032e4038f391087af7715885ba59046105cc4" + }, { "type": "archive", "url": "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz", @@ -89,6 +89,12 @@ "dest": "vendor/p/N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK", "sha256": "6c28059e2e3eeb42b5b4b16489e3916a6346c1095a74fee3bc65cdc5d89a6215" }, + { + "type": "archive", + "url": "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz", + "dest": "vendor/p/N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO26s", + "sha256": "1164d1b956d4bde248d7b2f0998c43cc94f5202431a1564a793895b1e73b0d04" + }, { "type": "archive", "url": "https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz", diff --git a/macos/Sources/App/macOS/AppDelegate.swift b/macos/Sources/App/macOS/AppDelegate.swift index 418005927..efc09ede9 100644 --- a/macos/Sources/App/macOS/AppDelegate.swift +++ b/macos/Sources/App/macOS/AppDelegate.swift @@ -255,6 +255,22 @@ class AppDelegate: NSObject, // Setup signal handlers setupSignals() + + // This is a hack used by our build scripts, specifically `zig build run`, + // to force our app to the foreground. + if ProcessInfo.processInfo.environment["GHOSTTY_MAC_ACTIVATE"] == "1" { + // This never gets called until we click the dock icon. This forces it + // activate immediately. + applicationDidBecomeActive(.init(name: NSApplication.didBecomeActiveNotification)) + + // We run in the background, this forces us to the front. + DispatchQueue.main.async { + NSApp.setActivationPolicy(.regular) + NSApp.activate(ignoringOtherApps: true) + NSApp.unhide(nil) + NSApp.arrangeInFront(nil) + } + } } func applicationDidBecomeActive(_ notification: Notification) { diff --git a/pkg/freetype/freetype-zig.h b/pkg/freetype/freetype-zig.h index 29e546154..dcc65e514 100644 --- a/pkg/freetype/freetype-zig.h +++ b/pkg/freetype/freetype-zig.h @@ -5,3 +5,5 @@ #include #include #include +#include +#include diff --git a/pkg/glfw/Cursor.zig b/pkg/glfw/Cursor.zig deleted file mode 100644 index cd79e8848..000000000 --- a/pkg/glfw/Cursor.zig +++ /dev/null @@ -1,209 +0,0 @@ -//! 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 | Yes1 | Maybe2 | Maybe2 | -/// | `.resize_nesw` | Yes | Yes1 | Maybe2 | Maybe2 | -/// | `.resize_all` | Yes | Yes | Yes | Yes | -/// | `.not_allowed` | Yes | Yes | Maybe2 | Maybe2 | -/// -/// 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 deleted file mode 100644 index 7b5a1c3fd..000000000 --- a/pkg/glfw/GammaRamp.zig +++ /dev/null @@ -1,74 +0,0 @@ -//! 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 deleted file mode 100644 index d32e5c310..000000000 --- a/pkg/glfw/Image.zig +++ /dev/null @@ -1,82 +0,0 @@ -//! 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 deleted file mode 100644 index a8152513e..000000000 --- a/pkg/glfw/Joystick.zig +++ /dev/null @@ -1,642 +0,0 @@ -//! 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 deleted file mode 100644 index 8c422bd23..000000000 --- a/pkg/glfw/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2021 Hexops Contributors (given via the Git commit history). -Copyright (c) 2025 Mitchell Hashimoto, Ghostty contributors - -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 deleted file mode 100644 index 3b194965a..000000000 --- a/pkg/glfw/Monitor.zig +++ /dev/null @@ -1,599 +0,0 @@ -//! 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 .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 deleted file mode 100644 index f433b8d05..000000000 --- a/pkg/glfw/VideoMode.zig +++ /dev/null @@ -1,50 +0,0 @@ -//! 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 deleted file mode 100644 index 804184f0e..000000000 --- a/pkg/glfw/Window.zig +++ /dev/null @@ -1,3551 +0,0 @@ -//! 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 deleted file mode 100644 index 59314709f..000000000 --- a/pkg/glfw/action.zig +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index d6517cf3e..000000000 --- a/pkg/glfw/allocator.zig +++ /dev/null @@ -1,143 +0,0 @@ -// 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 deleted file mode 100644 index 142a558da..000000000 --- a/pkg/glfw/build.zig +++ /dev/null @@ -1,271 +0,0 @@ -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); - } - - 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); - - // 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 deleted file mode 100644 index 467f2c327..000000000 --- a/pkg/glfw/build.zig.zon +++ /dev/null @@ -1,15 +0,0 @@ -.{ - .name = .glfw, - .version = "3.4.0", - .fingerprint = 0x3bbe0a5c667e2c62, - .paths = .{""}, - .dependencies = .{ - .glfw = .{ - .url = "https://github.com/glfw/glfw/archive/e7ea71be039836da3a98cea55ae5569cb5eb885c.tar.gz", - .hash = "N-V-__8AAMrJSwAUGb9-vTzkNR-5LXS81MR__ZRVfF3tWgG6", - .lazy = true, - }, - - .apple_sdk = .{ .path = "../apple-sdk" }, - }, -} diff --git a/pkg/glfw/c.zig b/pkg/glfw/c.zig deleted file mode 100644 index 58599025b..000000000 --- a/pkg/glfw/c.zig +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index a7e2d0e2f..000000000 --- a/pkg/glfw/clipboard.zig +++ /dev/null @@ -1,71 +0,0 @@ -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 deleted file mode 100644 index b9721fd05..000000000 --- a/pkg/glfw/errors.zig +++ /dev/null @@ -1,338 +0,0 @@ -//! 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 deleted file mode 100644 index 97fdf3748..000000000 --- a/pkg/glfw/gamepad_axis.zig +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index ac47ebea0..000000000 --- a/pkg/glfw/gamepad_button.zig +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index ffbb4a1c8..000000000 --- a/pkg/glfw/hat.zig +++ /dev/null @@ -1,100 +0,0 @@ -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 deleted file mode 100644 index 6e0ab4f1e..000000000 --- a/pkg/glfw/internal_debug.zig +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 27b13119c..000000000 --- a/pkg/glfw/key.zig +++ /dev/null @@ -1,266 +0,0 @@ -//! 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 deleted file mode 100644 index 329f17ed2..000000000 --- a/pkg/glfw/main.zig +++ /dev/null @@ -1,586 +0,0 @@ -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 deleted file mode 100644 index aa9c9371f..000000000 --- a/pkg/glfw/mod.zig +++ /dev/null @@ -1,167 +0,0 @@ -//! 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 deleted file mode 100644 index 847049f5e..000000000 --- a/pkg/glfw/mouse_button.zig +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index 6b8f1831a..000000000 --- a/pkg/glfw/native.zig +++ /dev/null @@ -1,393 +0,0 @@ -//! 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 deleted file mode 100644 index 8fe2efbed..000000000 --- a/pkg/glfw/opengl.zig +++ /dev/null @@ -1,256 +0,0 @@ -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 .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 deleted file mode 100644 index c731bb910..000000000 --- a/pkg/glfw/shims.zig +++ /dev/null @@ -1,84 +0,0 @@ -// 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 deleted file mode 100644 index c3432b105..000000000 --- a/pkg/glfw/time.zig +++ /dev/null @@ -1,153 +0,0 @@ -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 deleted file mode 100644 index e83a4d708..000000000 --- a/pkg/glfw/version.zig +++ /dev/null @@ -1,18 +0,0 @@ -//! 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 deleted file mode 100644 index 1b84145d5..000000000 --- a/pkg/glfw/vulkan.zig +++ /dev/null @@ -1,290 +0,0 @@ -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/fractional-scale-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/fractional-scale-v1-client-protocol-code.h deleted file mode 100644 index f847c1eaa..000000000 --- a/pkg/glfw/wayland-headers/fractional-scale-v1-client-protocol-code.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * Copyright © 2022 Kenny Levinsen - * - * 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 -#include -#include -#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_fractional_scale_v1_interface; - -static const struct wl_interface *fractional_scale_v1_types[] = { - NULL, - &wp_fractional_scale_v1_interface, - &wl_surface_interface, -}; - -static const struct wl_message wp_fractional_scale_manager_v1_requests[] = { - { "destroy", "", fractional_scale_v1_types + 0 }, - { "get_fractional_scale", "no", fractional_scale_v1_types + 1 }, -}; - -WL_PRIVATE const struct wl_interface wp_fractional_scale_manager_v1_interface = { - "wp_fractional_scale_manager_v1", 1, - 2, wp_fractional_scale_manager_v1_requests, - 0, NULL, -}; - -static const struct wl_message wp_fractional_scale_v1_requests[] = { - { "destroy", "", fractional_scale_v1_types + 0 }, -}; - -static const struct wl_message wp_fractional_scale_v1_events[] = { - { "preferred_scale", "u", fractional_scale_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface wp_fractional_scale_v1_interface = { - "wp_fractional_scale_v1", 1, - 1, wp_fractional_scale_v1_requests, - 1, wp_fractional_scale_v1_events, -}; - diff --git a/pkg/glfw/wayland-headers/fractional-scale-v1-client-protocol.h b/pkg/glfw/wayland-headers/fractional-scale-v1-client-protocol.h deleted file mode 100644 index 8df7558a7..000000000 --- a/pkg/glfw/wayland-headers/fractional-scale-v1-client-protocol.h +++ /dev/null @@ -1,264 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef FRACTIONAL_SCALE_V1_CLIENT_PROTOCOL_H -#define FRACTIONAL_SCALE_V1_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_fractional_scale_v1 The fractional_scale_v1 protocol - * Protocol for requesting fractional surface scales - * - * @section page_desc_fractional_scale_v1 Description - * - * This protocol allows a compositor to suggest for surfaces to render at - * fractional scales. - * - * A client can submit scaled content by utilizing wp_viewport. This is done by - * creating a wp_viewport object for the surface and setting the destination - * rectangle to the surface size before the scale factor is applied. - * - * The buffer size is calculated by multiplying the surface size by the - * intended scale. - * - * The wl_surface buffer scale should remain set to 1. - * - * If a surface has a surface-local size of 100 px by 50 px and wishes to - * submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should - * be used and the wp_viewport destination rectangle should be 100 px by 50 px. - * - * For toplevel surfaces, the size is rounded halfway away from zero. The - * rounding algorithm for subsurface position and size is not defined. - * - * @section page_ifaces_fractional_scale_v1 Interfaces - * - @subpage page_iface_wp_fractional_scale_manager_v1 - fractional surface scale information - * - @subpage page_iface_wp_fractional_scale_v1 - fractional scale interface to a wl_surface - * @section page_copyright_fractional_scale_v1 Copyright - *
- *
- * Copyright © 2022 Kenny Levinsen
- *
- * 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.
- * 
- */ -struct wl_surface; -struct wp_fractional_scale_manager_v1; -struct wp_fractional_scale_v1; - -#ifndef WP_FRACTIONAL_SCALE_MANAGER_V1_INTERFACE -#define WP_FRACTIONAL_SCALE_MANAGER_V1_INTERFACE -/** - * @page page_iface_wp_fractional_scale_manager_v1 wp_fractional_scale_manager_v1 - * @section page_iface_wp_fractional_scale_manager_v1_desc Description - * - * A global interface for requesting surfaces to use fractional scales. - * @section page_iface_wp_fractional_scale_manager_v1_api API - * See @ref iface_wp_fractional_scale_manager_v1. - */ -/** - * @defgroup iface_wp_fractional_scale_manager_v1 The wp_fractional_scale_manager_v1 interface - * - * A global interface for requesting surfaces to use fractional scales. - */ -extern const struct wl_interface wp_fractional_scale_manager_v1_interface; -#endif -#ifndef WP_FRACTIONAL_SCALE_V1_INTERFACE -#define WP_FRACTIONAL_SCALE_V1_INTERFACE -/** - * @page page_iface_wp_fractional_scale_v1 wp_fractional_scale_v1 - * @section page_iface_wp_fractional_scale_v1_desc Description - * - * An additional interface to a wl_surface object which allows the compositor - * to inform the client of the preferred scale. - * @section page_iface_wp_fractional_scale_v1_api API - * See @ref iface_wp_fractional_scale_v1. - */ -/** - * @defgroup iface_wp_fractional_scale_v1 The wp_fractional_scale_v1 interface - * - * An additional interface to a wl_surface object which allows the compositor - * to inform the client of the preferred scale. - */ -extern const struct wl_interface wp_fractional_scale_v1_interface; -#endif - -#ifndef WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM -#define WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM -enum wp_fractional_scale_manager_v1_error { - /** - * the surface already has a fractional_scale object associated - */ - WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS = 0, -}; -#endif /* WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM */ - -#define WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY 0 -#define WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE 1 - - -/** - * @ingroup iface_wp_fractional_scale_manager_v1 - */ -#define WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wp_fractional_scale_manager_v1 - */ -#define WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE_SINCE_VERSION 1 - -/** @ingroup iface_wp_fractional_scale_manager_v1 */ -static inline void -wp_fractional_scale_manager_v1_set_user_data(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wp_fractional_scale_manager_v1, user_data); -} - -/** @ingroup iface_wp_fractional_scale_manager_v1 */ -static inline void * -wp_fractional_scale_manager_v1_get_user_data(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wp_fractional_scale_manager_v1); -} - -static inline uint32_t -wp_fractional_scale_manager_v1_get_version(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1); -} - -/** - * @ingroup iface_wp_fractional_scale_manager_v1 - * - * Informs the server that the client will not be using this protocol - * object anymore. This does not affect any other objects, - * wp_fractional_scale_v1 objects included. - */ -static inline void -wp_fractional_scale_manager_v1_destroy(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_manager_v1, - WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wp_fractional_scale_manager_v1 - * - * Create an add-on object for the the wl_surface to let the compositor - * request fractional scales. If the given wl_surface already has a - * wp_fractional_scale_v1 object associated, the fractional_scale_exists - * protocol error is raised. - */ -static inline struct wp_fractional_scale_v1 * -wp_fractional_scale_manager_v1_get_fractional_scale(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1, struct wl_surface *surface) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_manager_v1, - WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE, &wp_fractional_scale_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1), 0, NULL, surface); - - return (struct wp_fractional_scale_v1 *) id; -} - -/** - * @ingroup iface_wp_fractional_scale_v1 - * @struct wp_fractional_scale_v1_listener - */ -struct wp_fractional_scale_v1_listener { - /** - * notify of new preferred scale - * - * Notification of a new preferred scale for this surface that - * the compositor suggests that the client should use. - * - * The sent scale is the numerator of a fraction with a denominator - * of 120. - * @param scale the new preferred scale - */ - void (*preferred_scale)(void *data, - struct wp_fractional_scale_v1 *wp_fractional_scale_v1, - uint32_t scale); -}; - -/** - * @ingroup iface_wp_fractional_scale_v1 - */ -static inline int -wp_fractional_scale_v1_add_listener(struct wp_fractional_scale_v1 *wp_fractional_scale_v1, - const struct wp_fractional_scale_v1_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wp_fractional_scale_v1, - (void (**)(void)) listener, data); -} - -#define WP_FRACTIONAL_SCALE_V1_DESTROY 0 - -/** - * @ingroup iface_wp_fractional_scale_v1 - */ -#define WP_FRACTIONAL_SCALE_V1_PREFERRED_SCALE_SINCE_VERSION 1 - -/** - * @ingroup iface_wp_fractional_scale_v1 - */ -#define WP_FRACTIONAL_SCALE_V1_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_wp_fractional_scale_v1 */ -static inline void -wp_fractional_scale_v1_set_user_data(struct wp_fractional_scale_v1 *wp_fractional_scale_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wp_fractional_scale_v1, user_data); -} - -/** @ingroup iface_wp_fractional_scale_v1 */ -static inline void * -wp_fractional_scale_v1_get_user_data(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wp_fractional_scale_v1); -} - -static inline uint32_t -wp_fractional_scale_v1_get_version(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_v1); -} - -/** - * @ingroup iface_wp_fractional_scale_v1 - * - * Destroy the fractional scale object. When this object is destroyed, - * preferred_scale events will no longer be sent. - */ -static inline void -wp_fractional_scale_v1_destroy(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_v1, - WP_FRACTIONAL_SCALE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_v1), WL_MARSHAL_FLAG_DESTROY); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/pkg/glfw/wayland-headers/idle-inhibit-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/idle-inhibit-unstable-v1-client-protocol-code.h deleted file mode 100644 index 0399e11ae..000000000 --- a/pkg/glfw/wayland-headers/idle-inhibit-unstable-v1-client-protocol-code.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * 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 -#include -#include -#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/idle-inhibit-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/idle-inhibit-unstable-v1-client-protocol.h deleted file mode 100644 index ef97ceb86..000000000 --- a/pkg/glfw/wayland-headers/idle-inhibit-unstable-v1-client-protocol.h +++ /dev/null @@ -1,232 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H -#define IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H - -#include -#include -#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 - *
- *
- * 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.
- * 
- */ -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/pointer-constraints-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol-code.h deleted file mode 100644 index 4184538d5..000000000 --- a/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol-code.h +++ /dev/null @@ -1,109 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * 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 -#include -#include -#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/pointer-constraints-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol.h deleted file mode 100644 index 09c05ea8c..000000000 --- a/pkg/glfw/wayland-headers/pointer-constraints-unstable-v1-client-protocol.h +++ /dev/null @@ -1,667 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H -#define POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H - -#include -#include -#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 - *
- *
- * 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.
- * 
- */ -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/relative-pointer-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol-code.h deleted file mode 100644 index 605149b2a..000000000 --- a/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol-code.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * 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 -#include -#include -#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/relative-pointer-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol.h deleted file mode 100644 index 5c79482f9..000000000 --- a/pkg/glfw/wayland-headers/relative-pointer-unstable-v1-client-protocol.h +++ /dev/null @@ -1,297 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H -#define RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H - -#include -#include -#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 - *
- *
- * 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.
- * 
- */ -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/viewporter-client-protocol-code.h b/pkg/glfw/wayland-headers/viewporter-client-protocol-code.h deleted file mode 100644 index d6858580e..000000000 --- a/pkg/glfw/wayland-headers/viewporter-client-protocol-code.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * 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 -#include -#include -#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/viewporter-client-protocol.h b/pkg/glfw/wayland-headers/viewporter-client-protocol.h deleted file mode 100644 index afe60ef59..000000000 --- a/pkg/glfw/wayland-headers/viewporter-client-protocol.h +++ /dev/null @@ -1,398 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef VIEWPORTER_CLIENT_PROTOCOL_H -#define VIEWPORTER_CLIENT_PROTOCOL_H - -#include -#include -#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 - *
- *
- * 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.
- * 
- */ -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-client-protocol-code.h b/pkg/glfw/wayland-headers/wayland-client-protocol-code.h deleted file mode 100644 index 7ea8e7c66..000000000 --- a/pkg/glfw/wayland-headers/wayland-client-protocol-code.h +++ /dev/null @@ -1,525 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * 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 -#include -#include -#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-client-protocol.h b/pkg/glfw/wayland-headers/wayland-client-protocol.h deleted file mode 100644 index 764c5958c..000000000 --- a/pkg/glfw/wayland-headers/wayland-client-protocol.h +++ /dev/null @@ -1,6236 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef WAYLAND_CLIENT_PROTOCOL_H -#define WAYLAND_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_wayland The wayland protocol - * @section page_ifaces_wayland Interfaces - * - @subpage page_iface_wl_display - core global object - * - @subpage page_iface_wl_registry - global registry object - * - @subpage page_iface_wl_callback - callback object - * - @subpage page_iface_wl_compositor - the compositor singleton - * - @subpage page_iface_wl_shm_pool - a shared memory pool - * - @subpage page_iface_wl_shm - shared memory support - * - @subpage page_iface_wl_buffer - content for a wl_surface - * - @subpage page_iface_wl_data_offer - offer to transfer data - * - @subpage page_iface_wl_data_source - offer to transfer data - * - @subpage page_iface_wl_data_device - data transfer device - * - @subpage page_iface_wl_data_device_manager - data transfer interface - * - @subpage page_iface_wl_shell - create desktop-style surfaces - * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface - * - @subpage page_iface_wl_surface - an onscreen surface - * - @subpage page_iface_wl_seat - group of input devices - * - @subpage page_iface_wl_pointer - pointer input device - * - @subpage page_iface_wl_keyboard - keyboard input device - * - @subpage page_iface_wl_touch - touchscreen input device - * - @subpage page_iface_wl_output - compositor output region - * - @subpage page_iface_wl_region - region interface - * - @subpage page_iface_wl_subcompositor - sub-surface compositing - * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface - * @section page_copyright_wayland Copyright - *
- *
- * 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.
- * 
- */ -struct wl_buffer; -struct wl_callback; -struct wl_compositor; -struct wl_data_device; -struct wl_data_device_manager; -struct wl_data_offer; -struct wl_data_source; -struct wl_display; -struct wl_keyboard; -struct wl_output; -struct wl_pointer; -struct wl_region; -struct wl_registry; -struct wl_seat; -struct wl_shell; -struct wl_shell_surface; -struct wl_shm; -struct wl_shm_pool; -struct wl_subcompositor; -struct wl_subsurface; -struct wl_surface; -struct wl_touch; - -#ifndef WL_DISPLAY_INTERFACE -#define WL_DISPLAY_INTERFACE -/** - * @page page_iface_wl_display wl_display - * @section page_iface_wl_display_desc Description - * - * The core global object. This is a special singleton object. It - * is used for internal Wayland protocol features. - * @section page_iface_wl_display_api API - * See @ref iface_wl_display. - */ -/** - * @defgroup iface_wl_display The wl_display interface - * - * The core global object. This is a special singleton object. It - * is used for internal Wayland protocol features. - */ -extern const struct wl_interface wl_display_interface; -#endif -#ifndef WL_REGISTRY_INTERFACE -#define WL_REGISTRY_INTERFACE -/** - * @page page_iface_wl_registry wl_registry - * @section page_iface_wl_registry_desc Description - * - * The singleton global registry object. The server has a number of - * global objects that are available to all clients. These objects - * typically represent an actual object in the server (for example, - * an input device) or they are singleton objects that provide - * extension functionality. - * - * When a client creates a registry object, the registry object - * will emit a global event for each global currently in the - * registry. Globals come and go as a result of device or - * monitor hotplugs, reconfiguration or other events, and the - * registry will send out global and global_remove events to - * keep the client up to date with the changes. To mark the end - * of the initial burst of events, the client can use the - * wl_display.sync request immediately after calling - * wl_display.get_registry. - * - * A client can bind to a global object by using the bind - * request. This creates a client-side handle that lets the object - * emit events to the client and lets the client invoke requests on - * the object. - * @section page_iface_wl_registry_api API - * See @ref iface_wl_registry. - */ -/** - * @defgroup iface_wl_registry The wl_registry interface - * - * The singleton global registry object. The server has a number of - * global objects that are available to all clients. These objects - * typically represent an actual object in the server (for example, - * an input device) or they are singleton objects that provide - * extension functionality. - * - * When a client creates a registry object, the registry object - * will emit a global event for each global currently in the - * registry. Globals come and go as a result of device or - * monitor hotplugs, reconfiguration or other events, and the - * registry will send out global and global_remove events to - * keep the client up to date with the changes. To mark the end - * of the initial burst of events, the client can use the - * wl_display.sync request immediately after calling - * wl_display.get_registry. - * - * A client can bind to a global object by using the bind - * request. This creates a client-side handle that lets the object - * emit events to the client and lets the client invoke requests on - * the object. - */ -extern const struct wl_interface wl_registry_interface; -#endif -#ifndef WL_CALLBACK_INTERFACE -#define WL_CALLBACK_INTERFACE -/** - * @page page_iface_wl_callback wl_callback - * @section page_iface_wl_callback_desc Description - * - * Clients can handle the 'done' event to get notified when - * the related request is done. - * - * Note, because wl_callback objects are created from multiple independent - * factory interfaces, the wl_callback interface is frozen at version 1. - * @section page_iface_wl_callback_api API - * See @ref iface_wl_callback. - */ -/** - * @defgroup iface_wl_callback The wl_callback interface - * - * Clients can handle the 'done' event to get notified when - * the related request is done. - * - * Note, because wl_callback objects are created from multiple independent - * factory interfaces, the wl_callback interface is frozen at version 1. - */ -extern const struct wl_interface wl_callback_interface; -#endif -#ifndef WL_COMPOSITOR_INTERFACE -#define WL_COMPOSITOR_INTERFACE -/** - * @page page_iface_wl_compositor wl_compositor - * @section page_iface_wl_compositor_desc Description - * - * A compositor. This object is a singleton global. The - * compositor is in charge of combining the contents of multiple - * surfaces into one displayable output. - * @section page_iface_wl_compositor_api API - * See @ref iface_wl_compositor. - */ -/** - * @defgroup iface_wl_compositor The wl_compositor interface - * - * A compositor. This object is a singleton global. The - * compositor is in charge of combining the contents of multiple - * surfaces into one displayable output. - */ -extern const struct wl_interface wl_compositor_interface; -#endif -#ifndef WL_SHM_POOL_INTERFACE -#define WL_SHM_POOL_INTERFACE -/** - * @page page_iface_wl_shm_pool wl_shm_pool - * @section page_iface_wl_shm_pool_desc Description - * - * The wl_shm_pool object encapsulates a piece of memory shared - * between the compositor and client. Through the wl_shm_pool - * object, the client can allocate shared memory wl_buffer objects. - * All objects created through the same pool share the same - * underlying mapped memory. Reusing the mapped memory avoids the - * setup/teardown overhead and is useful when interactively resizing - * a surface or for many small buffers. - * @section page_iface_wl_shm_pool_api API - * See @ref iface_wl_shm_pool. - */ -/** - * @defgroup iface_wl_shm_pool The wl_shm_pool interface - * - * The wl_shm_pool object encapsulates a piece of memory shared - * between the compositor and client. Through the wl_shm_pool - * object, the client can allocate shared memory wl_buffer objects. - * All objects created through the same pool share the same - * underlying mapped memory. Reusing the mapped memory avoids the - * setup/teardown overhead and is useful when interactively resizing - * a surface or for many small buffers. - */ -extern const struct wl_interface wl_shm_pool_interface; -#endif -#ifndef WL_SHM_INTERFACE -#define WL_SHM_INTERFACE -/** - * @page page_iface_wl_shm wl_shm - * @section page_iface_wl_shm_desc Description - * - * A singleton global object that provides support for shared - * memory. - * - * Clients can create wl_shm_pool objects using the create_pool - * request. - * - * On binding the wl_shm object one or more format events - * are emitted to inform clients about the valid pixel formats - * that can be used for buffers. - * @section page_iface_wl_shm_api API - * See @ref iface_wl_shm. - */ -/** - * @defgroup iface_wl_shm The wl_shm interface - * - * A singleton global object that provides support for shared - * memory. - * - * Clients can create wl_shm_pool objects using the create_pool - * request. - * - * On binding the wl_shm object one or more format events - * are emitted to inform clients about the valid pixel formats - * that can be used for buffers. - */ -extern const struct wl_interface wl_shm_interface; -#endif -#ifndef WL_BUFFER_INTERFACE -#define WL_BUFFER_INTERFACE -/** - * @page page_iface_wl_buffer wl_buffer - * @section page_iface_wl_buffer_desc Description - * - * A buffer provides the content for a wl_surface. Buffers are - * created through factory interfaces such as wl_shm, wp_linux_buffer_params - * (from the linux-dmabuf protocol extension) or similar. It has a width and - * a height and can be attached to a wl_surface, but the mechanism by which a - * client provides and updates the contents is defined by the buffer factory - * interface. - * - * If the buffer uses a format that has an alpha channel, the alpha channel - * is assumed to be premultiplied in the color channels unless otherwise - * specified. - * - * Note, because wl_buffer objects are created from multiple independent - * factory interfaces, the wl_buffer interface is frozen at version 1. - * @section page_iface_wl_buffer_api API - * See @ref iface_wl_buffer. - */ -/** - * @defgroup iface_wl_buffer The wl_buffer interface - * - * A buffer provides the content for a wl_surface. Buffers are - * created through factory interfaces such as wl_shm, wp_linux_buffer_params - * (from the linux-dmabuf protocol extension) or similar. It has a width and - * a height and can be attached to a wl_surface, but the mechanism by which a - * client provides and updates the contents is defined by the buffer factory - * interface. - * - * If the buffer uses a format that has an alpha channel, the alpha channel - * is assumed to be premultiplied in the color channels unless otherwise - * specified. - * - * Note, because wl_buffer objects are created from multiple independent - * factory interfaces, the wl_buffer interface is frozen at version 1. - */ -extern const struct wl_interface wl_buffer_interface; -#endif -#ifndef WL_DATA_OFFER_INTERFACE -#define WL_DATA_OFFER_INTERFACE -/** - * @page page_iface_wl_data_offer wl_data_offer - * @section page_iface_wl_data_offer_desc Description - * - * A wl_data_offer represents a piece of data offered for transfer - * by another client (the source client). It is used by the - * copy-and-paste and drag-and-drop mechanisms. The offer - * describes the different mime types that the data can be - * converted to and provides the mechanism for transferring the - * data directly from the source client. - * @section page_iface_wl_data_offer_api API - * See @ref iface_wl_data_offer. - */ -/** - * @defgroup iface_wl_data_offer The wl_data_offer interface - * - * A wl_data_offer represents a piece of data offered for transfer - * by another client (the source client). It is used by the - * copy-and-paste and drag-and-drop mechanisms. The offer - * describes the different mime types that the data can be - * converted to and provides the mechanism for transferring the - * data directly from the source client. - */ -extern const struct wl_interface wl_data_offer_interface; -#endif -#ifndef WL_DATA_SOURCE_INTERFACE -#define WL_DATA_SOURCE_INTERFACE -/** - * @page page_iface_wl_data_source wl_data_source - * @section page_iface_wl_data_source_desc Description - * - * The wl_data_source object is the source side of a wl_data_offer. - * It is created by the source client in a data transfer and - * provides a way to describe the offered data and a way to respond - * to requests to transfer the data. - * @section page_iface_wl_data_source_api API - * See @ref iface_wl_data_source. - */ -/** - * @defgroup iface_wl_data_source The wl_data_source interface - * - * The wl_data_source object is the source side of a wl_data_offer. - * It is created by the source client in a data transfer and - * provides a way to describe the offered data and a way to respond - * to requests to transfer the data. - */ -extern const struct wl_interface wl_data_source_interface; -#endif -#ifndef WL_DATA_DEVICE_INTERFACE -#define WL_DATA_DEVICE_INTERFACE -/** - * @page page_iface_wl_data_device wl_data_device - * @section page_iface_wl_data_device_desc Description - * - * There is one wl_data_device per seat which can be obtained - * from the global wl_data_device_manager singleton. - * - * A wl_data_device provides access to inter-client data transfer - * mechanisms such as copy-and-paste and drag-and-drop. - * @section page_iface_wl_data_device_api API - * See @ref iface_wl_data_device. - */ -/** - * @defgroup iface_wl_data_device The wl_data_device interface - * - * There is one wl_data_device per seat which can be obtained - * from the global wl_data_device_manager singleton. - * - * A wl_data_device provides access to inter-client data transfer - * mechanisms such as copy-and-paste and drag-and-drop. - */ -extern const struct wl_interface wl_data_device_interface; -#endif -#ifndef WL_DATA_DEVICE_MANAGER_INTERFACE -#define WL_DATA_DEVICE_MANAGER_INTERFACE -/** - * @page page_iface_wl_data_device_manager wl_data_device_manager - * @section page_iface_wl_data_device_manager_desc Description - * - * The wl_data_device_manager is a singleton global object that - * provides access to inter-client data transfer mechanisms such as - * copy-and-paste and drag-and-drop. These mechanisms are tied to - * a wl_seat and this interface lets a client get a wl_data_device - * corresponding to a wl_seat. - * - * Depending on the version bound, the objects created from the bound - * wl_data_device_manager object will have different requirements for - * functioning properly. See wl_data_source.set_actions, - * wl_data_offer.accept and wl_data_offer.finish for details. - * @section page_iface_wl_data_device_manager_api API - * See @ref iface_wl_data_device_manager. - */ -/** - * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface - * - * The wl_data_device_manager is a singleton global object that - * provides access to inter-client data transfer mechanisms such as - * copy-and-paste and drag-and-drop. These mechanisms are tied to - * a wl_seat and this interface lets a client get a wl_data_device - * corresponding to a wl_seat. - * - * Depending on the version bound, the objects created from the bound - * wl_data_device_manager object will have different requirements for - * functioning properly. See wl_data_source.set_actions, - * wl_data_offer.accept and wl_data_offer.finish for details. - */ -extern const struct wl_interface wl_data_device_manager_interface; -#endif -#ifndef WL_SHELL_INTERFACE -#define WL_SHELL_INTERFACE -/** - * @page page_iface_wl_shell wl_shell - * @section page_iface_wl_shell_desc Description - * - * This interface is implemented by servers that provide - * desktop-style user interfaces. - * - * It allows clients to associate a wl_shell_surface with - * a basic surface. - * - * Note! This protocol is deprecated and not intended for production use. - * For desktop-style user interfaces, use xdg_shell. Compositors and clients - * should not implement this interface. - * @section page_iface_wl_shell_api API - * See @ref iface_wl_shell. - */ -/** - * @defgroup iface_wl_shell The wl_shell interface - * - * This interface is implemented by servers that provide - * desktop-style user interfaces. - * - * It allows clients to associate a wl_shell_surface with - * a basic surface. - * - * Note! This protocol is deprecated and not intended for production use. - * For desktop-style user interfaces, use xdg_shell. Compositors and clients - * should not implement this interface. - */ -extern const struct wl_interface wl_shell_interface; -#endif -#ifndef WL_SHELL_SURFACE_INTERFACE -#define WL_SHELL_SURFACE_INTERFACE -/** - * @page page_iface_wl_shell_surface wl_shell_surface - * @section page_iface_wl_shell_surface_desc Description - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides requests to treat surfaces like toplevel, fullscreen - * or popup windows, move, resize or maximize them, associate - * metadata like title and class, etc. - * - * On the server side the object is automatically destroyed when - * the related wl_surface is destroyed. On the client side, - * wl_shell_surface_destroy() must be called before destroying - * the wl_surface object. - * @section page_iface_wl_shell_surface_api API - * See @ref iface_wl_shell_surface. - */ -/** - * @defgroup iface_wl_shell_surface The wl_shell_surface interface - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides requests to treat surfaces like toplevel, fullscreen - * or popup windows, move, resize or maximize them, associate - * metadata like title and class, etc. - * - * On the server side the object is automatically destroyed when - * the related wl_surface is destroyed. On the client side, - * wl_shell_surface_destroy() must be called before destroying - * the wl_surface object. - */ -extern const struct wl_interface wl_shell_surface_interface; -#endif -#ifndef WL_SURFACE_INTERFACE -#define WL_SURFACE_INTERFACE -/** - * @page page_iface_wl_surface wl_surface - * @section page_iface_wl_surface_desc Description - * - * A surface is a rectangular area that may be displayed on zero - * or more outputs, and shown any number of times at the compositor's - * discretion. They can present wl_buffers, receive user input, and - * define a local coordinate system. - * - * The size of a surface (and relative positions on it) is described - * in surface-local coordinates, which may differ from the buffer - * coordinates of the pixel content, in case a buffer_transform - * or a buffer_scale is used. - * - * A surface without a "role" is fairly useless: a compositor does - * not know where, when or how to present it. The role is the - * purpose of a wl_surface. Examples of roles are a cursor for a - * pointer (as set by wl_pointer.set_cursor), a drag icon - * (wl_data_device.start_drag), a sub-surface - * (wl_subcompositor.get_subsurface), and a window as defined by a - * shell protocol (e.g. wl_shell.get_shell_surface). - * - * A surface can have only one role at a time. Initially a - * wl_surface does not have a role. Once a wl_surface is given a - * role, it is set permanently for the whole lifetime of the - * wl_surface object. Giving the current role again is allowed, - * unless explicitly forbidden by the relevant interface - * specification. - * - * Surface roles are given by requests in other interfaces such as - * wl_pointer.set_cursor. The request should explicitly mention - * that this request gives a role to a wl_surface. Often, this - * request also creates a new protocol object that represents the - * role and adds additional functionality to wl_surface. When a - * client wants to destroy a wl_surface, they must destroy this role - * object before the wl_surface, otherwise a defunct_role_object error is - * sent. - * - * Destroying the role object does not remove the role from the - * wl_surface, but it may stop the wl_surface from "playing the role". - * For instance, if a wl_subsurface object is destroyed, the wl_surface - * it was created for will be unmapped and forget its position and - * z-order. It is allowed to create a wl_subsurface for the same - * wl_surface again, but it is not allowed to use the wl_surface as - * a cursor (cursor is a different role than sub-surface, and role - * switching is not allowed). - * @section page_iface_wl_surface_api API - * See @ref iface_wl_surface. - */ -/** - * @defgroup iface_wl_surface The wl_surface interface - * - * A surface is a rectangular area that may be displayed on zero - * or more outputs, and shown any number of times at the compositor's - * discretion. They can present wl_buffers, receive user input, and - * define a local coordinate system. - * - * The size of a surface (and relative positions on it) is described - * in surface-local coordinates, which may differ from the buffer - * coordinates of the pixel content, in case a buffer_transform - * or a buffer_scale is used. - * - * A surface without a "role" is fairly useless: a compositor does - * not know where, when or how to present it. The role is the - * purpose of a wl_surface. Examples of roles are a cursor for a - * pointer (as set by wl_pointer.set_cursor), a drag icon - * (wl_data_device.start_drag), a sub-surface - * (wl_subcompositor.get_subsurface), and a window as defined by a - * shell protocol (e.g. wl_shell.get_shell_surface). - * - * A surface can have only one role at a time. Initially a - * wl_surface does not have a role. Once a wl_surface is given a - * role, it is set permanently for the whole lifetime of the - * wl_surface object. Giving the current role again is allowed, - * unless explicitly forbidden by the relevant interface - * specification. - * - * Surface roles are given by requests in other interfaces such as - * wl_pointer.set_cursor. The request should explicitly mention - * that this request gives a role to a wl_surface. Often, this - * request also creates a new protocol object that represents the - * role and adds additional functionality to wl_surface. When a - * client wants to destroy a wl_surface, they must destroy this role - * object before the wl_surface, otherwise a defunct_role_object error is - * sent. - * - * Destroying the role object does not remove the role from the - * wl_surface, but it may stop the wl_surface from "playing the role". - * For instance, if a wl_subsurface object is destroyed, the wl_surface - * it was created for will be unmapped and forget its position and - * z-order. It is allowed to create a wl_subsurface for the same - * wl_surface again, but it is not allowed to use the wl_surface as - * a cursor (cursor is a different role than sub-surface, and role - * switching is not allowed). - */ -extern const struct wl_interface wl_surface_interface; -#endif -#ifndef WL_SEAT_INTERFACE -#define WL_SEAT_INTERFACE -/** - * @page page_iface_wl_seat wl_seat - * @section page_iface_wl_seat_desc Description - * - * A seat is a group of keyboards, pointer and touch devices. This - * object is published as a global during start up, or when such a - * device is hot plugged. A seat typically has a pointer and - * maintains a keyboard focus and a pointer focus. - * @section page_iface_wl_seat_api API - * See @ref iface_wl_seat. - */ -/** - * @defgroup iface_wl_seat The wl_seat interface - * - * A seat is a group of keyboards, pointer and touch devices. This - * object is published as a global during start up, or when such a - * device is hot plugged. A seat typically has a pointer and - * maintains a keyboard focus and a pointer focus. - */ -extern const struct wl_interface wl_seat_interface; -#endif -#ifndef WL_POINTER_INTERFACE -#define WL_POINTER_INTERFACE -/** - * @page page_iface_wl_pointer wl_pointer - * @section page_iface_wl_pointer_desc Description - * - * The wl_pointer interface represents one or more input devices, - * such as mice, which control the pointer location and pointer_focus - * of a seat. - * - * The wl_pointer interface generates motion, enter and leave - * events for the surfaces that the pointer is located over, - * and button and axis events for button presses, button releases - * and scrolling. - * @section page_iface_wl_pointer_api API - * See @ref iface_wl_pointer. - */ -/** - * @defgroup iface_wl_pointer The wl_pointer interface - * - * The wl_pointer interface represents one or more input devices, - * such as mice, which control the pointer location and pointer_focus - * of a seat. - * - * The wl_pointer interface generates motion, enter and leave - * events for the surfaces that the pointer is located over, - * and button and axis events for button presses, button releases - * and scrolling. - */ -extern const struct wl_interface wl_pointer_interface; -#endif -#ifndef WL_KEYBOARD_INTERFACE -#define WL_KEYBOARD_INTERFACE -/** - * @page page_iface_wl_keyboard wl_keyboard - * @section page_iface_wl_keyboard_desc Description - * - * The wl_keyboard interface represents one or more keyboards - * associated with a seat. - * @section page_iface_wl_keyboard_api API - * See @ref iface_wl_keyboard. - */ -/** - * @defgroup iface_wl_keyboard The wl_keyboard interface - * - * The wl_keyboard interface represents one or more keyboards - * associated with a seat. - */ -extern const struct wl_interface wl_keyboard_interface; -#endif -#ifndef WL_TOUCH_INTERFACE -#define WL_TOUCH_INTERFACE -/** - * @page page_iface_wl_touch wl_touch - * @section page_iface_wl_touch_desc Description - * - * The wl_touch interface represents a touchscreen - * associated with a seat. - * - * Touch interactions can consist of one or more contacts. - * For each contact, a series of events is generated, starting - * with a down event, followed by zero or more motion events, - * and ending with an up event. Events relating to the same - * contact point can be identified by the ID of the sequence. - * @section page_iface_wl_touch_api API - * See @ref iface_wl_touch. - */ -/** - * @defgroup iface_wl_touch The wl_touch interface - * - * The wl_touch interface represents a touchscreen - * associated with a seat. - * - * Touch interactions can consist of one or more contacts. - * For each contact, a series of events is generated, starting - * with a down event, followed by zero or more motion events, - * and ending with an up event. Events relating to the same - * contact point can be identified by the ID of the sequence. - */ -extern const struct wl_interface wl_touch_interface; -#endif -#ifndef WL_OUTPUT_INTERFACE -#define WL_OUTPUT_INTERFACE -/** - * @page page_iface_wl_output wl_output - * @section page_iface_wl_output_desc Description - * - * An output describes part of the compositor geometry. The - * compositor works in the 'compositor coordinate system' and an - * output corresponds to a rectangular area in that space that is - * actually visible. This typically corresponds to a monitor that - * displays part of the compositor space. This object is published - * as global during start up, or when a monitor is hotplugged. - * @section page_iface_wl_output_api API - * See @ref iface_wl_output. - */ -/** - * @defgroup iface_wl_output The wl_output interface - * - * An output describes part of the compositor geometry. The - * compositor works in the 'compositor coordinate system' and an - * output corresponds to a rectangular area in that space that is - * actually visible. This typically corresponds to a monitor that - * displays part of the compositor space. This object is published - * as global during start up, or when a monitor is hotplugged. - */ -extern const struct wl_interface wl_output_interface; -#endif -#ifndef WL_REGION_INTERFACE -#define WL_REGION_INTERFACE -/** - * @page page_iface_wl_region wl_region - * @section page_iface_wl_region_desc Description - * - * A region object describes an area. - * - * Region objects are used to describe the opaque and input - * regions of a surface. - * @section page_iface_wl_region_api API - * See @ref iface_wl_region. - */ -/** - * @defgroup iface_wl_region The wl_region interface - * - * A region object describes an area. - * - * Region objects are used to describe the opaque and input - * regions of a surface. - */ -extern const struct wl_interface wl_region_interface; -#endif -#ifndef WL_SUBCOMPOSITOR_INTERFACE -#define WL_SUBCOMPOSITOR_INTERFACE -/** - * @page page_iface_wl_subcompositor wl_subcompositor - * @section page_iface_wl_subcompositor_desc Description - * - * The global interface exposing sub-surface compositing capabilities. - * A wl_surface, that has sub-surfaces associated, is called the - * parent surface. Sub-surfaces can be arbitrarily nested and create - * a tree of sub-surfaces. - * - * The root surface in a tree of sub-surfaces is the main - * surface. The main surface cannot be a sub-surface, because - * sub-surfaces must always have a parent. - * - * A main surface with its sub-surfaces forms a (compound) window. - * For window management purposes, this set of wl_surface objects is - * to be considered as a single window, and it should also behave as - * such. - * - * The aim of sub-surfaces is to offload some of the compositing work - * within a window from clients to the compositor. A prime example is - * a video player with decorations and video in separate wl_surface - * objects. This should allow the compositor to pass YUV video buffer - * processing to dedicated overlay hardware when possible. - * @section page_iface_wl_subcompositor_api API - * See @ref iface_wl_subcompositor. - */ -/** - * @defgroup iface_wl_subcompositor The wl_subcompositor interface - * - * The global interface exposing sub-surface compositing capabilities. - * A wl_surface, that has sub-surfaces associated, is called the - * parent surface. Sub-surfaces can be arbitrarily nested and create - * a tree of sub-surfaces. - * - * The root surface in a tree of sub-surfaces is the main - * surface. The main surface cannot be a sub-surface, because - * sub-surfaces must always have a parent. - * - * A main surface with its sub-surfaces forms a (compound) window. - * For window management purposes, this set of wl_surface objects is - * to be considered as a single window, and it should also behave as - * such. - * - * The aim of sub-surfaces is to offload some of the compositing work - * within a window from clients to the compositor. A prime example is - * a video player with decorations and video in separate wl_surface - * objects. This should allow the compositor to pass YUV video buffer - * processing to dedicated overlay hardware when possible. - */ -extern const struct wl_interface wl_subcompositor_interface; -#endif -#ifndef WL_SUBSURFACE_INTERFACE -#define WL_SUBSURFACE_INTERFACE -/** - * @page page_iface_wl_subsurface wl_subsurface - * @section page_iface_wl_subsurface_desc Description - * - * An additional interface to a wl_surface object, which has been - * made a sub-surface. A sub-surface has one parent surface. A - * sub-surface's size and position are not limited to that of the parent. - * Particularly, a sub-surface is not automatically clipped to its - * parent's area. - * - * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied - * and the parent surface is mapped. The order of which one happens - * first is irrelevant. A sub-surface is hidden if the parent becomes - * hidden, or if a NULL wl_buffer is applied. These rules apply - * recursively through the tree of surfaces. - * - * The behaviour of a wl_surface.commit request on a sub-surface - * depends on the sub-surface's mode. The possible modes are - * synchronized and desynchronized, see methods - * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized - * mode caches the wl_surface state to be applied when the parent's - * state gets applied, and desynchronized mode applies the pending - * wl_surface state directly. A sub-surface is initially in the - * synchronized mode. - * - * Sub-surfaces also have another kind of state, which is managed by - * wl_subsurface requests, as opposed to wl_surface requests. This - * state includes the sub-surface position relative to the parent - * surface (wl_subsurface.set_position), and the stacking order of - * the parent and its sub-surfaces (wl_subsurface.place_above and - * .place_below). This state is applied when the parent surface's - * wl_surface state is applied, regardless of the sub-surface's mode. - * As the exception, set_sync and set_desync are effective immediately. - * - * The main surface can be thought to be always in desynchronized mode, - * since it does not have a parent in the sub-surfaces sense. - * - * Even if a sub-surface is in desynchronized mode, it will behave as - * in synchronized mode, if its parent surface behaves as in - * synchronized mode. This rule is applied recursively throughout the - * tree of surfaces. This means, that one can set a sub-surface into - * synchronized mode, and then assume that all its child and grand-child - * sub-surfaces are synchronized, too, without explicitly setting them. - * - * Destroying a sub-surface takes effect immediately. If you need to - * synchronize the removal of a sub-surface to the parent surface update, - * unmap the sub-surface first by attaching a NULL wl_buffer, update parent, - * and then destroy the sub-surface. - * - * If the parent wl_surface object is destroyed, the sub-surface is - * unmapped. - * @section page_iface_wl_subsurface_api API - * See @ref iface_wl_subsurface. - */ -/** - * @defgroup iface_wl_subsurface The wl_subsurface interface - * - * An additional interface to a wl_surface object, which has been - * made a sub-surface. A sub-surface has one parent surface. A - * sub-surface's size and position are not limited to that of the parent. - * Particularly, a sub-surface is not automatically clipped to its - * parent's area. - * - * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied - * and the parent surface is mapped. The order of which one happens - * first is irrelevant. A sub-surface is hidden if the parent becomes - * hidden, or if a NULL wl_buffer is applied. These rules apply - * recursively through the tree of surfaces. - * - * The behaviour of a wl_surface.commit request on a sub-surface - * depends on the sub-surface's mode. The possible modes are - * synchronized and desynchronized, see methods - * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized - * mode caches the wl_surface state to be applied when the parent's - * state gets applied, and desynchronized mode applies the pending - * wl_surface state directly. A sub-surface is initially in the - * synchronized mode. - * - * Sub-surfaces also have another kind of state, which is managed by - * wl_subsurface requests, as opposed to wl_surface requests. This - * state includes the sub-surface position relative to the parent - * surface (wl_subsurface.set_position), and the stacking order of - * the parent and its sub-surfaces (wl_subsurface.place_above and - * .place_below). This state is applied when the parent surface's - * wl_surface state is applied, regardless of the sub-surface's mode. - * As the exception, set_sync and set_desync are effective immediately. - * - * The main surface can be thought to be always in desynchronized mode, - * since it does not have a parent in the sub-surfaces sense. - * - * Even if a sub-surface is in desynchronized mode, it will behave as - * in synchronized mode, if its parent surface behaves as in - * synchronized mode. This rule is applied recursively throughout the - * tree of surfaces. This means, that one can set a sub-surface into - * synchronized mode, and then assume that all its child and grand-child - * sub-surfaces are synchronized, too, without explicitly setting them. - * - * Destroying a sub-surface takes effect immediately. If you need to - * synchronize the removal of a sub-surface to the parent surface update, - * unmap the sub-surface first by attaching a NULL wl_buffer, update parent, - * and then destroy the sub-surface. - * - * If the parent wl_surface object is destroyed, the sub-surface is - * unmapped. - */ -extern const struct wl_interface wl_subsurface_interface; -#endif - -#ifndef WL_DISPLAY_ERROR_ENUM -#define WL_DISPLAY_ERROR_ENUM -/** - * @ingroup iface_wl_display - * global error values - * - * These errors are global and can be emitted in response to any - * server request. - */ -enum wl_display_error { - /** - * server couldn't find object - */ - WL_DISPLAY_ERROR_INVALID_OBJECT = 0, - /** - * method doesn't exist on the specified interface or malformed request - */ - WL_DISPLAY_ERROR_INVALID_METHOD = 1, - /** - * server is out of memory - */ - WL_DISPLAY_ERROR_NO_MEMORY = 2, - /** - * implementation error in compositor - */ - WL_DISPLAY_ERROR_IMPLEMENTATION = 3, -}; -#endif /* WL_DISPLAY_ERROR_ENUM */ - -/** - * @ingroup iface_wl_display - * @struct wl_display_listener - */ -struct wl_display_listener { - /** - * fatal error event - * - * The error event is sent out when a fatal (non-recoverable) - * error has occurred. The object_id argument is the object where - * the error occurred, most often in response to a request to that - * object. The code identifies the error and is defined by the - * object interface. As such, each interface defines its own set of - * error codes. The message is a brief description of the error, - * for (debugging) convenience. - * @param object_id object where the error occurred - * @param code error code - * @param message error description - */ - void (*error)(void *data, - struct wl_display *wl_display, - void *object_id, - uint32_t code, - const char *message); - /** - * acknowledge object ID deletion - * - * This event is used internally by the object ID management - * logic. When a client deletes an object that it had created, the - * server will send this event to acknowledge that it has seen the - * delete request. When the client receives this event, it will - * know that it can safely reuse the object ID. - * @param id deleted object ID - */ - void (*delete_id)(void *data, - struct wl_display *wl_display, - uint32_t id); -}; - -/** - * @ingroup iface_wl_display - */ -static inline int -wl_display_add_listener(struct wl_display *wl_display, - const struct wl_display_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_display, - (void (**)(void)) listener, data); -} - -#define WL_DISPLAY_SYNC 0 -#define WL_DISPLAY_GET_REGISTRY 1 - -/** - * @ingroup iface_wl_display - */ -#define WL_DISPLAY_ERROR_SINCE_VERSION 1 -/** - * @ingroup iface_wl_display - */ -#define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_display - */ -#define WL_DISPLAY_SYNC_SINCE_VERSION 1 -/** - * @ingroup iface_wl_display - */ -#define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1 - -/** @ingroup iface_wl_display */ -static inline void -wl_display_set_user_data(struct wl_display *wl_display, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data); -} - -/** @ingroup iface_wl_display */ -static inline void * -wl_display_get_user_data(struct wl_display *wl_display) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_display); -} - -static inline uint32_t -wl_display_get_version(struct wl_display *wl_display) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_display); -} - -/** - * @ingroup iface_wl_display - * - * The sync request asks the server to emit the 'done' event - * on the returned wl_callback object. Since requests are - * handled in-order and events are delivered in-order, this can - * be used as a barrier to ensure all previous requests and the - * resulting events have been handled. - * - * The object returned by this request will be destroyed by the - * compositor after the callback is fired and as such the client must not - * attempt to use it after that point. - * - * The callback_data passed in the callback is the event serial. - */ -static inline struct wl_callback * -wl_display_sync(struct wl_display *wl_display) -{ - struct wl_proxy *callback; - - callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, - WL_DISPLAY_SYNC, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); - - return (struct wl_callback *) callback; -} - -/** - * @ingroup iface_wl_display - * - * This request creates a registry object that allows the client - * to list and bind the global objects available from the - * compositor. - * - * It should be noted that the server side resources consumed in - * response to a get_registry request can only be released when the - * client disconnects, not when the client side proxy is destroyed. - * Therefore, clients should invoke get_registry as infrequently as - * possible to avoid wasting memory. - */ -static inline struct wl_registry * -wl_display_get_registry(struct wl_display *wl_display) -{ - struct wl_proxy *registry; - - registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, - WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); - - return (struct wl_registry *) registry; -} - -/** - * @ingroup iface_wl_registry - * @struct wl_registry_listener - */ -struct wl_registry_listener { - /** - * announce global object - * - * Notify the client of global objects. - * - * The event notifies the client that a global object with the - * given name is now available, and it implements the given version - * of the given interface. - * @param name numeric name of the global object - * @param interface interface implemented by the object - * @param version interface version - */ - void (*global)(void *data, - struct wl_registry *wl_registry, - uint32_t name, - const char *interface, - uint32_t version); - /** - * announce removal of global object - * - * Notify the client of removed global objects. - * - * This event notifies the client that the global identified by - * name is no longer available. If the client bound to the global - * using the bind request, the client should now destroy that - * object. - * - * The object remains valid and requests to the object will be - * ignored until the client destroys it, to avoid races between the - * global going away and a client sending a request to it. - * @param name numeric name of the global object - */ - void (*global_remove)(void *data, - struct wl_registry *wl_registry, - uint32_t name); -}; - -/** - * @ingroup iface_wl_registry - */ -static inline int -wl_registry_add_listener(struct wl_registry *wl_registry, - const struct wl_registry_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_registry, - (void (**)(void)) listener, data); -} - -#define WL_REGISTRY_BIND 0 - -/** - * @ingroup iface_wl_registry - */ -#define WL_REGISTRY_GLOBAL_SINCE_VERSION 1 -/** - * @ingroup iface_wl_registry - */ -#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_registry - */ -#define WL_REGISTRY_BIND_SINCE_VERSION 1 - -/** @ingroup iface_wl_registry */ -static inline void -wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data); -} - -/** @ingroup iface_wl_registry */ -static inline void * -wl_registry_get_user_data(struct wl_registry *wl_registry) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_registry); -} - -static inline uint32_t -wl_registry_get_version(struct wl_registry *wl_registry) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_registry); -} - -/** @ingroup iface_wl_registry */ -static inline void -wl_registry_destroy(struct wl_registry *wl_registry) -{ - wl_proxy_destroy((struct wl_proxy *) wl_registry); -} - -/** - * @ingroup iface_wl_registry - * - * Binds a new, client-created object to the server using the - * specified name as the identifier. - */ -static inline void * -wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_registry, - WL_REGISTRY_BIND, interface, version, 0, name, interface->name, version, NULL); - - return (void *) id; -} - -/** - * @ingroup iface_wl_callback - * @struct wl_callback_listener - */ -struct wl_callback_listener { - /** - * done event - * - * Notify the client when the related request is done. - * @param callback_data request-specific data for the callback - */ - void (*done)(void *data, - struct wl_callback *wl_callback, - uint32_t callback_data); -}; - -/** - * @ingroup iface_wl_callback - */ -static inline int -wl_callback_add_listener(struct wl_callback *wl_callback, - const struct wl_callback_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_callback, - (void (**)(void)) listener, data); -} - -/** - * @ingroup iface_wl_callback - */ -#define WL_CALLBACK_DONE_SINCE_VERSION 1 - - -/** @ingroup iface_wl_callback */ -static inline void -wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data); -} - -/** @ingroup iface_wl_callback */ -static inline void * -wl_callback_get_user_data(struct wl_callback *wl_callback) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_callback); -} - -static inline uint32_t -wl_callback_get_version(struct wl_callback *wl_callback) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_callback); -} - -/** @ingroup iface_wl_callback */ -static inline void -wl_callback_destroy(struct wl_callback *wl_callback) -{ - wl_proxy_destroy((struct wl_proxy *) wl_callback); -} - -#define WL_COMPOSITOR_CREATE_SURFACE 0 -#define WL_COMPOSITOR_CREATE_REGION 1 - - -/** - * @ingroup iface_wl_compositor - */ -#define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_compositor - */ -#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1 - -/** @ingroup iface_wl_compositor */ -static inline void -wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data); -} - -/** @ingroup iface_wl_compositor */ -static inline void * -wl_compositor_get_user_data(struct wl_compositor *wl_compositor) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor); -} - -static inline uint32_t -wl_compositor_get_version(struct wl_compositor *wl_compositor) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_compositor); -} - -/** @ingroup iface_wl_compositor */ -static inline void -wl_compositor_destroy(struct wl_compositor *wl_compositor) -{ - wl_proxy_destroy((struct wl_proxy *) wl_compositor); -} - -/** - * @ingroup iface_wl_compositor - * - * Ask the compositor to create a new surface. - */ -static inline struct wl_surface * -wl_compositor_create_surface(struct wl_compositor *wl_compositor) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, - WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); - - return (struct wl_surface *) id; -} - -/** - * @ingroup iface_wl_compositor - * - * Ask the compositor to create a new region. - */ -static inline struct wl_region * -wl_compositor_create_region(struct wl_compositor *wl_compositor) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, - WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); - - return (struct wl_region *) id; -} - -#define WL_SHM_POOL_CREATE_BUFFER 0 -#define WL_SHM_POOL_DESTROY 1 -#define WL_SHM_POOL_RESIZE 2 - - -/** - * @ingroup iface_wl_shm_pool - */ -#define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shm_pool - */ -#define WL_SHM_POOL_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shm_pool - */ -#define WL_SHM_POOL_RESIZE_SINCE_VERSION 1 - -/** @ingroup iface_wl_shm_pool */ -static inline void -wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data); -} - -/** @ingroup iface_wl_shm_pool */ -static inline void * -wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool); -} - -static inline uint32_t -wl_shm_pool_get_version(struct wl_shm_pool *wl_shm_pool) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_shm_pool); -} - -/** - * @ingroup iface_wl_shm_pool - * - * Create a wl_buffer object from the pool. - * - * The buffer is created offset bytes into the pool and has - * width and height as specified. The stride argument specifies - * the number of bytes from the beginning of one row to the beginning - * of the next. The format is the pixel format of the buffer and - * must be one of those advertised through the wl_shm.format event. - * - * A buffer will keep a reference to the pool it was created from - * so it is valid to destroy the pool immediately after creating - * a buffer from it. - */ -static inline struct wl_buffer * -wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, NULL, offset, width, height, stride, format); - - return (struct wl_buffer *) id; -} - -/** - * @ingroup iface_wl_shm_pool - * - * Destroy the shared memory pool. - * - * The mmapped memory will be released when all - * buffers that have been created from this pool - * are gone. - */ -static inline void -wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_shm_pool - * - * This request will cause the server to remap the backing memory - * for the pool from the file descriptor passed when the pool was - * created, but using the new size. This request can only be - * used to make the pool bigger. - * - * This request only changes the amount of bytes that are mmapped - * by the server and does not touch the file corresponding to the - * file descriptor passed at creation time. It is the client's - * responsibility to ensure that the file is at least as big as - * the new pool size. - */ -static inline void -wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, size); -} - -#ifndef WL_SHM_ERROR_ENUM -#define WL_SHM_ERROR_ENUM -/** - * @ingroup iface_wl_shm - * wl_shm error values - * - * These errors can be emitted in response to wl_shm requests. - */ -enum wl_shm_error { - /** - * buffer format is not known - */ - WL_SHM_ERROR_INVALID_FORMAT = 0, - /** - * invalid size or stride during pool or buffer creation - */ - WL_SHM_ERROR_INVALID_STRIDE = 1, - /** - * mmapping the file descriptor failed - */ - WL_SHM_ERROR_INVALID_FD = 2, -}; -#endif /* WL_SHM_ERROR_ENUM */ - -#ifndef WL_SHM_FORMAT_ENUM -#define WL_SHM_FORMAT_ENUM -/** - * @ingroup iface_wl_shm - * pixel formats - * - * This describes the memory layout of an individual pixel. - * - * All renderers should support argb8888 and xrgb8888 but any other - * formats are optional and may not be supported by the particular - * renderer in use. - * - * The drm format codes match the macros defined in drm_fourcc.h, except - * argb8888 and xrgb8888. The formats actually supported by the compositor - * will be reported by the format event. - * - * For all wl_shm formats and unless specified in another protocol - * extension, pre-multiplied alpha is used for pixel values. - */ -enum wl_shm_format { - /** - * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian - */ - WL_SHM_FORMAT_ARGB8888 = 0, - /** - * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian - */ - WL_SHM_FORMAT_XRGB8888 = 1, - /** - * 8-bit color index format, [7:0] C - */ - WL_SHM_FORMAT_C8 = 0x20203843, - /** - * 8-bit RGB format, [7:0] R:G:B 3:3:2 - */ - WL_SHM_FORMAT_RGB332 = 0x38424752, - /** - * 8-bit BGR format, [7:0] B:G:R 2:3:3 - */ - WL_SHM_FORMAT_BGR233 = 0x38524742, - /** - * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian - */ - WL_SHM_FORMAT_XRGB4444 = 0x32315258, - /** - * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian - */ - WL_SHM_FORMAT_XBGR4444 = 0x32314258, - /** - * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian - */ - WL_SHM_FORMAT_RGBX4444 = 0x32315852, - /** - * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian - */ - WL_SHM_FORMAT_BGRX4444 = 0x32315842, - /** - * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian - */ - WL_SHM_FORMAT_ARGB4444 = 0x32315241, - /** - * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian - */ - WL_SHM_FORMAT_ABGR4444 = 0x32314241, - /** - * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian - */ - WL_SHM_FORMAT_RGBA4444 = 0x32314152, - /** - * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian - */ - WL_SHM_FORMAT_BGRA4444 = 0x32314142, - /** - * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian - */ - WL_SHM_FORMAT_XRGB1555 = 0x35315258, - /** - * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian - */ - WL_SHM_FORMAT_XBGR1555 = 0x35314258, - /** - * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian - */ - WL_SHM_FORMAT_RGBX5551 = 0x35315852, - /** - * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian - */ - WL_SHM_FORMAT_BGRX5551 = 0x35315842, - /** - * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian - */ - WL_SHM_FORMAT_ARGB1555 = 0x35315241, - /** - * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian - */ - WL_SHM_FORMAT_ABGR1555 = 0x35314241, - /** - * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian - */ - WL_SHM_FORMAT_RGBA5551 = 0x35314152, - /** - * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian - */ - WL_SHM_FORMAT_BGRA5551 = 0x35314142, - /** - * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian - */ - WL_SHM_FORMAT_RGB565 = 0x36314752, - /** - * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian - */ - WL_SHM_FORMAT_BGR565 = 0x36314742, - /** - * 24-bit RGB format, [23:0] R:G:B little endian - */ - WL_SHM_FORMAT_RGB888 = 0x34324752, - /** - * 24-bit BGR format, [23:0] B:G:R little endian - */ - WL_SHM_FORMAT_BGR888 = 0x34324742, - /** - * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian - */ - WL_SHM_FORMAT_XBGR8888 = 0x34324258, - /** - * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian - */ - WL_SHM_FORMAT_RGBX8888 = 0x34325852, - /** - * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian - */ - WL_SHM_FORMAT_BGRX8888 = 0x34325842, - /** - * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian - */ - WL_SHM_FORMAT_ABGR8888 = 0x34324241, - /** - * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian - */ - WL_SHM_FORMAT_RGBA8888 = 0x34324152, - /** - * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian - */ - WL_SHM_FORMAT_BGRA8888 = 0x34324142, - /** - * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian - */ - WL_SHM_FORMAT_XRGB2101010 = 0x30335258, - /** - * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian - */ - WL_SHM_FORMAT_XBGR2101010 = 0x30334258, - /** - * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian - */ - WL_SHM_FORMAT_RGBX1010102 = 0x30335852, - /** - * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian - */ - WL_SHM_FORMAT_BGRX1010102 = 0x30335842, - /** - * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian - */ - WL_SHM_FORMAT_ARGB2101010 = 0x30335241, - /** - * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian - */ - WL_SHM_FORMAT_ABGR2101010 = 0x30334241, - /** - * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian - */ - WL_SHM_FORMAT_RGBA1010102 = 0x30334152, - /** - * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian - */ - WL_SHM_FORMAT_BGRA1010102 = 0x30334142, - /** - * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian - */ - WL_SHM_FORMAT_YUYV = 0x56595559, - /** - * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian - */ - WL_SHM_FORMAT_YVYU = 0x55595659, - /** - * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian - */ - WL_SHM_FORMAT_UYVY = 0x59565955, - /** - * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian - */ - WL_SHM_FORMAT_VYUY = 0x59555956, - /** - * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian - */ - WL_SHM_FORMAT_AYUV = 0x56555941, - /** - * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane - */ - WL_SHM_FORMAT_NV12 = 0x3231564e, - /** - * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane - */ - WL_SHM_FORMAT_NV21 = 0x3132564e, - /** - * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane - */ - WL_SHM_FORMAT_NV16 = 0x3631564e, - /** - * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane - */ - WL_SHM_FORMAT_NV61 = 0x3136564e, - /** - * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV410 = 0x39565559, - /** - * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU410 = 0x39555659, - /** - * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV411 = 0x31315559, - /** - * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU411 = 0x31315659, - /** - * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV420 = 0x32315559, - /** - * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU420 = 0x32315659, - /** - * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV422 = 0x36315559, - /** - * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU422 = 0x36315659, - /** - * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes - */ - WL_SHM_FORMAT_YUV444 = 0x34325559, - /** - * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes - */ - WL_SHM_FORMAT_YVU444 = 0x34325659, - /** - * [7:0] R - */ - WL_SHM_FORMAT_R8 = 0x20203852, - /** - * [15:0] R little endian - */ - WL_SHM_FORMAT_R16 = 0x20363152, - /** - * [15:0] R:G 8:8 little endian - */ - WL_SHM_FORMAT_RG88 = 0x38384752, - /** - * [15:0] G:R 8:8 little endian - */ - WL_SHM_FORMAT_GR88 = 0x38385247, - /** - * [31:0] R:G 16:16 little endian - */ - WL_SHM_FORMAT_RG1616 = 0x32334752, - /** - * [31:0] G:R 16:16 little endian - */ - WL_SHM_FORMAT_GR1616 = 0x32335247, - /** - * [63:0] x:R:G:B 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XRGB16161616F = 0x48345258, - /** - * [63:0] x:B:G:R 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XBGR16161616F = 0x48344258, - /** - * [63:0] A:R:G:B 16:16:16:16 little endian - */ - WL_SHM_FORMAT_ARGB16161616F = 0x48345241, - /** - * [63:0] A:B:G:R 16:16:16:16 little endian - */ - WL_SHM_FORMAT_ABGR16161616F = 0x48344241, - /** - * [31:0] X:Y:Cb:Cr 8:8:8:8 little endian - */ - WL_SHM_FORMAT_XYUV8888 = 0x56555958, - /** - * [23:0] Cr:Cb:Y 8:8:8 little endian - */ - WL_SHM_FORMAT_VUY888 = 0x34325556, - /** - * Y followed by U then V, 10:10:10. Non-linear modifier only - */ - WL_SHM_FORMAT_VUY101010 = 0x30335556, - /** - * [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels - */ - WL_SHM_FORMAT_Y210 = 0x30313259, - /** - * [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels - */ - WL_SHM_FORMAT_Y212 = 0x32313259, - /** - * [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels - */ - WL_SHM_FORMAT_Y216 = 0x36313259, - /** - * [31:0] A:Cr:Y:Cb 2:10:10:10 little endian - */ - WL_SHM_FORMAT_Y410 = 0x30313459, - /** - * [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian - */ - WL_SHM_FORMAT_Y412 = 0x32313459, - /** - * [63:0] A:Cr:Y:Cb 16:16:16:16 little endian - */ - WL_SHM_FORMAT_Y416 = 0x36313459, - /** - * [31:0] X:Cr:Y:Cb 2:10:10:10 little endian - */ - WL_SHM_FORMAT_XVYU2101010 = 0x30335658, - /** - * [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian - */ - WL_SHM_FORMAT_XVYU12_16161616 = 0x36335658, - /** - * [63:0] X:Cr:Y:Cb 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XVYU16161616 = 0x38345658, - /** - * [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian - */ - WL_SHM_FORMAT_Y0L0 = 0x304c3059, - /** - * [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian - */ - WL_SHM_FORMAT_X0L0 = 0x304c3058, - /** - * [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian - */ - WL_SHM_FORMAT_Y0L2 = 0x324c3059, - /** - * [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian - */ - WL_SHM_FORMAT_X0L2 = 0x324c3058, - WL_SHM_FORMAT_YUV420_8BIT = 0x38305559, - WL_SHM_FORMAT_YUV420_10BIT = 0x30315559, - WL_SHM_FORMAT_XRGB8888_A8 = 0x38415258, - WL_SHM_FORMAT_XBGR8888_A8 = 0x38414258, - WL_SHM_FORMAT_RGBX8888_A8 = 0x38415852, - WL_SHM_FORMAT_BGRX8888_A8 = 0x38415842, - WL_SHM_FORMAT_RGB888_A8 = 0x38413852, - WL_SHM_FORMAT_BGR888_A8 = 0x38413842, - WL_SHM_FORMAT_RGB565_A8 = 0x38413552, - WL_SHM_FORMAT_BGR565_A8 = 0x38413542, - /** - * non-subsampled Cr:Cb plane - */ - WL_SHM_FORMAT_NV24 = 0x3432564e, - /** - * non-subsampled Cb:Cr plane - */ - WL_SHM_FORMAT_NV42 = 0x3234564e, - /** - * 2x1 subsampled Cr:Cb plane, 10 bit per channel - */ - WL_SHM_FORMAT_P210 = 0x30313250, - /** - * 2x2 subsampled Cr:Cb plane 10 bits per channel - */ - WL_SHM_FORMAT_P010 = 0x30313050, - /** - * 2x2 subsampled Cr:Cb plane 12 bits per channel - */ - WL_SHM_FORMAT_P012 = 0x32313050, - /** - * 2x2 subsampled Cr:Cb plane 16 bits per channel - */ - WL_SHM_FORMAT_P016 = 0x36313050, - /** - * [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian - */ - WL_SHM_FORMAT_AXBXGXRX106106106106 = 0x30314241, - /** - * 2x2 subsampled Cr:Cb plane - */ - WL_SHM_FORMAT_NV15 = 0x3531564e, - WL_SHM_FORMAT_Q410 = 0x30313451, - WL_SHM_FORMAT_Q401 = 0x31303451, - /** - * [63:0] x:R:G:B 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XRGB16161616 = 0x38345258, - /** - * [63:0] x:B:G:R 16:16:16:16 little endian - */ - WL_SHM_FORMAT_XBGR16161616 = 0x38344258, - /** - * [63:0] A:R:G:B 16:16:16:16 little endian - */ - WL_SHM_FORMAT_ARGB16161616 = 0x38345241, - /** - * [63:0] A:B:G:R 16:16:16:16 little endian - */ - WL_SHM_FORMAT_ABGR16161616 = 0x38344241, -}; -#endif /* WL_SHM_FORMAT_ENUM */ - -/** - * @ingroup iface_wl_shm - * @struct wl_shm_listener - */ -struct wl_shm_listener { - /** - * pixel format description - * - * Informs the client about a valid pixel format that can be used - * for buffers. Known formats include argb8888 and xrgb8888. - * @param format buffer pixel format - */ - void (*format)(void *data, - struct wl_shm *wl_shm, - uint32_t format); -}; - -/** - * @ingroup iface_wl_shm - */ -static inline int -wl_shm_add_listener(struct wl_shm *wl_shm, - const struct wl_shm_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_shm, - (void (**)(void)) listener, data); -} - -#define WL_SHM_CREATE_POOL 0 - -/** - * @ingroup iface_wl_shm - */ -#define WL_SHM_FORMAT_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_shm - */ -#define WL_SHM_CREATE_POOL_SINCE_VERSION 1 - -/** @ingroup iface_wl_shm */ -static inline void -wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data); -} - -/** @ingroup iface_wl_shm */ -static inline void * -wl_shm_get_user_data(struct wl_shm *wl_shm) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_shm); -} - -static inline uint32_t -wl_shm_get_version(struct wl_shm *wl_shm) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_shm); -} - -/** @ingroup iface_wl_shm */ -static inline void -wl_shm_destroy(struct wl_shm *wl_shm) -{ - wl_proxy_destroy((struct wl_proxy *) wl_shm); -} - -/** - * @ingroup iface_wl_shm - * - * Create a new wl_shm_pool object. - * - * The pool can be used to create shared memory based buffer - * objects. The server will mmap size bytes of the passed file - * descriptor, to use as backing memory for the pool. - */ -static inline struct wl_shm_pool * -wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm, - WL_SHM_CREATE_POOL, &wl_shm_pool_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm), 0, NULL, fd, size); - - return (struct wl_shm_pool *) id; -} - -/** - * @ingroup iface_wl_buffer - * @struct wl_buffer_listener - */ -struct wl_buffer_listener { - /** - * compositor releases buffer - * - * Sent when this wl_buffer is no longer used by the compositor. - * The client is now free to reuse or destroy this buffer and its - * backing storage. - * - * If a client receives a release event before the frame callback - * requested in the same wl_surface.commit that attaches this - * wl_buffer to a surface, then the client is immediately free to - * reuse the buffer and its backing storage, and does not need a - * second buffer for the next surface content update. Typically - * this is possible, when the compositor maintains a copy of the - * wl_surface contents, e.g. as a GL texture. This is an important - * optimization for GL(ES) compositors with wl_shm clients. - */ - void (*release)(void *data, - struct wl_buffer *wl_buffer); -}; - -/** - * @ingroup iface_wl_buffer - */ -static inline int -wl_buffer_add_listener(struct wl_buffer *wl_buffer, - const struct wl_buffer_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_buffer, - (void (**)(void)) listener, data); -} - -#define WL_BUFFER_DESTROY 0 - -/** - * @ingroup iface_wl_buffer - */ -#define WL_BUFFER_RELEASE_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_buffer - */ -#define WL_BUFFER_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_wl_buffer */ -static inline void -wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data); -} - -/** @ingroup iface_wl_buffer */ -static inline void * -wl_buffer_get_user_data(struct wl_buffer *wl_buffer) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer); -} - -static inline uint32_t -wl_buffer_get_version(struct wl_buffer *wl_buffer) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_buffer); -} - -/** - * @ingroup iface_wl_buffer - * - * Destroy a buffer. If and how you need to release the backing - * storage is defined by the buffer factory interface. - * - * For possible side-effects to a surface, see wl_surface.attach. - */ -static inline void -wl_buffer_destroy(struct wl_buffer *wl_buffer) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_buffer, - WL_BUFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_DATA_OFFER_ERROR_ENUM -#define WL_DATA_OFFER_ERROR_ENUM -enum wl_data_offer_error { - /** - * finish request was called untimely - */ - WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, - /** - * action mask contains invalid values - */ - WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, - /** - * action argument has an invalid value - */ - WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, - /** - * offer doesn't accept this request - */ - WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, -}; -#endif /* WL_DATA_OFFER_ERROR_ENUM */ - -/** - * @ingroup iface_wl_data_offer - * @struct wl_data_offer_listener - */ -struct wl_data_offer_listener { - /** - * advertise offered mime type - * - * Sent immediately after creating the wl_data_offer object. One - * event per offered mime type. - * @param mime_type offered mime type - */ - void (*offer)(void *data, - struct wl_data_offer *wl_data_offer, - const char *mime_type); - /** - * notify the source-side available actions - * - * This event indicates the actions offered by the data source. - * It will be sent immediately after creating the wl_data_offer - * object, or anytime the source side changes its offered actions - * through wl_data_source.set_actions. - * @param source_actions actions offered by the data source - * @since 3 - */ - void (*source_actions)(void *data, - struct wl_data_offer *wl_data_offer, - uint32_t source_actions); - /** - * notify the selected action - * - * This event indicates the action selected by the compositor - * after matching the source/destination side actions. Only one - * action (or none) will be offered here. - * - * This event can be emitted multiple times during the - * drag-and-drop operation in response to destination side action - * changes through wl_data_offer.set_actions. - * - * This event will no longer be emitted after wl_data_device.drop - * happened on the drag-and-drop destination, the client must honor - * the last action received, or the last preferred one set through - * wl_data_offer.set_actions when handling an "ask" action. - * - * Compositors may also change the selected action on the fly, - * mainly in response to keyboard modifier changes during the - * drag-and-drop operation. - * - * The most recent action received is always the valid one. Prior - * to receiving wl_data_device.drop, the chosen action may change - * (e.g. due to keyboard modifiers being pressed). At the time of - * receiving wl_data_device.drop the drag-and-drop destination must - * honor the last action received. - * - * Action changes may still happen after wl_data_device.drop, - * especially on "ask" actions, where the drag-and-drop destination - * may choose another action afterwards. Action changes happening - * at this stage are always the result of inter-client negotiation, - * the compositor shall no longer be able to induce a different - * action. - * - * Upon "ask" actions, it is expected that the drag-and-drop - * destination may potentially choose a different action and/or - * mime type, based on wl_data_offer.source_actions and finally - * chosen by the user (e.g. popping up a menu with the available - * options). The final wl_data_offer.set_actions and - * wl_data_offer.accept requests must happen before the call to - * wl_data_offer.finish. - * @param dnd_action action selected by the compositor - * @since 3 - */ - void (*action)(void *data, - struct wl_data_offer *wl_data_offer, - uint32_t dnd_action); -}; - -/** - * @ingroup iface_wl_data_offer - */ -static inline int -wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer, - const struct wl_data_offer_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer, - (void (**)(void)) listener, data); -} - -#define WL_DATA_OFFER_ACCEPT 0 -#define WL_DATA_OFFER_RECEIVE 1 -#define WL_DATA_OFFER_DESTROY 2 -#define WL_DATA_OFFER_FINISH 3 -#define WL_DATA_OFFER_SET_ACTIONS 4 - -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_OFFER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_ACTION_SINCE_VERSION 3 - -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_FINISH_SINCE_VERSION 3 -/** - * @ingroup iface_wl_data_offer - */ -#define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3 - -/** @ingroup iface_wl_data_offer */ -static inline void -wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data); -} - -/** @ingroup iface_wl_data_offer */ -static inline void * -wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer); -} - -static inline uint32_t -wl_data_offer_get_version(struct wl_data_offer *wl_data_offer) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_data_offer); -} - -/** - * @ingroup iface_wl_data_offer - * - * Indicate that the client can accept the given mime type, or - * NULL for not accepted. - * - * For objects of version 2 or older, this request is used by the - * client to give feedback whether the client can receive the given - * mime type, or NULL if none is accepted; the feedback does not - * determine whether the drag-and-drop operation succeeds or not. - * - * For objects of version 3 or newer, this request determines the - * final result of the drag-and-drop operation. If the end result - * is that no mime types were accepted, the drag-and-drop operation - * will be cancelled and the corresponding drag source will receive - * wl_data_source.cancelled. Clients may still use this event in - * conjunction with wl_data_source.action for feedback. - */ -static inline void -wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_ACCEPT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, serial, mime_type); -} - -/** - * @ingroup iface_wl_data_offer - * - * To transfer the offered data, the client issues this request - * and indicates the mime type it wants to receive. The transfer - * happens through the passed file descriptor (typically created - * with the pipe system call). The source client writes the data - * in the mime type representation requested and then closes the - * file descriptor. - * - * The receiving client reads from the read end of the pipe until - * EOF and then closes its end, at which point the transfer is - * complete. - * - * This request may happen multiple times for different mime types, - * both before and after wl_data_device.drop. Drag-and-drop destination - * clients may preemptively fetch data or examine it more closely to - * determine acceptance. - */ -static inline void -wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, mime_type, fd); -} - -/** - * @ingroup iface_wl_data_offer - * - * Destroy the data offer. - */ -static inline void -wl_data_offer_destroy(struct wl_data_offer *wl_data_offer) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_data_offer - * - * Notifies the compositor that the drag destination successfully - * finished the drag-and-drop operation. - * - * Upon receiving this request, the compositor will emit - * wl_data_source.dnd_finished on the drag source client. - * - * It is a client error to perform other requests than - * wl_data_offer.destroy after this one. It is also an error to perform - * this request after a NULL mime type has been set in - * wl_data_offer.accept or no action was received through - * wl_data_offer.action. - * - * If wl_data_offer.finish request is received for a non drag and drop - * operation, the invalid_finish protocol error is raised. - */ -static inline void -wl_data_offer_finish(struct wl_data_offer *wl_data_offer) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_FINISH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0); -} - -/** - * @ingroup iface_wl_data_offer - * - * Sets the actions that the destination side client supports for - * this operation. This request may trigger the emission of - * wl_data_source.action and wl_data_offer.action events if the compositor - * needs to change the selected action. - * - * This request can be called multiple times throughout the - * drag-and-drop operation, typically in response to wl_data_device.enter - * or wl_data_device.motion events. - * - * This request determines the final result of the drag-and-drop - * operation. If the end result is that no action is accepted, - * the drag source will receive wl_data_source.cancelled. - * - * The dnd_actions argument must contain only values expressed in the - * wl_data_device_manager.dnd_actions enum, and the preferred_action - * argument must only contain one of those values set, otherwise it - * will result in a protocol error. - * - * While managing an "ask" action, the destination drag-and-drop client - * may perform further wl_data_offer.receive requests, and is expected - * to perform one last wl_data_offer.set_actions request with a preferred - * action other than "ask" (and optionally wl_data_offer.accept) before - * requesting wl_data_offer.finish, in order to convey the action selected - * by the user. If the preferred action is not in the - * wl_data_offer.source_actions mask, an error will be raised. - * - * If the "ask" action is dismissed (e.g. user cancellation), the client - * is expected to perform wl_data_offer.destroy right away. - * - * This request can only be made on drag-and-drop offers, a protocol error - * will be raised otherwise. - */ -static inline void -wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, - WL_DATA_OFFER_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, dnd_actions, preferred_action); -} - -#ifndef WL_DATA_SOURCE_ERROR_ENUM -#define WL_DATA_SOURCE_ERROR_ENUM -enum wl_data_source_error { - /** - * action mask contains invalid values - */ - WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, - /** - * source doesn't accept this request - */ - WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, -}; -#endif /* WL_DATA_SOURCE_ERROR_ENUM */ - -/** - * @ingroup iface_wl_data_source - * @struct wl_data_source_listener - */ -struct wl_data_source_listener { - /** - * a target accepts an offered mime type - * - * Sent when a target accepts pointer_focus or motion events. If - * a target does not accept any of the offered types, type is NULL. - * - * Used for feedback during drag-and-drop. - * @param mime_type mime type accepted by the target - */ - void (*target)(void *data, - struct wl_data_source *wl_data_source, - const char *mime_type); - /** - * send the data - * - * Request for data from the client. Send the data as the - * specified mime type over the passed file descriptor, then close - * it. - * @param mime_type mime type for the data - * @param fd file descriptor for the data - */ - void (*send)(void *data, - struct wl_data_source *wl_data_source, - const char *mime_type, - int32_t fd); - /** - * selection was cancelled - * - * This data source is no longer valid. There are several reasons - * why this could happen: - * - * - The data source has been replaced by another data source. - - * The drag-and-drop operation was performed, but the drop - * destination did not accept any of the mime types offered through - * wl_data_source.target. - The drag-and-drop operation was - * performed, but the drop destination did not select any of the - * actions present in the mask offered through - * wl_data_source.action. - The drag-and-drop operation was - * performed but didn't happen over a surface. - The compositor - * cancelled the drag-and-drop operation (e.g. compositor dependent - * timeouts to avoid stale drag-and-drop transfers). - * - * The client should clean up and destroy this data source. - * - * For objects of version 2 or older, wl_data_source.cancelled will - * only be emitted if the data source was replaced by another data - * source. - */ - void (*cancelled)(void *data, - struct wl_data_source *wl_data_source); - /** - * the drag-and-drop operation physically finished - * - * The user performed the drop action. This event does not - * indicate acceptance, wl_data_source.cancelled may still be - * emitted afterwards if the drop destination does not accept any - * mime type. - * - * However, this event might however not be received if the - * compositor cancelled the drag-and-drop operation before this - * event could happen. - * - * Note that the data_source may still be used in the future and - * should not be destroyed here. - * @since 3 - */ - void (*dnd_drop_performed)(void *data, - struct wl_data_source *wl_data_source); - /** - * the drag-and-drop operation concluded - * - * The drop destination finished interoperating with this data - * source, so the client is now free to destroy this data source - * and free all associated data. - * - * If the action used to perform the operation was "move", the - * source can now delete the transferred data. - * @since 3 - */ - void (*dnd_finished)(void *data, - struct wl_data_source *wl_data_source); - /** - * notify the selected action - * - * This event indicates the action selected by the compositor - * after matching the source/destination side actions. Only one - * action (or none) will be offered here. - * - * This event can be emitted multiple times during the - * drag-and-drop operation, mainly in response to destination side - * changes through wl_data_offer.set_actions, and as the data - * device enters/leaves surfaces. - * - * It is only possible to receive this event after - * wl_data_source.dnd_drop_performed if the drag-and-drop operation - * ended in an "ask" action, in which case the final - * wl_data_source.action event will happen immediately before - * wl_data_source.dnd_finished. - * - * Compositors may also change the selected action on the fly, - * mainly in response to keyboard modifier changes during the - * drag-and-drop operation. - * - * The most recent action received is always the valid one. The - * chosen action may change alongside negotiation (e.g. an "ask" - * action can turn into a "move" operation), so the effects of the - * final action must always be applied in - * wl_data_offer.dnd_finished. - * - * Clients can trigger cursor surface changes from this point, so - * they reflect the current action. - * @param dnd_action action selected by the compositor - * @since 3 - */ - void (*action)(void *data, - struct wl_data_source *wl_data_source, - uint32_t dnd_action); -}; - -/** - * @ingroup iface_wl_data_source - */ -static inline int -wl_data_source_add_listener(struct wl_data_source *wl_data_source, - const struct wl_data_source_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_data_source, - (void (**)(void)) listener, data); -} - -#define WL_DATA_SOURCE_OFFER 0 -#define WL_DATA_SOURCE_DESTROY 1 -#define WL_DATA_SOURCE_SET_ACTIONS 2 - -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_SEND_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3 - -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_source - */ -#define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3 - -/** @ingroup iface_wl_data_source */ -static inline void -wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data); -} - -/** @ingroup iface_wl_data_source */ -static inline void * -wl_data_source_get_user_data(struct wl_data_source *wl_data_source) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source); -} - -static inline uint32_t -wl_data_source_get_version(struct wl_data_source *wl_data_source) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_data_source); -} - -/** - * @ingroup iface_wl_data_source - * - * This request adds a mime type to the set of mime types - * advertised to targets. Can be called several times to offer - * multiple types. - */ -static inline void -wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, mime_type); -} - -/** - * @ingroup iface_wl_data_source - * - * Destroy the data source. - */ -static inline void -wl_data_source_destroy(struct wl_data_source *wl_data_source) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_data_source - * - * Sets the actions that the source side client supports for this - * operation. This request may trigger wl_data_source.action and - * wl_data_offer.action events if the compositor needs to change the - * selected action. - * - * The dnd_actions argument must contain only values expressed in the - * wl_data_device_manager.dnd_actions enum, otherwise it will result - * in a protocol error. - * - * This request must be made once only, and can only be made on sources - * used in drag-and-drop, so it must be performed before - * wl_data_device.start_drag. Attempting to use the source other than - * for drag-and-drop will raise a protocol error. - */ -static inline void -wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, - WL_DATA_SOURCE_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, dnd_actions); -} - -#ifndef WL_DATA_DEVICE_ERROR_ENUM -#define WL_DATA_DEVICE_ERROR_ENUM -enum wl_data_device_error { - /** - * given wl_surface has another role - */ - WL_DATA_DEVICE_ERROR_ROLE = 0, -}; -#endif /* WL_DATA_DEVICE_ERROR_ENUM */ - -/** - * @ingroup iface_wl_data_device - * @struct wl_data_device_listener - */ -struct wl_data_device_listener { - /** - * introduce a new wl_data_offer - * - * The data_offer event introduces a new wl_data_offer object, - * which will subsequently be used in either the data_device.enter - * event (for drag-and-drop) or the data_device.selection event - * (for selections). Immediately following the - * data_device.data_offer event, the new data_offer object will - * send out data_offer.offer events to describe the mime types it - * offers. - * @param id the new data_offer object - */ - void (*data_offer)(void *data, - struct wl_data_device *wl_data_device, - struct wl_data_offer *id); - /** - * initiate drag-and-drop session - * - * This event is sent when an active drag-and-drop pointer enters - * a surface owned by the client. The position of the pointer at - * enter time is provided by the x and y arguments, in - * surface-local coordinates. - * @param serial serial number of the enter event - * @param surface client surface entered - * @param x surface-local x coordinate - * @param y surface-local y coordinate - * @param id source data_offer object - */ - void (*enter)(void *data, - struct wl_data_device *wl_data_device, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t x, - wl_fixed_t y, - struct wl_data_offer *id); - /** - * end drag-and-drop session - * - * This event is sent when the drag-and-drop pointer leaves the - * surface and the session ends. The client must destroy the - * wl_data_offer introduced at enter time at this point. - */ - void (*leave)(void *data, - struct wl_data_device *wl_data_device); - /** - * drag-and-drop session motion - * - * This event is sent when the drag-and-drop pointer moves within - * the currently focused surface. The new position of the pointer - * is provided by the x and y arguments, in surface-local - * coordinates. - * @param time timestamp with millisecond granularity - * @param x surface-local x coordinate - * @param y surface-local y coordinate - */ - void (*motion)(void *data, - struct wl_data_device *wl_data_device, - uint32_t time, - wl_fixed_t x, - wl_fixed_t y); - /** - * end drag-and-drop session successfully - * - * The event is sent when a drag-and-drop operation is ended - * because the implicit grab is removed. - * - * The drag-and-drop destination is expected to honor the last - * action received through wl_data_offer.action, if the resulting - * action is "copy" or "move", the destination can still perform - * wl_data_offer.receive requests, and is expected to end all - * transfers with a wl_data_offer.finish request. - * - * If the resulting action is "ask", the action will not be - * considered final. The drag-and-drop destination is expected to - * perform one last wl_data_offer.set_actions request, or - * wl_data_offer.destroy in order to cancel the operation. - */ - void (*drop)(void *data, - struct wl_data_device *wl_data_device); - /** - * advertise new selection - * - * The selection event is sent out to notify the client of a new - * wl_data_offer for the selection for this device. The - * data_device.data_offer and the data_offer.offer events are sent - * out immediately before this event to introduce the data offer - * object. The selection event is sent to a client immediately - * before receiving keyboard focus and when a new selection is set - * while the client has keyboard focus. The data_offer is valid - * until a new data_offer or NULL is received or until the client - * loses keyboard focus. Switching surface with keyboard focus - * within the same client doesn't mean a new selection will be - * sent. The client must destroy the previous selection data_offer, - * if any, upon receiving this event. - * @param id selection data_offer object - */ - void (*selection)(void *data, - struct wl_data_device *wl_data_device, - struct wl_data_offer *id); -}; - -/** - * @ingroup iface_wl_data_device - */ -static inline int -wl_data_device_add_listener(struct wl_data_device *wl_data_device, - const struct wl_data_device_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_data_device, - (void (**)(void)) listener, data); -} - -#define WL_DATA_DEVICE_START_DRAG 0 -#define WL_DATA_DEVICE_SET_SELECTION 1 -#define WL_DATA_DEVICE_RELEASE 2 - -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_DROP_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device - */ -#define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2 - -/** @ingroup iface_wl_data_device */ -static inline void -wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data); -} - -/** @ingroup iface_wl_data_device */ -static inline void * -wl_data_device_get_user_data(struct wl_data_device *wl_data_device) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device); -} - -static inline uint32_t -wl_data_device_get_version(struct wl_data_device *wl_data_device) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_data_device); -} - -/** @ingroup iface_wl_data_device */ -static inline void -wl_data_device_destroy(struct wl_data_device *wl_data_device) -{ - wl_proxy_destroy((struct wl_proxy *) wl_data_device); -} - -/** - * @ingroup iface_wl_data_device - * - * This request asks the compositor to start a drag-and-drop - * operation on behalf of the client. - * - * The source argument is the data source that provides the data - * for the eventual data transfer. If source is NULL, enter, leave - * and motion events are sent only to the client that initiated the - * drag and the client is expected to handle the data passing - * internally. If source is destroyed, the drag-and-drop session will be - * cancelled. - * - * The origin surface is the surface where the drag originates and - * the client must have an active implicit grab that matches the - * serial. - * - * The icon surface is an optional (can be NULL) surface that - * provides an icon to be moved around with the cursor. Initially, - * the top-left corner of the icon surface is placed at the cursor - * hotspot, but subsequent wl_surface.attach request can move the - * relative position. Attach requests must be confirmed with - * wl_surface.commit as usual. The icon surface is given the role of - * a drag-and-drop icon. If the icon surface already has another role, - * it raises a protocol error. - * - * The input region is ignored for wl_surfaces with the role of a - * drag-and-drop icon. - */ -static inline void -wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_START_DRAG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, origin, icon, serial); -} - -/** - * @ingroup iface_wl_data_device - * - * This request asks the compositor to set the selection - * to the data from the source on behalf of the client. - * - * To unset the selection, set the source to NULL. - */ -static inline void -wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, serial); -} - -/** - * @ingroup iface_wl_data_device - * - * This request destroys the data device. - */ -static inline void -wl_data_device_release(struct wl_data_device *wl_data_device) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, - WL_DATA_DEVICE_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM -#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM -/** - * @ingroup iface_wl_data_device_manager - * drag and drop actions - * - * This is a bitmask of the available/preferred actions in a - * drag-and-drop operation. - * - * In the compositor, the selected action is a result of matching the - * actions offered by the source and destination sides. "action" events - * with a "none" action will be sent to both source and destination if - * there is no match. All further checks will effectively happen on - * (source actions ∩ destination actions). - * - * In addition, compositors may also pick different actions in - * reaction to key modifiers being pressed. One common design that - * is used in major toolkits (and the behavior recommended for - * compositors) is: - * - * - If no modifiers are pressed, the first match (in bit order) - * will be used. - * - Pressing Shift selects "move", if enabled in the mask. - * - Pressing Control selects "copy", if enabled in the mask. - * - * Behavior beyond that is considered implementation-dependent. - * Compositors may for example bind other modifiers (like Alt/Meta) - * or drags initiated with other buttons than BTN_LEFT to specific - * actions (e.g. "ask"). - */ -enum wl_data_device_manager_dnd_action { - /** - * no action - */ - WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, - /** - * copy action - */ - WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, - /** - * move action - */ - WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, - /** - * ask action - */ - WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, -}; -#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ - -#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0 -#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1 - - -/** - * @ingroup iface_wl_data_device_manager - */ -#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_data_device_manager - */ -#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1 - -/** @ingroup iface_wl_data_device_manager */ -static inline void -wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data); -} - -/** @ingroup iface_wl_data_device_manager */ -static inline void * -wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager); -} - -static inline uint32_t -wl_data_device_manager_get_version(struct wl_data_device_manager *wl_data_device_manager) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager); -} - -/** @ingroup iface_wl_data_device_manager */ -static inline void -wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager) -{ - wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager); -} - -/** - * @ingroup iface_wl_data_device_manager - * - * Create a new data source. - */ -static inline struct wl_data_source * -wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, - WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL); - - return (struct wl_data_source *) id; -} - -/** - * @ingroup iface_wl_data_device_manager - * - * Create a new data device for a given seat. - */ -static inline struct wl_data_device * -wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, - WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL, seat); - - return (struct wl_data_device *) id; -} - -#ifndef WL_SHELL_ERROR_ENUM -#define WL_SHELL_ERROR_ENUM -enum wl_shell_error { - /** - * given wl_surface has another role - */ - WL_SHELL_ERROR_ROLE = 0, -}; -#endif /* WL_SHELL_ERROR_ENUM */ - -#define WL_SHELL_GET_SHELL_SURFACE 0 - - -/** - * @ingroup iface_wl_shell - */ -#define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1 - -/** @ingroup iface_wl_shell */ -static inline void -wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data); -} - -/** @ingroup iface_wl_shell */ -static inline void * -wl_shell_get_user_data(struct wl_shell *wl_shell) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_shell); -} - -static inline uint32_t -wl_shell_get_version(struct wl_shell *wl_shell) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_shell); -} - -/** @ingroup iface_wl_shell */ -static inline void -wl_shell_destroy(struct wl_shell *wl_shell) -{ - wl_proxy_destroy((struct wl_proxy *) wl_shell); -} - -/** - * @ingroup iface_wl_shell - * - * Create a shell surface for an existing surface. This gives - * the wl_surface the role of a shell surface. If the wl_surface - * already has another role, it raises a protocol error. - * - * Only one shell surface can be associated with a given surface. - */ -static inline struct wl_shell_surface * -wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shell, - WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_shell), 0, NULL, surface); - - return (struct wl_shell_surface *) id; -} - -#ifndef WL_SHELL_SURFACE_RESIZE_ENUM -#define WL_SHELL_SURFACE_RESIZE_ENUM -/** - * @ingroup iface_wl_shell_surface - * edge values for resizing - * - * These values are used to indicate which edge of a surface - * is being dragged in a resize operation. The server may - * use this information to adapt its behavior, e.g. choose - * an appropriate cursor image. - */ -enum wl_shell_surface_resize { - /** - * no edge - */ - WL_SHELL_SURFACE_RESIZE_NONE = 0, - /** - * top edge - */ - WL_SHELL_SURFACE_RESIZE_TOP = 1, - /** - * bottom edge - */ - WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, - /** - * left edge - */ - WL_SHELL_SURFACE_RESIZE_LEFT = 4, - /** - * top and left edges - */ - WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, - /** - * bottom and left edges - */ - WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, - /** - * right edge - */ - WL_SHELL_SURFACE_RESIZE_RIGHT = 8, - /** - * top and right edges - */ - WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, - /** - * bottom and right edges - */ - WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, -}; -#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ - -#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM -#define WL_SHELL_SURFACE_TRANSIENT_ENUM -/** - * @ingroup iface_wl_shell_surface - * details of transient behaviour - * - * These flags specify details of the expected behaviour - * of transient surfaces. Used in the set_transient request. - */ -enum wl_shell_surface_transient { - /** - * do not set keyboard focus - */ - WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, -}; -#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ - -#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM -#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM -/** - * @ingroup iface_wl_shell_surface - * different method to set the surface fullscreen - * - * Hints to indicate to the compositor how to deal with a conflict - * between the dimensions of the surface and the dimensions of the - * output. The compositor is free to ignore this parameter. - */ -enum wl_shell_surface_fullscreen_method { - /** - * no preference, apply default policy - */ - WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, - /** - * scale, preserve the surface's aspect ratio and center on output - */ - WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, - /** - * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch - */ - WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, - /** - * no upscaling, center on output and add black borders to compensate size mismatch - */ - WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, -}; -#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ - -/** - * @ingroup iface_wl_shell_surface - * @struct wl_shell_surface_listener - */ -struct wl_shell_surface_listener { - /** - * ping client - * - * Ping a client to check if it is receiving events and sending - * requests. A client is expected to reply with a pong request. - * @param serial serial number of the ping - */ - void (*ping)(void *data, - struct wl_shell_surface *wl_shell_surface, - uint32_t serial); - /** - * suggest resize - * - * The configure event asks the client to resize its surface. - * - * The size is a hint, in the sense that the client is free to - * ignore it if it doesn't resize, pick a smaller size (to satisfy - * aspect ratio or resize in steps of NxM pixels). - * - * The edges parameter provides a hint about how the surface was - * resized. The client may use this information to decide how to - * adjust its content to the new size (e.g. a scrolling area might - * adjust its content position to leave the viewable content - * unmoved). - * - * The client is free to dismiss all but the last configure event - * it received. - * - * The width and height arguments specify the size of the window in - * surface-local coordinates. - * @param edges how the surface was resized - * @param width new width of the surface - * @param height new height of the surface - */ - void (*configure)(void *data, - struct wl_shell_surface *wl_shell_surface, - uint32_t edges, - int32_t width, - int32_t height); - /** - * popup interaction is done - * - * The popup_done event is sent out when a popup grab is broken, - * that is, when the user clicks a surface that doesn't belong to - * the client owning the popup surface. - */ - void (*popup_done)(void *data, - struct wl_shell_surface *wl_shell_surface); -}; - -/** - * @ingroup iface_wl_shell_surface - */ -static inline int -wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface, - const struct wl_shell_surface_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface, - (void (**)(void)) listener, data); -} - -#define WL_SHELL_SURFACE_PONG 0 -#define WL_SHELL_SURFACE_MOVE 1 -#define WL_SHELL_SURFACE_RESIZE 2 -#define WL_SHELL_SURFACE_SET_TOPLEVEL 3 -#define WL_SHELL_SURFACE_SET_TRANSIENT 4 -#define WL_SHELL_SURFACE_SET_FULLSCREEN 5 -#define WL_SHELL_SURFACE_SET_POPUP 6 -#define WL_SHELL_SURFACE_SET_MAXIMIZED 7 -#define WL_SHELL_SURFACE_SET_TITLE 8 -#define WL_SHELL_SURFACE_SET_CLASS 9 - -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_PING_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1 - -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_shell_surface - */ -#define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1 - -/** @ingroup iface_wl_shell_surface */ -static inline void -wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data); -} - -/** @ingroup iface_wl_shell_surface */ -static inline void * -wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface); -} - -static inline uint32_t -wl_shell_surface_get_version(struct wl_shell_surface *wl_shell_surface) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_shell_surface); -} - -/** @ingroup iface_wl_shell_surface */ -static inline void -wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface) -{ - wl_proxy_destroy((struct wl_proxy *) wl_shell_surface); -} - -/** - * @ingroup iface_wl_shell_surface - * - * A client must respond to a ping event with a pong request or - * the client may be deemed unresponsive. - */ -static inline void -wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, serial); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Start a pointer-driven move of the surface. - * - * This request must be used in response to a button press event. - * The server may ignore move requests depending on the state of - * the surface (e.g. fullscreen or maximized). - */ -static inline void -wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Start a pointer-driven resizing of the surface. - * - * This request must be used in response to a button press event. - * The server may ignore resize requests depending on the state of - * the surface (e.g. fullscreen or maximized). - */ -static inline void -wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, edges); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface as a toplevel surface. - * - * A toplevel surface is not fullscreen, maximized or transient. - */ -static inline void -wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TOPLEVEL, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface relative to an existing surface. - * - * The x and y arguments specify the location of the upper left - * corner of the surface relative to the upper left corner of the - * parent surface, in surface-local coordinates. - * - * The flags argument controls details of the transient behaviour. - */ -static inline void -wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TRANSIENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, parent, x, y, flags); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface as a fullscreen surface. - * - * If an output parameter is given then the surface will be made - * fullscreen on that output. If the client does not specify the - * output then the compositor will apply its policy - usually - * choosing the output on which the surface has the biggest surface - * area. - * - * The client may specify a method to resolve a size conflict - * between the output size and the surface size - this is provided - * through the method parameter. - * - * The framerate parameter is used only when the method is set - * to "driver", to indicate the preferred framerate. A value of 0 - * indicates that the client does not care about framerate. The - * framerate is specified in mHz, that is framerate of 60000 is 60Hz. - * - * A method of "scale" or "driver" implies a scaling operation of - * the surface, either via a direct scaling operation or a change of - * the output mode. This will override any kind of output scaling, so - * that mapping a surface with a buffer size equal to the mode can - * fill the screen independent of buffer_scale. - * - * A method of "fill" means we don't scale up the buffer, however - * any output scale is applied. This means that you may run into - * an edge case where the application maps a buffer with the same - * size of the output mode but buffer_scale 1 (thus making a - * surface larger than the output). In this case it is allowed to - * downscale the results to fit the screen. - * - * The compositor must reply to this request with a configure event - * with the dimensions for the output on which the surface will - * be made fullscreen. - */ -static inline void -wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, method, framerate, output); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface as a popup. - * - * A popup surface is a transient surface with an added pointer - * grab. - * - * An existing implicit grab will be changed to owner-events mode, - * and the popup grab will continue after the implicit grab ends - * (i.e. releasing the mouse button does not cause the popup to - * be unmapped). - * - * The popup grab continues until the window is destroyed or a - * mouse button is pressed in any other client's window. A click - * in any of the client's surfaces is reported as normal, however, - * clicks in other clients' surfaces will be discarded and trigger - * the callback. - * - * The x and y arguments specify the location of the upper left - * corner of the surface relative to the upper left corner of the - * parent surface, in surface-local coordinates. - */ -static inline void -wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, parent, x, y, flags); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Map the surface as a maximized surface. - * - * If an output parameter is given then the surface will be - * maximized on that output. If the client does not specify the - * output then the compositor will apply its policy - usually - * choosing the output on which the surface has the biggest surface - * area. - * - * The compositor will reply with a configure event telling - * the expected new surface size. The operation is completed - * on the next buffer attach to this surface. - * - * A maximized surface typically fills the entire output it is - * bound to, except for desktop elements such as panels. This is - * the main difference between a maximized shell surface and a - * fullscreen shell surface. - * - * The details depend on the compositor implementation. - */ -static inline void -wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, output); -} - -/** - * @ingroup iface_wl_shell_surface - * - * 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 -wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, title); -} - -/** - * @ingroup iface_wl_shell_surface - * - * Set a class for the surface. - * - * The surface class identifies the general class of applications - * to which the surface belongs. A common convention is to use the - * file name (or the full path if it is a non-standard location) of - * the application's .desktop file as the class. - */ -static inline void -wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, - WL_SHELL_SURFACE_SET_CLASS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, class_); -} - -#ifndef WL_SURFACE_ERROR_ENUM -#define WL_SURFACE_ERROR_ENUM -/** - * @ingroup iface_wl_surface - * wl_surface error values - * - * These errors can be emitted in response to wl_surface requests. - */ -enum wl_surface_error { - /** - * buffer scale value is invalid - */ - WL_SURFACE_ERROR_INVALID_SCALE = 0, - /** - * buffer transform value is invalid - */ - WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, - /** - * buffer size is invalid - */ - WL_SURFACE_ERROR_INVALID_SIZE = 2, - /** - * buffer offset is invalid - */ - WL_SURFACE_ERROR_INVALID_OFFSET = 3, - /** - * surface was destroyed before its role object - */ - WL_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 4, -}; -#endif /* WL_SURFACE_ERROR_ENUM */ - -/** - * @ingroup iface_wl_surface - * @struct wl_surface_listener - */ -struct wl_surface_listener { - /** - * surface enters an output - * - * This is emitted whenever a surface's creation, movement, or - * resizing results in some part of it being within the scanout - * region of an output. - * - * Note that a surface may be overlapping with zero or more - * outputs. - * @param output output entered by the surface - */ - void (*enter)(void *data, - struct wl_surface *wl_surface, - struct wl_output *output); - /** - * surface leaves an output - * - * This is emitted whenever a surface's creation, movement, or - * resizing results in it no longer having any part of it within - * the scanout region of an output. - * - * Clients should not use the number of outputs the surface is on - * for frame throttling purposes. The surface might be hidden even - * if no leave event has been sent, and the compositor might expect - * new surface content updates even if no enter event has been - * sent. The frame event should be used instead. - * @param output output left by the surface - */ - void (*leave)(void *data, - struct wl_surface *wl_surface, - struct wl_output *output); - /** - * preferred buffer scale for the surface - * - * This event indicates the preferred buffer scale for this - * surface. It is sent whenever the compositor's preference - * changes. - * - * It is intended that scaling aware clients use this event to - * scale their content and use wl_surface.set_buffer_scale to - * indicate the scale they have rendered with. This allows clients - * to supply a higher detail buffer. - * @param factor preferred scaling factor - * @since 6 - */ - void (*preferred_buffer_scale)(void *data, - struct wl_surface *wl_surface, - int32_t factor); - /** - * preferred buffer transform for the surface - * - * This event indicates the preferred buffer transform for this - * surface. It is sent whenever the compositor's preference - * changes. - * - * It is intended that transform aware clients use this event to - * apply the transform to their content and use - * wl_surface.set_buffer_transform to indicate the transform they - * have rendered with. - * @param transform preferred transform - * @since 6 - */ - void (*preferred_buffer_transform)(void *data, - struct wl_surface *wl_surface, - uint32_t transform); -}; - -/** - * @ingroup iface_wl_surface - */ -static inline int -wl_surface_add_listener(struct wl_surface *wl_surface, - const struct wl_surface_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_surface, - (void (**)(void)) listener, data); -} - -#define WL_SURFACE_DESTROY 0 -#define WL_SURFACE_ATTACH 1 -#define WL_SURFACE_DAMAGE 2 -#define WL_SURFACE_FRAME 3 -#define WL_SURFACE_SET_OPAQUE_REGION 4 -#define WL_SURFACE_SET_INPUT_REGION 5 -#define WL_SURFACE_COMMIT 6 -#define WL_SURFACE_SET_BUFFER_TRANSFORM 7 -#define WL_SURFACE_SET_BUFFER_SCALE 8 -#define WL_SURFACE_DAMAGE_BUFFER 9 -#define WL_SURFACE_OFFSET 10 - -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_ENTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_LEAVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION 6 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION 6 - -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_ATTACH_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_DAMAGE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_FRAME_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_COMMIT_SINCE_VERSION 1 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4 -/** - * @ingroup iface_wl_surface - */ -#define WL_SURFACE_OFFSET_SINCE_VERSION 5 - -/** @ingroup iface_wl_surface */ -static inline void -wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data); -} - -/** @ingroup iface_wl_surface */ -static inline void * -wl_surface_get_user_data(struct wl_surface *wl_surface) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_surface); -} - -static inline uint32_t -wl_surface_get_version(struct wl_surface *wl_surface) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_surface); -} - -/** - * @ingroup iface_wl_surface - * - * Deletes the surface and invalidates its object ID. - */ -static inline void -wl_surface_destroy(struct wl_surface *wl_surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_surface - * - * Set a buffer as the content of this surface. - * - * The new size of the surface is calculated based on the buffer - * size transformed by the inverse buffer_transform and the - * inverse buffer_scale. This means that at commit time the supplied - * buffer size must be an integer multiple of the buffer_scale. If - * that's not the case, an invalid_size error is sent. - * - * The x and y arguments specify the location of the new pending - * buffer's upper left corner, relative to the current buffer's upper - * left corner, in surface-local coordinates. In other words, the - * x and y, combined with the new surface size define in which - * directions the surface's size changes. Setting anything other than 0 - * as x and y arguments is discouraged, and should instead be replaced - * with using the separate wl_surface.offset request. - * - * When the bound wl_surface version is 5 or higher, passing any - * non-zero x or y is a protocol violation, and will result in an - * 'invalid_offset' error being raised. The x and y arguments are ignored - * and do not change the pending state. To achieve equivalent semantics, - * use wl_surface.offset. - * - * Surface contents are double-buffered state, see wl_surface.commit. - * - * The initial surface contents are void; there is no content. - * wl_surface.attach assigns the given wl_buffer as the pending - * wl_buffer. wl_surface.commit makes the pending wl_buffer the new - * surface contents, and the size of the surface becomes the size - * calculated from the wl_buffer, as described above. After commit, - * there is no pending buffer until the next attach. - * - * Committing a pending wl_buffer allows the compositor to read the - * pixels in the wl_buffer. The compositor may access the pixels at - * any time after the wl_surface.commit request. When the compositor - * will not access the pixels anymore, it will send the - * wl_buffer.release event. Only after receiving wl_buffer.release, - * the client may reuse the wl_buffer. A wl_buffer that has been - * attached and then replaced by another attach instead of committed - * will not receive a release event, and is not used by the - * compositor. - * - * If a pending wl_buffer has been committed to more than one wl_surface, - * the delivery of wl_buffer.release events becomes undefined. A well - * behaved client should not rely on wl_buffer.release events in this - * case. Alternatively, a client could create multiple wl_buffer objects - * from the same backing storage or use wp_linux_buffer_release. - * - * Destroying the wl_buffer after wl_buffer.release does not change - * the surface contents. Destroying the wl_buffer before wl_buffer.release - * is allowed as long as the underlying buffer storage isn't re-used (this - * can happen e.g. on client process termination). However, if the client - * destroys the wl_buffer before receiving the wl_buffer.release event and - * mutates the underlying buffer storage, the surface contents become - * undefined immediately. - * - * If wl_surface.attach is sent with a NULL wl_buffer, the - * following wl_surface.commit will remove the surface content. - */ -static inline void -wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, buffer, x, y); -} - -/** - * @ingroup iface_wl_surface - * - * This request is used to describe the regions where the pending - * buffer is different from the current surface contents, and where - * the surface therefore needs to be repainted. The compositor - * ignores the parts of the damage that fall outside of the surface. - * - * Damage is double-buffered state, see wl_surface.commit. - * - * The damage rectangle is specified in surface-local coordinates, - * where x and y specify the upper left corner of the damage rectangle. - * - * The initial value for pending damage is empty: no damage. - * wl_surface.damage adds pending damage: the new pending damage - * is the union of old pending damage and the given rectangle. - * - * wl_surface.commit assigns pending damage as the current damage, - * and clears pending damage. The server will clear the current - * damage as it repaints the surface. - * - * Note! New clients should not use this request. Instead damage can be - * posted with wl_surface.damage_buffer which uses buffer coordinates - * instead of surface coordinates. - */ -static inline void -wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_DAMAGE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); -} - -/** - * @ingroup iface_wl_surface - * - * Request a notification when it is a good time to start drawing a new - * frame, by creating a frame callback. This is useful for throttling - * redrawing operations, and driving animations. - * - * When a client is animating on a wl_surface, it can use the 'frame' - * request to get notified when it is a good time to draw and commit the - * next frame of animation. If the client commits an update earlier than - * that, it is likely that some updates will not make it to the display, - * and the client is wasting resources by drawing too often. - * - * The frame request will take effect on the next wl_surface.commit. - * The notification will only be posted for one frame unless - * requested again. For a wl_surface, the notifications are posted in - * the order the frame requests were committed. - * - * The server must send the notifications so that a client - * will not send excessive updates, while still allowing - * the highest possible update rate for clients that wait for the reply - * before drawing again. The server should give some time for the client - * to draw and commit after sending the frame callback events to let it - * hit the next output refresh. - * - * A server should avoid signaling the frame callbacks if the - * surface is not visible in any way, e.g. the surface is off-screen, - * or completely obscured by other opaque surfaces. - * - * The object returned by this request will be destroyed by the - * compositor after the callback is fired and as such the client must not - * attempt to use it after that point. - * - * The callback_data passed in the callback is the current time, in - * milliseconds, with an undefined base. - */ -static inline struct wl_callback * -wl_surface_frame(struct wl_surface *wl_surface) -{ - struct wl_proxy *callback; - - callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_FRAME, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL); - - return (struct wl_callback *) callback; -} - -/** - * @ingroup iface_wl_surface - * - * This request sets the region of the surface that contains - * opaque content. - * - * The opaque region is an optimization hint for the compositor - * that lets it optimize the redrawing of content behind opaque - * regions. Setting an opaque region is not required for correct - * behaviour, but marking transparent content as opaque will result - * in repaint artifacts. - * - * The opaque region is specified in surface-local coordinates. - * - * The compositor ignores the parts of the opaque region that fall - * outside of the surface. - * - * Opaque region is double-buffered state, see wl_surface.commit. - * - * wl_surface.set_opaque_region changes the pending opaque region. - * wl_surface.commit copies the pending region to the current region. - * Otherwise, the pending and current regions are never changed. - * - * The initial value for an opaque region is empty. Setting the pending - * opaque region has copy semantics, and the wl_region object can be - * destroyed immediately. A NULL wl_region causes the pending opaque - * region to be set to empty. - */ -static inline void -wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_OPAQUE_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); -} - -/** - * @ingroup iface_wl_surface - * - * This request sets the region of the surface that can receive - * pointer and touch events. - * - * Input events happening outside of this region will try the next - * surface in the server surface stack. The compositor ignores the - * parts of the input region that fall outside of the surface. - * - * The input region is specified in surface-local coordinates. - * - * Input region is double-buffered state, see wl_surface.commit. - * - * wl_surface.set_input_region changes the pending input region. - * wl_surface.commit copies the pending region to the current region. - * Otherwise the pending and current regions are never changed, - * except cursor and icon surfaces are special cases, see - * wl_pointer.set_cursor and wl_data_device.start_drag. - * - * The initial value for an input region is infinite. That means the - * whole surface will accept input. Setting the pending input region - * has copy semantics, and the wl_region object can be destroyed - * immediately. A NULL wl_region causes the input region to be set - * to infinite. - */ -static inline void -wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_INPUT_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); -} - -/** - * @ingroup iface_wl_surface - * - * Surface state (input, opaque, and damage regions, attached buffers, - * etc.) is double-buffered. Protocol requests modify the pending state, - * as opposed to the current state in use by the compositor. A commit - * request atomically applies all pending state, replacing the current - * state. After commit, the new pending state is as documented for each - * related request. - * - * On commit, a pending wl_buffer is applied first, and all other state - * second. This means that all coordinates in double-buffered state are - * relative to the new wl_buffer coming into use, except for - * wl_surface.attach itself. If there is no pending wl_buffer, the - * coordinates are relative to the current surface contents. - * - * All requests that need a commit to become effective are documented - * to affect double-buffered state. - * - * Other interfaces may add further double-buffered surface state. - */ -static inline void -wl_surface_commit(struct wl_surface *wl_surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0); -} - -/** - * @ingroup iface_wl_surface - * - * This request sets an optional transformation on how the compositor - * interprets the contents of the buffer attached to the surface. The - * accepted values for the transform parameter are the values for - * wl_output.transform. - * - * Buffer transform is double-buffered state, see wl_surface.commit. - * - * A newly created surface has its buffer transformation set to normal. - * - * wl_surface.set_buffer_transform changes the pending buffer - * transformation. wl_surface.commit copies the pending buffer - * transformation to the current one. Otherwise, the pending and current - * values are never changed. - * - * The purpose of this request is to allow clients to render content - * according to the output transform, thus permitting the compositor to - * use certain optimizations even if the display is rotated. Using - * hardware overlays and scanning out a client buffer for fullscreen - * surfaces are examples of such optimizations. Those optimizations are - * highly dependent on the compositor implementation, so the use of this - * request should be considered on a case-by-case basis. - * - * Note that if the transform value includes 90 or 270 degree rotation, - * the width of the buffer will become the surface height and the height - * of the buffer will become the surface width. - * - * If transform is not one of the values from the - * wl_output.transform enum the invalid_transform protocol error - * is raised. - */ -static inline void -wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_BUFFER_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, transform); -} - -/** - * @ingroup iface_wl_surface - * - * This request sets an optional scaling factor on how the compositor - * interprets the contents of the buffer attached to the window. - * - * Buffer scale is double-buffered state, see wl_surface.commit. - * - * A newly created surface has its buffer scale set to 1. - * - * wl_surface.set_buffer_scale changes the pending buffer scale. - * wl_surface.commit copies the pending buffer scale to the current one. - * Otherwise, the pending and current values are never changed. - * - * The purpose of this request is to allow clients to supply higher - * resolution buffer data for use on high resolution outputs. It is - * intended that you pick the same buffer scale as the scale of the - * output that the surface is displayed on. This means the compositor - * can avoid scaling when rendering the surface on that output. - * - * Note that if the scale is larger than 1, then you have to attach - * a buffer that is larger (by a factor of scale in each dimension) - * than the desired surface size. - * - * If scale is not positive the invalid_scale protocol error is - * raised. - */ -static inline void -wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_SET_BUFFER_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, scale); -} - -/** - * @ingroup iface_wl_surface - * - * This request is used to describe the regions where the pending - * buffer is different from the current surface contents, and where - * the surface therefore needs to be repainted. The compositor - * ignores the parts of the damage that fall outside of the surface. - * - * Damage is double-buffered state, see wl_surface.commit. - * - * The damage rectangle is specified in buffer coordinates, - * where x and y specify the upper left corner of the damage rectangle. - * - * The initial value for pending damage is empty: no damage. - * wl_surface.damage_buffer adds pending damage: the new pending - * damage is the union of old pending damage and the given rectangle. - * - * wl_surface.commit assigns pending damage as the current damage, - * and clears pending damage. The server will clear the current - * damage as it repaints the surface. - * - * This request differs from wl_surface.damage in only one way - it - * takes damage in buffer coordinates instead of surface-local - * coordinates. While this generally is more intuitive than surface - * coordinates, it is especially desirable when using wp_viewport - * or when a drawing library (like EGL) is unaware of buffer scale - * and buffer transform. - * - * Note: Because buffer transformation changes and damage requests may - * be interleaved in the protocol stream, it is impossible to determine - * the actual mapping between surface and buffer damage until - * wl_surface.commit time. Therefore, compositors wishing to take both - * kinds of damage into account will have to accumulate damage from the - * two requests separately and only transform from one to the other - * after receiving the wl_surface.commit. - */ -static inline void -wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_DAMAGE_BUFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); -} - -/** - * @ingroup iface_wl_surface - * - * The x and y arguments specify the location of the new pending - * buffer's upper left corner, relative to the current buffer's upper - * left corner, in surface-local coordinates. In other words, the - * x and y, combined with the new surface size define in which - * directions the surface's size changes. - * - * Surface location offset is double-buffered state, see - * wl_surface.commit. - * - * This request is semantically equivalent to and the replaces the x and y - * arguments in the wl_surface.attach request in wl_surface versions prior - * to 5. See wl_surface.attach for details. - */ -static inline void -wl_surface_offset(struct wl_surface *wl_surface, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, - WL_SURFACE_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y); -} - -#ifndef WL_SEAT_CAPABILITY_ENUM -#define WL_SEAT_CAPABILITY_ENUM -/** - * @ingroup iface_wl_seat - * seat capability bitmask - * - * This is a bitmask of capabilities this seat has; if a member is - * set, then it is present on the seat. - */ -enum wl_seat_capability { - /** - * the seat has pointer devices - */ - WL_SEAT_CAPABILITY_POINTER = 1, - /** - * the seat has one or more keyboards - */ - WL_SEAT_CAPABILITY_KEYBOARD = 2, - /** - * the seat has touch devices - */ - WL_SEAT_CAPABILITY_TOUCH = 4, -}; -#endif /* WL_SEAT_CAPABILITY_ENUM */ - -#ifndef WL_SEAT_ERROR_ENUM -#define WL_SEAT_ERROR_ENUM -/** - * @ingroup iface_wl_seat - * wl_seat error values - * - * These errors can be emitted in response to wl_seat requests. - */ -enum wl_seat_error { - /** - * get_pointer, get_keyboard or get_touch called on seat without the matching capability - */ - WL_SEAT_ERROR_MISSING_CAPABILITY = 0, -}; -#endif /* WL_SEAT_ERROR_ENUM */ - -/** - * @ingroup iface_wl_seat - * @struct wl_seat_listener - */ -struct wl_seat_listener { - /** - * seat capabilities changed - * - * This is emitted whenever a seat gains or loses the pointer, - * keyboard or touch capabilities. The argument is a capability - * enum containing the complete set of capabilities this seat has. - * - * When the pointer capability is added, a client may create a - * wl_pointer object using the wl_seat.get_pointer request. This - * object will receive pointer events until the capability is - * removed in the future. - * - * When the pointer capability is removed, a client should destroy - * the wl_pointer objects associated with the seat where the - * capability was removed, using the wl_pointer.release request. No - * further pointer events will be received on these objects. - * - * In some compositors, if a seat regains the pointer capability - * and a client has a previously obtained wl_pointer object of - * version 4 or less, that object may start sending pointer events - * again. This behavior is considered a misinterpretation of the - * intended behavior and must not be relied upon by the client. - * wl_pointer objects of version 5 or later must not send events if - * created before the most recent event notifying the client of an - * added pointer capability. - * - * The above behavior also applies to wl_keyboard and wl_touch with - * the keyboard and touch capabilities, respectively. - * @param capabilities capabilities of the seat - */ - void (*capabilities)(void *data, - struct wl_seat *wl_seat, - uint32_t capabilities); - /** - * unique identifier for this seat - * - * In a multi-seat configuration the seat name can be used by - * clients to help identify which physical devices the seat - * represents. - * - * The seat name is a UTF-8 string with no convention defined for - * its contents. Each name is unique among all wl_seat globals. The - * name is only guaranteed to be unique for the current compositor - * instance. - * - * The same seat names are used for all clients. Thus, the name can - * be shared across processes to refer to a specific wl_seat - * global. - * - * The name event is sent after binding to the seat global. This - * event is only sent once per seat object, and the name does not - * change over the lifetime of the wl_seat global. - * - * Compositors may re-use the same seat name if the wl_seat global - * is destroyed and re-created later. - * @param name seat identifier - * @since 2 - */ - void (*name)(void *data, - struct wl_seat *wl_seat, - const char *name); -}; - -/** - * @ingroup iface_wl_seat - */ -static inline int -wl_seat_add_listener(struct wl_seat *wl_seat, - const struct wl_seat_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_seat, - (void (**)(void)) listener, data); -} - -#define WL_SEAT_GET_POINTER 0 -#define WL_SEAT_GET_KEYBOARD 1 -#define WL_SEAT_GET_TOUCH 2 -#define WL_SEAT_RELEASE 3 - -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_CAPABILITIES_SINCE_VERSION 1 -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_NAME_SINCE_VERSION 2 - -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_GET_POINTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1 -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_GET_TOUCH_SINCE_VERSION 1 -/** - * @ingroup iface_wl_seat - */ -#define WL_SEAT_RELEASE_SINCE_VERSION 5 - -/** @ingroup iface_wl_seat */ -static inline void -wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data); -} - -/** @ingroup iface_wl_seat */ -static inline void * -wl_seat_get_user_data(struct wl_seat *wl_seat) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_seat); -} - -static inline uint32_t -wl_seat_get_version(struct wl_seat *wl_seat) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_seat); -} - -/** @ingroup iface_wl_seat */ -static inline void -wl_seat_destroy(struct wl_seat *wl_seat) -{ - wl_proxy_destroy((struct wl_proxy *) wl_seat); -} - -/** - * @ingroup iface_wl_seat - * - * The ID provided will be initialized to the wl_pointer interface - * for this seat. - * - * This request only takes effect if the seat has the pointer - * capability, or has had the pointer capability in the past. - * It is a protocol violation to issue this request on a seat that has - * never had the pointer capability. The missing_capability error will - * be sent in this case. - */ -static inline struct wl_pointer * -wl_seat_get_pointer(struct wl_seat *wl_seat) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, - WL_SEAT_GET_POINTER, &wl_pointer_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); - - return (struct wl_pointer *) id; -} - -/** - * @ingroup iface_wl_seat - * - * The ID provided will be initialized to the wl_keyboard interface - * for this seat. - * - * This request only takes effect if the seat has the keyboard - * capability, or has had the keyboard capability in the past. - * It is a protocol violation to issue this request on a seat that has - * never had the keyboard capability. The missing_capability error will - * be sent in this case. - */ -static inline struct wl_keyboard * -wl_seat_get_keyboard(struct wl_seat *wl_seat) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, - WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); - - return (struct wl_keyboard *) id; -} - -/** - * @ingroup iface_wl_seat - * - * The ID provided will be initialized to the wl_touch interface - * for this seat. - * - * This request only takes effect if the seat has the touch - * capability, or has had the touch capability in the past. - * It is a protocol violation to issue this request on a seat that has - * never had the touch capability. The missing_capability error will - * be sent in this case. - */ -static inline struct wl_touch * -wl_seat_get_touch(struct wl_seat *wl_seat) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, - WL_SEAT_GET_TOUCH, &wl_touch_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); - - return (struct wl_touch *) id; -} - -/** - * @ingroup iface_wl_seat - * - * Using this request a client can tell the server that it is not going to - * use the seat object anymore. - */ -static inline void -wl_seat_release(struct wl_seat *wl_seat) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, - WL_SEAT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_seat), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_POINTER_ERROR_ENUM -#define WL_POINTER_ERROR_ENUM -enum wl_pointer_error { - /** - * given wl_surface has another role - */ - WL_POINTER_ERROR_ROLE = 0, -}; -#endif /* WL_POINTER_ERROR_ENUM */ - -#ifndef WL_POINTER_BUTTON_STATE_ENUM -#define WL_POINTER_BUTTON_STATE_ENUM -/** - * @ingroup iface_wl_pointer - * physical button state - * - * Describes the physical state of a button that produced the button - * event. - */ -enum wl_pointer_button_state { - /** - * the button is not pressed - */ - WL_POINTER_BUTTON_STATE_RELEASED = 0, - /** - * the button is pressed - */ - WL_POINTER_BUTTON_STATE_PRESSED = 1, -}; -#endif /* WL_POINTER_BUTTON_STATE_ENUM */ - -#ifndef WL_POINTER_AXIS_ENUM -#define WL_POINTER_AXIS_ENUM -/** - * @ingroup iface_wl_pointer - * axis types - * - * Describes the axis types of scroll events. - */ -enum wl_pointer_axis { - /** - * vertical axis - */ - WL_POINTER_AXIS_VERTICAL_SCROLL = 0, - /** - * horizontal axis - */ - WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, -}; -#endif /* WL_POINTER_AXIS_ENUM */ - -#ifndef WL_POINTER_AXIS_SOURCE_ENUM -#define WL_POINTER_AXIS_SOURCE_ENUM -/** - * @ingroup iface_wl_pointer - * axis source types - * - * Describes the source types for axis events. This indicates to the - * client how an axis event was physically generated; a client may - * adjust the user interface accordingly. For example, scroll events - * from a "finger" source may be in a smooth coordinate space with - * kinetic scrolling whereas a "wheel" source may be in discrete steps - * of a number of lines. - * - * The "continuous" axis source is a device generating events in a - * continuous coordinate space, but using something other than a - * finger. One example for this source is button-based scrolling where - * the vertical motion of a device is converted to scroll events while - * a button is held down. - * - * The "wheel tilt" axis source indicates that the actual device is a - * wheel but the scroll event is not caused by a rotation but a - * (usually sideways) tilt of the wheel. - */ -enum wl_pointer_axis_source { - /** - * a physical wheel rotation - */ - WL_POINTER_AXIS_SOURCE_WHEEL = 0, - /** - * finger on a touch surface - */ - WL_POINTER_AXIS_SOURCE_FINGER = 1, - /** - * continuous coordinate space - */ - WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, - /** - * a physical wheel tilt - * @since 6 - */ - WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, -}; -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 -#endif /* WL_POINTER_AXIS_SOURCE_ENUM */ - -#ifndef WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM -#define WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM -/** - * @ingroup iface_wl_pointer - * axis relative direction - * - * This specifies the direction of the physical motion that caused a - * wl_pointer.axis event, relative to the wl_pointer.axis direction. - */ -enum wl_pointer_axis_relative_direction { - /** - * physical motion matches axis direction - */ - WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL = 0, - /** - * physical motion is the inverse of the axis direction - */ - WL_POINTER_AXIS_RELATIVE_DIRECTION_INVERTED = 1, -}; -#endif /* WL_POINTER_AXIS_RELATIVE_DIRECTION_ENUM */ - -/** - * @ingroup iface_wl_pointer - * @struct wl_pointer_listener - */ -struct wl_pointer_listener { - /** - * enter event - * - * Notification that this seat's pointer is focused on a certain - * surface. - * - * When a seat's focus enters a surface, the pointer image is - * undefined and a client should respond to this event by setting - * an appropriate pointer image with the set_cursor request. - * @param serial serial number of the enter event - * @param surface surface entered by the pointer - * @param surface_x surface-local x coordinate - * @param surface_y surface-local y coordinate - */ - void (*enter)(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t surface_x, - wl_fixed_t surface_y); - /** - * leave event - * - * Notification that this seat's pointer is no longer focused on - * a certain surface. - * - * The leave notification is sent before the enter notification for - * the new focus. - * @param serial serial number of the leave event - * @param surface surface left by the pointer - */ - void (*leave)(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface); - /** - * pointer motion event - * - * Notification of pointer location change. The arguments - * surface_x and surface_y are the location relative to the focused - * surface. - * @param time timestamp with millisecond granularity - * @param surface_x surface-local x coordinate - * @param surface_y surface-local y coordinate - */ - void (*motion)(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - wl_fixed_t surface_x, - wl_fixed_t surface_y); - /** - * pointer button event - * - * Mouse button click and release notifications. - * - * The location of the click is given by the last motion or enter - * event. The time argument is a timestamp with millisecond - * granularity, with an undefined base. - * - * The button is a button code as defined in the Linux kernel's - * linux/input-event-codes.h header file, e.g. BTN_LEFT. - * - * Any 16-bit button code value is reserved for future additions to - * the kernel's event code list. All other button codes above - * 0xFFFF are currently undefined but may be used in future - * versions of this protocol. - * @param serial serial number of the button event - * @param time timestamp with millisecond granularity - * @param button button that produced the event - * @param state physical state of the button - */ - void (*button)(void *data, - struct wl_pointer *wl_pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state); - /** - * axis event - * - * Scroll and other axis notifications. - * - * For scroll events (vertical and horizontal scroll axes), the - * value parameter is the length of a vector along the specified - * axis in a coordinate space identical to those of motion events, - * representing a relative movement along the specified axis. - * - * For devices that support movements non-parallel to axes multiple - * axis events will be emitted. - * - * When applicable, for example for touch pads, the server can - * choose to emit scroll events where the motion vector is - * equivalent to a motion event vector. - * - * When applicable, a client can transform its content relative to - * the scroll distance. - * @param time timestamp with millisecond granularity - * @param axis axis type - * @param value length of vector in surface-local coordinate space - */ - void (*axis)(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value); - /** - * end of a pointer event sequence - * - * Indicates the end of a set of events that logically belong - * together. A client is expected to accumulate the data in all - * events within the frame before proceeding. - * - * All wl_pointer events before a wl_pointer.frame event belong - * logically together. For example, in a diagonal scroll motion the - * compositor will send an optional wl_pointer.axis_source event, - * two wl_pointer.axis events (horizontal and vertical) and finally - * a wl_pointer.frame event. The client may use this information to - * calculate a diagonal vector for scrolling. - * - * When multiple wl_pointer.axis events occur within the same - * frame, the motion vector is the combined motion of all events. - * When a wl_pointer.axis and a wl_pointer.axis_stop event occur - * within the same frame, this indicates that axis movement in one - * axis has stopped but continues in the other axis. When multiple - * wl_pointer.axis_stop events occur within the same frame, this - * indicates that these axes stopped in the same instance. - * - * A wl_pointer.frame event is sent for every logical event group, - * even if the group only contains a single wl_pointer event. - * Specifically, a client may get a sequence: motion, frame, - * button, frame, axis, frame, axis_stop, frame. - * - * The wl_pointer.enter and wl_pointer.leave events are logical - * events generated by the compositor and not the hardware. These - * events are also grouped by a wl_pointer.frame. When a pointer - * moves from one surface to another, a compositor should group the - * wl_pointer.leave event within the same wl_pointer.frame. - * However, a client must not rely on wl_pointer.leave and - * wl_pointer.enter being in the same wl_pointer.frame. - * Compositor-specific policies may require the wl_pointer.leave - * and wl_pointer.enter event being split across multiple - * wl_pointer.frame groups. - * @since 5 - */ - void (*frame)(void *data, - struct wl_pointer *wl_pointer); - /** - * axis source event - * - * Source information for scroll and other axes. - * - * This event does not occur on its own. It is sent before a - * wl_pointer.frame event and carries the source information for - * all events within that frame. - * - * The source specifies how this event was generated. If the source - * is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event - * will be sent when the user lifts the finger off the device. - * - * If the source is wl_pointer.axis_source.wheel, - * wl_pointer.axis_source.wheel_tilt or - * wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event - * may or may not be sent. Whether a compositor sends an axis_stop - * event for these sources is hardware-specific and - * implementation-dependent; clients must not rely on receiving an - * axis_stop event for these scroll sources and should treat scroll - * sequences from these scroll sources as unterminated by default. - * - * This event is optional. If the source is unknown for a - * particular axis event sequence, no event is sent. Only one - * wl_pointer.axis_source event is permitted per frame. - * - * The order of wl_pointer.axis_discrete and wl_pointer.axis_source - * is not guaranteed. - * @param axis_source source of the axis event - * @since 5 - */ - void (*axis_source)(void *data, - struct wl_pointer *wl_pointer, - uint32_t axis_source); - /** - * axis stop event - * - * Stop notification for scroll and other axes. - * - * For some wl_pointer.axis_source types, a wl_pointer.axis_stop - * event is sent to notify a client that the axis sequence has - * terminated. This enables the client to implement kinetic - * scrolling. See the wl_pointer.axis_source documentation for - * information on when this event may be generated. - * - * Any wl_pointer.axis events with the same axis_source after this - * event should be considered as the start of a new axis motion. - * - * The timestamp is to be interpreted identical to the timestamp in - * the wl_pointer.axis event. The timestamp value may be the same - * as a preceding wl_pointer.axis event. - * @param time timestamp with millisecond granularity - * @param axis the axis stopped with this event - * @since 5 - */ - void (*axis_stop)(void *data, - struct wl_pointer *wl_pointer, - uint32_t time, - uint32_t axis); - /** - * axis click event - * - * Discrete step information for scroll and other axes. - * - * This event carries the axis value of the wl_pointer.axis event - * in discrete steps (e.g. mouse wheel clicks). - * - * This event is deprecated with wl_pointer version 8 - this event - * is not sent to clients supporting version 8 or later. - * - * This event does not occur on its own, it is coupled with a - * wl_pointer.axis event that represents this axis value on a - * continuous scale. The protocol guarantees that each - * axis_discrete event is always followed by exactly one axis event - * with the same axis number within the same wl_pointer.frame. Note - * that the protocol allows for other events to occur between the - * axis_discrete and its coupled axis event, including other - * axis_discrete or axis events. A wl_pointer.frame must not - * contain more than one axis_discrete event per axis type. - * - * This event is optional; continuous scrolling devices like - * two-finger scrolling on touchpads do not have discrete steps and - * do not generate this event. - * - * The discrete value carries the directional information. e.g. a - * value of -2 is two steps towards the negative direction of this - * axis. - * - * The axis number is identical to the axis number in the - * associated axis event. - * - * The order of wl_pointer.axis_discrete and wl_pointer.axis_source - * is not guaranteed. - * @param axis axis type - * @param discrete number of steps - * @since 5 - */ - void (*axis_discrete)(void *data, - struct wl_pointer *wl_pointer, - uint32_t axis, - int32_t discrete); - /** - * axis high-resolution scroll event - * - * Discrete high-resolution scroll information. - * - * This event carries high-resolution wheel scroll information, - * with each multiple of 120 representing one logical scroll step - * (a wheel detent). For example, an axis_value120 of 30 is one - * quarter of a logical scroll step in the positive direction, a - * value120 of -240 are two logical scroll steps in the negative - * direction within the same hardware event. Clients that rely on - * discrete scrolling should accumulate the value120 to multiples - * of 120 before processing the event. - * - * The value120 must not be zero. - * - * This event replaces the wl_pointer.axis_discrete event in - * clients supporting wl_pointer version 8 or later. - * - * Where a wl_pointer.axis_source event occurs in the same - * wl_pointer.frame, the axis source applies to this event. - * - * The order of wl_pointer.axis_value120 and wl_pointer.axis_source - * is not guaranteed. - * @param axis axis type - * @param value120 scroll distance as fraction of 120 - * @since 8 - */ - void (*axis_value120)(void *data, - struct wl_pointer *wl_pointer, - uint32_t axis, - int32_t value120); - /** - * axis relative physical direction event - * - * Relative directional information of the entity causing the - * axis motion. - * - * For a wl_pointer.axis event, the - * wl_pointer.axis_relative_direction event specifies the movement - * direction of the entity causing the wl_pointer.axis event. For - * example: - if a user's fingers on a touchpad move down and this - * causes a wl_pointer.axis vertical_scroll down event, the - * physical direction is 'identical' - if a user's fingers on a - * touchpad move down and this causes a wl_pointer.axis - * vertical_scroll up scroll up event ('natural scrolling'), the - * physical direction is 'inverted'. - * - * A client may use this information to adjust scroll motion of - * components. Specifically, enabling natural scrolling causes the - * content to change direction compared to traditional scrolling. - * Some widgets like volume control sliders should usually match - * the physical direction regardless of whether natural scrolling - * is active. This event enables clients to match the scroll - * direction of a widget to the physical direction. - * - * This event does not occur on its own, it is coupled with a - * wl_pointer.axis event that represents this axis value. The - * protocol guarantees that each axis_relative_direction event is - * always followed by exactly one axis event with the same axis - * number within the same wl_pointer.frame. Note that the protocol - * allows for other events to occur between the - * axis_relative_direction and its coupled axis event. - * - * The axis number is identical to the axis number in the - * associated axis event. - * - * The order of wl_pointer.axis_relative_direction, - * wl_pointer.axis_discrete and wl_pointer.axis_source is not - * guaranteed. - * @param axis axis type - * @param direction physical direction relative to axis motion - * @since 9 - */ - void (*axis_relative_direction)(void *data, - struct wl_pointer *wl_pointer, - uint32_t axis, - uint32_t direction); -}; - -/** - * @ingroup iface_wl_pointer - */ -static inline int -wl_pointer_add_listener(struct wl_pointer *wl_pointer, - const struct wl_pointer_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_pointer, - (void (**)(void)) listener, data); -} - -#define WL_POINTER_SET_CURSOR 0 -#define WL_POINTER_RELEASE 1 - -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_ENTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_LEAVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_MOTION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_BUTTON_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_FRAME_SINCE_VERSION 5 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_STOP_SINCE_VERSION 5 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_VALUE120_SINCE_VERSION 8 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION 9 - -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_SET_CURSOR_SINCE_VERSION 1 -/** - * @ingroup iface_wl_pointer - */ -#define WL_POINTER_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_wl_pointer */ -static inline void -wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data); -} - -/** @ingroup iface_wl_pointer */ -static inline void * -wl_pointer_get_user_data(struct wl_pointer *wl_pointer) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer); -} - -static inline uint32_t -wl_pointer_get_version(struct wl_pointer *wl_pointer) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_pointer); -} - -/** @ingroup iface_wl_pointer */ -static inline void -wl_pointer_destroy(struct wl_pointer *wl_pointer) -{ - wl_proxy_destroy((struct wl_proxy *) wl_pointer); -} - -/** - * @ingroup iface_wl_pointer - * - * Set the pointer surface, i.e., the surface that contains the - * pointer image (cursor). This request gives the surface the role - * of a cursor. If the surface already has another role, it raises - * a protocol error. - * - * The cursor actually changes only if the pointer - * focus for this device is one of the requesting client's surfaces - * or the surface parameter is the current pointer surface. If - * there was a previous surface set with this request it is - * replaced. If surface is NULL, the pointer image is hidden. - * - * The parameters hotspot_x and hotspot_y define the position of - * the pointer surface relative to the pointer location. Its - * top-left corner is always at (x, y) - (hotspot_x, hotspot_y), - * where (x, y) are the coordinates of the pointer location, in - * surface-local coordinates. - * - * On surface.attach requests to the pointer surface, hotspot_x - * and hotspot_y are decremented by the x and y parameters - * passed to the request. Attach must be confirmed by - * wl_surface.commit as usual. - * - * The hotspot can also be updated by passing the currently set - * pointer surface to this request with new values for hotspot_x - * and hotspot_y. - * - * The input region is ignored for wl_surfaces with the role of - * a cursor. When the use as a cursor ends, the wl_surface is - * unmapped. - * - * The serial parameter must match the latest wl_pointer.enter - * serial number sent to the client. Otherwise the request will be - * ignored. - */ -static inline void -wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, - WL_POINTER_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), 0, serial, surface, hotspot_x, hotspot_y); -} - -/** - * @ingroup iface_wl_pointer - * - * Using this request a client can tell the server that it is not going to - * use the pointer object anymore. - * - * This request destroys the pointer proxy object, so clients must not call - * wl_pointer_destroy() after using this request. - */ -static inline void -wl_pointer_release(struct wl_pointer *wl_pointer) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, - WL_POINTER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM -#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM -/** - * @ingroup iface_wl_keyboard - * keyboard mapping format - * - * This specifies the format of the keymap provided to the - * client with the wl_keyboard.keymap event. - */ -enum wl_keyboard_keymap_format { - /** - * no keymap; client must understand how to interpret the raw keycode - */ - WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, - /** - * libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode - */ - WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, -}; -#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ - -#ifndef WL_KEYBOARD_KEY_STATE_ENUM -#define WL_KEYBOARD_KEY_STATE_ENUM -/** - * @ingroup iface_wl_keyboard - * physical key state - * - * Describes the physical state of a key that produced the key event. - */ -enum wl_keyboard_key_state { - /** - * key is not pressed - */ - WL_KEYBOARD_KEY_STATE_RELEASED = 0, - /** - * key is pressed - */ - WL_KEYBOARD_KEY_STATE_PRESSED = 1, -}; -#endif /* WL_KEYBOARD_KEY_STATE_ENUM */ - -/** - * @ingroup iface_wl_keyboard - * @struct wl_keyboard_listener - */ -struct wl_keyboard_listener { - /** - * keyboard mapping - * - * This event provides a file descriptor to the client which can - * be memory-mapped in read-only mode to provide a keyboard mapping - * description. - * - * From version 7 onwards, the fd must be mapped with MAP_PRIVATE - * by the recipient, as MAP_SHARED may fail. - * @param format keymap format - * @param fd keymap file descriptor - * @param size keymap size, in bytes - */ - void (*keymap)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t format, - int32_t fd, - uint32_t size); - /** - * enter event - * - * Notification that this seat's keyboard focus is on a certain - * surface. - * - * The compositor must send the wl_keyboard.modifiers event after - * this event. - * @param serial serial number of the enter event - * @param surface surface gaining keyboard focus - * @param keys the currently pressed keys - */ - void (*enter)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - struct wl_surface *surface, - struct wl_array *keys); - /** - * leave event - * - * Notification that this seat's keyboard focus is no longer on a - * certain surface. - * - * The leave notification is sent before the enter notification for - * the new focus. - * - * After this event client must assume that all keys, including - * modifiers, are lifted and also it must stop key repeating if - * there's some going on. - * @param serial serial number of the leave event - * @param surface surface that lost keyboard focus - */ - void (*leave)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - struct wl_surface *surface); - /** - * key event - * - * A key was pressed or released. The time argument is a - * timestamp with millisecond granularity, with an undefined base. - * - * The key is a platform-specific key code that can be interpreted - * by feeding it to the keyboard mapping (see the keymap event). - * - * If this event produces a change in modifiers, then the resulting - * wl_keyboard.modifiers event must be sent after this event. - * @param serial serial number of the key event - * @param time timestamp with millisecond granularity - * @param key key that produced the event - * @param state physical state of the key - */ - void (*key)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - uint32_t time, - uint32_t key, - uint32_t state); - /** - * modifier and group state - * - * Notifies clients that the modifier and/or group state has - * changed, and it should update its local state. - * @param serial serial number of the modifiers event - * @param mods_depressed depressed modifiers - * @param mods_latched latched modifiers - * @param mods_locked locked modifiers - * @param group keyboard layout - */ - void (*modifiers)(void *data, - struct wl_keyboard *wl_keyboard, - uint32_t serial, - uint32_t mods_depressed, - uint32_t mods_latched, - uint32_t mods_locked, - uint32_t group); - /** - * repeat rate and delay - * - * Informs the client about the keyboard's repeat rate and delay. - * - * This event is sent as soon as the wl_keyboard object has been - * created, and is guaranteed to be received by the client before - * any key press event. - * - * Negative values for either rate or delay are illegal. A rate of - * zero will disable any repeating (regardless of the value of - * delay). - * - * This event can be sent later on as well with a new value if - * necessary, so clients should continue listening for the event - * past the creation of wl_keyboard. - * @param rate the rate of repeating keys in characters per second - * @param delay delay in milliseconds since key down until repeating starts - * @since 4 - */ - void (*repeat_info)(void *data, - struct wl_keyboard *wl_keyboard, - int32_t rate, - int32_t delay); -}; - -/** - * @ingroup iface_wl_keyboard - */ -static inline int -wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard, - const struct wl_keyboard_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard, - (void (**)(void)) listener, data); -} - -#define WL_KEYBOARD_RELEASE 0 - -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_ENTER_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_LEAVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_KEY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1 -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4 - -/** - * @ingroup iface_wl_keyboard - */ -#define WL_KEYBOARD_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_wl_keyboard */ -static inline void -wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data); -} - -/** @ingroup iface_wl_keyboard */ -static inline void * -wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard); -} - -static inline uint32_t -wl_keyboard_get_version(struct wl_keyboard *wl_keyboard) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_keyboard); -} - -/** @ingroup iface_wl_keyboard */ -static inline void -wl_keyboard_destroy(struct wl_keyboard *wl_keyboard) -{ - wl_proxy_destroy((struct wl_proxy *) wl_keyboard); -} - -/** - * @ingroup iface_wl_keyboard - */ -static inline void -wl_keyboard_release(struct wl_keyboard *wl_keyboard) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_keyboard, - WL_KEYBOARD_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_keyboard), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_touch - * @struct wl_touch_listener - */ -struct wl_touch_listener { - /** - * touch down event and beginning of a touch sequence - * - * A new touch point has appeared on the surface. This touch - * point is assigned a unique ID. Future events from this touch - * point reference this ID. The ID ceases to be valid after a touch - * up event and may be reused in the future. - * @param serial serial number of the touch down event - * @param time timestamp with millisecond granularity - * @param surface surface touched - * @param id the unique ID of this touch point - * @param x surface-local x coordinate - * @param y surface-local y coordinate - */ - void (*down)(void *data, - struct wl_touch *wl_touch, - uint32_t serial, - uint32_t time, - struct wl_surface *surface, - int32_t id, - wl_fixed_t x, - wl_fixed_t y); - /** - * end of a touch event sequence - * - * The touch point has disappeared. No further events will be - * sent for this touch point and the touch point's ID is released - * and may be reused in a future touch down event. - * @param serial serial number of the touch up event - * @param time timestamp with millisecond granularity - * @param id the unique ID of this touch point - */ - void (*up)(void *data, - struct wl_touch *wl_touch, - uint32_t serial, - uint32_t time, - int32_t id); - /** - * update of touch point coordinates - * - * A touch point has changed coordinates. - * @param time timestamp with millisecond granularity - * @param id the unique ID of this touch point - * @param x surface-local x coordinate - * @param y surface-local y coordinate - */ - void (*motion)(void *data, - struct wl_touch *wl_touch, - uint32_t time, - int32_t id, - wl_fixed_t x, - wl_fixed_t y); - /** - * end of touch frame event - * - * Indicates the end of a set of events that logically belong - * together. A client is expected to accumulate the data in all - * events within the frame before proceeding. - * - * A wl_touch.frame terminates at least one event but otherwise no - * guarantee is provided about the set of events within a frame. A - * client must assume that any state not updated in a frame is - * unchanged from the previously known state. - */ - void (*frame)(void *data, - struct wl_touch *wl_touch); - /** - * touch session cancelled - * - * Sent if the compositor decides the touch stream is a global - * gesture. No further events are sent to the clients from that - * particular gesture. Touch cancellation applies to all touch - * points currently active on this client's surface. The client is - * responsible for finalizing the touch points, future touch points - * on this surface may reuse the touch point ID. - */ - void (*cancel)(void *data, - struct wl_touch *wl_touch); - /** - * update shape of touch point - * - * Sent when a touchpoint has changed its shape. - * - * This event does not occur on its own. It is sent before a - * wl_touch.frame event and carries the new shape information for - * any previously reported, or new touch points of that frame. - * - * Other events describing the touch point such as wl_touch.down, - * wl_touch.motion or wl_touch.orientation may be sent within the - * same wl_touch.frame. A client should treat these events as a - * single logical touch point update. The order of wl_touch.shape, - * wl_touch.orientation and wl_touch.motion is not guaranteed. A - * wl_touch.down event is guaranteed to occur before the first - * wl_touch.shape event for this touch ID but both events may occur - * within the same wl_touch.frame. - * - * A touchpoint shape is approximated by an ellipse through the - * major and minor axis length. The major axis length describes the - * longer diameter of the ellipse, while the minor axis length - * describes the shorter diameter. Major and minor are orthogonal - * and both are specified in surface-local coordinates. The center - * of the ellipse is always at the touchpoint location as reported - * by wl_touch.down or wl_touch.move. - * - * This event is only sent by the compositor if the touch device - * supports shape reports. The client has to make reasonable - * assumptions about the shape if it did not receive this event. - * @param id the unique ID of this touch point - * @param major length of the major axis in surface-local coordinates - * @param minor length of the minor axis in surface-local coordinates - * @since 6 - */ - void (*shape)(void *data, - struct wl_touch *wl_touch, - int32_t id, - wl_fixed_t major, - wl_fixed_t minor); - /** - * update orientation of touch point - * - * Sent when a touchpoint has changed its orientation. - * - * This event does not occur on its own. It is sent before a - * wl_touch.frame event and carries the new shape information for - * any previously reported, or new touch points of that frame. - * - * Other events describing the touch point such as wl_touch.down, - * wl_touch.motion or wl_touch.shape may be sent within the same - * wl_touch.frame. A client should treat these events as a single - * logical touch point update. The order of wl_touch.shape, - * wl_touch.orientation and wl_touch.motion is not guaranteed. A - * wl_touch.down event is guaranteed to occur before the first - * wl_touch.orientation event for this touch ID but both events may - * occur within the same wl_touch.frame. - * - * The orientation describes the clockwise angle of a touchpoint's - * major axis to the positive surface y-axis and is normalized to - * the -180 to +180 degree range. The granularity of orientation - * depends on the touch device, some devices only support binary - * rotation values between 0 and 90 degrees. - * - * This event is only sent by the compositor if the touch device - * supports orientation reports. - * @param id the unique ID of this touch point - * @param orientation angle between major axis and positive surface y-axis in degrees - * @since 6 - */ - void (*orientation)(void *data, - struct wl_touch *wl_touch, - int32_t id, - wl_fixed_t orientation); -}; - -/** - * @ingroup iface_wl_touch - */ -static inline int -wl_touch_add_listener(struct wl_touch *wl_touch, - const struct wl_touch_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_touch, - (void (**)(void)) listener, data); -} - -#define WL_TOUCH_RELEASE 0 - -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_DOWN_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_UP_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_MOTION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_FRAME_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_CANCEL_SINCE_VERSION 1 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_SHAPE_SINCE_VERSION 6 -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_ORIENTATION_SINCE_VERSION 6 - -/** - * @ingroup iface_wl_touch - */ -#define WL_TOUCH_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_wl_touch */ -static inline void -wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data); -} - -/** @ingroup iface_wl_touch */ -static inline void * -wl_touch_get_user_data(struct wl_touch *wl_touch) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_touch); -} - -static inline uint32_t -wl_touch_get_version(struct wl_touch *wl_touch) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_touch); -} - -/** @ingroup iface_wl_touch */ -static inline void -wl_touch_destroy(struct wl_touch *wl_touch) -{ - wl_proxy_destroy((struct wl_proxy *) wl_touch); -} - -/** - * @ingroup iface_wl_touch - */ -static inline void -wl_touch_release(struct wl_touch *wl_touch) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_touch, - WL_TOUCH_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_touch), WL_MARSHAL_FLAG_DESTROY); -} - -#ifndef WL_OUTPUT_SUBPIXEL_ENUM -#define WL_OUTPUT_SUBPIXEL_ENUM -/** - * @ingroup iface_wl_output - * subpixel geometry information - * - * This enumeration describes how the physical - * pixels on an output are laid out. - */ -enum wl_output_subpixel { - /** - * unknown geometry - */ - WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, - /** - * no geometry - */ - WL_OUTPUT_SUBPIXEL_NONE = 1, - /** - * horizontal RGB - */ - WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, - /** - * horizontal BGR - */ - WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, - /** - * vertical RGB - */ - WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, - /** - * vertical BGR - */ - WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, -}; -#endif /* WL_OUTPUT_SUBPIXEL_ENUM */ - -#ifndef WL_OUTPUT_TRANSFORM_ENUM -#define WL_OUTPUT_TRANSFORM_ENUM -/** - * @ingroup iface_wl_output - * transform from framebuffer to output - * - * This describes the transform that a compositor will apply to a - * surface to compensate for the rotation or mirroring of an - * output device. - * - * The flipped values correspond to an initial flip around a - * vertical axis followed by rotation. - * - * The purpose is mainly to allow clients to render accordingly and - * tell the compositor, so that for fullscreen surfaces, the - * compositor will still be able to scan out directly from client - * surfaces. - */ -enum wl_output_transform { - /** - * no transform - */ - WL_OUTPUT_TRANSFORM_NORMAL = 0, - /** - * 90 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_90 = 1, - /** - * 180 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_180 = 2, - /** - * 270 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_270 = 3, - /** - * 180 degree flip around a vertical axis - */ - WL_OUTPUT_TRANSFORM_FLIPPED = 4, - /** - * flip and rotate 90 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, - /** - * flip and rotate 180 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, - /** - * flip and rotate 270 degrees counter-clockwise - */ - WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, -}; -#endif /* WL_OUTPUT_TRANSFORM_ENUM */ - -#ifndef WL_OUTPUT_MODE_ENUM -#define WL_OUTPUT_MODE_ENUM -/** - * @ingroup iface_wl_output - * mode information - * - * These flags describe properties of an output mode. - * They are used in the flags bitfield of the mode event. - */ -enum wl_output_mode { - /** - * indicates this is the current mode - */ - WL_OUTPUT_MODE_CURRENT = 0x1, - /** - * indicates this is the preferred mode - */ - WL_OUTPUT_MODE_PREFERRED = 0x2, -}; -#endif /* WL_OUTPUT_MODE_ENUM */ - -/** - * @ingroup iface_wl_output - * @struct wl_output_listener - */ -struct wl_output_listener { - /** - * properties of the output - * - * The geometry event describes geometric properties of the - * output. The event is sent when binding to the output object and - * whenever any of the properties change. - * - * The physical size can be set to zero if it doesn't make sense - * for this output (e.g. for projectors or virtual outputs). - * - * The geometry event will be followed by a done event (starting - * from version 2). - * - * Note: wl_output only advertises partial information about the - * output position and identification. Some compositors, for - * instance those not implementing a desktop-style output layout or - * those exposing virtual outputs, might fake this information. - * Instead of using x and y, clients should use - * xdg_output.logical_position. Instead of using make and model, - * clients should use name and description. - * @param x x position within the global compositor space - * @param y y position within the global compositor space - * @param physical_width width in millimeters of the output - * @param physical_height height in millimeters of the output - * @param subpixel subpixel orientation of the output - * @param make textual description of the manufacturer - * @param model textual description of the model - * @param transform transform that maps framebuffer to output - */ - void (*geometry)(void *data, - struct wl_output *wl_output, - int32_t x, - int32_t y, - int32_t physical_width, - int32_t physical_height, - int32_t subpixel, - const char *make, - const char *model, - int32_t transform); - /** - * advertise available modes for the output - * - * The mode event describes an available mode for the output. - * - * The event is sent when binding to the output object and there - * will always be one mode, the current mode. The event is sent - * again if an output changes mode, for the mode that is now - * current. In other words, the current mode is always the last - * mode that was received with the current flag set. - * - * Non-current modes are deprecated. A compositor can decide to - * only advertise the current mode and never send other modes. - * Clients should not rely on non-current modes. - * - * The size of a mode is given in physical hardware units of the - * output device. This is not necessarily the same as the output - * size in the global compositor space. For instance, the output - * may be scaled, as described in wl_output.scale, or transformed, - * as described in wl_output.transform. Clients willing to retrieve - * the output size in the global compositor space should use - * xdg_output.logical_size instead. - * - * The vertical refresh rate can be set to zero if it doesn't make - * sense for this output (e.g. for virtual outputs). - * - * The mode event will be followed by a done event (starting from - * version 2). - * - * Clients should not use the refresh rate to schedule frames. - * Instead, they should use the wl_surface.frame event or the - * presentation-time protocol. - * - * Note: this information is not always meaningful for all outputs. - * Some compositors, such as those exposing virtual outputs, might - * fake the refresh rate or the size. - * @param flags bitfield of mode flags - * @param width width of the mode in hardware units - * @param height height of the mode in hardware units - * @param refresh vertical refresh rate in mHz - */ - void (*mode)(void *data, - struct wl_output *wl_output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh); - /** - * sent all information about output - * - * This event is sent after all other properties have been sent - * after binding to the output object and after any other property - * changes done after that. This allows changes to the output - * properties to be seen as atomic, even if they happen via - * multiple events. - * @since 2 - */ - void (*done)(void *data, - struct wl_output *wl_output); - /** - * output scaling properties - * - * This event contains scaling geometry information that is not - * in the geometry event. It may be sent after binding the output - * object or if the output scale changes later. If it is not sent, - * the client should assume a scale of 1. - * - * A scale larger than 1 means that the compositor will - * automatically scale surface buffers by this amount when - * rendering. This is used for very high resolution displays where - * applications rendering at the native resolution would be too - * small to be legible. - * - * It is intended that scaling aware clients track the current - * output of a surface, and if it is on a scaled output it should - * use wl_surface.set_buffer_scale with the scale of the output. - * That way the compositor can avoid scaling the surface, and the - * client can supply a higher detail image. - * - * The scale event will be followed by a done event. - * @param factor scaling factor of output - * @since 2 - */ - void (*scale)(void *data, - struct wl_output *wl_output, - int32_t factor); - /** - * name of this output - * - * Many compositors will assign user-friendly names to their - * outputs, show them to the user, allow the user to refer to an - * output, etc. The client may wish to know this name as well to - * offer the user similar behaviors. - * - * The name is a UTF-8 string with no convention defined for its - * contents. Each name is unique among all wl_output globals. The - * name is only guaranteed to be unique for the compositor - * instance. - * - * The same output name is used for all clients for a given - * wl_output global. Thus, the name can be shared across processes - * to refer to a specific wl_output global. - * - * The name is not guaranteed to be persistent across sessions, - * thus cannot be used to reliably identify an output in e.g. - * configuration files. - * - * Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. - * However, do not assume that the name is a reflection of an - * underlying DRM connector, X11 connection, etc. - * - * The name event is sent after binding the output object. This - * event is only sent once per output object, and the name does not - * change over the lifetime of the wl_output global. - * - * Compositors may re-use the same output name if the wl_output - * global is destroyed and re-created later. Compositors should - * avoid re-using the same name if possible. - * - * The name event will be followed by a done event. - * @param name output name - * @since 4 - */ - void (*name)(void *data, - struct wl_output *wl_output, - const char *name); - /** - * human-readable description of this output - * - * Many compositors can produce human-readable descriptions of - * their outputs. The client may wish to know this description as - * well, e.g. for output selection purposes. - * - * The description is a UTF-8 string with no convention defined for - * its contents. The description is not guaranteed to be unique - * among all wl_output globals. Examples might include 'Foocorp 11" - * Display' or 'Virtual X11 output via :1'. - * - * The description event is sent after binding the output object - * and whenever the description changes. The description is - * optional, and may not be sent at all. - * - * The description event will be followed by a done event. - * @param description output description - * @since 4 - */ - void (*description)(void *data, - struct wl_output *wl_output, - const char *description); -}; - -/** - * @ingroup iface_wl_output - */ -static inline int -wl_output_add_listener(struct wl_output *wl_output, - const struct wl_output_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) wl_output, - (void (**)(void)) listener, data); -} - -#define WL_OUTPUT_RELEASE 0 - -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_MODE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_DONE_SINCE_VERSION 2 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_SCALE_SINCE_VERSION 2 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_NAME_SINCE_VERSION 4 -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_DESCRIPTION_SINCE_VERSION 4 - -/** - * @ingroup iface_wl_output - */ -#define WL_OUTPUT_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_wl_output */ -static inline void -wl_output_set_user_data(struct wl_output *wl_output, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data); -} - -/** @ingroup iface_wl_output */ -static inline void * -wl_output_get_user_data(struct wl_output *wl_output) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_output); -} - -static inline uint32_t -wl_output_get_version(struct wl_output *wl_output) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_output); -} - -/** @ingroup iface_wl_output */ -static inline void -wl_output_destroy(struct wl_output *wl_output) -{ - wl_proxy_destroy((struct wl_proxy *) wl_output); -} - -/** - * @ingroup iface_wl_output - * - * Using this request a client can tell the server that it is not going to - * use the output object anymore. - */ -static inline void -wl_output_release(struct wl_output *wl_output) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_output, - WL_OUTPUT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_output), WL_MARSHAL_FLAG_DESTROY); -} - -#define WL_REGION_DESTROY 0 -#define WL_REGION_ADD 1 -#define WL_REGION_SUBTRACT 2 - - -/** - * @ingroup iface_wl_region - */ -#define WL_REGION_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_region - */ -#define WL_REGION_ADD_SINCE_VERSION 1 -/** - * @ingroup iface_wl_region - */ -#define WL_REGION_SUBTRACT_SINCE_VERSION 1 - -/** @ingroup iface_wl_region */ -static inline void -wl_region_set_user_data(struct wl_region *wl_region, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data); -} - -/** @ingroup iface_wl_region */ -static inline void * -wl_region_get_user_data(struct wl_region *wl_region) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_region); -} - -static inline uint32_t -wl_region_get_version(struct wl_region *wl_region) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_region); -} - -/** - * @ingroup iface_wl_region - * - * Destroy the region. This will invalidate the object ID. - */ -static inline void -wl_region_destroy(struct wl_region *wl_region) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_region, - WL_REGION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_region - * - * Add the specified rectangle to the region. - */ -static inline void -wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_region, - WL_REGION_ADD, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); -} - -/** - * @ingroup iface_wl_region - * - * Subtract the specified rectangle from the region. - */ -static inline void -wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_region, - WL_REGION_SUBTRACT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); -} - -#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM -#define WL_SUBCOMPOSITOR_ERROR_ENUM -enum wl_subcompositor_error { - /** - * the to-be sub-surface is invalid - */ - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, - /** - * the to-be sub-surface parent is invalid - */ - WL_SUBCOMPOSITOR_ERROR_BAD_PARENT = 1, -}; -#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ - -#define WL_SUBCOMPOSITOR_DESTROY 0 -#define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1 - - -/** - * @ingroup iface_wl_subcompositor - */ -#define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subcompositor - */ -#define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1 - -/** @ingroup iface_wl_subcompositor */ -static inline void -wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data); -} - -/** @ingroup iface_wl_subcompositor */ -static inline void * -wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor); -} - -static inline uint32_t -wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_subcompositor); -} - -/** - * @ingroup iface_wl_subcompositor - * - * Informs the server that the client will not be using this - * protocol object anymore. This does not affect any other - * objects, wl_subsurface objects included. - */ -static inline void -wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, - WL_SUBCOMPOSITOR_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_subcompositor - * - * Create a sub-surface interface for the given surface, and - * associate it with the given parent surface. This turns a - * plain wl_surface into a sub-surface. - * - * The to-be sub-surface must not already have another role, and it - * must not have an existing wl_subsurface object. Otherwise the - * bad_surface protocol error is raised. - * - * Adding sub-surfaces to a parent is a double-buffered operation on the - * parent (see wl_surface.commit). The effect of adding a sub-surface - * becomes visible on the next time the state of the parent surface is - * applied. - * - * The parent surface must not be one of the child surface's descendants, - * and the parent must be different from the child surface, otherwise the - * bad_parent protocol error is raised. - * - * This request modifies the behaviour of wl_surface.commit request on - * the sub-surface, see the documentation on wl_subsurface interface. - */ -static inline struct wl_subsurface * -wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, - WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), 0, NULL, surface, parent); - - return (struct wl_subsurface *) id; -} - -#ifndef WL_SUBSURFACE_ERROR_ENUM -#define WL_SUBSURFACE_ERROR_ENUM -enum wl_subsurface_error { - /** - * wl_surface is not a sibling or the parent - */ - WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, -}; -#endif /* WL_SUBSURFACE_ERROR_ENUM */ - -#define WL_SUBSURFACE_DESTROY 0 -#define WL_SUBSURFACE_SET_POSITION 1 -#define WL_SUBSURFACE_PLACE_ABOVE 2 -#define WL_SUBSURFACE_PLACE_BELOW 3 -#define WL_SUBSURFACE_SET_SYNC 4 -#define WL_SUBSURFACE_SET_DESYNC 5 - - -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1 -/** - * @ingroup iface_wl_subsurface - */ -#define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1 - -/** @ingroup iface_wl_subsurface */ -static inline void -wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data); -} - -/** @ingroup iface_wl_subsurface */ -static inline void * -wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface); -} - -static inline uint32_t -wl_subsurface_get_version(struct wl_subsurface *wl_subsurface) -{ - return wl_proxy_get_version((struct wl_proxy *) wl_subsurface); -} - -/** - * @ingroup iface_wl_subsurface - * - * The sub-surface interface is removed from the wl_surface object - * that was turned into a sub-surface with a - * wl_subcompositor.get_subsurface request. The wl_surface's association - * to the parent is deleted. The wl_surface is unmapped immediately. - */ -static inline void -wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_wl_subsurface - * - * This schedules a sub-surface position change. - * The sub-surface will be moved so that its origin (top left - * corner pixel) will be at the location x, y of the parent surface - * coordinate system. The coordinates are not restricted to the parent - * surface area. Negative values are allowed. - * - * The scheduled coordinates will take effect whenever the state of the - * parent surface is applied. When this happens depends on whether the - * parent surface is in synchronized mode or not. See - * wl_subsurface.set_sync and wl_subsurface.set_desync for details. - * - * If more than one set_position request is invoked by the client before - * the commit of the parent surface, the position of a new request always - * replaces the scheduled position from any previous request. - * - * The initial position is 0, 0. - */ -static inline void -wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, x, y); -} - -/** - * @ingroup iface_wl_subsurface - * - * This sub-surface is taken from the stack, and put back just - * above the reference surface, changing the z-order of the sub-surfaces. - * The reference surface must be one of the sibling surfaces, or the - * parent surface. Using any other surface, including this sub-surface, - * will cause a protocol error. - * - * The z-order is double-buffered. Requests are handled in order and - * applied immediately to a pending state. The final pending state is - * copied to the active state the next time the state of the parent - * surface is applied. When this happens depends on whether the parent - * surface is in synchronized mode or not. See wl_subsurface.set_sync and - * wl_subsurface.set_desync for details. - * - * A new sub-surface is initially added as the top-most in the stack - * of its siblings and parent. - */ -static inline void -wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_PLACE_ABOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); -} - -/** - * @ingroup iface_wl_subsurface - * - * The sub-surface is placed just below the reference surface. - * See wl_subsurface.place_above. - */ -static inline void -wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_PLACE_BELOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); -} - -/** - * @ingroup iface_wl_subsurface - * - * Change the commit behaviour of the sub-surface to synchronized - * mode, also described as the parent dependent mode. - * - * In synchronized mode, wl_surface.commit on a sub-surface will - * accumulate the committed state in a cache, but the state will - * not be applied and hence will not change the compositor output. - * The cached state is applied to the sub-surface immediately after - * the parent surface's state is applied. This ensures atomic - * updates of the parent and all its synchronized sub-surfaces. - * Applying the cached state will invalidate the cache, so further - * parent surface commits do not (re-)apply old state. - * - * See wl_subsurface for the recursive effect of this mode. - */ -static inline void -wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); -} - -/** - * @ingroup iface_wl_subsurface - * - * Change the commit behaviour of the sub-surface to desynchronized - * mode, also described as independent or freely running mode. - * - * In desynchronized mode, wl_surface.commit on a sub-surface will - * apply the pending state directly, without caching, as happens - * normally with a wl_surface. Calling wl_surface.commit on the - * parent surface has no effect on the sub-surface's wl_surface - * state. This mode allows a sub-surface to be updated on its own. - * - * If cached state exists when wl_surface.commit is called in - * desynchronized mode, the pending state is added to the cached - * state, and applied as a whole. This invalidates the cache. - * - * Note: even if a sub-surface is set to desynchronized, a parent - * sub-surface may override it to behave as synchronized. For details, - * see wl_subsurface. - * - * If a surface's parent surface behaves as desynchronized, then - * the cached state is applied on set_desync. - */ -static inline void -wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, - WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol-code.h deleted file mode 100644 index ceece5a2b..000000000 --- a/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol-code.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * Copyright © 2020 Aleix Pol Gonzalez - * Copyright © 2020 Carlos Garnacho - * - * 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 -#include -#include -#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_seat_interface; -extern const struct wl_interface wl_surface_interface; -extern const struct wl_interface xdg_activation_token_v1_interface; - -static const struct wl_interface *xdg_activation_v1_types[] = { - NULL, - &xdg_activation_token_v1_interface, - NULL, - &wl_surface_interface, - NULL, - &wl_seat_interface, - &wl_surface_interface, -}; - -static const struct wl_message xdg_activation_v1_requests[] = { - { "destroy", "", xdg_activation_v1_types + 0 }, - { "get_activation_token", "n", xdg_activation_v1_types + 1 }, - { "activate", "so", xdg_activation_v1_types + 2 }, -}; - -WL_PRIVATE const struct wl_interface xdg_activation_v1_interface = { - "xdg_activation_v1", 1, - 3, xdg_activation_v1_requests, - 0, NULL, -}; - -static const struct wl_message xdg_activation_token_v1_requests[] = { - { "set_serial", "uo", xdg_activation_v1_types + 4 }, - { "set_app_id", "s", xdg_activation_v1_types + 0 }, - { "set_surface", "o", xdg_activation_v1_types + 6 }, - { "commit", "", xdg_activation_v1_types + 0 }, - { "destroy", "", xdg_activation_v1_types + 0 }, -}; - -static const struct wl_message xdg_activation_token_v1_events[] = { - { "done", "s", xdg_activation_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface xdg_activation_token_v1_interface = { - "xdg_activation_token_v1", 1, - 5, xdg_activation_token_v1_requests, - 1, xdg_activation_token_v1_events, -}; - diff --git a/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol.h b/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol.h deleted file mode 100644 index b26c548c9..000000000 --- a/pkg/glfw/wayland-headers/xdg-activation-v1-client-protocol.h +++ /dev/null @@ -1,415 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef XDG_ACTIVATION_V1_CLIENT_PROTOCOL_H -#define XDG_ACTIVATION_V1_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_xdg_activation_v1 The xdg_activation_v1 protocol - * Protocol for requesting activation of surfaces - * - * @section page_desc_xdg_activation_v1 Description - * - * The way for a client to pass focus to another toplevel is as follows. - * - * The client that intends to activate another toplevel uses the - * xdg_activation_v1.get_activation_token request to get an activation token. - * This token is then forwarded to the client, which is supposed to activate - * one of its surfaces, through a separate band of communication. - * - * One established way of doing this is through the XDG_ACTIVATION_TOKEN - * environment variable of a newly launched child process. The child process - * should unset the environment variable again right after reading it out in - * order to avoid propagating it to other child processes. - * - * Another established way exists for Applications implementing the D-Bus - * interface org.freedesktop.Application, which should get their token under - * activation-token on their platform_data. - * - * In general activation tokens may be transferred across clients through - * means not described in this protocol. - * - * The client to be activated will then pass the token - * it received to the xdg_activation_v1.activate request. The compositor can - * then use this token to decide how to react to the activation request. - * - * The token the activating client gets may be ineffective either already at - * the time it receives it, for example if it was not focused, for focus - * stealing prevention. The activating client will have no way to discover - * the validity of the token, and may still forward it to the to be activated - * client. - * - * The created activation token may optionally get information attached to it - * that can be used by the compositor to identify the application that we - * intend to activate. This can for example be used to display a visual hint - * about what application is being started. - * - * Warning! The protocol described in this file is currently in the testing - * phase. Backward compatible changes may be added together with the - * corresponding interface version bump. Backward incompatible changes can - * only be done by creating a new major version of the extension. - * - * @section page_ifaces_xdg_activation_v1 Interfaces - * - @subpage page_iface_xdg_activation_v1 - interface for activating surfaces - * - @subpage page_iface_xdg_activation_token_v1 - an exported activation handle - * @section page_copyright_xdg_activation_v1 Copyright - *
- *
- * Copyright © 2020 Aleix Pol Gonzalez 
- * Copyright © 2020 Carlos Garnacho 
- *
- * 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.
- * 
- */ -struct wl_seat; -struct wl_surface; -struct xdg_activation_token_v1; -struct xdg_activation_v1; - -#ifndef XDG_ACTIVATION_V1_INTERFACE -#define XDG_ACTIVATION_V1_INTERFACE -/** - * @page page_iface_xdg_activation_v1 xdg_activation_v1 - * @section page_iface_xdg_activation_v1_desc Description - * - * A global interface used for informing the compositor about applications - * being activated or started, or for applications to request to be - * activated. - * @section page_iface_xdg_activation_v1_api API - * See @ref iface_xdg_activation_v1. - */ -/** - * @defgroup iface_xdg_activation_v1 The xdg_activation_v1 interface - * - * A global interface used for informing the compositor about applications - * being activated or started, or for applications to request to be - * activated. - */ -extern const struct wl_interface xdg_activation_v1_interface; -#endif -#ifndef XDG_ACTIVATION_TOKEN_V1_INTERFACE -#define XDG_ACTIVATION_TOKEN_V1_INTERFACE -/** - * @page page_iface_xdg_activation_token_v1 xdg_activation_token_v1 - * @section page_iface_xdg_activation_token_v1_desc Description - * - * An object for setting up a token and receiving a token handle that can - * be passed as an activation token to another client. - * - * The object is created using the xdg_activation_v1.get_activation_token - * request. This object should then be populated with the app_id, surface - * and serial information and committed. The compositor shall then issue a - * done event with the token. In case the request's parameters are invalid, - * the compositor will provide an invalid token. - * @section page_iface_xdg_activation_token_v1_api API - * See @ref iface_xdg_activation_token_v1. - */ -/** - * @defgroup iface_xdg_activation_token_v1 The xdg_activation_token_v1 interface - * - * An object for setting up a token and receiving a token handle that can - * be passed as an activation token to another client. - * - * The object is created using the xdg_activation_v1.get_activation_token - * request. This object should then be populated with the app_id, surface - * and serial information and committed. The compositor shall then issue a - * done event with the token. In case the request's parameters are invalid, - * the compositor will provide an invalid token. - */ -extern const struct wl_interface xdg_activation_token_v1_interface; -#endif - -#define XDG_ACTIVATION_V1_DESTROY 0 -#define XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN 1 -#define XDG_ACTIVATION_V1_ACTIVATE 2 - - -/** - * @ingroup iface_xdg_activation_v1 - */ -#define XDG_ACTIVATION_V1_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_v1 - */ -#define XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_v1 - */ -#define XDG_ACTIVATION_V1_ACTIVATE_SINCE_VERSION 1 - -/** @ingroup iface_xdg_activation_v1 */ -static inline void -xdg_activation_v1_set_user_data(struct xdg_activation_v1 *xdg_activation_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_activation_v1, user_data); -} - -/** @ingroup iface_xdg_activation_v1 */ -static inline void * -xdg_activation_v1_get_user_data(struct xdg_activation_v1 *xdg_activation_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_activation_v1); -} - -static inline uint32_t -xdg_activation_v1_get_version(struct xdg_activation_v1 *xdg_activation_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1); -} - -/** - * @ingroup iface_xdg_activation_v1 - * - * Notify the compositor that the xdg_activation object will no longer be - * used. - * - * The child objects created via this interface are unaffected and should - * be destroyed separately. - */ -static inline void -xdg_activation_v1_destroy(struct xdg_activation_v1 *xdg_activation_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1, - XDG_ACTIVATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), WL_MARSHAL_FLAG_DESTROY); -} - -/** - * @ingroup iface_xdg_activation_v1 - * - * Creates an xdg_activation_token_v1 object that will provide - * the initiating client with a unique token for this activation. This - * token should be offered to the clients to be activated. - */ -static inline struct xdg_activation_token_v1 * -xdg_activation_v1_get_activation_token(struct xdg_activation_v1 *xdg_activation_v1) -{ - struct wl_proxy *id; - - id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1, - XDG_ACTIVATION_V1_GET_ACTIVATION_TOKEN, &xdg_activation_token_v1_interface, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), 0, NULL); - - return (struct xdg_activation_token_v1 *) id; -} - -/** - * @ingroup iface_xdg_activation_v1 - * - * Requests surface activation. It's up to the compositor to display - * this information as desired, for example by placing the surface above - * the rest. - * - * The compositor may know who requested this by checking the activation - * token and might decide not to follow through with the activation if it's - * considered unwanted. - * - * Compositors can ignore unknown activation tokens when an invalid - * token is passed. - */ -static inline void -xdg_activation_v1_activate(struct xdg_activation_v1 *xdg_activation_v1, const char *token, struct wl_surface *surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_v1, - XDG_ACTIVATION_V1_ACTIVATE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_v1), 0, token, surface); -} - -#ifndef XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM -#define XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM -enum xdg_activation_token_v1_error { - /** - * The token has already been used previously - */ - XDG_ACTIVATION_TOKEN_V1_ERROR_ALREADY_USED = 0, -}; -#endif /* XDG_ACTIVATION_TOKEN_V1_ERROR_ENUM */ - -/** - * @ingroup iface_xdg_activation_token_v1 - * @struct xdg_activation_token_v1_listener - */ -struct xdg_activation_token_v1_listener { - /** - * the exported activation token - * - * The 'done' event contains the unique token of this activation - * request and notifies that the provider is done. - * @param token the exported activation token - */ - void (*done)(void *data, - struct xdg_activation_token_v1 *xdg_activation_token_v1, - const char *token); -}; - -/** - * @ingroup iface_xdg_activation_token_v1 - */ -static inline int -xdg_activation_token_v1_add_listener(struct xdg_activation_token_v1 *xdg_activation_token_v1, - const struct xdg_activation_token_v1_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) xdg_activation_token_v1, - (void (**)(void)) listener, data); -} - -#define XDG_ACTIVATION_TOKEN_V1_SET_SERIAL 0 -#define XDG_ACTIVATION_TOKEN_V1_SET_APP_ID 1 -#define XDG_ACTIVATION_TOKEN_V1_SET_SURFACE 2 -#define XDG_ACTIVATION_TOKEN_V1_COMMIT 3 -#define XDG_ACTIVATION_TOKEN_V1_DESTROY 4 - -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_DONE_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_SET_SERIAL_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_SET_APP_ID_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_SET_SURFACE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_COMMIT_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_activation_token_v1 - */ -#define XDG_ACTIVATION_TOKEN_V1_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_xdg_activation_token_v1 */ -static inline void -xdg_activation_token_v1_set_user_data(struct xdg_activation_token_v1 *xdg_activation_token_v1, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) xdg_activation_token_v1, user_data); -} - -/** @ingroup iface_xdg_activation_token_v1 */ -static inline void * -xdg_activation_token_v1_get_user_data(struct xdg_activation_token_v1 *xdg_activation_token_v1) -{ - return wl_proxy_get_user_data((struct wl_proxy *) xdg_activation_token_v1); -} - -static inline uint32_t -xdg_activation_token_v1_get_version(struct xdg_activation_token_v1 *xdg_activation_token_v1) -{ - return wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * Provides information about the seat and serial event that requested the - * token. - * - * The serial can come from an input or focus event. For instance, if a - * click triggers the launch of a third-party client, the launcher client - * should send a set_serial request with the serial and seat from the - * wl_pointer.button event. - * - * Some compositors might refuse to activate toplevels when the token - * doesn't have a valid and recent enough event serial. - * - * Must be sent before commit. This information is optional. - */ -static inline void -xdg_activation_token_v1_set_serial(struct xdg_activation_token_v1 *xdg_activation_token_v1, uint32_t serial, struct wl_seat *seat) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_SET_SERIAL, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, serial, seat); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * The requesting client can specify an app_id to associate the token - * being created with it. - * - * Must be sent before commit. This information is optional. - */ -static inline void -xdg_activation_token_v1_set_app_id(struct xdg_activation_token_v1 *xdg_activation_token_v1, const char *app_id) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, app_id); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * This request sets the surface requesting the activation. Note, this is - * different from the surface that will be activated. - * - * Some compositors might refuse to activate toplevels when the token - * doesn't have a requesting surface. - * - * Must be sent before commit. This information is optional. - */ -static inline void -xdg_activation_token_v1_set_surface(struct xdg_activation_token_v1 *xdg_activation_token_v1, struct wl_surface *surface) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_SET_SURFACE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0, surface); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * Requests an activation token based on the different parameters that - * have been offered through set_serial, set_surface and set_app_id. - */ -static inline void -xdg_activation_token_v1_commit(struct xdg_activation_token_v1 *xdg_activation_token_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), 0); -} - -/** - * @ingroup iface_xdg_activation_token_v1 - * - * Notify the compositor that the xdg_activation_token_v1 object will no - * longer be used. The received token stays valid. - */ -static inline void -xdg_activation_token_v1_destroy(struct xdg_activation_token_v1 *xdg_activation_token_v1) -{ - wl_proxy_marshal_flags((struct wl_proxy *) xdg_activation_token_v1, - XDG_ACTIVATION_TOKEN_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_activation_token_v1), WL_MARSHAL_FLAG_DESTROY); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol-code.h b/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol-code.h deleted file mode 100644 index 85496afa3..000000000 --- a/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol-code.h +++ /dev/null @@ -1,76 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * 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 -#include -#include -#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/xdg-decoration-unstable-v1-client-protocol.h b/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol.h deleted file mode 100644 index 1aa6a0db1..000000000 --- a/pkg/glfw/wayland-headers/xdg-decoration-unstable-v1-client-protocol.h +++ /dev/null @@ -1,378 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H -#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H - -#include -#include -#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 - *
- *
- * 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.
- * 
- */ -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/xdg-shell-client-protocol-code.h b/pkg/glfw/wayland-headers/xdg-shell-client-protocol-code.h deleted file mode 100644 index d698c2ca5..000000000 --- a/pkg/glfw/wayland-headers/xdg-shell-client-protocol-code.h +++ /dev/null @@ -1,184 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -/* - * 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 -#include -#include -#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/xdg-shell-client-protocol.h b/pkg/glfw/wayland-headers/xdg-shell-client-protocol.h deleted file mode 100644 index 1e5a9664b..000000000 --- a/pkg/glfw/wayland-headers/xdg-shell-client-protocol.h +++ /dev/null @@ -1,2307 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef XDG_SHELL_CLIENT_PROTOCOL_H -#define XDG_SHELL_CLIENT_PROTOCOL_H - -#include -#include -#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 - *
- *
- * 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.
- * 
- */ -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/pkg/macos/graphics/context.zig b/pkg/macos/graphics/context.zig index d1c6c943f..77e4344e0 100644 --- a/pkg/macos/graphics/context.zig +++ b/pkg/macos/graphics/context.zig @@ -141,6 +141,22 @@ pub fn Context(comptime T: type) type { @bitCast(rect), ); } + + pub fn scaleCTM(self: *T, sx: c.CGFloat, sy: c.CGFloat) void { + c.CGContextScaleCTM( + @ptrCast(self), + sx, + sy, + ); + } + + pub fn translateCTM(self: *T, tx: c.CGFloat, ty: c.CGFloat) void { + c.CGContextTranslateCTM( + @ptrCast(self), + tx, + ty, + ); + } }; } diff --git a/src/apprt.zig b/src/apprt.zig index dd726b3f2..cb542875e 100644 --- a/src/apprt.zig +++ b/src/apprt.zig @@ -3,7 +3,7 @@ //! getting user input (mouse/keyboard), etc. //! //! This enables compile-time interfaces to be built to swap out the underlying -//! application runtime. For example: glfw, pure macOS Cocoa, GTK+, browser, etc. +//! application runtime. For example: pure macOS Cocoa, GTK+, browser, etc. //! //! The goal is to have different implementations share as much of the core //! logic as possible, and to only reach out to platform-specific implementation @@ -15,7 +15,6 @@ const build_config = @import("build_config.zig"); const structs = @import("apprt/structs.zig"); pub const action = @import("apprt/action.zig"); -pub const glfw = @import("apprt/glfw.zig"); pub const gtk = @import("apprt/gtk.zig"); pub const none = @import("apprt/none.zig"); pub const browser = @import("apprt/browser.zig"); @@ -42,7 +41,6 @@ pub const SurfaceSize = structs.SurfaceSize; pub const runtime = switch (build_config.artifact) { .exe => switch (build_config.app_runtime) { .none => none, - .glfw => glfw, .gtk => gtk, }, .lib => embedded, @@ -53,18 +51,12 @@ pub const App = runtime.App; pub const Surface = runtime.Surface; /// Runtime is the runtime to use for Ghostty. All runtimes do not provide -/// equivalent feature sets. For example, GTK offers tabbing and more features -/// that glfw does not provide. However, glfw may require many less -/// dependencies. +/// equivalent feature sets. pub const Runtime = enum { /// Will not produce an executable at all when `zig build` is called. /// This is only useful if you're only interested in the lib only (macOS). none, - /// Glfw-backed. Very simple. Glfw is statically linked. Tabbing and - /// other rich windowing features are not supported. - glfw, - /// GTK-backed. Rich windowed application. GTK is dynamically linked. gtk, @@ -72,12 +64,8 @@ pub const Runtime = enum { // The Linux default is GTK because it is full featured. if (target.os.tag == .linux) return .gtk; - // Windows we currently only support glfw - if (target.os.tag == .windows) return .glfw; - - // Otherwise, we do NONE so we don't create an exe. The GLFW - // build is opt-in because it is missing so many features compared - // to the other builds that are impossible due to the GLFW interface. + // Otherwise, we do NONE so we don't create an exe and we + // create libghostty. return .none; } }; diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index dec1e4135..0121494b7 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -236,7 +236,7 @@ pub const App = struct { var surface = try self.core_app.alloc.create(Surface); errdefer self.core_app.alloc.destroy(surface); - // Create the surface -- because windows are surfaces for glfw. + // Create the surface try surface.init(self, opts); errdefer surface.deinit(); diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig deleted file mode 100644 index b82771d75..000000000 --- a/src/apprt/glfw.zig +++ /dev/null @@ -1,1266 +0,0 @@ -//! Application runtime implementation that uses GLFW (https://www.glfw.org/). -//! -//! This works on macOS and Linux with OpenGL and Metal. -//! (The above sentence may be out of date). - -const std = @import("std"); -const builtin = @import("builtin"); -const build_config = @import("../build_config.zig"); -const assert = std.debug.assert; -const Allocator = std.mem.Allocator; -const glfw = @import("glfw"); -const macos = @import("macos"); -const objc = @import("objc"); -const cli = @import("../cli.zig"); -const input = @import("../input.zig"); -const internal_os = @import("../os/main.zig"); -const renderer = @import("../renderer.zig"); -const terminal = @import("../terminal/main.zig"); -const Renderer = renderer.Renderer; -const apprt = @import("../apprt.zig"); -const CoreApp = @import("../App.zig"); -const CoreSurface = @import("../Surface.zig"); -const configpkg = @import("../config.zig"); -const Config = @import("../config.zig").Config; - -// Get native API access on certain platforms so we can do more customization. -const glfwNative = glfw.Native(.{ - .cocoa = builtin.target.os.tag.isDarwin(), - .x11 = builtin.os.tag == .linux, -}); - -/// True if darwin-specific logic is enabled -const darwin_enabled = builtin.target.os.tag.isDarwin() and - build_config.artifact == .exe; - -const log = std.log.scoped(.glfw); - -pub const resourcesDir = internal_os.resourcesDir; - -pub const App = struct { - app: *CoreApp, - config: Config, - - /// Flips to true to quit on the next event loop tick. This - /// never goes false and forces the event loop to exit. - quit: bool = false, - - /// Mac-specific state. - darwin: if (darwin_enabled) Darwin else void, - - pub const Options = struct {}; - - pub fn init(self: *App, core_app: *CoreApp, _: Options) !void { - if (comptime builtin.target.os.tag.isDarwin()) { - log.warn("WARNING WARNING WARNING: GLFW ON MAC HAS BUGS.", .{}); - log.warn("You should use the AppKit-based app instead. The official download", .{}); - log.warn("is properly built and available from GitHub. If you're building from", .{}); - log.warn("source, see the README for details on how to build the AppKit app.", .{}); - } - - if (!glfw.init(.{})) { - if (glfw.getError()) |err| { - log.err("error initializing GLFW err={} msg={s}", .{ - err.error_code, - err.description, - }); - return err.error_code; - } - - return error.GlfwInitFailedUnknownReason; - } - glfw.setErrorCallback(glfwErrorCallback); - - // Mac-specific state. For example, on Mac we enable window tabbing. - var darwin = if (darwin_enabled) try Darwin.init() else {}; - errdefer if (darwin_enabled) darwin.deinit(); - - // Load our configuration - var config = try Config.load(core_app.alloc); - errdefer config.deinit(); - - // If we had configuration errors, then log them. - if (!config._diagnostics.empty()) { - var buf = std.ArrayList(u8).init(core_app.alloc); - defer buf.deinit(); - for (config._diagnostics.items()) |diag| { - try diag.write(buf.writer()); - log.warn("configuration error: {s}", .{buf.items}); - buf.clearRetainingCapacity(); - } - - // If we have any CLI errors, exit. - if (config._diagnostics.containsLocation(.cli)) { - log.warn("CLI errors detected, exiting", .{}); - _ = core_app.mailbox.push(.{ - .quit = {}, - }, .{ .forever = {} }); - } - } - - // Queue a single new window that starts on launch - // Note: above we may send a quit so this may never happen - _ = core_app.mailbox.push(.{ - .new_window = .{}, - }, .{ .forever = {} }); - - // We want the event loop to wake up instantly so we can process our tick. - glfw.postEmptyEvent(); - - self.* = .{ - .app = core_app, - .config = config, - .darwin = darwin, - }; - } - - pub fn terminate(self: *App) void { - self.config.deinit(); - glfw.terminate(); - } - - /// Run the event loop. This doesn't return until the app exits. - pub fn run(self: *App) !void { - while (true) { - // Wait for any events from the app event loop. wakeup will post - // an empty event so that this will return. - // - // Warning: a known issue on macOS is that this will block while - // a resize event is actively happening, which will prevent the - // app tick from happening. I don't know know a way around this - // but its not a big deal since we don't use glfw for the official - // mac app, but noting it in case anyone builds for macos using - // glfw. - glfw.waitEvents(); - - // Tick the terminal app - try self.app.tick(self); - - // If the tick caused us to quit, then we're done. - if (self.quit or self.app.surfaces.items.len == 0) { - for (self.app.surfaces.items) |surface| { - surface.close(false); - } - - return; - } - } - } - - /// Wakeup the event loop. This should be able to be called from any thread. - pub fn wakeup(self: *const App) void { - _ = self; - glfw.postEmptyEvent(); - } - - /// Perform a given action. Returns `true` if the action was able to be - /// performed, `false` otherwise. - pub fn performAction( - self: *App, - target: apprt.Target, - comptime action: apprt.Action.Key, - value: apprt.Action.Value(action), - ) !bool { - switch (action) { - .quit => self.quit = true, - - .new_window => _ = try self.newSurface(switch (target) { - .app => null, - .surface => |v| v, - }), - - .new_tab => try self.newTab(switch (target) { - .app => null, - .surface => |v| v, - }), - - .size_limit => switch (target) { - .app => {}, - .surface => |surface| try surface.rt_surface.setSizeLimits(.{ - .width = value.min_width, - .height = value.min_height, - }, if (value.max_width > 0) .{ - .width = value.max_width, - .height = value.max_height, - } else null), - }, - - .initial_size => switch (target) { - .app => {}, - .surface => |surface| try surface.rt_surface.setInitialWindowSize( - value.width, - value.height, - ), - }, - - .toggle_fullscreen => self.toggleFullscreen(target), - - .open_config => try configpkg.edit.open(self.app.alloc), - - .set_title => switch (target) { - .app => {}, - .surface => |surface| try surface.rt_surface.setTitle(value.title), - }, - - .mouse_shape => switch (target) { - .app => {}, - .surface => |surface| try surface.rt_surface.setMouseShape(value), - }, - - .mouse_visibility => switch (target) { - .app => {}, - .surface => |surface| surface.rt_surface.setMouseVisibility(switch (value) { - .visible => true, - .hidden => false, - }), - }, - - .reload_config => try self.reloadConfig(target, value), - - // Unimplemented - .new_split, - .goto_split, - .resize_split, - .equalize_splits, - .toggle_split_zoom, - .present_terminal, - .close_all_windows, - .close_window, - .close_tab, - .toggle_tab_overview, - .toggle_window_decorations, - .toggle_quick_terminal, - .toggle_command_palette, - .toggle_visibility, - .goto_tab, - .move_tab, - .inspector, - .render_inspector, - .quit_timer, - .float_window, - .secure_input, - .key_sequence, - .desktop_notification, - .mouse_over_link, - .cell_size, - .renderer_health, - .color_change, - .pwd, - .config_change, - .toggle_maximize, - .prompt_title, - .reset_window_size, - .ring_bell, - .check_for_updates, - .undo, - .redo, - .show_gtk_inspector, - => { - log.info("unimplemented action={}", .{action}); - return false; - }, - } - - return true; - } - - /// Reload the configuration. This should return the new configuration. - /// The old value can be freed immediately at this point assuming a - /// successful return. - /// - /// The returned pointer value is only valid for a stable self pointer. - fn reloadConfig( - self: *App, - target: apprt.action.Target, - opts: apprt.action.ReloadConfig, - ) !void { - if (opts.soft) { - switch (target) { - .app => try self.app.updateConfig(self, &self.config), - .surface => |core_surface| try core_surface.updateConfig( - &self.config, - ), - } - return; - } - - // Load our configuration - var config = try Config.load(self.app.alloc); - errdefer config.deinit(); - - // Call into our app to update - switch (target) { - .app => try self.app.updateConfig(self, &config), - .surface => |core_surface| try core_surface.updateConfig(&config), - } - - // Update the existing config, be sure to clean up the old one. - self.config.deinit(); - self.config = config; - } - - /// Toggle the window to fullscreen mode. - fn toggleFullscreen(self: *App, target: apprt.Target) void { - _ = self; - const surface: *Surface = switch (target) { - .app => return, - .surface => |v| v.rt_surface, - }; - const win = surface.window; - - if (surface.isFullscreen()) { - win.setMonitor( - null, - @intCast(surface.monitor_dims.position_x), - @intCast(surface.monitor_dims.position_y), - surface.monitor_dims.width, - surface.monitor_dims.height, - 0, - ); - return; - } - - const monitor = win.getMonitor() orelse monitor: { - log.warn("window had null monitor, getting primary monitor", .{}); - break :monitor glfw.Monitor.getPrimary() orelse { - log.warn("window could not get any monitor. will not perform action", .{}); - return; - }; - }; - - const video_mode = monitor.getVideoMode() orelse { - log.warn("failed to get video mode. will not perform action", .{}); - return; - }; - - const position = win.getPos(); - const size = surface.getSize() catch { - log.warn("failed to get window size. will not perform fullscreen action", .{}); - return; - }; - - surface.monitor_dims = .{ - .width = size.width, - .height = size.height, - .position_x = position.x, - .position_y = position.y, - }; - - win.setMonitor(monitor, 0, 0, video_mode.getWidth(), video_mode.getHeight(), 0); - } - - /// Create a new tab in the parent surface. - fn newTab(self: *App, parent_: ?*CoreSurface) !void { - if (comptime !darwin_enabled) { - log.warn("tabbing is not supported on this platform", .{}); - return; - } - - const parent = parent_ orelse { - _ = try self.newSurface(null); - return; - }; - - // Create the new window - const window = try self.newSurface(parent); - - // Add the new window the parent window - const parent_win = glfwNative.getCocoaWindow(parent.rt_surface.window).?; - const other_win = glfwNative.getCocoaWindow(window.window).?; - const NSWindowOrderingMode = enum(isize) { below = -1, out = 0, above = 1 }; - const nswindow = objc.Object.fromId(parent_win); - nswindow.msgSend(void, objc.sel("addTabbedWindow:ordered:"), .{ - objc.Object.fromId(other_win), - NSWindowOrderingMode.above, - }); - - // Adding a new tab can cause the tab bar to appear which changes - // our viewport size. We need to call the size callback in order to - // update values. For example, we need this to set the proper mouse selection - // point in the grid. - const size = parent.rt_surface.getSize() catch |err| { - log.err("error querying window size for size callback on new tab err={}", .{err}); - return; - }; - parent.sizeCallback(size) catch |err| { - log.err("error in size callback from new tab err={}", .{err}); - return; - }; - } - - fn newSurface(self: *App, parent_: ?*CoreSurface) !*Surface { - // Grab a surface allocation because we're going to need it. - var surface = try self.app.alloc.create(Surface); - errdefer self.app.alloc.destroy(surface); - - // Create the surface -- because windows are surfaces for glfw. - try surface.init(self); - errdefer surface.deinit(); - - // If we have a parent, inherit some properties - if (self.config.@"window-inherit-font-size") { - if (parent_) |parent| { - try surface.core_surface.setFontSize(parent.font_size); - } - } - - return surface; - } - - /// Close the given surface. - pub fn closeSurface(self: *App, surface: *Surface) void { - surface.deinit(); - self.app.alloc.destroy(surface); - } - - pub fn redrawSurface(self: *App, surface: *Surface) void { - _ = self; - _ = surface; - - @panic("This should never be called for GLFW."); - } - - pub fn redrawInspector(self: *App, surface: *Surface) void { - _ = self; - _ = surface; - - // GLFW doesn't support the inspector - } - - fn glfwErrorCallback(code: glfw.ErrorCode, desc: [:0]const u8) void { - std.log.warn("glfw error={} message={s}", .{ code, desc }); - - // Workaround for: https://github.com/ocornut/imgui/issues/5908 - // If we get an invalid value with "scancode" in the message we assume - // it is from the glfw key callback that imgui sets and we clear the - // error so that our future code doesn't crash. - if (code == glfw.ErrorCode.InvalidValue and - std.mem.indexOf(u8, desc, "scancode") != null) - { - _ = glfw.getError(); - } - } - - pub fn keyboardLayout(self: *const App) input.KeyboardLayout { - _ = self; - - // Not supported by glfw - return .unknown; - } - - /// Mac-specific settings. This is only enabled when the target is - /// Mac and the artifact is a standalone exe. We don't target libs because - /// the embedded API doesn't do windowing. - const Darwin = struct { - tabbing_id: *macos.foundation.String, - - pub fn init() !Darwin { - const NSWindow = objc.getClass("NSWindow").?; - NSWindow.msgSend(void, objc.sel("setAllowsAutomaticWindowTabbing:"), .{true}); - - // Our tabbing ID allows all of our windows to group together - const tabbing_id = try macos.foundation.String.createWithBytes( - "com.mitchellh.ghostty.window", - .utf8, - false, - ); - errdefer tabbing_id.release(); - - // Setup our Mac settings - return .{ .tabbing_id = tabbing_id }; - } - - pub fn deinit(self: *Darwin) void { - self.tabbing_id.release(); - self.* = undefined; - } - }; -}; - -/// These are used to keep track of the original monitor values so that we can -/// safely toggle on and off of fullscreen. -const MonitorDimensions = struct { - width: u32, - height: u32, - position_x: i64, - position_y: i64, -}; - -/// Surface represents the drawable surface for glfw. In glfw, a surface -/// is always a window because that is the only abstraction that glfw exposes. -/// -/// This means that there is no way for the glfw runtime to support tabs, -/// splits, etc. without considerable effort. In fact, on Darwin, we do -/// support tabs because the minimal tabbing interface is a window abstraction, -/// but this is a bit of a hack. The native Swift runtime should be used instead -/// which uses real native tabbing. -/// -/// Other runtimes a surface usually represents the equivalent of a "view" -/// or "widget" level granularity. -pub const Surface = struct { - /// The glfw window handle - window: glfw.Window, - - /// The glfw mouse cursor handle. - cursor: ?glfw.Cursor, - - /// The app we're part of - app: *App, - - /// A core surface - core_surface: CoreSurface, - - /// This is the key event that was processed in keyCallback. This is only - /// non-null if the event was NOT consumed in keyCallback. This lets us - /// know in charCallback whether we should populate it and call it again. - /// (GLFW guarantees that charCallback is called after keyCallback). - key_event: ?input.KeyEvent = null, - - /// The monitor dimensions so we can toggle fullscreen on and off. - monitor_dims: MonitorDimensions, - - /// Save the title text so that we can return it later when requested. - /// This is allocated from the heap so it must be freed when we deinit the - /// surface. - title_text: ?[:0]const u8 = null, - - pub const Options = struct {}; - - /// Initialize the surface into the given self pointer. This gives a - /// stable pointer to the destination that can be used for callbacks. - pub fn init(self: *Surface, app: *App) !void { - // Create our window - const win = glfw.Window.create( - 640, - 480, - "ghostty", - if (app.config.fullscreen) glfw.Monitor.getPrimary() else null, - null, - Renderer.glfwWindowHints(&app.config), - ) orelse return glfw.mustGetErrorCode(); - errdefer win.destroy(); - - // Setup our - setInitialWindowPosition( - win, - app.config.@"window-position-x", - app.config.@"window-position-y", - ); - - // Get our physical DPI - debug only because we don't have a use for - // this but the logging of it may be useful - if (builtin.mode == .Debug) { - const monitor = win.getMonitor() orelse monitor: { - log.warn("window had null monitor, getting primary monitor", .{}); - break :monitor glfw.Monitor.getPrimary().?; - }; - const video_mode = monitor.getVideoMode() orelse return glfw.mustGetErrorCode(); - const physical_size = monitor.getPhysicalSize(); - const physical_x_dpi = @as(f32, @floatFromInt(video_mode.getWidth())) / (@as(f32, @floatFromInt(physical_size.width_mm)) / 25.4); - const physical_y_dpi = @as(f32, @floatFromInt(video_mode.getHeight())) / (@as(f32, @floatFromInt(physical_size.height_mm)) / 25.4); - log.debug("physical dpi x={} y={}", .{ - physical_x_dpi, - physical_y_dpi, - }); - } - - // On Mac, enable window tabbing - if (comptime darwin_enabled) { - const NSWindowTabbingMode = enum(usize) { automatic = 0, preferred = 1, disallowed = 2 }; - const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(win).?); - - // Tabbing mode enables tabbing at all - nswindow.setProperty("tabbingMode", NSWindowTabbingMode.automatic); - - // All windows within a tab bar must have a matching tabbing ID. - // The app sets this up for us. - nswindow.setProperty("tabbingIdentifier", app.darwin.tabbing_id); - } - - // Set our callbacks - win.setUserPointer(&self.core_surface); - win.setSizeCallback(sizeCallback); - win.setCharCallback(charCallback); - win.setKeyCallback(keyCallback); - win.setFocusCallback(focusCallback); - win.setRefreshCallback(refreshCallback); - win.setScrollCallback(scrollCallback); - win.setCursorPosCallback(cursorPosCallback); - win.setMouseButtonCallback(mouseButtonCallback); - win.setDropCallback(dropCallback); - - const dimensions: MonitorDimensions = dimensions: { - const pos = win.getPos(); - const size = win.getFramebufferSize(); - break :dimensions .{ - .width = size.width, - .height = size.height, - .position_x = pos.x, - .position_y = pos.y, - }; - }; - - // Build our result - self.* = .{ - .app = app, - .window = win, - .cursor = null, - .core_surface = undefined, - .monitor_dims = dimensions, - }; - errdefer self.* = undefined; - - // Initialize our cursor - try self.setMouseShape(.text); - - // Add ourselves to the list of surfaces on the app. - try app.app.addSurface(self); - errdefer app.app.deleteSurface(self); - - // Get our new surface config - var config = try apprt.surface.newConfig(app.app, &app.config); - defer config.deinit(); - - // Initialize our surface now that we have the stable pointer. - try self.core_surface.init( - app.app.alloc, - &config, - app.app, - app, - self, - ); - errdefer self.core_surface.deinit(); - } - - pub fn deinit(self: *Surface) void { - if (self.title_text) |t| self.core_surface.alloc.free(t); - - // Remove ourselves from the list of known surfaces in the app. - self.app.app.deleteSurface(self); - - // Clean up our core surface so that all the rendering and IO stop. - self.core_surface.deinit(); - - if (comptime darwin_enabled) { - const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(self.window).?); - const tabgroup = nswindow.getProperty(objc.Object, "tabGroup"); - const windows = tabgroup.getProperty(objc.Object, "windows"); - switch (windows.getProperty(usize, "count")) { - // If we're going down to one window our tab bar is going to be - // destroyed so unset it so that the later logic doesn't try to - // use it. - 1 => {}, - - // If our tab bar is visible and we are going down to 1 window, - // hide the tab bar. The check is "2" because our current window - // is still present. - 2 => if (tabgroup.getProperty(bool, "tabBarVisible")) { - nswindow.msgSend(void, objc.sel("toggleTabBar:"), .{nswindow.value}); - }, - - else => {}, - } - } - - // We can now safely destroy our windows. We have to do this BEFORE - // setting up the new focused window below. - self.window.destroy(); - if (self.cursor) |c| { - c.destroy(); - self.cursor = null; - } - } - - /// Checks if the glfw window is in fullscreen. - pub fn isFullscreen(self: *Surface) bool { - return self.window.getMonitor() != null; - } - - /// Close this surface. - pub fn close(self: *Surface, processActive: bool) void { - _ = processActive; - self.setShouldClose(); - self.deinit(); - self.app.app.alloc.destroy(self); - } - - /// Set the initial window size. This is called exactly once at - /// surface initialization time. This may be called before "self" - /// is fully initialized. - fn setInitialWindowSize(self: *const Surface, width: u32, height: u32) !void { - const monitor = self.window.getMonitor() orelse glfw.Monitor.getPrimary() orelse { - log.warn("window is not on a monitor, not setting initial size", .{}); - return; - }; - - const workarea = monitor.getWorkarea(); - self.window.setSize(.{ - .width = @min(width, workarea.width), - .height = @min(height, workarea.height), - }); - } - - /// Set the initial window position. This is called exactly once at - /// surface initialization time. This may be called before "self" - /// is fully initialized. - fn setInitialWindowPosition(win: glfw.Window, x: ?i16, y: ?i16) void { - const start_position_x = x orelse return; - const start_position_y = y orelse return; - - log.debug("setting initial window position ({},{})", .{ start_position_x, start_position_y }); - win.setPos(.{ .x = start_position_x, .y = start_position_y }); - } - - /// Set the size limits of the window. - /// Note: this interface is not good, we should redo it if we plan - /// to use this more. i.e. you can't set max width but no max height, - /// or no mins. - fn setSizeLimits(self: *Surface, min: apprt.SurfaceSize, max_: ?apprt.SurfaceSize) !void { - self.window.setSizeLimits(.{ - .width = min.width, - .height = min.height, - }, if (max_) |max| .{ - .width = max.width, - .height = max.height, - } else .{ - .width = null, - .height = null, - }); - } - - /// Returns the content scale for the created window. - pub fn getContentScale(self: *const Surface) !apprt.ContentScale { - const scale = self.window.getContentScale(); - return apprt.ContentScale{ .x = scale.x_scale, .y = scale.y_scale }; - } - - /// Returns the size of the window in pixels. The pixel size may - /// not match screen coordinate size but we should be able to convert - /// back and forth using getContentScale. - pub fn getSize(self: *const Surface) !apprt.SurfaceSize { - const size = self.window.getFramebufferSize(); - return apprt.SurfaceSize{ .width = size.width, .height = size.height }; - } - - /// Returns the cursor position in scaled pixels relative to the - /// upper-left of the window. - pub fn getCursorPos(self: *const Surface) !apprt.CursorPos { - const unscaled_pos = self.window.getCursorPos(); - const pos = try self.cursorPosToPixels(unscaled_pos); - return apprt.CursorPos{ - .x = @floatCast(pos.xpos), - .y = @floatCast(pos.ypos), - }; - } - - /// Set the flag that notes this window should be closed for the next - /// iteration of the event loop. - pub fn setShouldClose(self: *Surface) void { - self.window.setShouldClose(true); - } - - /// Returns true if the window is flagged to close. - pub fn shouldClose(self: *const Surface) bool { - return self.window.shouldClose(); - } - - /// Set the title of the window. - fn setTitle(self: *Surface, slice: [:0]const u8) !void { - if (self.title_text) |t| self.core_surface.alloc.free(t); - self.title_text = try self.core_surface.alloc.dupeZ(u8, slice); - self.window.setTitle(self.title_text.?.ptr); - } - - /// Return the title of the window. - pub fn getTitle(self: *Surface) ?[:0]const u8 { - return self.title_text; - } - - /// Set the shape of the cursor. - fn setMouseShape(self: *Surface, shape: terminal.MouseShape) !void { - if ((comptime builtin.target.os.tag.isDarwin()) and - !internal_os.macos.isAtLeastVersion(13, 0, 0)) - { - // We only set our cursor if we're NOT on Mac, or if we are then the - // macOS version is >= 13 (Ventura). On prior versions, glfw crashes - // since we use a tab group. - return; - } - - const new = glfw.Cursor.createStandard(switch (shape) { - .default => .arrow, - .text => .ibeam, - .crosshair => .crosshair, - .pointer => .pointing_hand, - .ew_resize => .resize_ew, - .ns_resize => .resize_ns, - .nwse_resize => .resize_nwse, - .nesw_resize => .resize_nesw, - .all_scroll => .resize_all, - .not_allowed => .not_allowed, - else => return, // unsupported, ignore - }) orelse { - const err = glfw.mustGetErrorCode(); - log.warn("error creating cursor: {}", .{err}); - return; - }; - errdefer new.destroy(); - - // Set our cursor before we destroy the old one - self.window.setCursor(new); - - if (self.cursor) |c| c.destroy(); - self.cursor = new; - } - - /// Set the visibility of the mouse cursor. - fn setMouseVisibility(self: *Surface, visible: bool) void { - self.window.setInputModeCursor(if (visible) .normal else .hidden); - } - - pub fn supportsClipboard( - self: *const Surface, - clipboard_type: apprt.Clipboard, - ) bool { - _ = self; - return switch (clipboard_type) { - .standard => true, - .selection, .primary => comptime builtin.os.tag == .linux, - }; - } - - /// Start an async clipboard request. - pub fn clipboardRequest( - self: *Surface, - clipboard_type: apprt.Clipboard, - state: apprt.ClipboardRequest, - ) !void { - // GLFW can read clipboards immediately so just do that. - const str: [:0]const u8 = switch (clipboard_type) { - .standard => glfw.getClipboardString() orelse return glfw.mustGetErrorCode(), - .selection, .primary => selection: { - // Not supported except on Linux - if (comptime builtin.os.tag != .linux) break :selection ""; - - const raw = glfwNative.getX11SelectionString() orelse - return glfw.mustGetErrorCode(); - break :selection std.mem.span(raw); - }, - }; - - // Complete our request. We always allow unsafe because we don't - // want to deal with user confirmation in this runtime. - try self.core_surface.completeClipboardRequest(state, str, true); - } - - /// Set the clipboard. - pub fn setClipboardString( - self: *const Surface, - val: [:0]const u8, - clipboard_type: apprt.Clipboard, - confirm: bool, - ) !void { - _ = confirm; - _ = self; - switch (clipboard_type) { - .standard => glfw.setClipboardString(val), - .selection, .primary => { - // Not supported except on Linux - if (comptime builtin.os.tag != .linux) return; - glfwNative.setX11SelectionString(val.ptr); - }, - } - } - - /// The cursor position from glfw directly is in screen coordinates but - /// all our interface works in pixels. - fn cursorPosToPixels(self: *const Surface, pos: glfw.Window.CursorPos) !glfw.Window.CursorPos { - // The cursor position is in screen coordinates but we - // want it in pixels. we need to get both the size of the - // window in both to get the ratio to make the conversion. - const size = self.window.getSize(); - const fb_size = self.window.getFramebufferSize(); - - // If our framebuffer and screen are the same, then there is no scaling - // happening and we can short-circuit by returning the pos as-is. - if (fb_size.width == size.width and fb_size.height == size.height) - return pos; - - const x_scale = @as(f64, @floatFromInt(fb_size.width)) / @as(f64, @floatFromInt(size.width)); - const y_scale = @as(f64, @floatFromInt(fb_size.height)) / @as(f64, @floatFromInt(size.height)); - return .{ - .xpos = pos.xpos * x_scale, - .ypos = pos.ypos * y_scale, - }; - } - - pub fn defaultTermioEnv(self: *Surface) !std.process.EnvMap { - return try internal_os.getEnvMap(self.app.app.alloc); - } - - fn sizeCallback(window: glfw.Window, width: i32, height: i32) void { - _ = width; - _ = height; - - // Get the size. We are given a width/height but this is in screen - // coordinates and we want raw pixels. The core window uses the content - // scale to scale appropriately. - const core_win = window.getUserPointer(CoreSurface) orelse return; - const size = core_win.rt_surface.getSize() catch |err| { - log.err("error querying window size for size callback err={}", .{err}); - return; - }; - - // Call the primary callback. - core_win.sizeCallback(size) catch |err| { - log.err("error in size callback err={}", .{err}); - return; - }; - } - - fn charCallback(window: glfw.Window, codepoint: u21) void { - const core_win = window.getUserPointer(CoreSurface) orelse return; - - // We need a key event in order to process the charcallback. If it - // isn't set then the key event was consumed. - var key_event = core_win.rt_surface.key_event orelse return; - core_win.rt_surface.key_event = null; - - // Populate the utf8 value for the event - var buf: [4]u8 = undefined; - const len = std.unicode.utf8Encode(codepoint, &buf) catch |err| { - log.err("error encoding codepoint={} err={}", .{ codepoint, err }); - return; - }; - key_event.utf8 = buf[0..len]; - - // On macOS we need to also disable some modifiers because - // alt+key consumes the alt. - if (comptime builtin.target.os.tag.isDarwin()) { - // For GLFW, we say we always consume alt because - // GLFW doesn't have a way to disable the alt key. - key_event.consumed_mods.alt = true; - } - - _ = core_win.keyCallback(key_event) catch |err| { - log.err("error in key callback err={}", .{err}); - return; - }; - } - - fn keyCallback( - window: glfw.Window, - glfw_key: glfw.Key, - scancode: i32, - glfw_action: glfw.Action, - glfw_mods: glfw.Mods, - ) void { - _ = scancode; - - const core_win = window.getUserPointer(CoreSurface) orelse return; - - // Convert our glfw types into our input types - const mods: input.Mods = .{ - .shift = glfw_mods.shift, - .ctrl = glfw_mods.control, - .alt = glfw_mods.alt, - .super = glfw_mods.super, - }; - const action: input.Action = switch (glfw_action) { - .release => .release, - .press => .press, - .repeat => .repeat, - }; - const key: input.Key = switch (glfw_key) { - .a => .key_a, - .b => .key_b, - .c => .key_c, - .d => .key_d, - .e => .key_e, - .f => .key_f, - .g => .key_g, - .h => .key_h, - .i => .key_i, - .j => .key_j, - .k => .key_k, - .l => .key_l, - .m => .key_m, - .n => .key_n, - .o => .key_o, - .p => .key_p, - .q => .key_q, - .r => .key_r, - .s => .key_s, - .t => .key_t, - .u => .key_u, - .v => .key_v, - .w => .key_w, - .x => .key_x, - .y => .key_y, - .z => .key_z, - .zero => .digit_0, - .one => .digit_1, - .two => .digit_2, - .three => .digit_3, - .four => .digit_4, - .five => .digit_5, - .six => .digit_6, - .seven => .digit_7, - .eight => .digit_8, - .nine => .digit_9, - .up => .arrow_up, - .down => .arrow_down, - .right => .arrow_right, - .left => .arrow_left, - .home => .home, - .end => .end, - .page_up => .page_up, - .page_down => .page_down, - .escape => .escape, - .F1 => .f1, - .F2 => .f2, - .F3 => .f3, - .F4 => .f4, - .F5 => .f5, - .F6 => .f6, - .F7 => .f7, - .F8 => .f8, - .F9 => .f9, - .F10 => .f10, - .F11 => .f11, - .F12 => .f12, - .F13 => .f13, - .F14 => .f14, - .F15 => .f15, - .F16 => .f16, - .F17 => .f17, - .F18 => .f18, - .F19 => .f19, - .F20 => .f20, - .F21 => .f21, - .F22 => .f22, - .F23 => .f23, - .F24 => .f24, - .F25 => .f25, - .kp_0 => .numpad_0, - .kp_1 => .numpad_1, - .kp_2 => .numpad_2, - .kp_3 => .numpad_3, - .kp_4 => .numpad_4, - .kp_5 => .numpad_5, - .kp_6 => .numpad_6, - .kp_7 => .numpad_7, - .kp_8 => .numpad_8, - .kp_9 => .numpad_9, - .kp_decimal => .numpad_decimal, - .kp_divide => .numpad_divide, - .kp_multiply => .numpad_multiply, - .kp_subtract => .numpad_subtract, - .kp_add => .numpad_add, - .kp_enter => .numpad_enter, - .kp_equal => .numpad_equal, - .grave_accent => .backquote, - .minus => .minus, - .equal => .equal, - .space => .space, - .semicolon => .semicolon, - .apostrophe => .quote, - .comma => .comma, - .period => .period, - .slash => .slash, - .left_bracket => .bracket_left, - .right_bracket => .bracket_right, - .backslash => .backslash, - .enter => .enter, - .tab => .tab, - .backspace => .backspace, - .insert => .insert, - .delete => .delete, - .caps_lock => .caps_lock, - .scroll_lock => .scroll_lock, - .num_lock => .num_lock, - .print_screen => .print_screen, - .pause => .pause, - .left_shift => .shift_left, - .left_control => .control_left, - .left_alt => .alt_left, - .left_super => .meta_left, - .right_shift => .shift_right, - .right_control => .control_right, - .right_alt => .alt_right, - .right_super => .meta_right, - .menu => .context_menu, - - .world_1, - .world_2, - .unknown, - => .unidentified, - }; - - // This is a hack for GLFW. We require our apprts to send both - // the UTF8 encoding AND the keypress at the same time. Its critical - // for things like ctrl sequences to work. However, GLFW doesn't - // provide this information all at once. So we just infer based on - // the key press. This isn't portable but GLFW is only for testing. - const utf8 = switch (key) { - inline else => |k| utf8: { - if (mods.shift) break :utf8 ""; - const cp = k.codepoint() orelse break :utf8 ""; - const byte = std.math.cast(u8, cp) orelse break :utf8 ""; - break :utf8 &.{byte}; - }, - }; - - const key_event: input.KeyEvent = .{ - .action = action, - .key = key, - .mods = mods, - .consumed_mods = .{}, - .composing = false, - .utf8 = utf8, - .unshifted_codepoint = if (utf8.len > 0) @intCast(utf8[0]) else 0, - }; - - const effect = core_win.keyCallback(key_event) catch |err| { - log.err("error in key callback err={}", .{err}); - return; - }; - - // Surface closed. - if (effect == .closed) return; - - // If it wasn't consumed, we set it on our self so that charcallback - // can make another attempt. Otherwise, we set null so the charcallback - // is ignored. - core_win.rt_surface.key_event = null; - if (effect == .ignored and - (action == .press or action == .repeat)) - { - core_win.rt_surface.key_event = key_event; - } - } - - fn focusCallback(window: glfw.Window, focused: bool) void { - const core_win = window.getUserPointer(CoreSurface) orelse return; - core_win.focusCallback(focused) catch |err| { - log.err("error in focus callback err={}", .{err}); - return; - }; - } - - fn refreshCallback(window: glfw.Window) void { - const core_win = window.getUserPointer(CoreSurface) orelse return; - core_win.refreshCallback() catch |err| { - log.err("error in refresh callback err={}", .{err}); - return; - }; - } - - fn scrollCallback(window: glfw.Window, xoff: f64, yoff: f64) void { - // Glfw doesn't support any of the scroll mods. - const scroll_mods: input.ScrollMods = .{}; - - const core_win = window.getUserPointer(CoreSurface) orelse return; - core_win.scrollCallback(xoff, yoff, scroll_mods) catch |err| { - log.err("error in scroll callback err={}", .{err}); - return; - }; - } - - fn cursorPosCallback( - window: glfw.Window, - unscaled_xpos: f64, - unscaled_ypos: f64, - ) void { - const core_win = window.getUserPointer(CoreSurface) orelse return; - - // Convert our unscaled x/y to scaled. - const pos = core_win.rt_surface.cursorPosToPixels(.{ - .xpos = unscaled_xpos, - .ypos = unscaled_ypos, - }) catch |err| { - log.err( - "error converting cursor pos to scaled pixels in cursor pos callback err={}", - .{err}, - ); - return; - }; - - core_win.cursorPosCallback(.{ - .x = @floatCast(pos.xpos), - .y = @floatCast(pos.ypos), - }, null) catch |err| { - log.err("error in cursor pos callback err={}", .{err}); - return; - }; - } - - fn mouseButtonCallback( - window: glfw.Window, - glfw_button: glfw.MouseButton, - glfw_action: glfw.Action, - glfw_mods: glfw.Mods, - ) void { - const core_win = window.getUserPointer(CoreSurface) orelse return; - - // Convert glfw button to input button - const mods: input.Mods = .{ - .shift = glfw_mods.shift, - .ctrl = glfw_mods.control, - .alt = glfw_mods.alt, - .super = glfw_mods.super, - }; - const button: input.MouseButton = switch (glfw_button) { - .left => .left, - .right => .right, - .middle => .middle, - .four => .four, - .five => .five, - .six => .six, - .seven => .seven, - .eight => .eight, - }; - const action: input.MouseButtonState = switch (glfw_action) { - .press => .press, - .release => .release, - else => unreachable, - }; - - _ = core_win.mouseButtonCallback(action, button, mods) catch |err| { - log.err("error in scroll callback err={}", .{err}); - return; - }; - } - - fn dropCallback(window: glfw.Window, paths: [][*:0]const u8) void { - const surface = window.getUserPointer(CoreSurface) orelse return; - - var list = std.ArrayList(u8).init(surface.alloc); - defer list.deinit(); - - for (paths) |path| { - const path_slice = std.mem.span(path); - - // preallocate worst case of escaping every char + space - list.ensureTotalCapacity(path_slice.len * 2 + 1) catch |err| { - log.err("error in drop callback err={}", .{err}); - return; - }; - - const writer = list.writer(); - for (path_slice) |c| { - if (std.mem.indexOfScalar(u8, "\\ ()[]{}<>\"'`!#$&;|*?\t", c)) |_| { - writer.print("\\{c}", .{c}) catch unreachable; // memory preallocated - } else writer.writeByte(c) catch unreachable; // same here - } - writer.writeByte(' ') catch unreachable; // separate paths - - surface.textCallback(list.items) catch |err| { - log.err("error in drop callback err={}", .{err}); - return; - }; - - list.clearRetainingCapacity(); // avoid unnecessary reallocations - } - } -}; diff --git a/src/build/Config.zig b/src/build/Config.zig index 5f8780af9..a9a79fb53 100644 --- a/src/build/Config.zig +++ b/src/build/Config.zig @@ -9,6 +9,7 @@ const apprt = @import("../apprt.zig"); const font = @import("../font/main.zig"); const rendererpkg = @import("../renderer.zig"); const Command = @import("../Command.zig"); +const XCFramework = @import("GhosttyXCFramework.zig"); const WasmTarget = @import("../os/wasm/target.zig").Target; const gtk = @import("gtk.zig"); @@ -24,6 +25,7 @@ const app_version: std.SemanticVersion = .{ .major = 1, .minor = 1, .patch = 4 } /// Standard build configuration options. optimize: std.builtin.OptimizeMode, target: std.Build.ResolvedTarget, +xcframework_target: XCFramework.Target = .universal, wasm_target: WasmTarget, /// Comptime interfaces @@ -48,14 +50,15 @@ patch_rpath: ?[]const u8 = null, /// Artifacts flatpak: bool = false, -emit_test_exe: bool = false, emit_bench: bool = false, -emit_helpgen: bool = false, emit_docs: bool = false, -emit_webdata: bool = false, -emit_xcframework: bool = false, +emit_helpgen: bool = false, +emit_macos_app: bool = false, emit_terminfo: bool = false, emit_termcap: bool = false, +emit_test_exe: bool = false, +emit_xcframework: bool = false, +emit_webdata: bool = false, /// Environmental properties env: std.process.EnvMap, @@ -109,6 +112,14 @@ pub fn init(b: *std.Build) !Config { .env = env, }; + //--------------------------------------------------------------- + // Target-specific properties + config.xcframework_target = b.option( + XCFramework.Target, + "xcframework-target", + "The target for the xcframework.", + ) orelse .universal; + //--------------------------------------------------------------- // Comptime Interfaces config.font_backend = b.option( @@ -340,6 +351,12 @@ pub fn init(b: *std.Build) !Config { !config.emit_test_exe and !config.emit_helpgen); + config.emit_macos_app = b.option( + bool, + "emit-macos-app", + "Build and install the macOS app bundle.", + ) orelse config.emit_xcframework; + //--------------------------------------------------------------- // System Packages @@ -378,11 +395,6 @@ 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/GhosttyDocs.zig b/src/build/GhosttyDocs.zig index 4b5dbfd92..b95b56f74 100644 --- a/src/build/GhosttyDocs.zig +++ b/src/build/GhosttyDocs.zig @@ -93,5 +93,32 @@ pub fn init( pub fn install(self: *const GhosttyDocs) void { const b = self.steps[0].owner; - for (self.steps) |step| b.getInstallStep().dependOn(step); + self.addStepDependencies(b.getInstallStep()); +} + +pub fn addStepDependencies( + self: *const GhosttyDocs, + other_step: *std.Build.Step, +) void { + for (self.steps) |step| other_step.dependOn(step); +} + +/// Installs some dummy files to satisfy the folder structure of docs +/// without actually generating any documentation. This is useful +/// when the `emit-docs` option is not set to true, but we still +/// need the rough directory structure to exist, such as for the macOS +/// app. +pub fn installDummy(self: *const GhosttyDocs, step: *std.Build.Step) void { + _ = self; + + const b = step.owner; + var wf = b.addWriteFiles(); + const path = "share/man/.placeholder"; + step.dependOn(&b.addInstallFile( + wf.add( + path, + "emit-docs not true so no man pages", + ), + path, + ).step); } diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig index e0f6b5611..7667d30c3 100644 --- a/src/build/GhosttyI18n.zig +++ b/src/build/GhosttyI18n.zig @@ -50,7 +50,14 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n { } pub fn install(self: *const GhosttyI18n) void { - for (self.steps) |step| self.owner.getInstallStep().dependOn(step); + self.addStepDependencies(self.owner.getInstallStep()); +} + +pub fn addStepDependencies( + self: *const GhosttyI18n, + other_step: *std.Build.Step, +) void { + for (self.steps) |step| other_step.dependOn(step); } fn createUpdateStep(b: *std.Build) !*std.Build.Step { diff --git a/src/build/GhosttyResources.zig b/src/build/GhosttyResources.zig index 34b5e35f8..ef04b21fd 100644 --- a/src/build/GhosttyResources.zig +++ b/src/build/GhosttyResources.zig @@ -397,5 +397,12 @@ fn addLinuxAppResources( pub fn install(self: *const GhosttyResources) void { const b = self.steps[0].owner; - for (self.steps) |step| b.getInstallStep().dependOn(step); + self.addStepDependencies(b.getInstallStep()); +} + +pub fn addStepDependencies( + self: *const GhosttyResources, + other_step: *std.Build.Step, +) void { + for (self.steps) |step| other_step.dependOn(step); } diff --git a/src/build/GhosttyXCFramework.zig b/src/build/GhosttyXCFramework.zig index 0dc4f5762..7debd6906 100644 --- a/src/build/GhosttyXCFramework.zig +++ b/src/build/GhosttyXCFramework.zig @@ -7,11 +7,23 @@ const GhosttyLib = @import("GhosttyLib.zig"); const XCFrameworkStep = @import("XCFrameworkStep.zig"); xcframework: *XCFrameworkStep, -macos: GhosttyLib, +target: Target, -pub fn init(b: *std.Build, deps: *const SharedDeps) !GhosttyXCFramework { - // Create our universal macOS static library. - const macos = try GhosttyLib.initMacOSUniversal(b, deps); +pub const Target = enum { native, universal }; + +pub fn init( + b: *std.Build, + deps: *const SharedDeps, + target: Target, +) !GhosttyXCFramework { + // Universal macOS build + const macos_universal = try GhosttyLib.initMacOSUniversal(b, deps); + + // Native macOS build + const macos_native = try GhosttyLib.initStatic(b, &try deps.retarget( + b, + Config.genericMacOSTarget(b, null), + )); // iOS const ios = try GhosttyLib.initStatic(b, &try deps.retarget( @@ -47,29 +59,43 @@ pub fn init(b: *std.Build, deps: *const SharedDeps) !GhosttyXCFramework { const xcframework = XCFrameworkStep.create(b, .{ .name = "GhosttyKit", .out_path = "macos/GhosttyKit.xcframework", - .libraries = &.{ - .{ - .library = macos.output, - .headers = b.path("include"), + .libraries = switch (target) { + .universal => &.{ + .{ + .library = macos_universal.output, + .headers = b.path("include"), + }, + .{ + .library = ios.output, + .headers = b.path("include"), + }, + .{ + .library = ios_sim.output, + .headers = b.path("include"), + }, }, - .{ - .library = ios.output, + + .native => &.{.{ + .library = macos_native.output, .headers = b.path("include"), - }, - .{ - .library = ios_sim.output, - .headers = b.path("include"), - }, + }}, }, }); return .{ .xcframework = xcframework, - .macos = macos, + .target = target, }; } pub fn install(self: *const GhosttyXCFramework) void { const b = self.xcframework.step.owner; - b.getInstallStep().dependOn(self.xcframework.step); + self.addStepDependencies(b.getInstallStep()); +} + +pub fn addStepDependencies( + self: *const GhosttyXCFramework, + other_step: *std.Build.Step, +) void { + other_step.dependOn(self.xcframework.step); } diff --git a/src/build/GhosttyXcodebuild.zig b/src/build/GhosttyXcodebuild.zig new file mode 100644 index 000000000..9b472eda8 --- /dev/null +++ b/src/build/GhosttyXcodebuild.zig @@ -0,0 +1,149 @@ +const Ghostty = @This(); + +const std = @import("std"); +const builtin = @import("builtin"); +const RunStep = std.Build.Step.Run; +const Config = @import("Config.zig"); +const Docs = @import("GhosttyDocs.zig"); +const I18n = @import("GhosttyI18n.zig"); +const Resources = @import("GhosttyResources.zig"); +const XCFramework = @import("GhosttyXCFramework.zig"); + +build: *std.Build.Step.Run, +open: *std.Build.Step.Run, +copy: *std.Build.Step.Run, + +pub const Deps = struct { + xcframework: *const XCFramework, + docs: *const Docs, + i18n: *const I18n, + resources: *const Resources, +}; + +pub fn init( + b: *std.Build, + config: *const Config, + deps: Deps, +) !Ghostty { + const xc_config = switch (config.optimize) { + .Debug => "Debug", + .ReleaseSafe, + .ReleaseSmall, + .ReleaseFast, + => "Release", + }; + + const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config}); + + // Our step to build the Ghostty macOS app. + const build = build: { + // External environment variables can mess up xcodebuild, so + // we create a new empty environment. + const env_map = try b.allocator.create(std.process.EnvMap); + env_map.* = .init(b.allocator); + + const build = RunStep.create(b, "xcodebuild"); + build.has_side_effects = true; + build.cwd = b.path("macos"); + build.env_map = env_map; + build.addArgs(&.{ + "xcodebuild", + "-target", + "Ghostty", + "-configuration", + xc_config, + }); + + switch (deps.xcframework.target) { + // Universal is our default target, so we don't have to + // add anything. + .universal => {}, + + // Native we need to override the architecture in the Xcode + // project with the -arch flag. + .native => build.addArgs(&.{ + "-arch", + switch (builtin.cpu.arch) { + .aarch64 => "arm64", + .x86_64 => "x86_64", + else => @panic("unsupported macOS arch"), + }, + }), + } + + // We need the xcframework + deps.xcframework.addStepDependencies(&build.step); + + // We also need all these resources because the xcode project + // references them via symlinks. + deps.resources.addStepDependencies(&build.step); + deps.i18n.addStepDependencies(&build.step); + deps.docs.installDummy(&build.step); + + // Expect success + build.expectExitCode(0); + + break :build build; + }; + + // Our step to open the resulting Ghostty app. + const open = open: { + const open = RunStep.create(b, "run Ghostty app"); + open.has_side_effects = true; + open.cwd = b.path(""); + open.addArgs(&.{b.fmt( + "{s}/Contents/MacOS/ghostty", + .{app_path}, + )}); + + // Open depends on the app + open.step.dependOn(&build.step); + + // This overrides our default behavior and forces logs to show + // up on stderr (in addition to the centralized macOS log). + open.setEnvironmentVariable("GHOSTTY_LOG", "1"); + + // This is hack so that we can activate the app and bring it to + // the front forcibly even though we're executing directly + // via the binary and not launch services. + open.setEnvironmentVariable("GHOSTTY_MAC_ACTIVATE", "1"); + + if (b.args) |args| { + open.addArgs(args); + } else { + // This tricks the app into thinking it's running from the + // app bundle so we don't execute our CLI mode. + open.setEnvironmentVariable("GHOSTTY_MAC_APP", "1"); + } + + break :open open; + }; + + // Our step to copy the app bundle to the install path. + // We have to use `cp -R` because there are symlinks in the + // bundle. + const copy = copy: { + const step = RunStep.create(b, "copy app bundle"); + step.addArgs(&.{ "cp", "-R" }); + step.addFileArg(b.path(app_path)); + step.addArg(b.fmt("{s}", .{b.install_path})); + step.step.dependOn(&build.step); + break :copy step; + }; + + return .{ + .build = build, + .open = open, + .copy = copy, + }; +} + +pub fn install(self: *const Ghostty) void { + const b = self.copy.step.owner; + b.getInstallStep().dependOn(&self.copy.step); +} + +pub fn installXcframework(self: *const Ghostty) void { + const b = self.build.step.owner; + b.getInstallStep().dependOn(&self.build.step); +} diff --git a/src/build/SharedDeps.zig b/src/build/SharedDeps.zig index f173e4856..0aab5ecf8 100644 --- a/src/build/SharedDeps.zig +++ b/src/build/SharedDeps.zig @@ -500,6 +500,43 @@ pub fn add( try static_libs.append(utfcpp_dep.artifact("utfcpp").getEmittedBin()); } + // Fonts + { + // JetBrains Mono + const jb_mono = b.dependency("jetbrains_mono", .{}); + step.root_module.addAnonymousImport( + "jetbrains_mono_regular", + .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Regular.ttf") }, + ); + step.root_module.addAnonymousImport( + "jetbrains_mono_bold", + .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Bold.ttf") }, + ); + step.root_module.addAnonymousImport( + "jetbrains_mono_italic", + .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Italic.ttf") }, + ); + step.root_module.addAnonymousImport( + "jetbrains_mono_bold_italic", + .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-BoldItalic.ttf") }, + ); + step.root_module.addAnonymousImport( + "jetbrains_mono_variable", + .{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono[wght].ttf") }, + ); + step.root_module.addAnonymousImport( + "jetbrains_mono_variable_italic", + .{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono-Italic[wght].ttf") }, + ); + + // Symbols-only nerd font + const nf_symbols = b.dependency("nerd_fonts_symbols_only", .{}); + step.root_module.addAnonymousImport( + "nerd_fonts_symbols_only", + .{ .root_source_file = nf_symbols.path("SymbolsNerdFontMono-Regular.ttf") }, + ); + } + // If we're building an exe then we have additional dependencies. if (step.kind != .lib) { // We always statically compile glad @@ -515,17 +552,6 @@ pub fn add( switch (self.config.app_runtime) { .none => {}, - - .glfw => if (b.lazyDependency("glfw", .{ - .target = target, - .optimize = optimize, - })) |glfw_dep| { - step.root_module.addImport( - "glfw", - glfw_dep.module("glfw"), - ); - }, - .gtk => try self.addGTK(step), } } diff --git a/src/build/XCFrameworkStep.zig b/src/build/XCFrameworkStep.zig index 823e5aac4..8a0d5dc67 100644 --- a/src/build/XCFrameworkStep.zig +++ b/src/build/XCFrameworkStep.zig @@ -55,6 +55,9 @@ pub fn create(b: *std.Build, opts: Options) *XCFrameworkStep { } run.addArg("-output"); run.addArg(opts.out_path); + run.expectExitCode(0); + _ = run.captureStdOut(); + _ = run.captureStdErr(); break :run run; }; run_create.step.dependOn(&run_delete.step); diff --git a/src/build/main.zig b/src/build/main.zig index 3154d395f..f25ce1c23 100644 --- a/src/build/main.zig +++ b/src/build/main.zig @@ -15,6 +15,7 @@ pub const GhosttyFrameData = @import("GhosttyFrameData.zig"); pub const GhosttyLib = @import("GhosttyLib.zig"); pub const GhosttyResources = @import("GhosttyResources.zig"); pub const GhosttyI18n = @import("GhosttyI18n.zig"); +pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig"); pub const GhosttyXCFramework = @import("GhosttyXCFramework.zig"); pub const GhosttyWebdata = @import("GhosttyWebdata.zig"); pub const HelpStrings = @import("HelpStrings.zig"); diff --git a/src/config/Config.zig b/src/config/Config.zig index be0230da0..1690c49a6 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -432,13 +432,16 @@ pub const compatibility = std.StaticStringMap( /// /// Available flags: /// -/// * `hinting` - Enable or disable hinting, enabled by default. -/// * `force-autohint` - Use the freetype auto-hinter rather than the -/// font's native hinter. Enabled by default. -/// * `monochrome` - Instructs renderer to use 1-bit monochrome -/// rendering. This option doesn't impact the hinter. -/// Enabled by default. -/// * `autohint` - Use the freetype auto-hinter. Enabled by default. +/// * `hinting` - Enable or disable hinting. Enabled by default. +/// +/// * `force-autohint` - Always use the freetype auto-hinter instead of +/// the font's native hinter. Enabled by default. +/// +/// * `monochrome` - Instructs renderer to use 1-bit monochrome rendering. +/// This will disable anti-aliasing, and probably not look very good unless +/// you're using a pixel font. Disabled by default. +/// +/// * `autohint` - Enable the freetype auto-hinter. Enabled by default. /// /// Example: `hinting`, `no-hinting`, `force-autohint`, `no-force-autohint` @"freetype-load-flags": FreetypeLoadFlags = .{}, @@ -1582,9 +1585,9 @@ keybind: Keybinds = .{}, /// the visible screen area. This means that if the menu bar is visible, the /// window will be placed below the menu bar. /// -/// Note: this is only supported on macOS and Linux GLFW builds. The GTK -/// runtime does not support setting the window position, as windows are -/// only allowed position themselves in X11 and not Wayland. +/// Note: this is only supported on macOS. The GTK runtime does not support +/// setting the window position, as windows are only allowed position +/// themselves in X11 and not Wayland. @"window-position-x": ?i16 = null, @"window-position-y": ?i16 = null, @@ -2523,8 +2526,6 @@ keybind: Keybinds = .{}, /// /// The values `left` or `right` enable this for the left or right *Option* /// key, respectively. -/// -/// This does not work with GLFW builds. @"macos-option-as-alt": ?OptionAsAlt = null, /// Whether to enable the macOS window shadow. The default value is true. @@ -7105,7 +7106,7 @@ pub const FreetypeLoadFlags = packed struct { // to these defaults. hinting: bool = true, @"force-autohint": bool = true, - monochrome: bool = true, + monochrome: bool = false, autohint: bool = true, }; diff --git a/src/font/SharedGrid.zig b/src/font/SharedGrid.zig index dcfa0a551..3ccac7fa1 100644 --- a/src/font/SharedGrid.zig +++ b/src/font/SharedGrid.zig @@ -265,13 +265,35 @@ pub fn renderGlyph( .emoji => &self.atlas_color, }; + var render_opts = opts; + + // Always use these constraints for emoji. + if (p == .emoji) { + render_opts.constraint = .{ + // Make the emoji as wide as possible, scaling proportionally, + // but then scale it down as necessary if its new size exceeds + // the cell height. + .size_horizontal = .cover, + .size_vertical = .fit, + + // Center the emoji in its cells. + .align_horizontal = .center, + .align_vertical = .center, + + // Add a small bit of padding so the emoji + // doesn't quite touch the edges of the cells. + .pad_left = 0.025, + .pad_right = 0.025, + }; + } + // Render into the atlas const glyph = self.resolver.renderGlyph( alloc, atlas, index, glyph_index, - opts, + render_opts, ) catch |err| switch (err) { // If the atlas is full, we resize it error.AtlasFull => blk: { @@ -281,7 +303,7 @@ pub fn renderGlyph( atlas, index, glyph_index, - opts, + render_opts, ); }, @@ -325,7 +347,8 @@ const GlyphKey = struct { cell_width: u2, thicken: bool, thicken_strength: u8, - _padding: u5 = 0, + constraint_width: u2, + _padding: u3 = 0, }, inline fn from(key: GlyphKey) Packed { @@ -336,6 +359,7 @@ const GlyphKey = struct { .cell_width = key.opts.cell_width orelse 0, .thicken = key.opts.thicken, .thicken_strength = key.opts.thicken_strength, + .constraint_width = key.opts.constraint_width, }, }; } diff --git a/src/font/SharedGridSet.zig b/src/font/SharedGridSet.zig index e3e61907b..b77b44f23 100644 --- a/src/font/SharedGridSet.zig +++ b/src/font/SharedGridSet.zig @@ -260,34 +260,51 @@ fn collection( .regular, .{ .fallback_loaded = try .init( self.font_lib, - font.embedded.regular, + font.embedded.variable, load_options.faceOptions(), ) }, ); - _ = try c.add( + try (try c.getFace(try c.add( self.alloc, .bold, .{ .fallback_loaded = try .init( self.font_lib, - font.embedded.bold, + font.embedded.variable, load_options.faceOptions(), ) }, + ))).setVariations( + &.{.{ .id = .init("wght"), .value = 700 }}, + load_options.faceOptions(), ); _ = try c.add( self.alloc, .italic, .{ .fallback_loaded = try .init( self.font_lib, - font.embedded.italic, + font.embedded.variable_italic, load_options.faceOptions(), ) }, ); - _ = try c.add( + try (try c.getFace(try c.add( self.alloc, .bold_italic, .{ .fallback_loaded = try .init( self.font_lib, - font.embedded.bold_italic, + font.embedded.variable_italic, + load_options.faceOptions(), + ) }, + ))).setVariations( + &.{.{ .id = .init("wght"), .value = 700 }}, + load_options.faceOptions(), + ); + + // Nerd-font symbols fallback. + _ = try c.add( + self.alloc, + .regular, + .{ .fallback_loaded = try Face.init( + self.font_lib, + font.embedded.symbols_nerd_font, load_options.faceOptions(), ) }, ); diff --git a/src/font/embedded.zig b/src/font/embedded.zig index 31b07ff31..1e496075d 100644 --- a/src/font/embedded.zig +++ b/src/font/embedded.zig @@ -6,19 +6,29 @@ //! redistribution and include their license as necessary. /// Default fonts that we prefer for Ghostty. -pub const regular = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf"); -pub const bold = @embedFile("res/JetBrainsMonoNerdFont-Bold.ttf"); -pub const italic = @embedFile("res/JetBrainsMonoNerdFont-Italic.ttf"); -pub const bold_italic = @embedFile("res/JetBrainsMonoNerdFont-BoldItalic.ttf"); +pub const variable = @embedFile("jetbrains_mono_variable"); +pub const variable_italic = @embedFile("jetbrains_mono_variable_italic"); + +/// Symbols-only nerd font. +pub const symbols_nerd_font = @embedFile("nerd_fonts_symbols_only"); + +/// Static jetbrains mono faces, currently unused. +pub const regular = @embedFile("jetbrains_mono_regular"); +pub const bold = @embedFile("jetbrains_mono_bold"); +pub const italic = @embedFile("jetbrains_mono_italic"); +pub const bold_italic = @embedFile("jetbrains_mono_bold_italic"); + +/// Emoji fonts pub const emoji = @embedFile("res/NotoColorEmoji.ttf"); pub const emoji_text = @embedFile("res/NotoEmoji-Regular.ttf"); +// Fonts below are ONLY used for testing. + /// Fonts with general properties pub const arabic = @embedFile("res/KawkabMono-Regular.ttf"); -pub const variable = @embedFile("res/Lilex-VF.ttf"); -/// Font with nerd fonts embedded. -pub const nerd_font = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf"); +/// A font for testing which is patched with nerd font symbols. +pub const test_nerd_font = @embedFile("res/JetBrainsMonoNerdFont-Regular.ttf"); /// Specific font families below: pub const code_new_roman = @embedFile("res/CodeNewRoman-Regular.otf"); diff --git a/src/font/face.zig b/src/font/face.zig index 6355578db..363576ff0 100644 --- a/src/font/face.zig +++ b/src/font/face.zig @@ -94,6 +94,17 @@ pub const RenderOptions = struct { /// optionally by the rasterizer to better layout the glyph. cell_width: ?u2 = null, + /// Constraint and alignment properties for the glyph. The rasterizer + /// should call the `constrain` function on this with the original size + /// and bearings of the glyph to get remapped values that the glyph + /// should be scaled/moved to. + constraint: Constraint = .none, + + /// The number of cells, horizontally that the glyph is free to take up + /// when resized and aligned by `constraint`. This is usually 1, but if + /// there's whitespace to the right of the cell then it can be 2. + constraint_width: u2 = 1, + /// Thicken the glyph. This draws the glyph with a thicker stroke width. /// This is purely an aesthetic setting. /// @@ -108,6 +119,198 @@ pub const RenderOptions = struct { /// /// CoreText only. thicken_strength: u8 = 255, + + /// See the `constraint` field. + pub const Constraint = struct { + /// Don't constrain the glyph in any way. + pub const none: Constraint = .{}; + + /// Vertical sizing rule. + size_vertical: Size = .none, + /// Horizontal sizing rule. + size_horizontal: Size = .none, + + /// Vertical alignment rule. + align_vertical: Align = .none, + /// Horizontal alignment rule. + align_horizontal: Align = .none, + + /// Top padding when resizing. + pad_top: f64 = 0.0, + /// Left padding when resizing. + pad_left: f64 = 0.0, + /// Right padding when resizing. + pad_right: f64 = 0.0, + /// Bottom padding when resizing. + pad_bottom: f64 = 0.0, + + /// Maximum ratio of width to height when resizing. + max_xy_ratio: ?f64 = null, + + pub const Size = enum { + /// Don't change the size of this glyph. + none, + /// Move the glyph and optionally scale it down + /// proportionally to fit within the given axis. + fit, + /// Move and resize the glyph proportionally to + /// cover the given axis. + cover, + /// Same as `cover` but not proportional. + stretch, + }; + + pub const Align = enum { + /// Don't move the glyph on this axis. + none, + /// Move the glyph so that its leading (bottom/left) + /// edge aligns with the leading edge of the axis. + start, + /// Move the glyph so that its trailing (top/right) + /// edge aligns with the trailing edge of the axis. + end, + /// Move the glyph so that it is centered on this axis. + center, + }; + + /// The size and position of a glyph. + pub const GlyphSize = struct { + width: f64, + height: f64, + x: f64, + y: f64, + }; + + /// Apply this constraint to the provided glyph + /// size, given the available width and height. + pub fn constrain( + self: Constraint, + glyph: GlyphSize, + /// Available width + cell_width: f64, + /// Available height + cell_height: f64, + ) GlyphSize { + var g = glyph; + + const w = cell_width - + self.pad_left * cell_width - + self.pad_right * cell_width; + const h = cell_height - + self.pad_top * cell_height - + self.pad_bottom * cell_height; + + // Subtract padding from the bearings so that our + // alignment and sizing code works correctly. We + // re-add before returning. + g.x -= self.pad_left * cell_width; + g.y -= self.pad_bottom * cell_height; + + switch (self.size_horizontal) { + .none => {}, + .fit => if (g.width > w) { + const orig_height = g.height; + // Adjust our height and width to proportionally + // scale them to fit the glyph to the cell width. + g.height *= w / g.width; + g.width = w; + // Set our x to 0 since anything else would mean + // the glyph extends outside of the cell width. + g.x = 0; + // Compensate our y to keep things vertically + // centered as they're scaled down. + g.y += (orig_height - g.height) / 2; + } else if (g.width + g.x > w) { + // If the width of the glyph can fit in the cell but + // is currently outside due to the left bearing, then + // we reduce the left bearing just enough to fit it + // back in the cell. + g.x = w - g.width; + } else if (g.x < 0) { + g.x = 0; + }, + .cover => { + const orig_height = g.height; + + g.height *= w / g.width; + g.width = w; + + g.x = 0; + + g.y += (orig_height - g.height) / 2; + }, + .stretch => { + g.width = w; + g.x = 0; + }, + } + + switch (self.size_vertical) { + .none => {}, + .fit => if (g.height > h) { + const orig_width = g.width; + // Adjust our height and width to proportionally + // scale them to fit the glyph to the cell height. + g.width *= h / g.height; + g.height = h; + // Set our y to 0 since anything else would mean + // the glyph extends outside of the cell height. + g.y = 0; + // Compensate our x to keep things horizontally + // centered as they're scaled down. + g.x += (orig_width - g.width) / 2; + } else if (g.height + g.y > h) { + // If the height of the glyph can fit in the cell but + // is currently outside due to the bottom bearing, then + // we reduce the bottom bearing just enough to fit it + // back in the cell. + g.y = h - g.height; + } else if (g.y < 0) { + g.y = 0; + }, + .cover => { + const orig_width = g.width; + + g.width *= h / g.height; + g.height = h; + + g.y = 0; + + g.x += (orig_width - g.width) / 2; + }, + .stretch => { + g.height = h; + g.y = 0; + }, + } + + if (self.max_xy_ratio) |ratio| if (g.width > g.height * ratio) { + const orig_width = g.width; + g.width = g.height * ratio; + g.x += (orig_width - g.width) / 2; + }; + + switch (self.align_horizontal) { + .none => {}, + .start => g.x = 0, + .end => g.x = w - g.width, + .center => g.x = (w - g.width) / 2, + } + + switch (self.align_vertical) { + .none => {}, + .start => g.y = 0, + .end => g.y = h - g.height, + .center => g.y = (h - g.height) / 2, + } + + // Re-add our padding before returning. + g.x += self.pad_left * cell_width; + g.y += self.pad_bottom * cell_height; + + return g; + } + }; }; test { diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig index 06bba661f..35f094848 100644 --- a/src/font/face/coretext.zig +++ b/src/font/face/coretext.zig @@ -291,22 +291,29 @@ pub const Face = struct { // in the bottom left and +Y pointing up. var rect = self.font.getBoundingRectsForGlyphs(.horizontal, &glyphs, null); + // Determine whether this is a color glyph. + const is_color = self.isColorGlyph(glyph_index); + // And whether it's (probably) a bitmap (sbix). + const sbix = is_color and self.color != null and self.color.?.sbix; + // If we're rendering a synthetic bold then we will gain 50% of // the line width on every edge, which means we should increase // our width and height by the line width and subtract half from // our origin points. - if (self.synthetic_bold) |line_width| { + // + // We don't add extra size if it's a sbix color font though, + // since bitmaps aren't affected by synthetic bold. + if (!sbix) if (self.synthetic_bold) |line_width| { rect.size.width += line_width; rect.size.height += line_width; rect.origin.x -= line_width / 2; rect.origin.y -= line_width / 2; - } + }; // We make an assumption that font smoothing ("thicken") // adds no more than 1 extra pixel to any edge. We don't // add extra size if it's a sbix color font though, since // bitmaps aren't affected by smoothing. - const sbix = self.color != null and self.color.?.sbix; if (opts.thicken and !sbix) { rect.size.width += 2.0; rect.size.height += 2.0; @@ -314,29 +321,43 @@ pub const Face = struct { rect.origin.y -= 1.0; } - // We compute the minimum and maximum x and y values. - // We round our min points down and max points up. - const x0: i32, const x1: i32, const y0: i32, const y1: i32 = .{ - @intFromFloat(@floor(rect.origin.x)), - @intFromFloat(@ceil(rect.origin.x) + @ceil(rect.size.width)), - @intFromFloat(@floor(rect.origin.y)), - @intFromFloat(@ceil(rect.origin.y) + @ceil(rect.size.height)), - }; + // If our rect is smaller than a quarter pixel in either axis + // then it has no outlines or they're too small to render. + // + // In this case we just return 0-sized glyph struct. + if (rect.size.width < 0.25 or rect.size.height < 0.25) + return font.Glyph{ + .width = 0, + .height = 0, + .offset_x = 0, + .offset_y = 0, + .atlas_x = 0, + .atlas_y = 0, + .advance_x = 0, + }; - // This bitmap is blank. I've seen it happen in a font, I don't know why. - // If it is empty, we just return a valid glyph struct that does nothing. - if (x1 <= x0 or y1 <= y0) return font.Glyph{ - .width = 0, - .height = 0, - .offset_x = 0, - .offset_y = 0, - .atlas_x = 0, - .atlas_y = 0, - .advance_x = 0, - }; + const metrics = opts.grid_metrics; + const cell_width: f64 = @floatFromInt(metrics.cell_width * opts.constraint_width); + const cell_height: f64 = @floatFromInt(metrics.cell_height); - const width: u32 = @intCast(x1 - x0); - const height: u32 = @intCast(y1 - y0); + const glyph_size = opts.constraint.constrain( + .{ + .width = rect.size.width, + .height = rect.size.height, + .x = rect.origin.x, + .y = rect.origin.y + @as(f64, @floatFromInt(metrics.cell_baseline)), + }, + cell_width, + cell_height, + ); + + const width = glyph_size.width; + const height = glyph_size.height; + const x = glyph_size.x; + const y = glyph_size.y; + + const px_width: u32 = @intFromFloat(@ceil(width)); + const px_height: u32 = @intFromFloat(@ceil(height)); // Settings that are specific to if we are rendering text or emoji. const color: struct { @@ -344,7 +365,7 @@ pub const Face = struct { depth: u32, space: *macos.graphics.ColorSpace, context_opts: c_uint, - } = if (!self.isColorGlyph(glyph_index)) .{ + } = if (!is_color) .{ .color = false, .depth = 1, .space = try macos.graphics.ColorSpace.createNamed(.linearGray), @@ -371,17 +392,17 @@ pub const Face = struct { // usually stabilizes pretty quickly and is very infrequent so I think // the allocation overhead is acceptable compared to the cost of // caching it forever or having to deal with a cache lifetime. - const buf = try alloc.alloc(u8, width * height * color.depth); + const buf = try alloc.alloc(u8, px_width * px_height * color.depth); defer alloc.free(buf); @memset(buf, 0); const context = macos.graphics.BitmapContext.context; const ctx = try macos.graphics.BitmapContext.create( buf, - width, - height, + px_width, + px_height, 8, - width * color.depth, + px_width * color.depth, color.space, color.context_opts, ); @@ -390,14 +411,14 @@ pub const Face = struct { // Perform an initial fill. This ensures that we don't have any // uninitialized pixels in the bitmap. if (color.color) - context.setRGBFillColor(ctx, 1, 1, 1, 0) + context.setRGBFillColor(ctx, 0, 0, 0, 0) else - context.setGrayFillColor(ctx, 1, 0); + context.setGrayFillColor(ctx, 0, 0); context.fillRect(ctx, .{ .origin = .{ .x = 0, .y = 0 }, .size = .{ - .width = @floatFromInt(width), - .height = @floatFromInt(height), + .width = @floatFromInt(px_width), + .height = @floatFromInt(px_height), }, }); @@ -427,49 +448,34 @@ pub const Face = struct { context.setLineWidth(ctx, line_width); } + context.scaleCTM( + ctx, + width / rect.size.width, + height / rect.size.height, + ); + // We want to render the glyphs at (0,0), but the glyphs themselves // are offset by bearings, so we have to undo those bearings in order // to get them to 0,0. - self.font.drawGlyphs(&glyphs, &.{ - .{ - .x = @floatFromInt(-x0), - .y = @floatFromInt(-y0), - }, - }, ctx); + self.font.drawGlyphs(&glyphs, &.{.{ + .x = -@floor(rect.origin.x), + .y = -@floor(rect.origin.y), + }}, ctx); - const region = region: { - // We reserve a region that's 1px wider and taller than we need - // in order to create a 1px separation between adjacent glyphs - // to prevent interpolation with adjacent glyphs while sampling - // from the atlas. - var region = try atlas.reserve( - alloc, - width + 1, - height + 1, - ); - - // We adjust the region width and height back down since we - // don't need the extra pixel, we just needed to reserve it - // so that it isn't used for other glyphs in the future. - region.width -= 1; - region.height -= 1; - break :region region; - }; + // Write our rasterized glyph to the atlas. + const region = try atlas.reserve(alloc, px_width, px_height); atlas.set(region, buf); - const metrics = opts.grid_metrics; - // This should be the distance from the bottom of // the cell to the top of the glyph's bounding box. - // - // The calculation is distance from bottom of cell to - // baseline plus distance from baseline to top of glyph. - const offset_y: i32 = @as(i32, @intCast(metrics.cell_baseline)) + y1; + const offset_y: i32 = + @as(i32, @intFromFloat(@floor(y))) + + @as(i32, @intCast(px_height)); // This should be the distance from the left of // the cell to the left of the glyph's bounding box. const offset_x: i32 = offset_x: { - var result: i32 = x0; + var result: i32 = @intFromFloat(@round(x)); // If our cell was resized then we adjust our glyph's // position relative to the new center. This keeps glyphs @@ -490,8 +496,8 @@ pub const Face = struct { _ = self.font.getAdvancesForGlyphs(.horizontal, &glyphs, &advances); return .{ - .width = width, - .height = height, + .width = px_width, + .height = px_height, .offset_x = offset_x, .offset_y = offset_y, .atlas_x = region.x, diff --git a/src/font/face/freetype.zig b/src/font/face/freetype.zig index accb891a4..c23ede04a 100644 --- a/src/font/face/freetype.zig +++ b/src/font/face/freetype.zig @@ -15,12 +15,13 @@ const Allocator = std.mem.Allocator; const font = @import("../main.zig"); const Glyph = font.Glyph; const Library = font.Library; -const convert = @import("freetype_convert.zig"); const opentype = @import("../opentype.zig"); const fastmem = @import("../../fastmem.zig"); const quirks = @import("../../quirks.zig"); const config = @import("../../config.zig"); +const F26Dot6 = opentype.sfnt.F26Dot6; + const log = std.log.scoped(.font_face); pub const Face = struct { @@ -58,14 +59,6 @@ pub const Face = struct { bold: bool = false, } = .{}, - /// The matrix applied to a regular font to create a synthetic italic. - const italic_matrix: freetype.c.FT_Matrix = .{ - .xx = 0x10000, - .xy = 0x044ED, // approx. tan(15) - .yx = 0, - .yy = 0x10000, - }; - /// Initialize a new font face with the given source in-memory. pub fn initFile( lib: Library, @@ -330,26 +323,32 @@ pub const Face = struct { self.ft_mutex.lock(); defer self.ft_mutex.unlock(); - const metrics = opts.grid_metrics; + // We enable hinting by default, and disable it if either of the + // constraint alignments are not center or none, since this means + // that the glyph needs to be aligned flush to the cell edge, and + // hinting can mess that up. + const do_hinting = self.load_flags.hinting and + switch (opts.constraint.align_horizontal) { + .start, .end => false, + .center, .none => true, + } and + switch (opts.constraint.align_vertical) { + .start, .end => false, + .center, .none => true, + }; - // If we have synthetic italic, then we apply a transformation matrix. - // We have to undo this because synthetic italic works by increasing - // the ref count of the base face. - if (self.synthetic.italic) self.face.setTransform(&italic_matrix, null); - defer if (self.synthetic.italic) self.face.setTransform(null, null); - - // If our glyph has color, we want to render the color + // Load the glyph. try self.face.loadGlyph(glyph_index, .{ + // If our glyph has color, we want to render the color .color = self.face.hasColor(), - // If we have synthetic bold, we have to set some additional - // glyph properties before render so we don't render here. - .render = !self.synthetic.bold, + // We don't render, because we'll invoke the render + // manually after applying constraints further down. + .render = false, // use options from config - .no_hinting = !self.load_flags.hinting, + .no_hinting = !do_hinting, .force_autohint = !self.load_flags.@"force-autohint", - .monochrome = !self.load_flags.monochrome, .no_autohint = !self.load_flags.autohint, // NO_SVG set to true because we don't currently support rendering @@ -359,260 +358,310 @@ pub const Face = struct { }); const glyph = self.face.handle.*.glyph; - // For synthetic bold, we embolden the glyph and render it. + const glyph_width: f64 = f26dot6ToF64(glyph.*.metrics.width); + const glyph_height: f64 = f26dot6ToF64(glyph.*.metrics.height); + + // If our glyph is smaller than a quarter pixel in either axis + // then it has no outlines or they're too small to render. + // + // In this case we just return 0-sized glyph struct. + if (glyph_width < 0.25 or glyph_height < 0.25) + return font.Glyph{ + .width = 0, + .height = 0, + .offset_x = 0, + .offset_y = 0, + .atlas_x = 0, + .atlas_y = 0, + .advance_x = 0, + }; + + // For synthetic bold, we embolden the glyph. if (self.synthetic.bold) { // We need to scale the embolden amount based on the font size. // This is a heuristic I found worked well across a variety of // founts: 1 pixel per 64 units of height. - const height: f64 = @floatFromInt(self.face.handle.*.size.*.metrics.height); + const font_height: f64 = @floatFromInt(self.face.handle.*.size.*.metrics.height); const ratio: f64 = 64.0 / 2048.0; - const amount = @ceil(height * ratio); + const amount = @ceil(font_height * ratio); _ = freetype.c.FT_Outline_Embolden(&glyph.*.outline, @intFromFloat(amount)); - try self.face.renderGlyph(.normal); } - // This bitmap is blank. I've seen it happen in a font, I don't know why. - // If it is empty, we just return a valid glyph struct that does nothing. - const bitmap_ft = glyph.*.bitmap; - if (bitmap_ft.rows == 0) return .{ - .width = 0, - .height = 0, - .offset_x = 0, - .offset_y = 0, - .atlas_x = 0, - .atlas_y = 0, - .advance_x = 0, - }; + // Next we need to apply any constraints. + const metrics = opts.grid_metrics; - // Ensure we know how to work with the font format. And assure that - // or color depth is as expected on the texture atlas. If format is null - // it means there is no native color format for our Atlas and we must try - // conversion. - const format: ?font.Atlas.Format = switch (bitmap_ft.pixel_mode) { - freetype.c.FT_PIXEL_MODE_MONO => null, - freetype.c.FT_PIXEL_MODE_GRAY => .grayscale, - freetype.c.FT_PIXEL_MODE_BGRA => .bgra, + const cell_width: f64 = @floatFromInt(metrics.cell_width * opts.constraint_width); + const cell_height: f64 = @floatFromInt(metrics.cell_height); + + const glyph_x: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingX); + const glyph_y: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingY) - glyph_height; + + const glyph_size = opts.constraint.constrain( + .{ + .width = glyph_width, + .height = glyph_height, + .x = glyph_x, + .y = glyph_y + @as(f64, @floatFromInt(metrics.cell_baseline)), + }, + cell_width, + cell_height, + ); + + const width = glyph_size.width; + const height = glyph_size.height; + // This may need to be adjusted later on. + var x = glyph_size.x; + const y = glyph_size.y; + + // Now we can render the glyph. + var bitmap: freetype.c.FT_Bitmap = undefined; + _ = freetype.c.FT_Bitmap_Init(&bitmap); + defer _ = freetype.c.FT_Bitmap_Done(self.lib.lib.handle, &bitmap); + switch (glyph.*.format) { + freetype.c.FT_GLYPH_FORMAT_OUTLINE => { + // Manually adjust the glyph outline with this transform. + // + // This offers better precision than using the freetype transform + // matrix, since that has 16.16 coefficients, and also I was having + // weird issues that I can only assume where due to freetype doing + // some bad caching or something when I did this using the matrix. + const scale_x = width / glyph_width; + const scale_y = height / glyph_height; + const skew: f64 = + if (self.synthetic.italic) + // We skew by 12 degrees to synthesize italics. + @tan(std.math.degreesToRadians(12)) + else + 0.0; + + var bbox_before: freetype.c.FT_BBox = undefined; + _ = freetype.c.FT_Outline_Get_BBox(&glyph.*.outline, &bbox_before); + + const outline = &glyph.*.outline; + for (outline.points[0..@intCast(outline.n_points)]) |*p| { + // Convert to f64 for processing + var px = f26dot6ToF64(p.x); + var py = f26dot6ToF64(p.y); + + // Scale + px *= scale_x; + py *= scale_y; + + // Skew + px += py * skew; + + // Convert back and store + p.x = @as(i32, @bitCast(F26Dot6.from(px))); + p.y = @as(i32, @bitCast(F26Dot6.from(py))); + } + + var bbox_after: freetype.c.FT_BBox = undefined; + _ = freetype.c.FT_Outline_Get_BBox(&glyph.*.outline, &bbox_after); + + // If our bounding box changed, account for the lsb difference. + // + // This can happen when we skew glyphs that have a bit sticking + // out to the left higher up, like the top of the T or the serif + // on the lower case l in many monospace fonts. + x += f26dot6ToF64(bbox_after.xMin) - f26dot6ToF64(bbox_before.xMin); + + try self.face.renderGlyph( + if (self.load_flags.monochrome) + .mono + else + .normal, + ); + + // Copy the glyph's bitmap, making sure + // that it's 8bpp and densely packed. + if (freetype.c.FT_Bitmap_Convert( + self.lib.lib.handle, + &glyph.*.bitmap, + &bitmap, + 1, + ) != 0) { + return error.BitmapHandlingError; + } + }, + + freetype.c.FT_GLYPH_FORMAT_BITMAP => { + // If our glyph has a non-color bitmap, we need + // to convert it to dense 8bpp so that the scale + // operation works correctly. + switch (glyph.*.bitmap.pixel_mode) { + freetype.c.FT_PIXEL_MODE_BGRA, + freetype.c.FT_PIXEL_MODE_GRAY, + => {}, + else => { + var converted: freetype.c.FT_Bitmap = undefined; + freetype.c.FT_Bitmap_Init(&converted); + if (freetype.c.FT_Bitmap_Convert( + self.lib.lib.handle, + &glyph.*.bitmap, + &converted, + 1, + ) != 0) { + return error.BitmapHandlingError; + } + // Free the existing glyph bitmap and + // replace it with the converted one. + _ = freetype.c.FT_Bitmap_Done( + self.lib.lib.handle, + &glyph.*.bitmap, + ); + glyph.*.bitmap = converted; + }, + } + + const glyph_bitmap = glyph.*.bitmap; + + // Round our target width and height + // as the size for our scaled bitmap. + const w: u32 = @intFromFloat(@round(width)); + const h: u32 = @intFromFloat(@round(height)); + const pitch = w * atlas.format.depth(); + + // Allocate a buffer for our scaled bitmap. + // + // We'll copy this to the original bitmap once we're + // done so we can free it at the end of this scope. + const buf = try alloc.alloc(u8, pitch * h); + defer alloc.free(buf); + + // Resize + if (stb.stbir_resize_uint8( + glyph_bitmap.buffer, + @intCast(glyph_bitmap.width), + @intCast(glyph_bitmap.rows), + glyph_bitmap.pitch, + buf.ptr, + @intCast(w), + @intCast(h), + @intCast(pitch), + atlas.format.depth(), + ) == 0) { + // This should never fail because this is a + // fairly straightforward in-memory operation... + return error.GlyphResizeFailed; + } + + const scaled_bitmap: freetype.c.FT_Bitmap = .{ + .buffer = buf.ptr, + .width = @intCast(w), + .rows = @intCast(h), + .pitch = @intCast(pitch), + .pixel_mode = glyph_bitmap.pixel_mode, + .num_grays = glyph_bitmap.num_grays, + }; + + // Replace the bitmap's buffer and size info. + if (freetype.c.FT_Bitmap_Copy( + self.lib.lib.handle, + &scaled_bitmap, + &bitmap, + ) != 0) { + return error.BitmapHandlingError; + } + }, + + else => |f| { + // Glyph formats are tags, so we can + // output a semi-readable error here. + log.err( + "Can't render glyph with unsupported glyph format \"{s}\"", + .{[4]u8{ + @truncate(f >> 24), + @truncate(f >> 16), + @truncate(f >> 8), + @truncate(f >> 0), + }}, + ); + return error.UnsupportedGlyphFormat; + }, + } + + // If this is a color glyph but we're trying to render it to the + // grayscale atlas, or vice versa, then we throw and error. Maybe + // in the future we could convert, but for now it should be fine. + switch (bitmap.pixel_mode) { + freetype.c.FT_PIXEL_MODE_GRAY => if (atlas.format != .grayscale) { + return error.WrongAtlas; + }, + freetype.c.FT_PIXEL_MODE_BGRA => if (atlas.format != .bgra) { + return error.WrongAtlas; + }, else => { - log.warn("glyph={} pixel mode={}", .{ glyph_index, bitmap_ft.pixel_mode }); + log.warn("glyph={} pixel mode={}", .{ glyph_index, bitmap.pixel_mode }); @panic("unsupported pixel mode"); }, - }; - - // If our atlas format doesn't match, look for conversions if possible. - const bitmap_converted = if (format == null or atlas.format != format.?) blk: { - const func = convert.map[bitmap_ft.pixel_mode].get(atlas.format) orelse { - log.warn("glyph={} pixel mode={}", .{ glyph_index, bitmap_ft.pixel_mode }); - return error.UnsupportedPixelMode; - }; - - log.debug("converting from pixel_mode={} to atlas_format={}", .{ - bitmap_ft.pixel_mode, - atlas.format, - }); - break :blk try func(alloc, bitmap_ft); - } else null; - defer if (bitmap_converted) |bm| { - const len = @as(usize, @intCast(bm.pitch)) * @as(usize, @intCast(bm.rows)); - alloc.free(bm.buffer[0..len]); - }; - - // Now we need to see if we need to resize this bitmap. This can happen - // in scenarios where we have fixed size glyphs. For example, emoji - // can be quite large (i.e. 128x128) when we have a cell width of 24! - // The issue with large bitmaps is they take a huge amount of space in - // the atlas and force resizes quite frequently. We pay some CPU cost - // up front to resize the glyph to avoid significant CPU cost to resize - // and copy the atlas. - const bitmap_original = bitmap_converted orelse bitmap_ft; - const bitmap_resized: ?freetype.c.struct_FT_Bitmap_ = resized: { - const original_width = bitmap_original.width; - const original_height = bitmap_original.rows; - var result = bitmap_original; - // TODO: We are limiting this to only color glyphs, so mainly emoji. - // We can rework this after a future improvement (promised by Qwerasd) - // which implements more flexible resizing rules. - if (atlas.format != .grayscale and opts.cell_width != null) { - const cell_width = opts.cell_width orelse unreachable; - // If we have a cell_width, we constrain - // the glyph to fit within the cell(s). - result.width = metrics.cell_width * @as(u32, cell_width); - result.rows = (result.width * original_height) / original_width; - } else { - // If we don't have a cell_width, we scale to fill vertically - result.rows = metrics.cell_height; - result.width = (metrics.cell_height * original_width) / original_height; - } - - // If we already fit, we don't need to resize - if (original_height <= result.rows and original_width <= result.width) { - break :resized null; - } - - result.pitch = @as(c_int, @intCast(result.width)) * atlas.format.depth(); - - const buf = try alloc.alloc( - u8, - @as(usize, @intCast(result.pitch)) * @as(usize, @intCast(result.rows)), - ); - result.buffer = buf.ptr; - errdefer alloc.free(buf); - - if (stb.stbir_resize_uint8( - bitmap_original.buffer, - @intCast(original_width), - @intCast(original_height), - bitmap_original.pitch, - result.buffer, - @intCast(result.width), - @intCast(result.rows), - result.pitch, - atlas.format.depth(), - ) == 0) { - // This should never fail because this is a fairly straightforward - // in-memory operation... - return error.GlyphResizeFailed; - } - - break :resized result; - }; - defer if (bitmap_resized) |bm| { - const len = @as(usize, @intCast(bm.pitch)) * @as(usize, @intCast(bm.rows)); - alloc.free(bm.buffer[0..len]); - }; - - const bitmap = bitmap_resized orelse (bitmap_converted orelse bitmap_ft); - const tgt_w = bitmap.width; - const tgt_h = bitmap.rows; - - // Must have non-empty bitmap because we return earlier - // if zero. We assume the rest of this that it is nont-zero so - // this is important. - assert(tgt_w > 0 and tgt_h > 0); - - // If we resized our bitmap, we need to recalculate some metrics that - // we use such as the top/left offsets. These need to be scaled by the - // same ratio as the resize. - const glyph_metrics = if (bitmap_resized) |bm| metrics: { - // Our ratio for the resize - const ratio = ratio: { - const new: f64 = @floatFromInt(bm.rows); - const old: f64 = @floatFromInt(bitmap_original.rows); - break :ratio new / old; - }; - - var copy = glyph.*; - copy.bitmap_top = @as(c_int, @intFromFloat(@round(@as(f64, @floatFromInt(copy.bitmap_top)) * ratio))); - copy.bitmap_left = @as(c_int, @intFromFloat(@round(@as(f64, @floatFromInt(copy.bitmap_left)) * ratio))); - break :metrics copy; - } else glyph.*; - - // Allocate our texture atlas region - const region = region: { - // We need to add a 1px padding to the font so that we don't - // get fuzzy issues when blending textures. - const padding = 1; - - // Get the full padded region - var region = try atlas.reserve( - alloc, - tgt_w + (padding * 2), // * 2 because left+right - tgt_h + (padding * 2), // * 2 because top+bottom - ); - - // Modify the region so that we remove the padding so that - // we write to the non-zero location. The data in an Altlas - // is always initialized to zero (Atlas.clear) so we don't - // need to worry about zero-ing that. - region.x += padding; - region.y += padding; - region.width -= padding * 2; - region.height -= padding * 2; - break :region region; - }; - - // Copy the image into the region. - assert(region.width > 0 and region.height > 0); - { - const depth = atlas.format.depth(); - - // We can avoid a buffer copy if our atlas width and bitmap - // width match and the bitmap pitch is just the width (meaning - // the data is tightly packed). - const needs_copy = !(tgt_w == bitmap.width and (bitmap.width * depth) == bitmap.pitch); - - // If we need to copy the data, we copy it into a temporary buffer. - const buffer = if (needs_copy) buffer: { - const temp = try alloc.alloc(u8, tgt_w * tgt_h * depth); - var dst_ptr = temp; - var src_ptr = bitmap.buffer; - var i: usize = 0; - while (i < bitmap.rows) : (i += 1) { - fastmem.copy(u8, dst_ptr, src_ptr[0 .. bitmap.width * depth]); - dst_ptr = dst_ptr[tgt_w * depth ..]; - src_ptr += @as(usize, @intCast(bitmap.pitch)); - } - break :buffer temp; - } else bitmap.buffer[0..(tgt_w * tgt_h * depth)]; - defer if (buffer.ptr != bitmap.buffer) alloc.free(buffer); - - // Write the glyph information into the atlas - assert(region.width == tgt_w); - assert(region.height == tgt_h); - atlas.set(region, buffer); } - const offset_y: c_int = offset_y: { - // For non-scalable colorized fonts, we assume they are pictographic - // and just center the glyph. So far this has only applied to emoji - // fonts. Emoji fonts don't always report a correct ascender/descender - // (mainly Apple Emoji) so we just center them. Also, since emoji font - // aren't scalable, cell_baseline is incorrect anyways. - // - // NOTE(mitchellh): I don't know if this is right, this doesn't - // _feel_ right, but it makes all my limited test cases work. - if (self.face.hasColor() and !self.face.isScalable()) { - break :offset_y @intCast(tgt_h + (metrics.cell_height -| tgt_h) / 2); + const px_width = bitmap.width; + const px_height = bitmap.rows; + const len: usize = @intCast( + @as(c_uint, @intCast(@abs(bitmap.pitch))) * bitmap.rows, + ); + + // If our bitmap is grayscale, make sure to multiply all pixel + // values by the right factor to bring `num_grays` up to 256. + // + // This is necessary because FT_Bitmap_Convert doesn't do this, + // it just sets num_grays to the correct number and uses the + // original smaller pixel values. + if (bitmap.pixel_mode == freetype.c.FT_PIXEL_MODE_GRAY and + bitmap.num_grays < 256) + { + const factor: u8 = @intCast(255 / (bitmap.num_grays - 1)); + for (bitmap.buffer[0..len]) |*p| { + p.* *= factor; } + bitmap.num_grays = 256; + } - // The Y offset is the offset of the top of our bitmap PLUS our - // baseline calculation. The baseline calculation is so that everything - // is properly centered when we render it out into a monospace grid. - // Note: we add here because our X/Y is actually reversed, adding goes UP. - break :offset_y glyph_metrics.bitmap_top + @as(c_int, @intCast(metrics.cell_baseline)); - }; + // Must have non-empty bitmap because we return earlier if zero. + // We assume the rest of this that it is non-zero so this is important. + assert(px_width > 0 and px_height > 0); + // If this doesn't match then something is wrong. + assert(px_width * atlas.format.depth() == bitmap.pitch); + + // Allocate our texture atlas region and copy our bitmap in to it. + const region = try atlas.reserve(alloc, px_width, px_height); + atlas.set(region, bitmap.buffer[0..len]); + + // This should be the distance from the bottom of + // the cell to the top of the glyph's bounding box. + const offset_y: i32 = + @as(i32, @intFromFloat(@floor(y))) + + @as(i32, @intCast(px_height)); + + // This should be the distance from the left of + // the cell to the left of the glyph's bounding box. const offset_x: i32 = offset_x: { - var result: i32 = glyph_metrics.bitmap_left; + var result: i32 = @intFromFloat(@floor(x)); - // If our cell was resized to be wider then we center our - // glyph in the cell. + // If our cell was resized then we adjust our glyph's + // position relative to the new center. This keeps glyphs + // centered in the cell whether it was made wider or narrower. if (metrics.original_cell_width) |original_width| { - if (original_width < metrics.cell_width) { - const diff = (metrics.cell_width - original_width) / 2; - result += @intCast(diff); - } + const before: i32 = @intCast(original_width); + const after: i32 = @intCast(metrics.cell_width); + // Increase the offset by half of the difference + // between the widths to keep things centered. + result += @divTrunc(after - before, 2); } break :offset_x result; }; - // log.warn("renderGlyph width={} height={} offset_x={} offset_y={} glyph_metrics={}", .{ - // tgt_w, - // tgt_h, - // glyph_metrics.bitmap_left, - // offset_y, - // glyph_metrics, - // }); - - // Store glyph metadata return Glyph{ - .width = tgt_w, - .height = tgt_h, + .width = px_width, + .height = px_height, .offset_x = offset_x, .offset_y = offset_y, .atlas_x = region.x, .atlas_y = region.y, - .advance_x = f26dot6ToFloat(glyph_metrics.advance.x), + .advance_x = f26dot6ToFloat(glyph.*.advance.x), }; } @@ -631,7 +680,7 @@ pub const Face = struct { } fn f26dot6ToF64(v: freetype.c.FT_F26Dot6) f64 { - return @as(opentype.sfnt.F26Dot6, @bitCast(@as(u32, @intCast(v)))).to(f64); + return @as(F26Dot6, @bitCast(@as(i32, @intCast(v)))).to(f64); } pub const GetMetricsError = error{ @@ -950,13 +999,15 @@ test "color emoji" { } // resize + // TODO: Comprehensive tests for constraints, + // this is just an adapted legacy test. { const glyph = try ft_font.renderGlyph( alloc, &atlas, ft_font.glyphIndex('🥸').?, .{ .grid_metrics = .{ - .cell_width = 10, + .cell_width = 13, .cell_height = 24, .cell_baseline = 0, .underline_position = 0, @@ -967,6 +1018,11 @@ test "color emoji" { .overline_thickness = 0, .box_thickness = 0, .cursor_height = 0, + }, .constraint_width = 2, .constraint = .{ + .size_horizontal = .cover, + .size_vertical = .cover, + .align_horizontal = .center, + .align_vertical = .center, } }, ); try testing.expectEqual(@as(u32, 24), glyph.height); diff --git a/src/font/face/freetype_convert.zig b/src/font/face/freetype_convert.zig deleted file mode 100644 index 3a7cf8c98..000000000 --- a/src/font/face/freetype_convert.zig +++ /dev/null @@ -1,88 +0,0 @@ -//! Various conversions from Freetype formats to Atlas formats. These are -//! currently implemented naively. There are definitely MUCH faster ways -//! to do this (likely using SIMD), but I started simple. -const std = @import("std"); -const freetype = @import("freetype"); -const font = @import("../main.zig"); -const assert = std.debug.assert; -const Allocator = std.mem.Allocator; - -/// The mapping from freetype format to atlas format. -pub const map = genMap(); - -/// The map type. -pub const Map = [freetype.c.FT_PIXEL_MODE_MAX]AtlasArray; - -/// Conversion function type. The returning bitmap buffer is guaranteed -/// to be exactly `width * rows * depth` long for freeing it. The caller must -/// free the bitmap buffer. The depth is the depth of the atlas format in the -/// map. -pub const Func = *const fn (Allocator, Bitmap) Allocator.Error!Bitmap; - -/// Alias for the freetype FT_Bitmap type to make it easier to type. -pub const Bitmap = freetype.c.struct_FT_Bitmap_; - -const AtlasArray = std.EnumArray(font.Atlas.Format, ?Func); - -fn genMap() Map { - var result: Map = undefined; - - // Initialize to no converter - var i: usize = 0; - while (i < freetype.c.FT_PIXEL_MODE_MAX) : (i += 1) { - result[i] = .initFill(null); - } - - // Map our converters - result[freetype.c.FT_PIXEL_MODE_MONO].set(.grayscale, monoToGrayscale); - - return result; -} - -pub fn monoToGrayscale(alloc: Allocator, bm: Bitmap) Allocator.Error!Bitmap { - var buf = try alloc.alloc(u8, bm.width * bm.rows); - errdefer alloc.free(buf); - - for (0..bm.rows) |y| { - const row_offset = y * @as(usize, @intCast(bm.pitch)); - for (0..bm.width) |x| { - const byte_offset = row_offset + @divTrunc(x, 8); - const mask = @as(u8, 1) << @intCast(7 - (x % 8)); - const bit: u8 = @intFromBool((bm.buffer[byte_offset] & mask) != 0); - buf[y * bm.width + x] = bit * 255; - } - } - - var copy = bm; - copy.buffer = buf.ptr; - copy.pixel_mode = freetype.c.FT_PIXEL_MODE_GRAY; - copy.pitch = @as(c_int, @intCast(bm.width)); - return copy; -} - -test { - // Force comptime to run - _ = map; -} - -test "mono to grayscale" { - const testing = std.testing; - const alloc = testing.allocator; - - var mono_data = [_]u8{0b1010_0101}; - const source: Bitmap = .{ - .rows = 1, - .width = 8, - .pitch = 1, - .buffer = @ptrCast(&mono_data), - .num_grays = 0, - .pixel_mode = freetype.c.FT_PIXEL_MODE_MONO, - .palette_mode = 0, - .palette = null, - }; - - const result = try monoToGrayscale(alloc, source); - defer alloc.free(result.buffer[0..(result.width * result.rows)]); - try testing.expect(result.pixel_mode == freetype.c.FT_PIXEL_MODE_GRAY); - try testing.expectEqual(@as(u8, 255), result.buffer[0]); -} diff --git a/src/font/nerd_font_attributes.zig b/src/font/nerd_font_attributes.zig new file mode 100644 index 000000000..1465a8466 --- /dev/null +++ b/src/font/nerd_font_attributes.zig @@ -0,0 +1,349 @@ +//! This is a generate file, produced by nerd_font_codegen.py +//! DO NOT EDIT BY HAND! +//! +//! This file provides info extracted from the nerd fonts patcher script, +//! specifying the scaling/positioning attributes of various glyphs. + +const Constraint = @import("face.zig").RenderOptions.Constraint; + +/// Get the a constraints for the provided codepoint. +pub fn getConstraint(cp: u21) Constraint { + return switch (cp) { + 0x2500...0x259f, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .center, + .align_vertical = .center, + .pad_left = -0.02, + .pad_right = -0.02, + .pad_top = -0.01, + .pad_bottom = -0.01, + }, + 0x2630, + => .{ + .size_horizontal = .cover, + .size_vertical = .fit, + .align_horizontal = .center, + .align_vertical = .center, + .pad_left = 0.1, + .pad_right = 0.1, + .pad_top = 0.01, + .pad_bottom = 0.01, + }, + 0x276c...0x2771, + => .{ + .size_horizontal = .cover, + .size_vertical = .fit, + .align_horizontal = .center, + .align_vertical = .center, + }, + 0xe0b0, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = -0.06, + .pad_right = -0.06, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.7, + }, + 0xe0b1, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .max_xy_ratio = 0.7, + }, + 0xe0b2, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .pad_left = -0.06, + .pad_right = -0.06, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.7, + }, + 0xe0b3, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .max_xy_ratio = 0.7, + }, + 0xe0b4, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = -0.06, + .pad_right = -0.06, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.59, + }, + 0xe0b5, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .max_xy_ratio = 0.5, + }, + 0xe0b6, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .pad_left = -0.06, + .pad_right = -0.06, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.59, + }, + 0xe0b7, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .max_xy_ratio = 0.5, + }, + 0xe0b8, + 0xe0bc, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = -0.05, + .pad_right = -0.05, + .pad_top = -0.01, + .pad_bottom = -0.01, + }, + 0xe0b9, + 0xe0bd, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + }, + 0xe0ba, + 0xe0be, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .pad_left = -0.05, + .pad_right = -0.05, + .pad_top = -0.01, + .pad_bottom = -0.01, + }, + 0xe0bb, + 0xe0bf, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + }, + 0xe0c0, + 0xe0c8, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = -0.05, + .pad_right = -0.05, + .pad_top = -0.01, + .pad_bottom = -0.01, + }, + 0xe0c1, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + }, + 0xe0c2, + 0xe0ca, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .pad_left = -0.05, + .pad_right = -0.05, + .pad_top = -0.01, + .pad_bottom = -0.01, + }, + 0xe0c3, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + }, + 0xe0c4, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = 0.03, + .pad_right = 0.03, + .pad_top = 0.01, + .pad_bottom = 0.01, + .max_xy_ratio = 0.86, + }, + 0xe0c5, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .pad_left = 0.03, + .pad_right = 0.03, + .pad_top = 0.01, + .pad_bottom = 0.01, + .max_xy_ratio = 0.86, + }, + 0xe0c6, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = 0.03, + .pad_right = 0.03, + .pad_top = 0.01, + .pad_bottom = 0.01, + .max_xy_ratio = 0.78, + }, + 0xe0c7, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .pad_left = 0.03, + .pad_right = 0.03, + .pad_top = 0.01, + .pad_bottom = 0.01, + .max_xy_ratio = 0.78, + }, + 0xe0cc, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = -0.02, + .pad_right = -0.02, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.85, + }, + 0xe0cd, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .max_xy_ratio = 0.865, + }, + 0xe0ce, + 0xe0d0...0xe0d1, + => .{ + .size_horizontal = .cover, + .size_vertical = .cover, + .align_horizontal = .start, + .align_vertical = .center, + }, + 0xe0cf, + 0xe0d3, + 0xe0d5, + => .{ + .size_horizontal = .cover, + .size_vertical = .cover, + .align_horizontal = .center, + .align_vertical = .center, + }, + 0xe0d2, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = -0.02, + .pad_right = -0.02, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.7, + }, + 0xe0d4, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .pad_left = -0.02, + .pad_right = -0.02, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.7, + }, + 0xe0d6, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .start, + .align_vertical = .center, + .pad_left = -0.05, + .pad_right = -0.05, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.7, + }, + 0xe0d7, + => .{ + .size_horizontal = .stretch, + .size_vertical = .stretch, + .align_horizontal = .end, + .align_vertical = .center, + .pad_left = -0.05, + .pad_right = -0.05, + .pad_top = -0.01, + .pad_bottom = -0.01, + .max_xy_ratio = 0.7, + }, + 0x23fb...0x23fe, + 0x2665, + 0x26a1, + 0x2b58, + 0xe000...0xe0a9, + 0xe4fa...0xe7ef, + 0xea60...0xec1e, + 0xed00...0xf847, + 0xf0001...0xf1af0, + => .{ + .size_horizontal = .fit, + .size_vertical = .fit, + .align_horizontal = .center, + .align_vertical = .center, + }, + else => .none, + }; +} diff --git a/src/font/nerd_font_codegen.py b/src/font/nerd_font_codegen.py new file mode 100644 index 000000000..c2dd7314f --- /dev/null +++ b/src/font/nerd_font_codegen.py @@ -0,0 +1,259 @@ +""" +This file is mostly vibe coded because I don't like Python. It extracts the +patch sets from the nerd fonts font patcher file in order to extract scaling +rules and attributes for different codepoint ranges which it then codegens +in to a Zig file with a function that switches over codepoints and returns +the attributes and scaling rules. + +This does include an `eval` call! This is spooky, but we trust +the nerd fonts code to be safe and not malicious or anything. +""" + +import ast +import math +from pathlib import Path +from collections import defaultdict + + +class PatchSetExtractor(ast.NodeVisitor): + def __init__(self): + self.symbol_table = {} + self.patch_set_values = [] + + def visit_ClassDef(self, node): + if node.name == "font_patcher": + for item in node.body: + if isinstance(item, ast.FunctionDef) and item.name == "setup_patch_set": + self.visit_setup_patch_set(item) + + def visit_setup_patch_set(self, node): + # First pass: gather variable assignments + for stmt in node.body: + if isinstance(stmt, ast.Assign): + # Store simple variable assignments in the symbol table + if len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Name): + var_name = stmt.targets[0].id + self.symbol_table[var_name] = stmt.value + + # Second pass: process self.patch_set + for stmt in node.body: + if isinstance(stmt, ast.Assign): + for target in stmt.targets: + if isinstance(target, ast.Attribute) and target.attr == "patch_set": + if isinstance(stmt.value, ast.List): + for elt in stmt.value.elts: + if isinstance(elt, ast.Dict): + self.process_patch_entry(elt) + + def resolve_symbol(self, node): + """Resolve named variables to their actual values from the symbol table.""" + if isinstance(node, ast.Name) and node.id in self.symbol_table: + return self.safe_literal_eval(self.symbol_table[node.id]) + return self.safe_literal_eval(node) + + def safe_literal_eval(self, node): + """Try to evaluate or stringify an AST node.""" + try: + return ast.literal_eval(node) + except Exception: + # Spooky eval! But we trust nerd fonts to be safe... + if hasattr(ast, "unparse"): + return eval( + ast.unparse(node), {"box_keep": True}, {"self": SpoofSelf()} + ) + else: + return f"" + + def process_patch_entry(self, dict_node): + entry = {} + for key_node, value_node in zip(dict_node.keys, dict_node.values): + if isinstance(key_node, ast.Constant) and key_node.value in ( + "Enabled", + "Name", + "Filename", + "Exact", + ): + continue + key = ast.literal_eval(key_node) + value = self.resolve_symbol(value_node) + entry[key] = value + self.patch_set_values.append(entry) + + +def extract_patch_set_values(source_code): + tree = ast.parse(source_code) + extractor = PatchSetExtractor() + extractor.visit(tree) + return extractor.patch_set_values + + +# We have to spoof `self` and `self.args` for the eval. +class SpoofArgs: + careful = True + + +class SpoofSelf: + args = SpoofArgs() + + +def parse_alignment(val): + return { + "l": ".start", + "r": ".end", + "c": ".center", + "": None, + }.get(val, ".none") + + +def get_param(d, key, default): + return float(d.get(key, default)) + + +def attr_key(attr): + """Convert attributes to a hashable key for grouping.""" + stretch = attr.get("stretch", "") + return ( + parse_alignment(attr.get("align", "")), + parse_alignment(attr.get("valign", "")), + stretch, + float(attr.get("params", {}).get("overlap", 0.0)), + float(attr.get("params", {}).get("xy-ratio", -1.0)), + float(attr.get("params", {}).get("ypadding", 0.0)), + ) + + +def coalesce_codepoints_to_ranges(codepoints): + """Convert a sorted list of integers to a list of single values and ranges.""" + ranges = [] + cp_iter = iter(sorted(codepoints)) + try: + start = prev = next(cp_iter) + for cp in cp_iter: + if cp == prev + 1: + prev = cp + else: + ranges.append((start, prev)) + start = prev = cp + ranges.append((start, prev)) + except StopIteration: + pass + return ranges + + +def emit_zig_entry_multikey(codepoints, attr): + align = parse_alignment(attr.get("align", "")) + valign = parse_alignment(attr.get("valign", "")) + stretch = attr.get("stretch", "") + params = attr.get("params", {}) + + overlap = get_param(params, "overlap", 0.0) + xy_ratio = get_param(params, "xy-ratio", -1.0) + y_padding = get_param(params, "ypadding", 0.0) + + ranges = coalesce_codepoints_to_ranges(codepoints) + keys = "\n".join( + f" 0x{start:x}...0x{end:x}," if start != end else f" 0x{start:x}," + for start, end in ranges + ) + + s = f"""{keys} + => .{{\n""" + + # These translations don't quite capture the way + # the actual patcher does scaling, but they're a + # good enough compromise. + if ("xy" in stretch): + s += " .size_horizontal = .stretch,\n" + s += " .size_vertical = .stretch,\n" + elif ("!" in stretch): + s += " .size_horizontal = .cover,\n" + s += " .size_vertical = .fit,\n" + elif ("^" in stretch): + s += " .size_horizontal = .cover,\n" + s += " .size_vertical = .cover,\n" + else: + s += " .size_horizontal = .fit,\n" + s += " .size_vertical = .fit,\n" + + if (align is not None): + s += f" .align_horizontal = {align},\n" + if (valign is not None): + s += f" .align_vertical = {valign},\n" + + if (overlap != 0.0): + pad = -overlap + s += f" .pad_left = {pad},\n" + s += f" .pad_right = {pad},\n" + v_pad = y_padding - math.copysign(min(0.01, abs(overlap)), overlap) + s += f" .pad_top = {v_pad},\n" + s += f" .pad_bottom = {v_pad},\n" + + if (xy_ratio > 0): + s += f" .max_xy_ratio = {xy_ratio},\n" + + s += " }," + + return s + +def generate_zig_switch_arms(patch_set): + entries = {} + for entry in patch_set: + attributes = entry["Attributes"] + + for cp in range(entry["SymStart"], entry["SymEnd"] + 1): + entries[cp] = attributes["default"] + + for k, v in attributes.items(): + if isinstance(k, int): + entries[k] = v + + del entries[0] + + # Group codepoints by attribute key + grouped = defaultdict(list) + for cp, attr in entries.items(): + grouped[attr_key(attr)].append(cp) + + # Emit zig switch arms + result = [] + for _, codepoints in sorted(grouped.items(), key=lambda x: x[1]): + # Use one of the attrs in the group to emit the value + attr = entries[codepoints[0]] + result.append(emit_zig_entry_multikey(codepoints, attr)) + + return "\n".join(result) + + +if __name__ == "__main__": + path = ( + Path(__file__).resolve().parent + / ".." + / ".." + / "vendor" + / "nerd-fonts" + / "font-patcher.py" + ) + with open(path, "r", encoding="utf-8") as f: + source = f.read() + + patch_set = extract_patch_set_values(source) + + out_path = Path(__file__).resolve().parent / "nerd_font_attributes.zig" + + with open(out_path, "w", encoding="utf-8") as f: + f.write("""//! This is a generate file, produced by nerd_font_codegen.py +//! DO NOT EDIT BY HAND! +//! +//! This file provides info extracted from the nerd fonts patcher script, +//! specifying the scaling/positioning attributes of various glyphs. + +const Constraint = @import("face.zig").RenderOptions.Constraint; + +/// Get the a constraints for the provided codepoint. +pub fn getConstraint(cp: u21) Constraint { + return switch (cp) { +""") + f.write(generate_zig_switch_arms(patch_set)) + f.write("\n") + + f.write(" else => .none,\n };\n}\n") diff --git a/src/font/opentype/sfnt.zig b/src/font/opentype/sfnt.zig index 14a3b795a..82c118bce 100644 --- a/src/font/opentype/sfnt.zig +++ b/src/font/opentype/sfnt.zig @@ -76,24 +76,22 @@ fn FixedPoint(comptime T: type, int_bits: u64, frac_bits: u64) type { )); const half = @as(T, 1) << @intCast(frac_bits - 1); - frac: std.meta.Int(.unsigned, frac_bits), - int: std.meta.Int(type_info.signedness, int_bits), + const Frac = std.meta.Int(.unsigned, frac_bits); + const Int = std.meta.Int(type_info.signedness, int_bits); + + frac: Frac, + int: Int, pub fn to(self: Self, comptime FloatType: type) FloatType { - const i: FloatType = @floatFromInt(self.int); - const f: FloatType = @floatFromInt(self.frac); - - return i + f / frac_factor; + return @as(FloatType, @floatFromInt( + @as(T, @bitCast(self)), + )) / frac_factor; } pub fn from(float: anytype) Self { - const int = @floor(float); - const frac = @abs(float - int); - - return .{ - .int = @intFromFloat(int), - .frac = @intFromFloat(@round(frac * frac_factor)), - }; + return @bitCast( + @as(T, @intFromFloat(@round(float * frac_factor))), + ); } /// Round to the nearest integer, .5 rounds away from 0. diff --git a/src/font/shaper/coretext.zig b/src/font/shaper/coretext.zig index 1aaa029dc..f4f01d105 100644 --- a/src/font/shaper/coretext.zig +++ b/src/font/shaper/coretext.zig @@ -1769,7 +1769,7 @@ fn testShaperWithFont(alloc: Allocator, font_req: TestFont) !TestShaper { .geist_mono => font.embedded.geist_mono, .jetbrains_mono => font.embedded.jetbrains_mono, .monaspace_neon => font.embedded.monaspace_neon, - .nerd_font => font.embedded.nerd_font, + .nerd_font => font.embedded.test_nerd_font, }; var lib = try Library.init(alloc); diff --git a/src/main_ghostty.zig b/src/main_ghostty.zig index 567eec5f9..b747fe6f0 100644 --- a/src/main_ghostty.zig +++ b/src/main_ghostty.zig @@ -7,7 +7,6 @@ const Allocator = std.mem.Allocator; const posix = std.posix; const build_config = @import("build_config.zig"); const options = @import("build_options"); -const glfw = @import("glfw"); const glslang = @import("glslang"); const macos = @import("macos"); const oni = @import("oniguruma"); diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 3899bb8c5..70be1a96b 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -5,7 +5,6 @@ const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const builtin = @import("builtin"); -const glfw = @import("glfw"); const objc = @import("objc"); const macos = @import("macos"); const graphics = macos.graphics; @@ -38,11 +37,6 @@ pub const swap_chain_count = 3; const log = std.log.scoped(.metal); -// Get native API access on certain platforms so we can do more customization. -const glfwNative = glfw.Native(.{ - .cocoa = builtin.os.tag == .macos, -}); - layer: IOSurfaceLayer, /// MTLDevice @@ -87,27 +81,6 @@ pub fn init(alloc: Allocator, opts: rendererpkg.Options) !Metal { // Get the metadata about our underlying view that we'll be rendering to. const info: ViewInfo = switch (apprt.runtime) { - apprt.glfw => info: { - // Everything in glfw is window-oriented so we grab the backing - // window, then derive everything from that. - const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow( - opts.rt_surface.window, - ).?); - - const contentView = objc.Object.fromId( - nswindow.getProperty(?*anyopaque, "contentView").?, - ); - const scaleFactor = nswindow.getProperty( - graphics.c.CGFloat, - "backingScaleFactor", - ); - - break :info .{ - .view = contentView, - .scaleFactor = scaleFactor, - }; - }, - apprt.embedded => .{ .scaleFactor = @floatCast(opts.rt_surface.content_scale.x), .view = switch (opts.rt_surface.platform) { diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index cf195361e..00df8e273 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -5,7 +5,6 @@ const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const builtin = @import("builtin"); -const glfw = @import("glfw"); const gl = @import("opengl"); const shadertoy = @import("shadertoy.zig"); const apprt = @import("../apprt.zig"); @@ -60,18 +59,6 @@ pub fn deinit(self: *OpenGL) void { self.* = undefined; } -/// Returns the hints that we want for this -pub fn glfwWindowHints(config: *const configpkg.Config) glfw.Window.Hints { - _ = config; - return .{ - .context_version_major = MIN_VERSION_MAJOR, - .context_version_minor = MIN_VERSION_MINOR, - .opengl_profile = .opengl_core_profile, - .opengl_forward_compat = true, - .transparent_framebuffer = true, - }; -} - /// 32-bit windows cross-compilation breaks with `.c` for some reason, so... const gl_debug_proc_callconv = @typeInfo( @@ -172,8 +159,7 @@ fn prepareContext(getProcAddress: anytype) !void { /// This is called early right after surface creation. pub fn surfaceInit(surface: *apprt.Surface) !void { - // Treat this like a thread entry - const self: OpenGL = undefined; + _ = surface; switch (apprt.runtime) { else => @compileError("unsupported app runtime for OpenGL"), @@ -181,8 +167,6 @@ pub fn surfaceInit(surface: *apprt.Surface) !void { // GTK uses global OpenGL context so we load from null. apprt.gtk => try prepareContext(null), - apprt.glfw => try self.threadEnter(surface), - apprt.embedded => { // TODO(mitchellh): this does nothing today to allow libghostty // to compile for OpenGL targets but libghostty is strictly @@ -205,17 +189,12 @@ pub fn surfaceInit(surface: *apprt.Surface) !void { pub fn finalizeSurfaceInit(self: *const OpenGL, surface: *apprt.Surface) !void { _ = self; _ = surface; - - // For GLFW, we grabbed the OpenGL context in surfaceInit and - // we need to release it before we start the renderer thread. - if (apprt.runtime == apprt.glfw) { - glfw.makeContextCurrent(null); - } } /// Callback called by renderer.Thread when it begins. pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void { _ = self; + _ = surface; switch (apprt.runtime) { else => @compileError("unsupported app runtime for OpenGL"), @@ -227,21 +206,6 @@ pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void { // on the main thread. As such, we don't do anything here. }, - apprt.glfw => { - // We need to make the OpenGL context current. OpenGL requires - // that a single thread own the a single OpenGL context (if any). - // This ensures that the context switches over to our thread. - // Important: the prior thread MUST have detached the context - // prior to calling this entrypoint. - glfw.makeContextCurrent(surface.window); - errdefer glfw.makeContextCurrent(null); - glfw.swapInterval(1); - - // Load OpenGL bindings. This API is context-aware so this sets - // a threadlocal context for these pointers. - try prepareContext(&glfw.getProcAddress); - }, - apprt.embedded => { // TODO(mitchellh): this does nothing today to allow libghostty // to compile for OpenGL targets but libghostty is strictly @@ -262,11 +226,6 @@ pub fn threadExit(self: *const OpenGL) void { // be sharing the global bindings with other windows. }, - apprt.glfw => { - gl.glad.unload(); - glfw.makeContextCurrent(null); - }, - apprt.embedded => { // TODO: see threadEnter }, diff --git a/src/renderer/cell.zig b/src/renderer/cell.zig index 97b24aa90..43d744176 100644 --- a/src/renderer/cell.zig +++ b/src/renderer/cell.zig @@ -218,103 +218,64 @@ pub fn isCovering(cp: u21) bool { }; } -pub const FgMode = enum { - /// Normal non-colored text rendering. The text can leave the cell - /// size if it is larger than the cell to allow for ligatures. - normal, +/// Returns the appropriate `constraint_width` for +/// the provided cell when rendering its glyph(s). +pub fn constraintWidth(cell_pin: terminal.Pin) u2 { + const cell = cell_pin.rowAndCell().cell; + const cp = cell.codepoint(); - /// Colored text rendering, specifically Emoji. - color, + if (!ziglyph.general_category.isPrivateUse(cp) and + !ziglyph.blocks.isDingbats(cp)) + { + return cell.gridWidth(); + } - /// Similar to normal but the text must be constrained to the cell - /// size. If a glyph is larger than the cell then it must be resized - /// to fit. - constrained, + // If we are at the end of the screen it must be constrained to one cell. + if (cell_pin.x == cell_pin.node.data.size.cols - 1) return 1; - /// Similar to normal, but the text consists of Powerline glyphs and is - /// optionally exempt from padding color extension and minimum contrast requirements. - powerline, -}; + // If we have a previous cell and it was PUA then we need to + // also constrain. This is so that multiple PUA glyphs align. + // As an exception, we ignore powerline glyphs since they are + // used for box drawing and we consider them whitespace. + if (cell_pin.x > 0) prev: { + const prev_cp = prev_cp: { + var copy = cell_pin; + copy.x -= 1; + const prev_cell = copy.rowAndCell().cell; + break :prev_cp prev_cell.codepoint(); + }; -/// Returns the appropriate foreground mode for the given cell. This is -/// meant to be called from the typical updateCell function within a -/// renderer. -pub fn fgMode( - presentation: font.Presentation, - cell_pin: terminal.Pin, -) FgMode { - return switch (presentation) { - // Emoji is always full size and color. - .emoji => .color, + // We consider powerline glyphs whitespace. + if (isPowerline(prev_cp)) break :prev; - // If it is text it is slightly more complex. If we are a codepoint - // in the private use area and we are at the end or the next cell - // is not empty, we need to constrain rendering. - // - // We do this specifically so that Nerd Fonts can render their - // icons without overlapping with subsequent characters. But if - // the subsequent character is empty, then we allow it to use - // the full glyph size. See #1071. - .text => text: { - const cell = cell_pin.rowAndCell().cell; - const cp = cell.codepoint(); + if (ziglyph.general_category.isPrivateUse(prev_cp)) { + return 1; + } + } - if (!ziglyph.general_category.isPrivateUse(cp) and - !ziglyph.blocks.isDingbats(cp)) - { - break :text .normal; - } - - // Special-case Powerline glyphs. They exhibit box drawing behavior - // and should not be constrained. They have their own special category - // though because they're used for other logic (i.e. disabling - // min contrast). - if (isPowerline(cp)) { - break :text .powerline; - } - - // If we are at the end of the screen its definitely constrained - if (cell_pin.x == cell_pin.node.data.size.cols - 1) break :text .constrained; - - // If we have a previous cell and it was PUA then we need to - // also constrain. This is so that multiple PUA glyphs align. - // As an exception, we ignore powerline glyphs since they are - // used for box drawing and we consider them whitespace. - if (cell_pin.x > 0) prev: { - const prev_cp = prev_cp: { - var copy = cell_pin; - copy.x -= 1; - const prev_cell = copy.rowAndCell().cell; - break :prev_cp prev_cell.codepoint(); - }; - - // Powerline is whitespace - if (isPowerline(prev_cp)) break :prev; - - if (ziglyph.general_category.isPrivateUse(prev_cp)) { - break :text .constrained; - } - } - - // If the next cell is empty, then we allow it to use the - // full glyph size. - const next_cp = next_cp: { - var copy = cell_pin; - copy.x += 1; - const next_cell = copy.rowAndCell().cell; - break :next_cp next_cell.codepoint(); - }; - if (next_cp == 0 or - isSpace(next_cp) or - isPowerline(next_cp)) - { - break :text .normal; - } - - // Must be constrained - break :text .constrained; - }, + // If the next cell is whitespace, then + // we allow it to be up to two cells wide. + const next_cp = next_cp: { + var copy = cell_pin; + copy.x += 1; + const next_cell = copy.rowAndCell().cell; + break :next_cp next_cell.codepoint(); }; + if (next_cp == 0 or + isSpace(next_cp) or + isPowerline(next_cp)) + { + return 2; + } + + // Must be constrained + return 1; +} + +/// Whether min contrast should be disabled for a given glyph. +pub fn noMinContrast(cp: u21) bool { + // TODO: We should disable for all box drawing type characters. + return isPowerline(cp); } // Some general spaces, others intentionally kept @@ -361,7 +322,7 @@ test Contents { // Add some contents. const bg_cell: shaderpkg.CellBg = .{ 0, 0, 0, 1 }; const fg_cell: shaderpkg.CellText = .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ 4, 1 }, .color = .{ 0, 0, 0, 1 }, }; @@ -382,7 +343,8 @@ test Contents { // Add a block cursor. const cursor_cell: shaderpkg.CellText = .{ - .mode = .cursor, + .atlas = .grayscale, + .bools = .{ .is_cursor_glyph = true }, .grid_pos = .{ 2, 3 }, .color = .{ 0, 0, 0, 1 }, }; @@ -413,7 +375,7 @@ test "Contents clear retains other content" { // bg and fg cells in row 1 const bg_cell_1: shaderpkg.CellBg = .{ 0, 0, 0, 1 }; const fg_cell_1: shaderpkg.CellText = .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ 4, 1 }, .color = .{ 0, 0, 0, 1 }, }; @@ -422,7 +384,7 @@ test "Contents clear retains other content" { // bg and fg cells in row 2 const bg_cell_2: shaderpkg.CellBg = .{ 0, 0, 0, 1 }; const fg_cell_2: shaderpkg.CellText = .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ 4, 2 }, .color = .{ 0, 0, 0, 1 }, }; @@ -453,7 +415,7 @@ test "Contents clear last added content" { // bg and fg cells in row 1 const bg_cell_1: shaderpkg.CellBg = .{ 0, 0, 0, 1 }; const fg_cell_1: shaderpkg.CellText = .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ 4, 1 }, .color = .{ 0, 0, 0, 1 }, }; @@ -462,7 +424,7 @@ test "Contents clear last added content" { // bg and fg cells in row 2 const bg_cell_2: shaderpkg.CellBg = .{ 0, 0, 0, 1 }; const fg_cell_2: shaderpkg.CellText = .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ 4, 2 }, .color = .{ 0, 0, 0, 1 }, }; diff --git a/src/renderer/generic.zig b/src/renderer/generic.zig index 3a65b9ac5..829563075 100644 --- a/src/renderer/generic.zig +++ b/src/renderer/generic.zig @@ -1,6 +1,5 @@ const std = @import("std"); const builtin = @import("builtin"); -const glfw = @import("glfw"); const xev = @import("xev"); const wuffs = @import("wuffs"); const apprt = @import("../apprt.zig"); @@ -13,7 +12,8 @@ const math = @import("../math.zig"); const Surface = @import("../Surface.zig"); const link = @import("link.zig"); const cellpkg = @import("cell.zig"); -const fgMode = cellpkg.fgMode; +const noMinContrast = cellpkg.noMinContrast; +const constraintWidth = cellpkg.constraintWidth; const isCovering = cellpkg.isCovering; const imagepkg = @import("image.zig"); const Image = imagepkg.Image; @@ -26,6 +26,8 @@ const ArenaAllocator = std.heap.ArenaAllocator; const Terminal = terminal.Terminal; const Health = renderer.Health; +const getConstraint = @import("../font/nerd_font_attributes.zig").getConstraint; + const FileType = @import("../file_type.zig").FileType; const macos = switch (builtin.os.tag) { @@ -606,20 +608,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type { } }; - /// Returns the hints that we want for this window. - pub fn glfwWindowHints(config: *const configpkg.Config) glfw.Window.Hints { - // If our graphics API provides hints, use them, - // otherwise fall back to generic hints. - if (@hasDecl(GraphicsAPI, "glfwWindowHints")) { - return GraphicsAPI.glfwWindowHints(config); - } - - return .{ - .client_api = .no_api, - .transparent_framebuffer = config.@"background-opacity" < 1, - }; - } - pub fn init(alloc: Allocator, options: renderer.Options) !Self { // Initialize our graphics API wrapper, this will prepare the // surface provided by the apprt and set up any API-specific @@ -2939,9 +2927,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type { ); try self.cells.add(self.alloc, .underline, .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ @intCast(x), @intCast(y) }, - .constraint_width = 1, .color = .{ color.r, color.g, color.b, alpha }, .glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y }, .glyph_size = .{ render.glyph.width, render.glyph.height }, @@ -2971,9 +2958,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type { ); try self.cells.add(self.alloc, .overline, .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ @intCast(x), @intCast(y) }, - .constraint_width = 1, .color = .{ color.r, color.g, color.b, alpha }, .glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y }, .glyph_size = .{ render.glyph.width, render.glyph.height }, @@ -3003,9 +2989,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type { ); try self.cells.add(self.alloc, .strikethrough, .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ @intCast(x), @intCast(y) }, - .constraint_width = 1, .color = .{ color.r, color.g, color.b, alpha }, .glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y }, .glyph_size = .{ render.glyph.width, render.glyph.height }, @@ -3030,6 +3015,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type { const rac = cell_pin.rowAndCell(); const cell = rac.cell; + const cp = cell.codepoint(); + // Render const render = try self.font_grid.renderGlyph( self.alloc, @@ -3039,6 +3026,9 @@ pub fn Renderer(comptime GraphicsAPI: type) type { .grid_metrics = self.grid_metrics, .thicken = self.config.font_thicken, .thicken_strength = self.config.font_thicken_strength, + .cell_width = cell.gridWidth(), + .constraint = getConstraint(cp), + .constraint_width = constraintWidth(cell_pin), }, ); @@ -3048,27 +3038,13 @@ pub fn Renderer(comptime GraphicsAPI: type) type { return; } - // We always use fg mode for sprite glyphs, since we know we never - // need to constrain them, and we don't have any color sprites. - // - // Otherwise we defer to `fgMode`. - const mode: shaderpkg.CellText.Mode = - if (render.glyph.sprite) - .fg - else switch (fgMode( - render.presentation, - cell_pin, - )) { - .normal => .fg, - .color => .fg_color, - .constrained => .fg_constrained, - .powerline => .fg_powerline, - }; - try self.cells.add(self.alloc, .text, .{ - .mode = mode, + .atlas = switch (render.presentation) { + .emoji => .color, + .text => .grayscale, + }, + .bools = .{ .no_min_contrast = noMinContrast(cp) }, .grid_pos = .{ @intCast(x), @intCast(y) }, - .constraint_width = cell.gridWidth(), .color = .{ color.r, color.g, color.b, alpha }, .glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y }, .glyph_size = .{ render.glyph.width, render.glyph.height }, @@ -3153,7 +3129,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type { }; self.cells.setCursor(.{ - .mode = .cursor, + .atlas = .grayscale, + .bools = .{ .is_cursor_glyph = true }, .grid_pos = .{ x, screen.cursor.y }, .color = .{ cursor_color.r, cursor_color.g, cursor_color.b, alpha }, .glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y }, @@ -3202,7 +3179,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type { // Add our text try self.cells.add(self.alloc, .text, .{ - .mode = .fg, + .atlas = .grayscale, .grid_pos = .{ @intCast(coord.x), @intCast(coord.y) }, .color = .{ fg.r, fg.g, fg.b, 255 }, .glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y }, diff --git a/src/renderer/metal/shaders.zig b/src/renderer/metal/shaders.zig index 9fe0862ed..bf3bcc6e4 100644 --- a/src/renderer/metal/shaders.zig +++ b/src/renderer/metal/shaders.zig @@ -269,15 +269,16 @@ pub const CellText = extern struct { bearings: [2]i16 align(4) = .{ 0, 0 }, grid_pos: [2]u16 align(4), color: [4]u8 align(4), - mode: Mode align(1), - constraint_width: u8 align(1) = 0, + atlas: Atlas align(1), + bools: packed struct(u8) { + no_min_contrast: bool = false, + is_cursor_glyph: bool = false, + _padding: u6 = 0, + } align(1) = .{}, - pub const Mode = enum(u8) { - fg = 1, - fg_constrained = 2, - fg_color = 3, - cursor = 4, - fg_powerline = 5, + pub const Atlas = enum(u8) { + grayscale = 0, + color = 1, }; test { diff --git a/src/renderer/opengl/shaders.zig b/src/renderer/opengl/shaders.zig index 0b67eaff0..80980bac7 100644 --- a/src/renderer/opengl/shaders.zig +++ b/src/renderer/opengl/shaders.zig @@ -237,15 +237,16 @@ pub const CellText = extern struct { bearings: [2]i16 align(4) = .{ 0, 0 }, grid_pos: [2]u16 align(4), color: [4]u8 align(4), - mode: Mode align(4), - constraint_width: u32 align(4) = 0, + atlas: Atlas align(1), + bools: packed struct(u8) { + no_min_contrast: bool = false, + is_cursor_glyph: bool = false, + _padding: u6 = 0, + } align(1) = .{}, - pub const Mode = enum(u32) { - fg = 1, - fg_constrained = 2, - fg_color = 3, - cursor = 4, - fg_powerline = 5, + pub const Atlas = enum(u8) { + grayscale = 0, + color = 1, }; // test { diff --git a/src/renderer/shaders/glsl/cell_text.f.glsl b/src/renderer/shaders/glsl/cell_text.f.glsl index fda6d8134..176efcbde 100644 --- a/src/renderer/shaders/glsl/cell_text.f.glsl +++ b/src/renderer/shaders/glsl/cell_text.f.glsl @@ -4,21 +4,15 @@ layout(binding = 0) uniform sampler2DRect atlas_grayscale; layout(binding = 1) uniform sampler2DRect atlas_color; in CellTextVertexOut { - flat uint mode; + flat uint atlas; flat vec4 color; flat vec4 bg_color; vec2 tex_coord; } in_data; -// These are the possible modes that "mode" can be set to. This is -// used to multiplex multiple render modes into a single shader. -// -// NOTE: this must be kept in sync with the fragment shader -const uint MODE_TEXT = 1u; -const uint MODE_TEXT_CONSTRAINED = 2u; -const uint MODE_TEXT_COLOR = 3u; -const uint MODE_TEXT_CURSOR = 4u; -const uint MODE_TEXT_POWERLINE = 5u; +// Values `atlas` can take. +const uint ATLAS_GRAYSCALE = 0u; +const uint ATLAS_COLOR = 1u; // Must declare this output for some versions of OpenGL. layout(location = 0) out vec4 out_FragColor; @@ -27,12 +21,9 @@ void main() { bool use_linear_blending = (bools & USE_LINEAR_BLENDING) != 0; bool use_linear_correction = (bools & USE_LINEAR_CORRECTION) != 0; - switch (in_data.mode) { + switch (in_data.atlas) { default: - case MODE_TEXT_CURSOR: - case MODE_TEXT_CONSTRAINED: - case MODE_TEXT_POWERLINE: - case MODE_TEXT: + case ATLAS_GRAYSCALE: { // Our input color is always linear. vec4 color = in_data.color; @@ -84,7 +75,7 @@ void main() { return; } - case MODE_TEXT_COLOR: + case ATLAS_COLOR: { // For now, we assume that color glyphs // are already premultiplied linear colors. diff --git a/src/renderer/shaders/glsl/cell_text.v.glsl b/src/renderer/shaders/glsl/cell_text.v.glsl index 10965ddd2..7e38e2f0c 100644 --- a/src/renderer/shaders/glsl/cell_text.v.glsl +++ b/src/renderer/shaders/glsl/cell_text.v.glsl @@ -15,22 +15,22 @@ layout(location = 3) in uvec2 grid_pos; // The color of the rendered text glyph. layout(location = 4) in uvec4 color; -// The mode for this cell. -layout(location = 5) in uint mode; +// Which atlas this glyph is in. +layout(location = 5) in uint atlas; -// The width to constrain the glyph to, in cells, or 0 for no constraint. -layout(location = 6) in uint constraint_width; +// Misc glyph properties. +layout(location = 6) in uint glyph_bools; -// These are the possible modes that "mode" can be set to. This is -// used to multiplex multiple render modes into a single shader. -const uint MODE_TEXT = 1u; -const uint MODE_TEXT_CONSTRAINED = 2u; -const uint MODE_TEXT_COLOR = 3u; -const uint MODE_TEXT_CURSOR = 4u; -const uint MODE_TEXT_POWERLINE = 5u; +// Values `atlas` can take. +const uint ATLAS_GRAYSCALE = 0u; +const uint ATLAS_COLOR = 1u; + +// Masks for the `glyph_bools` attribute +const uint NO_MIN_CONTRAST = 1u; +const uint IS_CURSOR_GLYPH = 2u; out CellTextVertexOut { - flat uint mode; + flat uint atlas; flat vec4 color; flat vec4 bg_color; vec2 tex_coord; @@ -69,7 +69,7 @@ void main() { corner.x = float(vid == 1 || vid == 3); corner.y = float(vid == 2 || vid == 3); - out_data.mode = mode; + out_data.atlas = atlas; // === Grid Cell === // +X @@ -102,25 +102,6 @@ void main() { offset.y = cell_size.y - offset.y; - // If we're constrained then we need to scale the glyph. - if (mode == MODE_TEXT_CONSTRAINED) { - float max_width = cell_size.x * constraint_width; - // If this glyph is wider than the constraint width, - // fit it to the width and remove its horizontal offset. - if (size.x > max_width) { - float new_y = size.y * (max_width / size.x); - offset.y += (size.y - new_y) / 2.0; - offset.x = 0.0; - size.y = new_y; - size.x = max_width; - } else if (max_width - size.x > offset.x) { - // However, if it does fit in the constraint width, make - // sure the offset is small enough to not push it over the - // right edge of the constraint width. - offset.x = max_width - size.x; - } - } - // Calculate the final position of the cell which uses our glyph size // and glyph offset to create the correct bounding box for the glyph. cell_pos = cell_pos + size * corner + offset; @@ -149,11 +130,7 @@ void main() { // If we have a minimum contrast, we need to check if we need to // change the color of the text to ensure it has enough contrast // with the background. - // We only apply this adjustment to "normal" text with MODE_TEXT, - // since we want color glyphs to appear in their original color - // and Powerline glyphs to be unaffected (else parts of the line would - // have different colors as some parts are displayed via background colors). - if (min_contrast > 1.0f && mode == MODE_TEXT) { + if (min_contrast > 1.0f && (glyph_bools & NO_MIN_CONTRAST) == 0) { // Ensure our minimum contrast out_data.color = contrasted_color(min_contrast, out_data.color, out_data.bg_color); } @@ -161,8 +138,9 @@ void main() { // Check if current position is under cursor (including wide cursor) bool is_cursor_pos = ((grid_pos.x == cursor_pos.x) || (cursor_wide && (grid_pos.x == (cursor_pos.x + 1)))) && (grid_pos.y == cursor_pos.y); - // If this cell is the cursor cell, then we need to change the color. - if (mode != MODE_TEXT_CURSOR && is_cursor_pos) { + // If this cell is the cursor cell, but we're not processing + // the cursor glyph itself, then we need to change the color. + if ((glyph_bools & IS_CURSOR_GLYPH) == 0 && is_cursor_pos) { out_data.color = load_color(unpack4u8(cursor_color_packed_4u8), use_linear_blending); } } diff --git a/src/renderer/shaders/shaders.metal b/src/renderer/shaders/shaders.metal index b62e0c3cf..4797f89e4 100644 --- a/src/renderer/shaders/shaders.metal +++ b/src/renderer/shaders/shaders.metal @@ -509,13 +509,17 @@ fragment float4 cell_bg_fragment( //------------------------------------------------------------------- #pragma mark - Cell Text Shader -// The possible modes that a cell fg entry can take. -enum CellTextMode : uint8_t { - MODE_TEXT = 1u, - MODE_TEXT_CONSTRAINED = 2u, - MODE_TEXT_COLOR = 3u, - MODE_TEXT_CURSOR = 4u, - MODE_TEXT_POWERLINE = 5u, +enum CellTextAtlas : uint8_t { + ATLAS_GRAYSCALE = 0u, + ATLAS_COLOR = 1u, +}; + +// We use a packed struct of bools for misc properties of the glyph. +enum CellTextBools : uint8_t { + // Don't apply min contrast to this glyph. + NO_MIN_CONTRAST = 1u, + // This is the cursor glyph. + IS_CURSOR_GLYPH = 2u, }; struct CellTextVertexIn { @@ -534,16 +538,16 @@ struct CellTextVertexIn { // The color of the rendered text glyph. uchar4 color [[attribute(4)]]; - // The mode for this cell. - uint8_t mode [[attribute(5)]]; + // Which atlas to sample for our glyph. + uint8_t atlas [[attribute(5)]]; - // The width to constrain the glyph to, in cells, or 0 for no constraint. - uint8_t constraint_width [[attribute(6)]]; + // Misc properties of the glyph. + uint8_t bools [[attribute(6)]]; }; struct CellTextVertexOut { float4 position [[position]]; - uint8_t mode [[flat]]; + uint8_t atlas [[flat]]; float4 color [[flat]]; float4 bg_color [[flat]]; float2 tex_coord; @@ -577,7 +581,7 @@ vertex CellTextVertexOut cell_text_vertex( corner.y = float(vid == 2 || vid == 3); CellTextVertexOut out; - out.mode = in.mode; + out.atlas = in.atlas; // === Grid Cell === // +X @@ -610,25 +614,6 @@ vertex CellTextVertexOut cell_text_vertex( offset.y = uniforms.cell_size.y - offset.y; - // If we're constrained then we need to scale the glyph. - if (in.mode == MODE_TEXT_CONSTRAINED) { - float max_width = uniforms.cell_size.x * in.constraint_width; - // If this glyph is wider than the constraint width, - // fit it to the width and remove its horizontal offset. - if (size.x > max_width) { - float new_y = size.y * (max_width / size.x); - offset.y += (size.y - new_y) / 2; - offset.x = 0; - size.y = new_y; - size.x = max_width; - } else if (max_width - size.x > offset.x) { - // However, if it does fit in the constraint width, make - // sure the offset is small enough to not push it over the - // right edge of the constraint width. - offset.x = max_width - size.x; - } - } - // Calculate the final position of the cell which uses our glyph size // and glyph offset to create the correct bounding box for the glyph. cell_pos = cell_pos + size * corner + offset; @@ -665,11 +650,7 @@ vertex CellTextVertexOut cell_text_vertex( // If we have a minimum contrast, we need to check if we need to // change the color of the text to ensure it has enough contrast // with the background. - // We only apply this adjustment to "normal" text with MODE_TEXT, - // since we want color glyphs to appear in their original color - // and Powerline glyphs to be unaffected (else parts of the line would - // have different colors as some parts are displayed via background colors). - if (uniforms.min_contrast > 1.0f && in.mode == MODE_TEXT) { + if (uniforms.min_contrast > 1.0f && (in.bools & NO_MIN_CONTRAST) == 0) { // Ensure our minimum contrast out.color = contrasted_color(uniforms.min_contrast, out.color, out.bg_color); } @@ -681,8 +662,9 @@ vertex CellTextVertexOut cell_text_vertex( in.grid_pos.x == uniforms.cursor_pos.x + 1 ) && in.grid_pos.y == uniforms.cursor_pos.y; - // If this cell is the cursor cell, then we need to change the color. - if (in.mode != MODE_TEXT_CURSOR && is_cursor_pos) { + // If this cell is the cursor cell, but we're not processing + // the cursor glyph itself, then we need to change the color. + if ((in.bools & IS_CURSOR_GLYPH) == 0 && is_cursor_pos) { out.color = load_color( uniforms.cursor_color, uniforms.use_display_p3, @@ -702,19 +684,12 @@ fragment float4 cell_text_fragment( constexpr sampler textureSampler( coord::pixel, address::clamp_to_edge, - // TODO(qwerasd): This can be changed back to filter::nearest when - // we move the constraint logic out of the GPU code - // which should once again guarantee pixel perfect - // sizing. - filter::linear + filter::nearest ); - switch (in.mode) { + switch (in.atlas) { default: - case MODE_TEXT_CURSOR: - case MODE_TEXT_CONSTRAINED: - case MODE_TEXT_POWERLINE: - case MODE_TEXT: { + case ATLAS_GRAYSCALE: { // Our input color is always linear. float4 color = in.color; @@ -764,7 +739,7 @@ fragment float4 cell_text_fragment( return color; } - case MODE_TEXT_COLOR: { + case ATLAS_COLOR: { // For now, we assume that color glyphs // are already premultiplied linear colors. float4 color = textureColor.sample(textureSampler, in.tex_coord); diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 040132f03..039b11c03 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -15,11 +15,6 @@ const posix = std.posix; const log = std.log.scoped(.io_handler); -/// True if we should disable the kitty keyboard protocol. We have to -/// disable this on GLFW because GLFW input events don't support the -/// correct granularity of events. -const disable_kitty_keyboard_protocol = apprt.runtime == apprt.glfw; - /// This is used as the handler for the terminal.Stream type. This is /// stateful and is expected to live for the entire lifetime of the terminal. /// It is NOT VALID to stop a stream handler, create a new one, and use that @@ -913,8 +908,6 @@ pub const StreamHandler = struct { } pub fn queryKittyKeyboard(self: *StreamHandler) !void { - if (comptime disable_kitty_keyboard_protocol) return; - log.debug("querying kitty keyboard mode", .{}); var data: termio.Message.WriteReq.Small.Array = undefined; const resp = try std.fmt.bufPrint(&data, "\x1b[?{}u", .{ @@ -933,15 +926,11 @@ pub const StreamHandler = struct { self: *StreamHandler, flags: terminal.kitty.KeyFlags, ) !void { - if (comptime disable_kitty_keyboard_protocol) return; - log.debug("pushing kitty keyboard mode: {}", .{flags}); self.terminal.screen.kitty_keyboard.push(flags); } pub fn popKittyKeyboard(self: *StreamHandler, n: u16) !void { - if (comptime disable_kitty_keyboard_protocol) return; - log.debug("popping kitty keyboard mode n={}", .{n}); self.terminal.screen.kitty_keyboard.pop(@intCast(n)); } @@ -951,8 +940,6 @@ pub const StreamHandler = struct { mode: terminal.kitty.KeySetMode, flags: terminal.kitty.KeyFlags, ) !void { - if (comptime disable_kitty_keyboard_protocol) return; - log.debug("setting kitty keyboard mode: {} {}", .{ mode, flags }); self.terminal.screen.kitty_keyboard.set(mode, flags); } diff --git a/vendor/nerd-fonts/LICENSE b/vendor/nerd-fonts/LICENSE new file mode 100644 index 000000000..d163912b3 --- /dev/null +++ b/vendor/nerd-fonts/LICENSE @@ -0,0 +1,126 @@ +# Nerd Fonts Licensing + +There are various sources used under various licenses: + +* Nerd Fonts source fonts, patched fonts, and folders with explict OFL SIL files are licensed under SIL OPEN FONT LICENSE Version 1.1 (see below). +* Nerd Fonts original source code files (such as `.sh`, `.py`, `font-patcher` and others) are licensed under the MIT License (MIT) (see below). +* Many other licenses are present in this project for even more detailed breakdown see: [License Audit](https://github.com/ryanoasis/nerd-fonts/blob/-/license-audit.md). + +## Source files not in folders containing an explicit license are using the MIT License (MIT) + +The MIT License (MIT) + +Copyright (c) 2014 Ryan L McIntyre + +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. + +## Various Fonts, Patched Fonts, SVGs, Glyph Fonts, and any files in a folder with explicit SIL OFL 1.1 License + +Copyright (c) 2014, Ryan L McIntyre (https://ryanlmcintyre.com). + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/vendor/nerd-fonts/README.md b/vendor/nerd-fonts/README.md new file mode 100644 index 000000000..66dec54cb --- /dev/null +++ b/vendor/nerd-fonts/README.md @@ -0,0 +1,10 @@ +We have a copy of the `font-patcher` file from `nerd-fonts` here, fetched from +https://github.com/ryanoasis/nerd-fonts/blob/master/font-patcher. + +This is MIT licensed, see `LICENSE` in this directory. + +We use parse a section of this file to codegen a lookup table of the nerd font +scaling rules. See `src/font/nerd_font_codegen.py` in the main Ghostty source +tree for more info. + +Last fetched commit: ebc376cbd43f609d8084f47dd348646595ce066e diff --git a/vendor/nerd-fonts/font-patcher.py b/vendor/nerd-fonts/font-patcher.py new file mode 100644 index 000000000..6c7ebfe37 --- /dev/null +++ b/vendor/nerd-fonts/font-patcher.py @@ -0,0 +1,2296 @@ +#!/usr/bin/env python +# coding=utf8 +# Nerd Fonts Version: 3.4.0 +# Script version is further down + +from __future__ import absolute_import, print_function, unicode_literals + +# Change the script version when you edit this script: +script_version = "4.20.5" + +version = "3.4.0" +projectName = "Nerd Fonts" +projectNameAbbreviation = "NF" +projectNameSingular = projectName[:-1] + +import sys +import re +import os +import argparse +from argparse import RawTextHelpFormatter +import errno +import subprocess +import json +from enum import Enum +import logging +try: + import configparser +except ImportError: + sys.exit(projectName + ": configparser module is probably not installed. Try `pip install configparser` or equivalent") +try: + import psMat + import fontforge +except ImportError: + sys.exit( + projectName + ( + ": FontForge module could not be loaded. Try installing fontforge python bindings " + "[e.g. on Linux Debian or Ubuntu: `sudo apt install fontforge python3-fontforge`]" + ) + ) + +sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'bin', 'scripts', 'name_parser')) +try: + from FontnameParser import FontnameParser + from FontnameTools import FontnameTools + FontnameParserOK = True +except ImportError: + FontnameParserOK = False + +class TableHEADWriter: + """ Access to the HEAD table without external dependencies """ + def getlong(self, pos = None): + """ Get four bytes from the font file as integer number """ + if pos: + self.goto(pos) + return (ord(self.f.read(1)) << 24) + (ord(self.f.read(1)) << 16) + (ord(self.f.read(1)) << 8) + ord(self.f.read(1)) + + def getshort(self, pos = None): + """ Get two bytes from the font file as integer number """ + if pos: + self.goto(pos) + return (ord(self.f.read(1)) << 8) + ord(self.f.read(1)) + + def putlong(self, num, pos = None): + """ Put number as four bytes into font file """ + if pos: + self.goto(pos) + self.f.write(bytearray([(num >> 24) & 0xFF, (num >> 16) & 0xFF ,(num >> 8) & 0xFF, num & 0xFF])) + self.modified = True + + def putshort(self, num, pos = None): + """ Put number as two bytes into font file """ + if pos: + self.goto(pos) + self.f.write(bytearray([(num >> 8) & 0xFF, num & 0xFF])) + self.modified = True + + def calc_checksum(self, start, end, checksum = 0): + """ Calculate a font table checksum, optionally ignoring another embedded checksum value (for table 'head') """ + self.f.seek(start) + for i in range(start, end - 4, 4): + checksum += self.getlong() + checksum &= 0xFFFFFFFF + i += 4 + extra = 0 + for j in range(4): + extra = extra << 8 + if i + j <= end: + extra += ord(self.f.read(1)) + checksum = (checksum + extra) & 0xFFFFFFFF + return checksum + + def find_table(self, tablenames, idx): + """ Search all tables for one of the tables in tablenames and store its metadata """ + # Use font with index idx if this is a font collection file + self.f.seek(0, 0) + tag = self.f.read(4) + if tag == b'ttcf': + self.f.seek(2*2, 1) + self.num_fonts = self.getlong() + if (idx >= self.num_fonts): + raise Exception('Trying to access subfont index {} but have only {} fonts'.format(idx, num_fonts)) + for _ in range(idx + 1): + offset = self.getlong() + self.f.seek(offset, 0) + elif idx != 0: + raise Exception('Trying to access subfont but file is no collection') + else: + self.f.seek(0, 0) + self.num_fonts = 1 + + self.f.seek(4, 1) + numtables = self.getshort() + self.f.seek(3*2, 1) + + for i in range(numtables): + tab_name = self.f.read(4) + self.tab_check_offset = self.f.tell() + self.tab_check = self.getlong() + self.tab_offset = self.getlong() + self.tab_length = self.getlong() + if tab_name in tablenames: + return True + return False + + def find_head_table(self, idx): + """ Search all tables for the HEAD table and store its metadata """ + # Use font with index idx if this is a font collection file + found = self.find_table([ b'head' ], idx) + if not found: + raise Exception('No HEAD table found in font idx {}'.format(idx)) + + + def goto(self, where): + """ Go to a named location in the file or to the specified index """ + if isinstance(where, str): + positions = {'checksumAdjustment': 2+2+4, + 'flags': 2+2+4+4+4, + 'lowestRecPPEM': 2+2+4+4+4+2+2+8+8+2+2+2+2+2, + 'avgWidth': 2, + } + where = self.tab_offset + positions[where] + self.f.seek(where) + + + def calc_full_checksum(self, check = False): + """ Calculate the whole file's checksum """ + self.f.seek(0, 2) + self.end = self.f.tell() + full_check = self.calc_checksum(0, self.end, (-self.checksum_adj) & 0xFFFFFFFF) + if check and (0xB1B0AFBA - full_check) & 0xFFFFFFFF != self.checksum_adj: + sys.exit("Checksum of whole font is bad") + return full_check + + def calc_table_checksum(self, check = False): + tab_check_new = self.calc_checksum(self.tab_offset, self.tab_offset + self.tab_length - 1, (-self.checksum_adj) & 0xFFFFFFFF) + if check and tab_check_new != self.tab_check: + sys.exit("Checksum of 'head' in font is bad") + return tab_check_new + + def reset_table_checksum(self): + new_check = self.calc_table_checksum() + self.putlong(new_check, self.tab_check_offset) + + def reset_full_checksum(self): + new_adj = (0xB1B0AFBA - self.calc_full_checksum()) & 0xFFFFFFFF + self.putlong(new_adj, 'checksumAdjustment') + + def close(self): + self.f.close() + + + def __init__(self, filename): + self.modified = False + self.f = open(filename, 'r+b') + + self.find_head_table(0) + + self.flags = self.getshort('flags') + self.lowppem = self.getshort('lowestRecPPEM') + self.checksum_adj = self.getlong('checksumAdjustment') + +def check_panose_monospaced(font): + """ Check if the font's Panose flags say it is monospaced """ + # https://forum.high-logic.com/postedfiles/Panose.pdf + panose = list(font.os2_panose) + if panose[0] < 2 or panose[0] > 5: + return -1 # invalid Panose info + panose_mono = ((panose[0] == 2 and panose[3] == 9) or + (panose[0] == 3 and panose[3] == 3)) + return 1 if panose_mono else 0 + +def panose_check_to_text(value, panose = False): + """ Convert value from check_panose_monospaced() to human readable string """ + if value == 0: + return "Panose says \"not monospaced\"" + if value == 1: + return "Panose says \"monospaced\"" + return "Panose is invalid" + (" ({})".format(list(panose)) if panose else "") + +def panose_proportion_to_text(value): + """ Interpret a Panose proportion value (4th value) for family 2 (latin text) """ + proportion = { + 0: "Any", 1: "No Fit", 2: "Old Style", 3: "Modern", 4: "Even Width", + 5: "Extended", 6: "Condensed", 7: "Very Extended", 8: "Very Condensed", + 9: "Monospaced" } + return proportion.get(value, "??? {}".format(value)) + +def is_monospaced(font): + """ Check if a font is probably monospaced """ + # Some fonts lie (or have not any Panose flag set), spot check monospaced: + width = -1 + width_mono = True + for glyph in [ 0x49, 0x4D, 0x57, 0x61, 0x69, 0x6d, 0x2E ]: # wide and slim glyphs 'I', 'M', 'W', 'a', 'i', 'm', '.' + if not glyph in font: + # A 'strange' font, believe Panose + return (check_panose_monospaced(font) == 1, None) + # print(" -> {} {}".format(glyph, font[glyph].width)) + if width < 0: + width = font[glyph].width + continue + if font[glyph].width != width: + # Exception for fonts like Code New Roman Regular or Hermit Light/Bold: + # Allow small 'i' and dot to be smaller than normal + # I believe the source fonts are buggy + if glyph in [ 0x69, 0x2E ]: + if width > font[glyph].width: + continue + (xmin, _, xmax, _) = font[glyph].boundingBox() + if width > xmax - xmin: + continue + width_mono = False + break + # We believe our own check more then Panose ;-D + return (width_mono, None if width_mono else glyph) + +def force_panose_monospaced(font): + """ Forces the Panose flag to monospaced if they are unset or halfway ok already """ + # For some Windows applications (e.g. 'cmd'), they seem to honour the Panose table + # https://forum.high-logic.com/postedfiles/Panose.pdf + panose = list(font.os2_panose) + if panose[0] == 0: # 0 (1st value) = family kind; 0 = any (default) + panose[0] = 2 # make kind latin text and display + logger.info("Setting Panose 'Family Kind' to 'Latin Text and Display' (was 'Any')") + font.os2_panose = tuple(panose) + if panose[0] == 2 and panose[3] != 9: + logger.info("Setting Panose 'Proportion' to 'Monospaced' (was '%s')", panose_proportion_to_text(panose[3])) + panose[3] = 9 # 3 (4th value) = proportion; 9 = monospaced + font.os2_panose = tuple(panose) + +def get_advance_width(font, extended, minimum): + """ Get the maximum/minimum advance width in the extended(?) range """ + width = 0 + if not extended: + r = range(0x021, 0x07e) + else: + r = range(0x07f, 0x17f) + for glyph in r: + if not glyph in font: + continue + if glyph in range(0x7F, 0xBF): + continue # ignore special characters like '1/4' etc + if width == 0: + width = font[glyph].width + continue + if not minimum and width < font[glyph].width: + width = font[glyph].width + elif minimum and width > font[glyph].width: + width = font[glyph].width + return width + +def report_advance_widths(font): + return "Advance widths (base/extended): {} - {} / {} - {}".format( + get_advance_width(font, False, True), get_advance_width(font, False, False), + get_advance_width(font, True, True), get_advance_width(font, True, False)) + +def get_btb_metrics(font): + """ Get the baseline to baseline distance for all three metrics """ + hhea_height = font.hhea_ascent - font.hhea_descent + typo_height = font.os2_typoascent - font.os2_typodescent + win_height = font.os2_winascent + font.os2_windescent + win_gap = max(0, font.hhea_linegap - win_height + hhea_height) + hhea_btb = hhea_height + font.hhea_linegap + typo_btb = typo_height + font.os2_typolinegap + win_btb = win_height + win_gap + return (hhea_btb, typo_btb, win_btb, win_gap) + +def get_metrics_names(): + """ Helper to get the line metrics names consistent """ + return ['HHEA','TYPO','WIN'] + +def get_old_average_x_width(font): + """ Determine xAvgCharWidth of the OS/2 table """ + # Fontforge can not create fonts with old (i.e. prior to OS/2 version 3) + # table values, but some very old applications do need them sometimes + # https://learn.microsoft.com/en-us/typography/opentype/spec/os2#xavgcharwidth + s = 0 + weights = { + 'a': 64, 'b': 14, 'c': 27, 'd': 35, 'e': 100, 'f': 20, 'g': 14, 'h': 42, 'i': 63, + 'j': 3, 'k': 6, 'l': 35, 'm': 20, 'n': 56, 'o': 56, 'p': 17, 'q': 4, 'r': 49, + 's': 56, 't': 71, 'u': 31, 'v': 10, 'w': 18, 'x': 3, 'y': 18, 'z': 2, 32: 166, + } + for g in weights: + if g not in font: + logger.critical("Can not determine ancient style xAvgCharWidth") + sys.exit(1) + s += font[g].width * weights[g] + return int(s / 1000) + +def create_filename(fonts): + """ Determine filename from font object(s) """ + # Only consider the standard (i.e. English-US) names + sfnt = { k: v for l, k, v in fonts[0].sfnt_names if l == 'English (US)' } + sfnt_pfam = sfnt.get('Preferred Family', sfnt['Family']) + sfnt_psubfam = sfnt.get('Preferred Styles', sfnt['SubFamily']) + if len(fonts) > 1: + return sfnt_pfam + if len(sfnt_psubfam) > 0: + sfnt_psubfam = '-' + sfnt_psubfam + return (sfnt_pfam + sfnt_psubfam).replace(' ', '') + +def fetch_glyphnames(): + """ Read the glyphname database and put it into a dictionary """ + try: + glyphnamefile = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), 'glyphnames.json')) + with open(glyphnamefile, 'rb') as f: + namelist = json.load(f) + return { int(v['code'], 16): k for k, v in namelist.items() if 'code' in v } + except Exception as error: + logger.warning("Can not read glyphnames file (%s)", repr(error)) + return {} + +class font_patcher: + def __init__(self, args, conf): + self.args = args # class 'argparse.Namespace' + self.sym_font_args = [] + self.config = conf # class 'configparser.ConfigParser' + self.sourceFont = None # class 'fontforge.font' + self.patch_set = None # class 'list' + self.font_dim = None # class 'dict' + self.font_extrawide = False + self.source_monospaced = None # Later True or False + self.symbolsonly = False # Are we generating the SymbolsOnly font? + self.onlybitmaps = 0 + self.essential = set() + self.xavgwidth = [] # list of ints + self.glyphnames = fetch_glyphnames() + + def patch(self, font): + self.sourceFont = font + self.setup_version() + self.assert_monospace() + self.remove_ligatures() + self.manipulate_hints() + self.get_essential_references() + self.get_sourcefont_dimensions() + self.setup_patch_set() + self.improve_line_dimensions() + self.sourceFont.encoding = 'UnicodeFull' # Update the font encoding to ensure that the Unicode glyphs are available + self.onlybitmaps = self.sourceFont.onlybitmaps # Fetch this property before adding outlines. NOTE self.onlybitmaps initialized and never used + + if self.args.forcemono: + # Force width to be equal on all glyphs to ensure the font is considered monospaced on Windows. + # This needs to be done on all characters, as some information seems to be lost from the original font file. + self.set_sourcefont_glyph_widths() + + # For very wide (almost square or wider) fonts we do not want to generate 2 cell wide Powerline glyphs + if self.font_dim['height'] * 1.8 < self.font_dim['width'] * 2: + logger.warning("Very wide and short font, disabling 2 cell Powerline glyphs") + self.font_extrawide = True + + # Prevent opening and closing the fontforge font. Makes things faster when patching + # multiple ranges using the same symbol font. + PreviousSymbolFilename = "" + symfont = None + + if not os.path.isdir(self.args.glyphdir): + logger.critical("Can not find symbol glyph directory %s " + "(probably you need to download the src/glyphs/ directory?)", self.args.glyphdir) + sys.exit(1) + + if self.args.dry_run: + return + + for patch in self.patch_set: + if patch['Enabled']: + if PreviousSymbolFilename != patch['Filename']: + # We have a new symbol font, so close the previous one if it exists + if symfont: + symfont.close() + symfont = None + symfont_file = os.path.join(self.args.glyphdir, patch['Filename']) + if not os.path.isfile(symfont_file): + logger.critical("Can not find symbol source for '%s' (i.e. %s)", + patch['Name'], symfont_file) + sys.exit(1) + if not os.access(symfont_file, os.R_OK): + logger.critical("Can not open symbol source for '%s' (i.e. %s)", + patch['Name'], symfont_file) + sys.exit(1) + symfont = fontforge.open(symfont_file) + symfont.encoding = 'UnicodeFull' + + # Match the symbol font size to the source font size + symfont.em = self.sourceFont.em + PreviousSymbolFilename = patch['Filename'] + + # If patch table doesn't include a source start, re-use the symbol font values + SrcStart = patch['SrcStart'] + if not SrcStart: + SrcStart = patch['SymStart'] + self.copy_glyphs(SrcStart, symfont, patch['SymStart'], patch['SymEnd'], patch['Exact'], patch['ScaleRules'], patch['Name'], patch['Attributes']) + + if symfont: + symfont.close() + + # The grave accent and fontforge: + # If the type is 'auto' fontforge changes it to 'mark' on export. + # We can not prevent this. So set it to 'baseglyph' instead, as + # that resembles the most common expectations. + # This is not needed with fontforge March 2022 Release anymore. + if "grave" in self.sourceFont: + self.sourceFont["grave"].glyphclass="baseglyph" + + + def generate(self, sourceFonts): + sourceFont = sourceFonts[0] + # the `PfEd-comments` flag is required for Fontforge to save '.comment' and '.fontlog'. + if int(fontforge.version()) >= 20201107: + gen_flags = (str('opentype'), str('PfEd-comments'), str('no-FFTM-table')) + else: + gen_flags = (str('opentype'), str('PfEd-comments')) + if len(sourceFonts) > 1: + layer = None + # use first non-background layer + for l in sourceFont.layers: + if not sourceFont.layers[l].is_background: + layer = l + break + outfile = os.path.normpath(os.path.join( + sanitize_filename(self.args.outputdir, True), + sanitize_filename(create_filename(sourceFonts)) + ".ttc")) + sourceFonts[0].generateTtc(outfile, sourceFonts[1:], flags=gen_flags, layer=layer) + message = " Generated {} fonts\n \\===> '{}'".format(len(sourceFonts), outfile) + else: + fontname = create_filename(sourceFonts) + if not fontname: + fontname = sourceFont.cidfontname + outfile = os.path.normpath(os.path.join( + sanitize_filename(self.args.outputdir, True), + sanitize_filename(fontname) + self.args.extension)) + bitmaps = str() + if len(sourceFont.bitmapSizes): + logger.debug("Preserving bitmaps %s", repr(sourceFont.bitmapSizes)) + bitmaps = str('otf') # otf/ttf, both is bf_ttf + if self.args.dry_run: + logger.debug("=====> Filename '%s'", outfile) + return + sourceFont.generate(outfile, bitmap_type=bitmaps, flags=gen_flags) + message = " {}\n \\===> '{}'".format(sourceFont.fullname, outfile) + + # Adjust flags that can not be changed via fontforge + if re.search(r'\.[ot]tf$', self.args.font, re.IGNORECASE) and re.search(r'\.[ot]tf$', outfile, re.IGNORECASE): + if not os.path.isfile(outfile) or os.path.getsize(outfile) < 1: + logger.critical("Something went wrong and Fontforge did not generate the new font - look for messages above") + sys.exit(1) + try: + source_font = TableHEADWriter(self.args.font) + dest_font = TableHEADWriter(outfile) + for idx in range(source_font.num_fonts): + logger.debug("Tweaking %d/%d", idx + 1, source_font.num_fonts) + xwidth_s = '' + xwidth = self.xavgwidth[idx] if len(self.xavgwidth) > idx else None + if isinstance(xwidth, int): + if isinstance(xwidth, bool) and xwidth: + source_font.find_table([b'OS/2'], idx) + xwidth = source_font.getshort('avgWidth') + xwidth_s = ' (copied from source)' + dest_font.find_table([b'OS/2'], idx) + d_xwidth = dest_font.getshort('avgWidth') + if d_xwidth != xwidth: + logger.debug("Changing xAvgCharWidth from %d to %d%s", d_xwidth, xwidth, xwidth_s) + dest_font.putshort(xwidth, 'avgWidth') + dest_font.reset_table_checksum() + source_font.find_head_table(idx) + dest_font.find_head_table(idx) + if source_font.flags & 0x08 == 0 and dest_font.flags & 0x08 != 0: + logger.debug("Changing flags from 0x%X to 0x%X", dest_font.flags, dest_font.flags & ~0x08) + dest_font.putshort(dest_font.flags & ~0x08, 'flags') # clear 'ppem_to_int' + if source_font.lowppem != dest_font.lowppem: + logger.debug("Changing lowestRecPPEM from %d to %d", dest_font.lowppem, source_font.lowppem) + dest_font.putshort(source_font.lowppem, 'lowestRecPPEM') + if dest_font.modified: + dest_font.reset_table_checksum() + if dest_font.modified: + dest_font.reset_full_checksum() + except Exception as error: + logger.error("Can not handle font flags (%s)", repr(error)) + finally: + try: + source_font.close() + dest_font.close() + except: + pass + if self.args.is_variable: + logger.critical("Source font is a variable open type font (VF) and the patch results will most likely not be what you want") + print(message) + + if self.args.postprocess: + subprocess.call([self.args.postprocess, outfile]) + print("\n") + logger.info("Post Processed: %s", outfile) + + + def setup_name_backup(self, font): + """ Store the original font names to be able to rename the font multiple times """ + font.persistent = { + "fontname": font.fontname, + "fullname": font.fullname, + "familyname": font.familyname, + } + + + def setup_font_names(self, font): + font.fontname = font.persistent["fontname"] + if isinstance(font.persistent["fullname"], str): + font.fullname = font.persistent["fullname"] + if isinstance(font.persistent["familyname"], str): + font.familyname = font.persistent["familyname"] + verboseAdditionalFontNameSuffix = "" + additionalFontNameSuffix = "" + if not self.args.complete: + # NOTE not all symbol fonts have appended their suffix here + if self.args.fontawesome: + additionalFontNameSuffix += " A" + verboseAdditionalFontNameSuffix += " Plus Font Awesome" + if self.args.fontawesomeextension: + additionalFontNameSuffix += " AE" + verboseAdditionalFontNameSuffix += " Plus Font Awesome Extension" + if self.args.octicons: + additionalFontNameSuffix += " O" + verboseAdditionalFontNameSuffix += " Plus Octicons" + if self.args.powersymbols: + additionalFontNameSuffix += " PS" + verboseAdditionalFontNameSuffix += " Plus Power Symbols" + if self.args.codicons: + additionalFontNameSuffix += " C" + verboseAdditionalFontNameSuffix += " Plus Codicons" + if self.args.pomicons: + additionalFontNameSuffix += " P" + verboseAdditionalFontNameSuffix += " Plus Pomicons" + if self.args.fontlogos: + additionalFontNameSuffix += " L" + verboseAdditionalFontNameSuffix += " Plus Font Logos" + if self.args.material: + additionalFontNameSuffix += " MDI" + verboseAdditionalFontNameSuffix += " Plus Material Design Icons" + if self.args.weather: + additionalFontNameSuffix += " WEA" + verboseAdditionalFontNameSuffix += " Plus Weather Icons" + + # add mono signifier to beginning of name suffix + if self.args.single: + variant_abbrev = "M" + variant_full = " Mono" + elif self.args.nonmono and not self.symbolsonly: + variant_abbrev = "P" + variant_full = " Propo" + else: + variant_abbrev = "" + variant_full = "" + + ps_suffix = projectNameAbbreviation + variant_abbrev + additionalFontNameSuffix + + # add 'Nerd Font' to beginning of name suffix + verboseAdditionalFontNameSuffix = " " + projectNameSingular + variant_full + verboseAdditionalFontNameSuffix + additionalFontNameSuffix = " " + projectNameSingular + variant_full + additionalFontNameSuffix + + if FontnameParserOK and self.args.makegroups > 0: + user_supplied_name = False # User supplied names are kept unchanged + if not isinstance(self.args.force_name, str): + use_fullname = isinstance(font.fullname, str) # Usually the fullname is better to parse + # Use fullname if it is 'equal' to the fontname + if font.fullname: + use_fullname |= font.fontname.lower() == FontnameTools.postscript_char_filter(font.fullname).lower() + # Use fullname for any of these source fonts (that are impossible to disentangle from the fontname, we need the blanks) + for hit in [ 'Meslo' ]: + use_fullname |= font.fontname.lower().startswith(hit.lower()) + parser_name = font.fullname if use_fullname else font.fontname + # Gohu fontnames hide the weight, but the file names are ok... + if parser_name.startswith('Gohu'): + parser_name = os.path.splitext(os.path.basename(self.args.font))[0] + else: + if self.args.force_name == 'full': + parser_name = font.fullname + elif self.args.force_name == 'postscript': + parser_name = font.fontname + elif self.args.force_name == 'filename': + parser_name = os.path.basename(font.path).split('.')[0] + else: + parser_name = self.args.force_name + user_supplied_name = True + if not isinstance(parser_name, str) or len(parser_name) < 1: + logger.critical("Specified --name not usable because the name will be empty") + sys.exit(2) + n = FontnameParser(parser_name, logger) + if not n.parse_ok: + logger.warning("Have only minimal naming information, check resulting name. Maybe specify --makegroups 0") + n.drop_for_powerline() + n.enable_short_families(not user_supplied_name, self.args.makegroups in [ 2, 3, 5, 6, ], self.args.makegroups in [ 3, 6, ]) + if not n.set_expect_no_italic(self.args.noitalic): + logger.critical("Detected 'Italic' slant but --has-no-italic specified") + sys.exit(1) + + # All the following stuff is ignored in makegroups-mode + + # basically split the font name around the dash "-" to get the fontname and the style (e.g. Bold) + # this does not seem very reliable so only use the style here as a fallback if the font does not + # have an internal style defined (in sfnt_names) + # using '([^-]*?)' to get the item before the first dash "-" + # using '([^-]*(?!.*-))' to get the item after the last dash "-" + fontname, fallbackStyle = re.match("^([^-]*).*?([^-]*(?!.*-))$", font.fontname).groups() + + # dont trust 'font.familyname' + familyname = fontname + + # fullname (filename) can always use long/verbose font name, even in windows + if font.fullname != None: + fullname = font.fullname + verboseAdditionalFontNameSuffix + else: + fullname = font.cidfontname + verboseAdditionalFontNameSuffix + + fontname = fontname + additionalFontNameSuffix.replace(" ", "") + + # let us try to get the 'style' from the font info in sfnt_names and fallback to the + # parse fontname if it fails: + try: + # search tuple: + subFamilyTupleIndex = [x[1] for x in font.sfnt_names].index("SubFamily") + + # String ID is at the second index in the Tuple lists + sfntNamesStringIDIndex = 2 + + # now we have the correct item: + subFamily = font.sfnt_names[subFamilyTupleIndex][sfntNamesStringIDIndex] + except IndexError: + sys.stderr.write("{}: Could not find 'SubFamily' for given font, falling back to parsed fontname\n".format(projectName)) + subFamily = fallbackStyle + + # some fonts have inaccurate 'SubFamily', if it is Regular let us trust the filename more: + if subFamily == "Regular" and len(fallbackStyle): + subFamily = fallbackStyle + + # This is meant to cover the case where the SubFamily is "Italic" and the filename is *-BoldItalic. + if len(subFamily) < len(fallbackStyle): + subFamily = fallbackStyle + + if len(subFamily) == 0: + subFamily = "Regular" + + familyname += " " + projectNameSingular + variant_full + + # Don't truncate the subfamily to keep fontname unique. MacOS treats fonts with + # the same name as the same font, even if subFamily is different. Make sure to + # keep the resulting fontname (PostScript name) valid by removing spaces. + fontname += '-' + subFamily.replace(' ', '') + + # rename font + # + # comply with SIL Open Font License (OFL) + reservedFontNameReplacements = { + 'source' : 'sauce', + 'Source' : 'Sauce', + 'Bitstream Vera Sans Mono' : 'Bitstrom Wera', + 'BitstreamVeraSansMono' : 'BitstromWera', + 'bitstream vera sans mono' : 'bitstrom wera', + 'bitstreamverasansmono' : 'bitstromwera', + 'hermit' : 'hurmit', + 'Hermit' : 'Hurmit', + 'hasklig' : 'hasklug', + 'Hasklig' : 'Hasklug', + 'Share' : 'Shure', + 'share' : 'shure', + 'IBMPlex' : 'Blex', + 'ibmplex' : 'blex', + 'IBM-Plex' : 'Blex', + 'IBM Plex' : 'Blex', + 'terminus' : 'terminess', + 'Terminus' : 'Terminess', + 'liberation' : 'literation', + 'Liberation' : 'Literation', + 'iAWriter' : 'iMWriting', + 'iA Writer' : 'iM Writing', + 'iA-Writer' : 'iM-Writing', + 'Anka/Coder' : 'AnaConder', + 'anka/coder' : 'anaconder', + 'Cascadia Code' : 'Caskaydia Cove', + 'cascadia code' : 'caskaydia cove', + 'CascadiaCode' : 'CaskaydiaCove', + 'cascadiacode' : 'caskaydiacove', + 'Cascadia Mono' : 'Caskaydia Mono', + 'cascadia mono' : 'caskaydia mono', + 'CascadiaMono' : 'CaskaydiaMono', + 'cascadiamono' : 'caskaydiamono', + 'Fira Mono' : 'Fura Mono', + 'Fira Sans' : 'Fura Sans', + 'FiraMono' : 'FuraMono', + 'FiraSans' : 'FuraSans', + 'fira mono' : 'fura mono', + 'fira sans' : 'fura sans', + 'firamono' : 'furamono', + 'firasans' : 'furasans', + 'IntelOneMono' : 'IntoneMono', + 'IntelOne Mono' : 'Intone Mono', + 'Intel One Mono' : 'Intone Mono', + } + + # remove overly verbose font names + # particularly regarding Powerline sourced Fonts (https://github.com/powerline/fonts) + additionalFontNameReplacements = { + 'for Powerline': '', + 'ForPowerline': '' + } + + additionalFontNameReplacements2 = { + 'Powerline': '' + } + + projectInfo = ( + "Patched with '" + projectName + " Patcher' (https://github.com/ryanoasis/nerd-fonts)\n\n" + "* Website: https://www.nerdfonts.com\n" + "* Version: " + version + "\n" + "* Development Website: https://github.com/ryanoasis/nerd-fonts\n" + "* Changelog: https://github.com/ryanoasis/nerd-fonts/blob/-/changelog.md" + ) + + familyname = replace_font_name(familyname, reservedFontNameReplacements) + fullname = replace_font_name(fullname, reservedFontNameReplacements) + fontname = replace_font_name(fontname, reservedFontNameReplacements) + familyname = replace_font_name(familyname, additionalFontNameReplacements) + fullname = replace_font_name(fullname, additionalFontNameReplacements) + fontname = replace_font_name(fontname, additionalFontNameReplacements) + familyname = replace_font_name(familyname, additionalFontNameReplacements2) + fullname = replace_font_name(fullname, additionalFontNameReplacements2) + fontname = replace_font_name(fontname, additionalFontNameReplacements2) + + if self.args.makegroups < 0: + logger.warning("Renaming disabled! Make sure to comply with font license, esp RFN clause!") + elif not (FontnameParserOK and self.args.makegroups > 0): + # replace any extra whitespace characters: + font.familyname = " ".join(familyname.split()) + font.fullname = " ".join(fullname.split()) + font.fontname = " ".join(fontname.split()) + + font.appendSFNTName(str('English (US)'), str('Preferred Family'), font.familyname) + font.appendSFNTName(str('English (US)'), str('Family'), font.familyname) + font.appendSFNTName(str('English (US)'), str('Compatible Full'), font.fullname) + font.appendSFNTName(str('English (US)'), str('SubFamily'), subFamily) + else: + # Add Nerd Font suffix unless user specifically asked for some excplicit name via --name + if not user_supplied_name: + short_family = projectNameAbbreviation + variant_abbrev if self.args.makegroups >= 4 else projectNameSingular + variant_full + # inject_suffix(family, ps_fontname, short_family) + n.inject_suffix(verboseAdditionalFontNameSuffix, ps_suffix, short_family) + n.rename_font(font) + + font.comment = projectInfo + font.fontlog = projectInfo + + + def setup_version(self): + """ Add the Nerd Font version to the original version """ + # print("Version was {}".format(sourceFont.version)) + if self.sourceFont.version != None: + self.sourceFont.version += ";" + projectName + " " + version + else: + self.sourceFont.version = str(self.sourceFont.cidversion) + ";" + projectName + " " + version + self.sourceFont.sfntRevision = None # Auto-set (refreshed) by fontforge + self.sourceFont.appendSFNTName(str('English (US)'), str('Version'), "Version " + self.sourceFont.version) + # The Version SFNT name is later reused by the NameParser for UniqueID + # print("Version now is {}".format(sourceFont.version)) + + + def remove_ligatures(self): + # let's deal with ligatures (mostly for monospaced fonts) + # Usually removes 'fi' ligs that end up being only one cell wide, and 'ldot' + if self.args.removeligatures: + logger.info("Removing ligatures from configfile `Subtables` section") + if 'Subtables' not in self.config: + logger.warning("No ligature data (config file missing?)") + return + ligature_subtables = json.loads(self.config.get('Subtables', 'ligatures', fallback='[]')) + for subtable in ligature_subtables: + logger.debug("Removing subtable: %s", subtable) + try: + self.sourceFont.removeLookupSubtable(subtable) + logger.debug("Successfully removed subtable: %s", subtable) + except Exception: + logger.error("Failed to remove subtable: %s", subtable) + + + def manipulate_hints(self): + """ Redo the hinting on some problematic glyphs """ + if 'Hinting' not in self.config: + return + redo = json.loads(self.config.get('Hinting', 're_hint', fallback='[]')) + if not len(redo): + return + logger.debug("Working on {} rehinting rules (this may create a lot of fontforge warnings)".format(len(redo))) + count = 0 + for gname in self.sourceFont: + for regex in redo: + if re.fullmatch(regex, gname): + glyph = self.sourceFont[gname] + glyph.autoHint() + glyph.autoInstr() + count += 1 + break + logger.info("Rehinted {} glyphs".format(count)) + + def assert_monospace(self): + # Check if the sourcefont is monospaced + width_mono, offending_char = is_monospaced(self.sourceFont) + self.source_monospaced = width_mono + if self.args.nonmono: + return + panose_mono = check_panose_monospaced(self.sourceFont) + logger.debug("Monospace check: %s; glyph-width-mono %s", + panose_check_to_text(panose_mono, self.sourceFont.os2_panose), repr(width_mono)) + # The following is in fact "width_mono != panose_mono", but only if panose_mono is not 'unknown' + if (width_mono and panose_mono == 0) or (not width_mono and panose_mono == 1): + logger.warning("Monospaced check: Panose assumed to be wrong") + logger.warning("Monospaced check: %s and %s", + report_advance_widths(self.sourceFont), + panose_check_to_text(panose_mono, self.sourceFont.os2_panose)) + if self.args.forcemono and not width_mono: + logger.warning("Sourcefont is not monospaced - forcing to monospace not advisable, " + "results might be useless%s", + " - offending char: {:X}".format(offending_char) if offending_char is not None else "") + if self.args.forcemono <= 1: + logger.critical("Font will not be patched! Give --mono (or -s) twice to force patching") + sys.exit(1) + if width_mono: + force_panose_monospaced(self.sourceFont) + + + def setup_patch_set(self): + """ Creates list of dicts to with instructions on copying glyphs from each symbol font into self.sourceFont """ + + box_enabled = self.source_monospaced and not self.symbolsonly # Box glyph only for monospaced and not for Symbols Only + box_keep = False + if box_enabled or self.args.forcebox: + self.sourceFont.selection.select(("ranges",), 0x2500, 0x259f) + box_glyphs_target = len(list(self.sourceFont.selection)) + box_glyphs_current = len(list(self.sourceFont.selection.byGlyphs)) + if box_glyphs_target > box_glyphs_current or self.args.forcebox: + # Sourcefont does not have all of these glyphs, do not mix sets (overwrite existing) + if box_glyphs_current > 0: + logger.debug("%d/%d box drawing glyphs will be replaced", + box_glyphs_current, box_glyphs_target) + box_enabled = True + else: + # Sourcefont does have all of these glyphs + # box_keep = True # just scale do not copy (need to scale to fit new cell size) + box_enabled = False # Cowardly not scaling existing glyphs, although the code would allow this + + # Stretch 'xz' or 'pa' (preserve aspect ratio) + # Supported params: overlap | careful | xy-ratio | dont_copy | ypadding + # Overlap value is used horizontally but vertically limited to 0.01 + # Careful does not overwrite/modify existing glyphs + # The xy-ratio limits the x-scale for a given y-scale to make the ratio <= this value (to prevent over-wide glyphs) + # '1' means occupu 1 cell (default for 'xy') + # '2' means occupy 2 cells (default for 'pa') + # '!' means do the 'pa' scaling even with non mono fonts (else it just scales down, never up) + # '^' means that scaling shall fill the whole cell and not only the icon-cap-height (for mono fonts, other always use the whole cell) + # Dont_copy does not overwrite existing glyphs but rescales the preexisting ones + # + # Be careful, stretch may not change within a ScaleRule! + + SYM_ATTR_DEFAULT = { + 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {}} + } + SYM_ATTR_POWERLINE = { + 'default': {'align': 'c', 'valign': 'c', 'stretch': '^pa', 'params': {}}, + + # Arrow tips + 0xe0b0: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.06, 'xy-ratio': 0.7}}, + 0xe0b1: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'xy-ratio': 0.7}}, + 0xe0b2: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.06, 'xy-ratio': 0.7}}, + 0xe0b3: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'xy-ratio': 0.7}}, + + # Inverse arrow tips + 0xe0d6: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'xy-ratio': 0.7}}, + 0xe0d7: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'xy-ratio': 0.7}}, + + # Rounded arcs + 0xe0b4: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.06, 'xy-ratio': 0.59}}, + 0xe0b5: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'xy-ratio': 0.5}}, + 0xe0b6: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.06, 'xy-ratio': 0.59}}, + 0xe0b7: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'xy-ratio': 0.5}}, + + # Bottom Triangles + 0xe0b8: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05}}, + 0xe0b9: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {}}, + 0xe0ba: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05}}, + 0xe0bb: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {}}, + + # Top Triangles + 0xe0bc: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05}}, + 0xe0bd: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {}}, + 0xe0be: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05}}, + 0xe0bf: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {}}, + + # Flames + 0xe0c0: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.05}}, + 0xe0c1: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {}}, + 0xe0c2: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.05}}, + 0xe0c3: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {}}, + + # Small squares + 0xe0c4: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': -0.03, 'xy-ratio': 0.86}}, + 0xe0c5: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': -0.03, 'xy-ratio': 0.86}}, + + # Bigger squares + 0xe0c6: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': -0.03, 'xy-ratio': 0.78}}, + 0xe0c7: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': -0.03, 'xy-ratio': 0.78}}, + + # Waveform + 0xe0c8: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.05}}, + 0xe0ca: {'align': 'r', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.05}}, + + # Hexagons + 0xe0cc: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'overlap': 0.02, 'xy-ratio': 0.85}}, + 0xe0cd: {'align': 'l', 'valign': 'c', 'stretch': '^xy2', 'params': {'xy-ratio': 0.865}}, + + # Legos + 0xe0ce: {'align': 'l', 'valign': 'c', 'stretch': '^pa', 'params': {}}, + 0xe0cf: {'align': 'c', 'valign': 'c', 'stretch': '^pa', 'params': {}}, + 0xe0d0: {'align': 'l', 'valign': 'c', 'stretch': '^pa', 'params': {}}, + 0xe0d1: {'align': 'l', 'valign': 'c', 'stretch': '^pa', 'params': {}}, + + # Top and bottom trapezoid + 0xe0d2: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.02, 'xy-ratio': 0.7}}, + 0xe0d4: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.02, 'xy-ratio': 0.7}} + } + SYM_ATTR_TRIGRAPH = { + 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa1!', 'params': {'overlap': -0.10, 'careful': True}} + } + SYM_ATTR_FONTA = { + # 'pa' == preserve aspect ratio + 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {}}, + + # Don't center these arrows vertically + 0xf0dc: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}}, + 0xf0dd: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}}, + 0xf0de: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}} + } + SYM_ATTR_HEAVYBRACKETS = { + 'default': {'align': 'c', 'valign': 'c', 'stretch': '^pa1!', 'params': {'ypadding': 0.3, 'careful': True}} + } + SYM_ATTR_BOX = { + 'default': {'align': 'c', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.02, 'dont_copy': box_keep}}, + # No overlap with checkered greys (commented out because that raises problems on rescaling clients) + # 0x2591: {'align': 'c', 'valign': 'c', 'stretch': 'xy', 'params': {'dont_copy': box_keep}}, + # 0x2592: {'align': 'c', 'valign': 'c', 'stretch': 'xy', 'params': {'dont_copy': box_keep}}, + # 0x2593: {'align': 'c', 'valign': 'c', 'stretch': 'xy', 'params': {'dont_copy': box_keep}}, + } + SYM_ATTR_PROGRESS = { + 'default': {'align': 'c', 'valign': 'c', 'stretch': '^pa1!', 'params': {'overlap': -0.03, 'careful': True}}, # Cirles + # All the squares: + 0xee00: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'careful': True}}, + 0xee01: {'align': 'c', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.10, 'careful': True}}, + 0xee02: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'careful': True}}, + 0xee03: {'align': 'r', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'careful': True}}, + 0xee04: {'align': 'c', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.10, 'careful': True}}, + 0xee05: {'align': 'l', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.05, 'careful': True}}, + } + CUSTOM_ATTR = { + # previous custom scaling => do not touch the icons + # 'default': {'align': 'c', 'valign': '', 'stretch': '', 'params': {}} + 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {'careful': self.args.careful}} + } + + # Most glyphs we want to maximize (individually) during the scale + # However, there are some that need to be small or stay relative in + # size to each other. + # The glyph-specific behavior can be given as ScaleRules in the patch-set. + # + # ScaleRules can contain two different kind of rules (possibly in parallel): + # - ScaleGlyph: + # Here one specific glyph is used as 'scale blueprint'. Other glyphs are + # scaled by the same factor as this glyph. This is useful if you have one + # 'biggest' glyph and all others should stay relatively in size. + # Shifting in addition to scaling can be selected too (see below). + # - ScaleGroups: + # Here you specify a group of glyphs that should be handled together + # with the same scaling and shifting (see bottom). The basis for it is + # a 'combined bounding box' of all glyphs in that group. All glyphs are + # handled as if they fill that combined bounding box. + # (- ScaleGroupsVert: Removed with this commit) + # + # The ScaleGlyph method: You set 'ScaleGlyph' to the unicode of the reference glyph. + # Note that there can be only one per patch-set. + # Additionally you set 'GlyphsToScale' that contains all the glyphs that shall be + # handled (scaled) like the reference glyph. + # It is a List of: ((glyph code) or (tuple of two glyph codes that form a closed range)) + # 'GlyphsToScale': [ + # 0x0100, 0x0300, 0x0400, # The single glyphs 0x0100, 0x0300, and 0x0400 + # (0x0200, 0x0210), # All glyphs 0x0200 to 0x0210 including both 0x0200 and 0x0210 + # ]} + # If you want to not only scale but also shift as the reference glyph you give the + # data as 'GlyphsToScale+'. Note that only one set is used and the plus version is preferred. + # + # For the ScaleGroup method you define any number groups of glyphs and each group is + # handled separately. The combined bounding box of all glyphs in the group is determined + # and based on that the scale and shift (see bottom) for all the glyphs in the group. + # You define the groups as value of 'ScaleGroups'. + # It is a List of: ((lists of glyph codes) or (ranges of glyph codes)) + # 'ScaleGroups': [ + # [0x0100, 0x0300, 0x0400], # One group consists of glyphs 0x0100, 0x0300, and 0x0400 + # range(0x0200, 0x0210 + 1), # Another group contains glyphs 0x0200 to 0x0210 incl. + # + # Note the subtle differences: tuple vs. range; closed vs open range; etc + # See prepareScaleRules() for some more details. + # For historic reasons ScaleGroups is sometimes called 'new method' and ScaleGlyph 'old'. + # The codepoints mentioned here are symbol-font-codepoints. + # + # Shifting: + # If we have a combined bounding box stored in a range, that + # box is used to align all symbols in the range identically. + # - If the symbol font is proportinal only the v alignment is synced. + # - If the symbol font is monospaced v and h alignemnts are synced. + # To make sure the behavior is as expected you are required to set a ShiftMode property + # accordingly. It just checks, you can not (!) select what is done with that property. + + BOX_SCALE_LIST = {'ShiftMode': 'xy', 'ScaleGroups': [ + [*range(0x2500, 0x2570 + 1), *range(0x2574, 0x257f + 1)], # box drawing + range(0x2571, 0x2573 + 1), # diagonals + range(0x2580, 0x259f + 1), # blocks and greys (greys are less tall originally, so overlap will be less) + ]} + CODI_SCALE_LIST = {'ShiftMode': 'xy', 'ScaleGroups': [ + [0xea61, 0xeb13], # lightbulb + range(0xeab4, 0xeab7 + 1), # chevrons + [0xea7d, *range(0xea99, 0xeaa1 + 1), 0xebcb], # arrows + [0xeaa2, 0xeb9a, 0xec08, 0xec09], # bells + range(0xead4, 0xead6 + 1), # dot and arrow + [0xeb43, 0xec0b, 0xec0c], # (pull) request changes + range(0xeb6e, 0xeb71 + 1), # triangles + [*range(0xeb89, 0xeb8b + 1), 0xec07], # smallish dots + range(0xebd5, 0xebd7 + 1), # compasses + ]} + DEVI_SCALE_LIST = None + FONTA_SCALE_LIST = {'ShiftMode': '', 'ScaleGroups': [ + [0xf005, 0xf006, 0xf089], # star, star empty, half star + range(0xf026, 0xf028 + 1), # volume off, down, up + range(0xf02b, 0xf02c + 1), # tag, tags + range(0xf031, 0xf035 + 1), # font et al + range(0xf044, 0xf046 + 1), # edit, share, check (boxes) + range(0xf048, 0xf052 + 1), # multimedia buttons + range(0xf060, 0xf063 + 1), # arrows + [0xf053, 0xf054, 0xf077, 0xf078], # chevron all directions + range(0xf07d, 0xf07e + 1), # resize + range(0xf0a4, 0xf0a7 + 1), # pointing hands + [0xf0d7, 0xf0d8, 0xf0d9, 0xf0da, 0xf0dc, 0xf0dd, 0xf0de], # caret all directions and same looking sort + range(0xf100, 0xf107 + 1), # angle + range(0xf130, 0xf131 + 1), # mic + range(0xf141, 0xf142 + 1), # ellipsis + range(0xf153, 0xf15a + 1), # currencies + range(0xf175, 0xf178 + 1), # long arrows + range(0xf182, 0xf183 + 1), # male and female + range(0xf221, 0xf22d + 1), # gender or so + range(0xf255, 0xf25b + 1), # hand symbols + ]} + HEAVY_SCALE_LIST = {'ShiftMode': 'xy', 'ScaleGroups': [ + range(0x276c, 0x2771+1) + ]} + OCTI_SCALE_LIST = {'ShiftMode': '', 'ScaleGroups': [ + [*range(0xf03d, 0xf040 + 1), 0xf019, 0xf030, 0xf04a, 0xf051, 0xf071, 0xf08c ], # arrows + [0xF0E7, # Smily and ... + 0xf044, 0xf05a, 0xf05b, 0xf0aa, # triangles + 0xf052, 0xf053, 0xf296, 0xf2f0, # small stuff + 0xf078, 0xf0a2, 0xf0a3, 0xf0a4, # chevrons + 0xf0ca, 0xf081, 0xf092, # dash, X, github-text + ], + [0xf09c, 0xf09f, 0xf0de], # bells + range(0xf2c2, 0xf2c5 + 1), # move to + [0xf07b, 0xf0a1, 0xf0d6, 0xf306], # bookmarks + ]} + PROGR_SCALE_LIST = {'ShiftMode': 'xy', 'ScaleGroups': [ + range(0xedff, 0xee05 + 1), # boxes... with helper glyph EDFF for Y padding + range(0xee06, 0xee0b + 1), # circles + ]} + WEATH_SCALE_LIST = {'ShiftMode': '', 'ScaleGroups': [ + [0xf03c, 0xf042, 0xf045 ], # degree signs + [0xf043, 0xf044, 0xf048, 0xf04b, 0xf04c, 0xf04d, 0xf057, 0xf058, 0xf087, 0xf088], # arrows + range(0xf053, 0xf055 + 1), # thermometers + [*range(0xf059, 0xf061 + 1), 0xf0b1], # wind directions + range(0xf089, 0xf094 + 1), # clocks + range(0xf095, 0xf0b0 + 1), # moon phases + range(0xf0b7, 0xf0c3 + 1), # wind strengths + [0xf06e, 0xf070 ], # solar/lunar eclipse + [0xf051, 0xf052, 0xf0c9, 0xf0ca, 0xf072 ], # sun/moon up/down + [0xf049, 0xf056, 0xf071, *range(0xf073, 0xf07c + 1), 0xf08a], # other things + # Note: Codepoints listed before that are also in the following range + # will take the scaling of the previous group (the ScaleGroups are + # searched through in definition order). + # But be careful, the combined bounding box for the following group + # _will_ include all glyphs in its definition: Make sure the exempt + # glyphs from above are smaller (do not extend) the combined bounding + # box of this range: + [ *range(0xf000, 0xf041 + 1), + *range(0xf064, 0xf06d + 1), + *range(0xf07d, 0xf083 + 1), + *range(0xf085, 0xf086 + 1), + *range(0xf0b2, 0xf0b6 + 1) + ], # lots of clouds (weather states) (Please read note above!) + ]} + MDI_SCALE_LIST = None # Maybe later add some selected ScaleGroups + + + # Define the character ranges + # Symbol font ranges + self.patch_set = [ + {'Enabled': True, 'Name': "Seti-UI + Custom", 'Filename': "original-source.otf", 'Exact': False, 'SymStart': 0xE4FA, 'SymEnd': 0xE5FF, 'SrcStart': 0xE5FA, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': True, 'Name': "Heavy Angle Brackets", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0x276C, 'SymEnd': 0x2771, 'SrcStart': None, 'ScaleRules': HEAVY_SCALE_LIST, 'Attributes': SYM_ATTR_HEAVYBRACKETS}, + {'Enabled': box_enabled, 'Name': "Box Drawing", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0x2500, 'SymEnd': 0x259F, 'SrcStart': None, 'ScaleRules': BOX_SCALE_LIST, 'Attributes': SYM_ATTR_BOX}, + {'Enabled': True, 'Name': "Progress Indicators", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0xEE00, 'SymEnd': 0xEE0B, 'SrcStart': None, 'ScaleRules': PROGR_SCALE_LIST, 'Attributes': SYM_ATTR_PROGRESS}, + {'Enabled': True, 'Name': "Devicons", 'Filename': "devicons/devicons.otf", 'Exact': False, 'SymStart': 0xE600, 'SymEnd': 0xE7EF, 'SrcStart': 0xE700, 'ScaleRules': DEVI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0A3, 'SymEnd': 0xE0A3, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0B4, 'SymEnd': 0xE0C8, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0CA, 'SymEnd': 0xE0CA, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0xE0CC, 'SymEnd': 0xE0D7, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE}, + {'Enabled': self.args.powerlineextra, 'Name': "Powerline Extra Symbols", 'Filename': "powerline-extra/PowerlineExtraSymbols.otf", 'Exact': True, 'SymStart': 0x2630, 'SymEnd': 0x2630, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_TRIGRAPH}, + {'Enabled': self.args.pomicons, 'Name': "Pomicons", 'Filename': "pomicons/Pomicons.otf", 'Exact': True, 'SymStart': 0xE000, 'SymEnd': 0xE00A, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.fontawesome, 'Name': "Font Awesome", 'Filename': "font-awesome/FontAwesome.otf", 'Exact': True, 'SymStart': 0xED00, 'SymEnd': 0xF2FF, 'SrcStart': None, 'ScaleRules': FONTA_SCALE_LIST, 'Attributes': SYM_ATTR_FONTA}, + {'Enabled': self.args.fontawesomeextension, 'Name': "Font Awesome Extension", 'Filename': "font-awesome-extension.ttf", 'Exact': False, 'SymStart': 0xE000, 'SymEnd': 0xE0A9, 'SrcStart': 0xE200, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Maximize + {'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x23FB, 'SymEnd': 0x23FE, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Power, Power On/Off, Power On, Sleep + {'Enabled': self.args.powersymbols, 'Name': "Power Symbols", 'Filename': "Unicode_IEC_symbol_font.otf", 'Exact': True, 'SymStart': 0x2B58, 'SymEnd': 0x2B58, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, # Heavy Circle (aka Power Off) + {'Enabled': False , 'Name': "Material legacy", 'Filename': "materialdesign/materialdesignicons-webfont.ttf", 'Exact': False, 'SymStart': 0xF001, 'SymEnd': 0xF847, 'SrcStart': 0xF500, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0001,'SymEnd': 0xF1AF0,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.weather, 'Name': "Weather Icons", 'Filename': "weather-icons/weathericons-regular-webfont.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF0EB, 'SrcStart': 0xE300, 'ScaleRules': WEATH_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.fontlogos, 'Name': "Font Logos", 'Filename': "font-logos.ttf", 'Exact': True, 'SymStart': 0xF300, 'SymEnd': 0xF381, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.otf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.otf", 'Exact': True, 'SymStart': 0x2665, 'SymEnd': 0x2665, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Heart + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.otf", 'Exact': True, 'SymStart': 0X26A1, 'SymEnd': 0X26A1, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Zap + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.otf", 'Exact': False, 'SymStart': 0xF27C, 'SymEnd': 0xF306, 'SrcStart': 0xF4A9, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.codicons, 'Name': "Codicons", 'Filename': "codicons/codicon.ttf", 'Exact': True, 'SymStart': 0xEA60, 'SymEnd': 0xEC1E, 'SrcStart': None, 'ScaleRules': CODI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, + {'Enabled': self.args.custom, 'Name': "Custom", 'Filename': self.args.custom, 'Exact': True, 'SymStart': 0x0000, 'SymEnd': 0x0000, 'SrcStart': None, 'ScaleRules': None, 'Attributes': CUSTOM_ATTR} + ] + + def improve_line_dimensions(self): + # Make the total line size even. This seems to make the powerline separators + # center more evenly. + if self.args.adjustLineHeight: + if (self.sourceFont.os2_winascent + self.sourceFont.os2_windescent) % 2 != 0: + # All three are equal before due to get_sourcefont_dimensions() + self.sourceFont.hhea_ascent += 1 + self.sourceFont.os2_typoascent += 1 + self.sourceFont.os2_winascent += 1 + + def add_glyphrefs_to_essential(self, unicode): + self.essential.add(unicode) + # According to fontforge spec, altuni is either None or a tuple of tuples + # Those tuples contained in altuni are of the following "format": + # (unicode-value, variation-selector, reserved-field) + altuni = self.sourceFont[unicode].altuni + if altuni is not None: + for altcode in [ v for v, s, r in altuni if v >= 0 ]: + # If alternate unicode already exists in self.essential, + # that means it has gone through this function before. + # Therefore we skip it to avoid infinite loop. + # A unicode value of -1 basically means unused and is also worth skipping. + if altcode not in self.essential: + self.add_glyphrefs_to_essential(altcode) + # From fontforge documentation: + # glyph.references return a tuple of tuples containing, for each reference in foreground, + # a glyph name, a transformation matrix, and (depending on ff version) whether the + # reference is currently selected. + references = self.sourceFont[unicode].references + for refcode in [ self.sourceFont[n].unicode for n, *_ in references ]: # tuple of 2 or 3 depending on ff version + if refcode not in self.essential and refcode >= 0: + self.add_glyphrefs_to_essential(refcode) + + def get_essential_references(self): + """Find glyphs that are needed for the basic glyphs""" + # Sometimes basic glyphs are constructed from multiple other glyphs. + # Find out which other glyphs are also needed to keep the basic + # glyphs intact. + # 0x0000-0x017f is the Latin Extended-A range + # 0xfb00-0xfb06 are 'fi' and other ligatures + basic_glyphs = { c for c in range(0x21, 0x17f + 1) if c in self.sourceFont } + # Collect substitution destinations + for glyph in list(basic_glyphs) + [*range(0xfb00, 0xfb06 + 1)]: + if not glyph in self.sourceFont: + continue + for possub in self.sourceFont[glyph].getPosSub('*'): + if possub[1] == 'Substitution' or possub[1] == 'Ligature': + basic_glyphs.add(glyph) + basic_glyphs.add(self.sourceFont[possub[2]].unicode) + basic_glyphs.discard(-1) # the .notdef glyph + for glyph in basic_glyphs: + self.add_glyphrefs_to_essential(glyph) + + def get_sourcefont_dimensions(self): + """ This gets the font dimensions (cell width and height), and makes them equal on all platforms """ + # Step 1 + # There are three ways to describe the baseline to baseline distance + # (a.k.a. line spacing) of a font. That is all a kuddelmuddel + # and we try to sort this out here + # See also https://glyphsapp.com/learn/vertical-metrics + # See also https://github.com/source-foundry/font-line + (hhea_btb, typo_btb, win_btb, win_gap) = get_btb_metrics(self.sourceFont) + use_typo = self.sourceFont.os2_use_typo_metrics != 0 + + Metric = Enum('Metric', get_metrics_names()) + + if not self.args.metrics: + # We use either TYPO (1) or WIN (2) and compare with HHEA + # and use HHEA (0) if the fonts seems broken - no WIN, see #1056 + our_btb = typo_btb if use_typo else win_btb + if our_btb == hhea_btb: + metrics = Metric.TYPO if use_typo else Metric.WIN # conforming font + elif abs(our_btb - hhea_btb) / our_btb < 0.03: + logger.info("Font vertical metrics slightly off (%.1f%%)", (our_btb - hhea_btb) / our_btb * 100.0) + metrics = Metric.TYPO if use_typo else Metric.WIN + else: + # Try the other metric + our_btb = typo_btb if not use_typo else win_btb + if our_btb == hhea_btb: + use_typo = not use_typo + logger.warning("Font vertical metrics probably wrong USE TYPO METRICS, assume opposite (i.e. %s)", repr(use_typo)) + self.sourceFont.os2_use_typo_metrics = 1 if use_typo else 0 + metrics = Metric.TYPO if use_typo else Metric.WIN + else: + # We trust the WIN metric more, see experiments in #1056 + logger.warning("Font vertical metrics inconsistent (HHEA %d / TYPO %d / WIN %d), using WIN", hhea_btb, typo_btb, win_btb) + our_btb = win_btb + metrics = Metric.WIN + else: + metrics = Metric[self.args.metrics] + logger.debug("Metrics in the font: HHEA %d / TYPO %d / WIN %d", hhea_btb, typo_btb, win_btb) + if metrics == Metric.HHEA: + our_btb = hhea_btb + elif metrics == Metric.TYPO: + our_btb = typo_btb + else: + our_btb = win_btb + logger.info("Manually selected metrics: %s (%d)", self.args.metrics, our_btb) + + # print("FINI hhea {} typo {} win {} use {} {} {}".format(hhea_btb, typo_btb, win_btb, use_typo, our_btb != hhea_btb, self.sourceFont.fontname)) + + self.font_dim = {'xmin': 0, 'ymin': 0, 'xmax': 0, 'ymax': 0, 'width' : 0, 'height': 0, 'iconheight': 0, 'ypadding': 0} + + if metrics == Metric.HHEA: + self.font_dim['ymin'] = self.sourceFont.hhea_descent - half_gap(self.sourceFont.hhea_linegap, False) + self.font_dim['ymax'] = self.sourceFont.hhea_ascent + half_gap(self.sourceFont.hhea_linegap, True) + elif metrics == Metric.TYPO: + self.font_dim['ymin'] = self.sourceFont.os2_typodescent - half_gap(self.sourceFont.os2_typolinegap, False) + self.font_dim['ymax'] = self.sourceFont.os2_typoascent + half_gap(self.sourceFont.os2_typolinegap, True) + elif metrics == Metric.WIN: + self.font_dim['ymin'] = -self.sourceFont.os2_windescent - half_gap(win_gap, False) + self.font_dim['ymax'] = self.sourceFont.os2_winascent + half_gap(win_gap, True) + else: + logger.debug("Metrics is strange") + pass # Will fail the metrics check some line later + + if isinstance(self.args.cellopt, list): + logger.debug("Overriding cell Y{%d:%d} with Y{%d:%d}", + self.font_dim['ymin'], self.font_dim['ymax'], + self.args.cellopt[2], self.args.cellopt[3]) + self.font_dim['ymin'] = self.args.cellopt[2] + self.font_dim['ymax'] = self.args.cellopt[3] + our_btb = self.args.cellopt[3] - self.args.cellopt[2] + + # Calculate font height + self.font_dim['height'] = -self.font_dim['ymin'] + self.font_dim['ymax'] + if self.font_dim['height'] == 0: + # This can only happen if the input font is empty + # Assume we are using our prepared templates + self.symbolsonly = True + self.font_dim = { + 'xmin' : 0, + 'ymin' : -self.sourceFont.descent, + 'xmax' : self.sourceFont.em, + 'ymax' : self.sourceFont.ascent, + 'width' : self.sourceFont.em, + 'height' : self.sourceFont.descent + self.sourceFont.ascent, + 'iconheight': self.sourceFont.descent + self.sourceFont.ascent, + 'ypadding' : 0, + } + our_btb = self.sourceFont.descent + self.sourceFont.ascent + if self.font_dim['height'] <= 0: + logger.critical("Can not detect sane font height") + sys.exit(1) + + self.font_dim['iconheight'] = self.font_dim['height'] + if self.args.single and self.sourceFont.capHeight > 0 and not isinstance(self.args.cellopt, list): + # Limit the icon height on monospaced fonts because very slender and tall icons render + # excessively tall otherwise. We ignore that effect for the other variants because it + # does not look so much out of place there. + # Icons can be bigger than the letter capitals, but not the whole cell: + self.font_dim['iconheight'] = (self.sourceFont.capHeight * 2 + self.font_dim['height']) / 3 + + # Make all metrics equal + self.sourceFont.os2_typolinegap = 0 + self.sourceFont.os2_typoascent = self.font_dim['ymax'] + self.sourceFont.os2_typodescent = self.font_dim['ymin'] + self.sourceFont.os2_winascent = self.sourceFont.os2_typoascent + self.sourceFont.os2_windescent = -self.sourceFont.os2_typodescent + self.sourceFont.hhea_ascent = self.sourceFont.os2_typoascent + self.sourceFont.hhea_descent = self.sourceFont.os2_typodescent + self.sourceFont.hhea_linegap = self.sourceFont.os2_typolinegap + self.sourceFont.os2_use_typo_metrics = 1 + (check_hhea_btb, check_typo_btb, check_win_btb, _) = get_btb_metrics(self.sourceFont) + if check_hhea_btb != check_typo_btb or check_typo_btb != check_win_btb or check_win_btb != our_btb: + logger.critical("Error in baseline to baseline code detected") + sys.exit(1) + + # Step 2 + # Find the biggest char width and advance width + # 0x00-0x17f is the Latin Extended-A range + warned1 = self.args.nonmono # Do not warn if proportional target + warned2 = warned1 + for glyph in range(0x21, 0x17f): + if glyph in range(0x7F, 0xBF) or glyph in [ + 0x132, 0x133, # IJ, ij (in Overpass Mono) + 0x022, 0x027, 0x060, # Single and double quotes in Inconsolata LGC + 0x0D0, 0x10F, 0x110, 0x111, 0x127, 0x13E, 0x140, 0x165, # Eth and others with stroke or caron in RobotoMono + 0x149, # napostrophe in DaddyTimeMono + 0x02D, # hyphen for Monofur + ]: + continue # ignore special characters like '1/4' etc and some specifics + try: + (_, _, xmax, _) = self.sourceFont[glyph].boundingBox() + except TypeError: + continue + # print("WIDTH {:X} {} ({} {})".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) + if self.font_dim['width'] < self.sourceFont[glyph].width: + self.font_dim['width'] = self.sourceFont[glyph].width + if not warned1 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z + logger.debug("Extended glyphs wider than basic glyphs, results might be useless") + logger.debug("%s", report_advance_widths(self.sourceFont)) + warned1 = True + # print("New MAXWIDTH-A {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) + if xmax > self.font_dim['xmax']: + self.font_dim['xmax'] = xmax + if not warned2 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z + logger.debug("Extended glyphs wider bounding box than basic glyphs") + warned2 = True + # print("New MAXWIDTH-B {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax)) + if self.font_dim['width'] < self.font_dim['xmax']: + logger.debug("Font has negative right side bearing in extended glyphs") + self.font_dim['xmax'] = self.font_dim['width'] # In fact 'xmax' is never used + if self.font_dim['width'] <= 0: + logger.critical("Can not detect sane font width") + sys.exit(1) + if isinstance(self.args.cellopt, list): + logger.debug("Overriding cell X{%d:%d} with X{%d:%d}", + self.font_dim['xmin'], self.font_dim['xmin'] + self.font_dim['width'], + self.args.cellopt[0], self.args.cellopt[1]) + self.font_dim['xmin'] = self.args.cellopt[0] + self.font_dim['xmax'] = self.args.cellopt[1] + self.font_dim['width'] = self.args.cellopt[1] + if self.args.cellopt: + logger.info("Cell coordinates (Xmin:Xmax:Ymin:Ymax) %s%d:%d:%d:%d", + '' if not isinstance(self.args.cellopt, list) else 'overridden with ', + self.font_dim['xmin'], self.font_dim['width'], + self.font_dim['ymax'] - self.font_dim['height'], self.font_dim['ymax']) + logger.debug("Final font cell dimensions %d w x %d h%s", + self.font_dim['width'], self.font_dim['height'], + ' (with icon cell {} h)'.format(int(self.font_dim['iconheight'])) if self.font_dim['iconheight'] != self.font_dim['height'] else '') + try: + middle = lambda x, y: abs(x - y) / 2 + min(x, y) + x_bb = self.sourceFont['x'].boundingBox(); + X_bb = self.sourceFont['X'].boundingBox(); + logger.debug("Center x-height/cell/capitals %d/%d/%d", + middle(x_bb[1], x_bb[3]), + middle(self.font_dim['ymin'], self.font_dim['ymax']), + middle(X_bb[1], X_bb[3])) + except: + pass + + self.xavgwidth.append(self.args.xavgwidth) + if isinstance(self.xavgwidth[-1], int) and self.xavgwidth[-1] == 0: + self.xavgwidth[-1] = get_old_average_x_width(self.sourceFont) + + + def get_target_width(self, stretch): + """ Get the target width (1 or 2 'cell') for a given stretch parameter """ + # For monospaced fonts all chars need to be maximum 'one' space wide + # other fonts allows double width glyphs for 'pa' or if requested with '2' + if self.args.single or ('pa' not in stretch and '2' not in stretch) or '1' in stretch: + return 1 + return 2 + + def get_scale_factors(self, sym_dim, stretch, overlap=None): + """ Get scale in x and y as tuple """ + # It is possible to have empty glyphs, so we need to skip those. + if not sym_dim['width'] or not sym_dim['height']: + return (1.0, 1.0) + + target_width = self.font_dim['width'] * self.get_target_width(stretch) + if overlap: + target_width += self.font_dim['width'] * overlap + scale_ratio_x = target_width / sym_dim['width'] + + # font_dim['height'] represents total line height, keep our symbols sized based upon font's em + # Use the font_dim['height'] only for explicit 'y' scaling (not 'pa') + target_height = self.font_dim['height'] if '^' in stretch else self.font_dim['iconheight'] + target_height *= 1.0 - self.font_dim['ypadding'] + if overlap: + target_height *= 1.0 + min(0.01, overlap) # never aggressive vertical overlap + scale_ratio_y = target_height / sym_dim['height'] + + if 'pa' in stretch: + # We want to preserve x/y aspect ratio, so find biggest scale factor that allows symbol to fit + scale_ratio_x = min(scale_ratio_x, scale_ratio_y) + if not self.args.single and not '!' in stretch and not overlap: + # non monospaced fonts just scale down on 'pa', not up + scale_ratio_x = min(scale_ratio_x, 1.0) + scale_ratio_y = scale_ratio_x + else: + # Keep the not-stretched direction + if not 'x' in stretch: + scale_ratio_x = 1.0 + if not 'y' in stretch: + scale_ratio_y = 1.0 + + return (scale_ratio_x, scale_ratio_y) + + + def copy_glyphs(self, sourceFontStart, symbolFont, symbolFontStart, symbolFontEnd, exactEncoding, scaleRules, setName, attributes): + """ Copies symbol glyphs into self.sourceFont """ + progressText = '' + careful = False + sourceFontCounter = 0 + + if self.args.careful: + careful = True + + # Create glyphs from symbol font + # + # If we are going to copy all Glyphs, then assume we want to be careful + # and only copy those that are not already contained in the source font + if symbolFontStart == 0: + symbolFont.selection.all() + careful = True + else: + symbolFont.selection.select((str("ranges"), str("unicode")), symbolFontStart, symbolFontEnd) + + # Get number of selected non-empty glyphs with codes >=0 (i.e. not -1 == notdef) + symbolFontSelection = [ x for x in symbolFont.selection.byGlyphs if x.unicode >= 0 ] + glyphSetLength = len(symbolFontSelection) + + if not self.args.quiet: + modify = attributes['default']['params'].get('dont_copy') + sys.stdout.write("{} {} Glyphs from {} Set\n".format( + "Adding" if not modify else "Rescaling", glyphSetLength, setName)) + + currentSourceFontGlyph = -1 # initialize for the exactEncoding case + width_warning = False + + for index, sym_glyph in enumerate(symbolFontSelection): + sym_attr = attributes.get(sym_glyph.unicode) + if sym_attr is None: + sym_attr = attributes['default'] + + if self.font_extrawide: + # Do not allow 'xy2' scaling + sym_attr['stretch'] = sym_attr['stretch'].replace('2', '') + + if exactEncoding: + # Use the exact same hex values for the source font as for the symbol font. + # Problem is we do not know the codepoint of the sym_glyph and because it + # came from a selection.byGlyphs there might be skipped over glyphs. + # The iteration is still in the order of the selection by codepoint, + # so we take the next allowed codepoint of the current glyph + possible_codes = [ ] + if sym_glyph.unicode > currentSourceFontGlyph: + possible_codes += [ sym_glyph.unicode ] + if sym_glyph.altuni: + possible_codes += [ v for v, s, r in sym_glyph.altuni if v > currentSourceFontGlyph ] + if len(possible_codes) == 0: + logger.warning("Can not determine codepoint of %X. Skipping...", sym_glyph.unicode) + continue + currentSourceFontGlyph = min(possible_codes) + else: + # use source font defined hex values based on passed in start (fills gaps; symbols are packed) + currentSourceFontGlyph = sourceFontStart + sourceFontCounter + sourceFontCounter += 1 + + # For debugging process only limited glyphs + # if currentSourceFontGlyph != 0xe7bd: + # continue + + ypadding = sym_attr['params'].get('ypadding') + self.font_dim['ypadding'] = ypadding or 0.0 + + if not self.args.quiet: + if self.args.progressbars: + update_progress(round(float(index + 1) / glyphSetLength, 2)) + else: + progressText = "\nUpdating glyph: {} {} putting at: {:X}".format(sym_glyph, sym_glyph.glyphname, currentSourceFontGlyph) + sys.stdout.write(progressText) + sys.stdout.flush() + + # check if a glyph already exists in this location + do_careful = sym_attr['params'].get('careful', careful) # params take precedence + if do_careful or currentSourceFontGlyph in self.essential: + if currentSourceFontGlyph in self.sourceFont: + careful_type = 'essential' if currentSourceFontGlyph in self.essential else 'existing' + logger.debug("Found %s Glyph at %X. Skipping...", careful_type, currentSourceFontGlyph) + # We don't want to touch anything so move to next Glyph + continue + else: + # If we overwrite an existing glyph all subtable entries regarding it will be wrong + # (Probably; at least if we add a symbol and do not substitute a ligature or such) + if currentSourceFontGlyph in self.sourceFont: + self.sourceFont[currentSourceFontGlyph].removePosSub("*") + + stretch = sym_attr['stretch'] + dont_copy = sym_attr['params'].get('dont_copy') + + if dont_copy: + # Just prepare scaling of existing glyphs + glyph_scale_data = self.get_glyph_scale(sym_glyph.encoding, scaleRules, stretch, self.sourceFont, currentSourceFontGlyph) if scaleRules is not None else None + else: + # Break apart multiple unicodes linking to one glyph + if currentSourceFontGlyph in self.sourceFont: + altuni = self.sourceFont[currentSourceFontGlyph].altuni + if altuni: + codes = { v for v, s, r in altuni if v >= 0 } + codes.add(self.sourceFont[currentSourceFontGlyph].unicode) + codes.remove(currentSourceFontGlyph) + codes = [ "{:04X}".format(c) for c in sorted(list(codes)) ] + logger.debug("Removing alternate unicode on %X (%s)", currentSourceFontGlyph, ' '.join(codes)); + self.sourceFont[currentSourceFontGlyph].altuni = None + self.sourceFont.encoding = 'UnicodeFull' # Rebuild encoding table (needed after altuni changes) + + # This will destroy any content currently in currentSourceFontGlyph, so do it first + glyph_scale_data = self.get_glyph_scale(sym_glyph.encoding, scaleRules, stretch, symbolFont, currentSourceFontGlyph) if scaleRules is not None else None + + # Select and copy symbol from its encoding point + # We need to do this select after the careful check, this way we don't + # reset our selection before starting the next loop + symbolFont.selection.select(sym_glyph.encoding) + symbolFont.copy() + + # Paste it + self.sourceFont.selection.select(currentSourceFontGlyph) + self.sourceFont.paste() + self.sourceFont[currentSourceFontGlyph].glyphname = \ + self.glyphnames.get(currentSourceFontGlyph, sym_glyph.glyphname) if setName != 'Custom' else sym_glyph.glyphname + self.sourceFont[currentSourceFontGlyph].manualHints = True # No autohints for symbols + + # Prepare symbol glyph dimensions + sym_dim = get_glyph_dimensions(self.sourceFont[currentSourceFontGlyph]) + overlap = sym_attr['params'].get('overlap') + if overlap and ypadding: + logger.critical("Conflicting params: overlap and ypadding") + sys.exit(1) + + if glyph_scale_data is not None: + if glyph_scale_data[1] is not None: + sym_dim = glyph_scale_data[1] # Use combined bounding box + (scale_ratio_x, scale_ratio_y) = self.get_scale_factors(sym_dim, stretch, overlap) + else: + # This is roughly alike get_scale_factors(glyph_scale_data[1], 'pa') + # Except we do not have glyph_scale_data[1] always... + (scale_ratio_x, scale_ratio_y) = (glyph_scale_data[0], glyph_scale_data[0]) + if overlap: + scale_ratio_x *= 1.0 + (self.font_dim['width'] / (sym_dim['width'] * scale_ratio_x)) * overlap + y_overlap = min(0.01, overlap) # never aggressive vertical overlap + scale_ratio_y *= 1.0 + (self.font_dim['height'] / (sym_dim['height'] * scale_ratio_y)) * y_overlap + else: + (scale_ratio_x, scale_ratio_y) = self.get_scale_factors(sym_dim, stretch, overlap) + + + # Size in x to size in y ratio limit (to prevent over-wide glyphs) + xy_ratio_max = sym_attr['params'].get('xy-ratio') + if (xy_ratio_max): + xy_ratio = sym_dim['width'] * scale_ratio_x / (sym_dim['height'] * scale_ratio_y) + if xy_ratio > xy_ratio_max: + scale_ratio_x = scale_ratio_x * xy_ratio_max / xy_ratio + + if scale_ratio_x != 1.0 or scale_ratio_y != 1.0: + scale_ratio_x *= self.sourceFont.em / (self.sourceFont.em + 1) # scale a tiny bit too small to avoid rounding problems + self.sourceFont[currentSourceFontGlyph].transform(psMat.scale(scale_ratio_x, scale_ratio_y)) + + # Drop nonintegral part of nodes' coordinates; ttf will do it anyhow, otf will be much smaller + self.sourceFont[currentSourceFontGlyph].round() + + if self.args.single: + # Check and correct the scaling after rounding (if all 3 tries fail we will get a warning later on) + destmaxsize = self.font_dim['width'] * max(1, 1 + (overlap or 0)) + for increaser in range(3): + (xmin, _, xmax, _) = self.sourceFont[currentSourceFontGlyph].boundingBox() + sizeerror = (xmax - xmin) - destmaxsize + if sizeerror <= 0: + break + # Start from scratch with a new unscaled glyph + scale_ratio_x /= 1 + ((sizeerror + increaser) / destmaxsize) + self.sourceFont.paste() + self.sourceFont[currentSourceFontGlyph].transform(psMat.scale(scale_ratio_x, scale_ratio_y)) + self.sourceFont[currentSourceFontGlyph].round() + + # We pasted and scaled now we want to align/move + # Use the dimensions from the newly pasted and stretched glyph to avoid any rounding errors + sym_dim = get_glyph_dimensions(self.sourceFont[currentSourceFontGlyph]) + # Use combined bounding box? + if glyph_scale_data is not None and glyph_scale_data[1] is not None: + scaleglyph_dim = scale_bounding_box(glyph_scale_data[1], scale_ratio_x, scale_ratio_y) + if scaleglyph_dim['advance'] is None: + # On monospaced symbol collections use their advance with, otherwise align horizontally individually + scaleglyph_dim['xmin'] = sym_dim['xmin'] + scaleglyph_dim['xmax'] = sym_dim['xmax'] + scaleglyph_dim['width'] = sym_dim['width'] + sym_dim = scaleglyph_dim + + y_align_distance = 0 + if sym_attr['valign'] == 'c': + # Center the symbol vertically by matching the center of the line height and center of symbol + sym_ycenter = sym_dim['ymax'] - (sym_dim['height'] / 2) + font_ycenter = self.font_dim['ymax'] - (self.font_dim['height'] / 2) + y_align_distance = font_ycenter - sym_ycenter + + # Handle glyph l/r/c alignment + x_align_distance = 0 + simple_nonmono = self.args.nonmono and sym_dim['advance'] is None + if simple_nonmono: + # Remove left side bearing + # (i.e. do not remove left side bearing when combined BB is in use) + x_align_distance = -self.sourceFont[currentSourceFontGlyph].left_side_bearing + elif sym_attr['align']: + # First find the baseline x-alignment (left alignment amount) + x_align_distance = self.font_dim['xmin'] - sym_dim['xmin'] + if self.args.nonmono and 'pa' in stretch: + cell_width = sym_dim['advance'] or sym_dim['width'] + else: + cell_width = self.font_dim['width'] + if sym_attr['align'] == 'c': + # Center align + x_align_distance += (cell_width / 2) - (sym_dim['width'] / 2) + elif sym_attr['align'] == 'r': + # Right align + # (not really supported with pa scaling and 2x stretch in NFP) + x_align_distance += cell_width * self.get_target_width(stretch) - sym_dim['width'] + if not overlap: + # If symbol glyph is wider than target font cell, just left-align + x_align_distance = max(self.font_dim['xmin'] - sym_dim['xmin'], x_align_distance) + + if overlap: + overlap_width = self.font_dim['width'] * overlap + if sym_attr['align'] == 'l': + x_align_distance -= overlap_width + elif sym_attr['align'] == 'c': + # center aligned keeps being center aligned even with overlap + if overlap_width < 0 and simple_nonmono: # Keep positive bearing due to negative overlap (propo) + x_align_distance -= overlap_width / 2 + elif sym_attr['align'] == 'r' and not simple_nonmono: + # Check and correct overlap; it can go wrong if we have a xy-ratio limit + target_xmax = (self.font_dim['xmin'] + self.font_dim['width']) * self.get_target_width(stretch) + target_xmax += overlap_width + glyph_xmax = sym_dim['xmax'] + x_align_distance + correction = target_xmax - glyph_xmax + x_align_distance += correction + + align_matrix = psMat.translate(x_align_distance, y_align_distance) + self.sourceFont[currentSourceFontGlyph].transform(align_matrix) + + # Ensure after horizontal adjustments and centering that the glyph + # does not overlap the bearings (edges) + if not overlap: + self.remove_glyph_neg_bearings(self.sourceFont[currentSourceFontGlyph]) + + # Needed for setting 'advance width' on each glyph so they do not overlap, + # also ensures the font is considered monospaced on Windows by setting the + # same width for all character glyphs. This needs to be done for all glyphs, + # even the ones that are empty and didn't go through the scaling operations. + # It should come after setting the glyph bearings + if not self.args.nonmono: + self.set_glyph_width_mono(self.sourceFont[currentSourceFontGlyph]) + else: + # Target font with variable advance width get the icons with their native widths + # and keeping possible (right and/or negative) bearings in effect + if sym_dim['advance'] is not None: + # 'Width' from monospaced scale group + width = sym_dim['advance'] + else: + width = sym_dim['width'] + # If we have overlap we need to subtract that to keep/get negative bearings + if overlap: + width -= overlap_width + # Fontforge handles the width change like this: + # - Keep existing left_side_bearing + # - Set width + # - Calculate and set new right_side_bearing + self.sourceFont[currentSourceFontGlyph].width = int(width) + + # Check if the inserted glyph is scaled correctly for monospace + if self.args.single: + (xmin, _, xmax, _) = self.sourceFont[currentSourceFontGlyph].boundingBox() + if (xmax - xmin) > self.font_dim['width'] * max(1, 1 + (overlap or 0)): + logger.warning("Scaled glyph %X wider than one monospace width (%d / %d (overlap %s))", + currentSourceFontGlyph, int(xmax - xmin), self.font_dim['width'], repr(overlap)) + + # end for + + if not self.args.quiet: + sys.stdout.write("\n") + + + def set_sourcefont_glyph_widths(self): + """ Makes self.sourceFont monospace compliant """ + + for glyph in self.sourceFont.glyphs(): + if (glyph.width == self.font_dim['width']): + # Don't touch the (negative) bearings if the width is ok + # Ligatures will have these. + continue + + if (glyph.width != 0): + # If the width is zero this glyph is intended to be printed on top of another one. + # In this case we need to keep the negative bearings to shift it 'left'. + # Things like Ä have these: composed of U+0041 'A' and U+0308 'double dot above' + # + # If width is not zero, correct the bearings such that they are within the width: + self.remove_glyph_neg_bearings(glyph) + + self.set_glyph_width_mono(glyph) + + + def remove_glyph_neg_bearings(self, glyph): + """ Sets passed glyph's bearings 0 if they are negative. """ + try: + if glyph.left_side_bearing < 0: + glyph.left_side_bearing = 0 + if glyph.right_side_bearing < 0: + glyph.right_side_bearing = 0 + except: + pass + + + def set_glyph_width_mono(self, glyph): + """ Sets passed glyph.width to self.font_dim.width. + + self.font_dim.width is set with self.get_sourcefont_dimensions(). + """ + try: + # Fontforge handles the width change like this: + # - Keep existing left_side_bearing + # - Set width + # - Calculate and set new right_side_bearing + glyph.width = self.font_dim['width'] + except: + pass + + def prepareScaleRules(self, scaleRules, stretch, symbolFont, destGlyph): + """ Prepare raw ScaleRules data for use """ + # The scaleRules is/will be a dict with these (possible) entries: + # 'ScaleGroups': List of ((lists of glyph codes) or (ranges of glyph codes)) that shall be scaled + # 'scales': List of associated scale factors, one for each entry in 'ScaleGroups' (generated by this function) + # 'bbdims': List of associated sym_dim dicts, one for each entry in 'ScaleGroups' (generated by this function) + # Each dim_dict describes the combined bounding box of all glyphs in one ScaleGroups group + # Example: + # { 'ScaleGroups': [ range(1, 3), [ 7, 10 ], ], + # 'scales': [ 1.23, 1.33, ], + # 'bbdims': [ dim_dict1, dim_dict2, ] } + # + # Each item in 'ScaleGroups' (a range or an explicit list) forms a group of glyphs that shall be + # as rescaled all with the same and maximum possible (for the included glyphs) 'pa' factor. + # If the 'bbdims' is present they all shall be shifted in the same way. + # + # Previously this structure has been used: + # 'ScaleGlyph' Lead glyph, which scaling factor is taken + # 'GlyphsToScale': List of ((glyph code) or (tuple of two glyph codes that form a closed range)) that shall be scaled + # Note that this allows only one group for the whle symbol font, and that the scaling factor is defined by + # a specific character, which needs to be manually selected (on each symbol font update). + # Previous entries are automatically rewritten to the new style. + # + # Note that scaleRules is overwritten with the added data. + if 'scales' in scaleRules: + # Already prepared... must not happen, ignore call + return + + scaleRules['scales'] = [] + scaleRules['bbdims'] = [] + if 'ScaleGroups' not in scaleRules: + scaleRules['ScaleGroups'] = [] + + mode = scaleRules['ShiftMode'] # Mode is only documentary + for group in scaleRules['ScaleGroups']: + sym_dim = get_multiglyph_boundingBox([ symbolFont[g] if g in symbolFont else None for g in group ], destGlyph) + scale = self.get_scale_factors(sym_dim, stretch)[0] + scaleRules['scales'].append(scale) + scaleRules['bbdims'].append(sym_dim) + if (mode): + if ('x' in mode) != (sym_dim['advance'] is not None): + d = '0x{:X} - 0x{:X}'.format(group[0], group[-1]) + if ('x' in mode) : + logger.critical("Scaling in group %s is expected to do horizontal shifts but can not", d) + else: + logger.critical("Scaling in group %s is expected to not do horizontal shifts but will", d) + sys.exit(1) + + if 'ScaleGlyph' in scaleRules: + # Rewrite to equivalent ScaleGroup + group_list = [] + if 'GlyphsToScale+' in scaleRules: + key = 'GlyphsToScale+' + plus = True + else: + key = 'GlyphsToScale' + plus = False + for i in scaleRules[key]: + if isinstance(i, tuple): + group_list.append(range(i[0], i[1] + 1)) + else: + group_list.append(i) + sym_dim = get_glyph_dimensions(symbolFont[scaleRules['ScaleGlyph']]) + scale = self.get_scale_factors(sym_dim, stretch)[0] + scaleRules['ScaleGroups'].append(group_list) + scaleRules['scales'].append(scale) + if plus: + scaleRules['bbdims'].append(sym_dim) + else: + scaleRules['bbdims'].append(None) # The 'old' style keeps just the scale, not the positioning + + def get_glyph_scale(self, symbol_unicode, scaleRules, stretch, symbolFont, dest_unicode): + """ Determines whether or not to use scaled glyphs for glyph in passed symbol_unicode """ + # Potentially destroys the contents of self.sourceFont[dest_unicode] + if not 'scales' in scaleRules: + if not dest_unicode in self.sourceFont: + self.sourceFont.createChar(dest_unicode) + self.prepareScaleRules(scaleRules, stretch, symbolFont, self.sourceFont[dest_unicode]) + for glyph_list, scale, box in zip(scaleRules['ScaleGroups'], scaleRules['scales'], scaleRules['bbdims']): + for e in glyph_list: + if isinstance(e, range): + if symbol_unicode in e: + return (scale, box) + elif symbol_unicode == e: + return (scale, box) + return None + + +def half_gap(gap, top): + """ Divides integer value into two new integers """ + # Line gap add extra space on the bottom of the line which + # doesn't allow the powerline glyphs to fill the entire line. + # Put half of the gap into the 'cell', each top and bottom + if gap <= 0: + return 0 + gap_top = int(gap / 2) + gap_bottom = gap - gap_top + if top: + logger.info("Redistributing line gap of %d (%d top and %d bottom)", gap, gap_top, gap_bottom) + return gap_top + return gap_bottom + +def replace_font_name(font_name, replacement_dict): + """ Replaces all keys with vals from replacement_dict in font_name. """ + for key, val in replacement_dict.items(): + font_name = font_name.replace(key, val) + return font_name + + +def make_sure_path_exists(path): + """ Verifies path passed to it exists. """ + try: + os.makedirs(path) + except OSError as exception: + if exception.errno != errno.EEXIST: + raise + +def sanitize_filename(filename, allow_dirs = False): + """ Enforces to not use forbidden characters in a filename/path. """ + if filename == '.' and not allow_dirs: + return '_' + restore_colon = sys.platform == 'win32' and re.match('[a-z]:', filename, re.I) + trans = filename.maketrans('<>:"|?*', '_______') + for i in range(0x00, 0x20): + trans[i] = ord('_') + if not allow_dirs: + trans[ord('/')] = ord('_') + trans[ord('\\')] = ord('_') + else: + trans[ord('\\')] = ord('/') # We use Posix paths + new_filename = filename.translate(trans) + if restore_colon: + new_filename = new_filename[ :1] + ':' + new_filename[2: ] + return new_filename + +def get_multiglyph_boundingBox(glyphs, destGlyph = None): + """ Returns dict of the dimensions of multiple glyphs combined(, as if they are copied into destGlyph) """ + # If destGlyph is given the glyph(s) are first copied over into that + # glyph and measured in that font (to avoid rounding errors) + # Leaves the destGlyph in unknown state! + bbox = [ None, None, None, None, None ] + for glyph in glyphs: + if glyph is None: + # Glyph has been in defining range but is not in the actual font + continue + if destGlyph and glyph.font != destGlyph.font: + glyph.font.selection.select(glyph) + glyph.font.copy() + destGlyph.font.selection.select(destGlyph) + destGlyph.font.paste() + glyph = destGlyph + gbb = glyph.boundingBox() + gadvance = glyph.width + if len(glyphs) > 1 and gbb[0] == gbb[2] and gbb[1] == gbb[3]: + # Ignore empty glyphs if we examine more than one glyph + continue + bbox[0] = gbb[0] if bbox[0] is None or bbox[0] > gbb[0] else bbox[0] + bbox[1] = gbb[1] if bbox[1] is None or bbox[1] > gbb[1] else bbox[1] + bbox[2] = gbb[2] if bbox[2] is None or bbox[2] < gbb[2] else bbox[2] + bbox[3] = gbb[3] if bbox[3] is None or bbox[3] < gbb[3] else bbox[3] + if not bbox[4]: + bbox[4] = -gadvance # Negative for one/first glyph + else: + if abs(bbox[4]) != gadvance: + bbox[4] = -1 # Marker for not-monospaced + else: + bbox[4] = gadvance # Positive for 2 or more glyphs + if bbox[4] and bbox[4] < 0: + # Not monospaced when only one glyph is used or multiple glyphs with different advance widths + bbox[4] = None + return { + 'xmin' : bbox[0], + 'ymin' : bbox[1], + 'xmax' : bbox[2], + 'ymax' : bbox[3], + 'width' : bbox[2] + (-bbox[0]), + 'height' : bbox[3] + (-bbox[1]), + 'advance': bbox[4], # advance width if monospaced + } + +def get_glyph_dimensions(glyph): + """ Returns dict of the dimensions of the glyph passed to it. """ + return get_multiglyph_boundingBox([ glyph ]) + +def scale_bounding_box(bbox, scale_x, scale_y): + """ Return a scaled version of a glyph dimensions dict """ + # Simulate scaling on combined bounding box, round values for better simulation + new_dim = { + 'xmin' : int(bbox['xmin'] * scale_x), + 'ymin' : int(bbox['ymin'] * scale_y), + 'xmax' : int(bbox['xmax'] * scale_x), + 'ymax' : int(bbox['ymax'] * scale_y), + 'advance': int(bbox['advance'] * scale_x) if bbox['advance'] is not None else None, + } + new_dim['width'] = new_dim['xmax'] + (-new_dim['xmin']) + new_dim['height'] = new_dim['ymax'] + (-new_dim['ymin']) + return new_dim + +def update_progress(progress): + """ Updates progress bar length. + + Accepts a float between 0.0 and 1.0. Any int will be converted to a float. + A value at 1 or bigger represents 100% + modified from: https://stackoverflow.com/questions/3160699/python-progress-bar + """ + barLength = 40 # Modify this to change the length of the progress bar + if isinstance(progress, int): + progress = float(progress) + if progress >= 1: + progress = 1 + status = "Done...\r\n" # NOTE: status initialized and never used + block = int(round(barLength * progress)) + text = "\r╢{0}╟ {1}%".format("█" * block + "░" * (barLength - block), int(progress * 100)) + sys.stdout.write(text) + sys.stdout.flush() + + +def check_fontforge_min_version(): + """ Verifies installed FontForge version meets minimum requirement. """ + minimumVersion = 20141231 + actualVersion = int(fontforge.version()) + + # un-comment following line for testing invalid version error handling + # actualVersion = 20120731 + + # versions tested: 20150612, 20150824 + if actualVersion < minimumVersion: + logger.critical("You seem to be using an unsupported (old) version of fontforge: %d", actualVersion) + logger.critical("Please use at least version: %d", minimumVersion) + sys.exit(1) + +def check_version_with_git(version): + """ Upgraded the version to the current git tag version (starting with 'v') """ + git = subprocess.run("git describe --tags", + cwd=os.path.dirname(__file__), + shell=True, + stdout=subprocess.PIPE, stderr=subprocess.DEVNULL + ).stdout.decode('utf-8') + if len(git) == 0: + return False + tag = git.strip() + if len(tag) == 0 or not tag.startswith('v'): + return False + tag = tag[1:] + r = re.search('(.*?)(-[0-9]+)-g[0-9a-fA-F]+$', tag) + if r: + tag = r.group(1) + patchlevel = r.group(2) + else: + patchlevel = "" + # Inspired by Phaxmohdem's versiontuple https://stackoverflow.com/a/28568003 + + versiontuple = lambda v: tuple( p.zfill(8) for p in v.split(".") ) + if versiontuple(tag) > versiontuple(version): + return tag + patchlevel + if versiontuple(tag) == versiontuple(version) and len(patchlevel) > 0: + return tag + patchlevel + return False + +def setup_arguments(): + """ Parse the command line parameters and load the config file if needed """ + parser = argparse.ArgumentParser( + description=( + 'Nerd Fonts Font Patcher: patches a given font with programming and development related glyphs\n\n' + '* Website: https://www.nerdfonts.com\n' + '* Version: ' + version + '\n' + '* Development Website: https://github.com/ryanoasis/nerd-fonts\n' + '* Changelog: https://github.com/ryanoasis/nerd-fonts/blob/-/changelog.md'), + formatter_class=RawTextHelpFormatter, + add_help=False, + ) + + parser.add_argument('font', help='The path to the font to patch (e.g., Inconsolata.otf)') + # optional arguments + parser.add_argument('--careful', dest='careful', default=False, action='store_true', help='Do not overwrite existing glyphs if detected') + parser.add_argument('--debug', dest='debugmode', default=0, type=int, nargs='?', help='Verbose mode (optional: 1=just to file; 2*=just to terminal; 3=display and file)', const=2, choices=range(0, 3 + 1)) + parser.add_argument('--extension', '-ext', dest='extension', default="", type=str, help='Change font file type to create (e.g., ttf, otf)') + parser.add_argument('--help', '-h', action='help', default=argparse.SUPPRESS, help='Show this help message and exit') + parser.add_argument('--makegroups', dest='makegroups', default=1, type=int, nargs='?', help='Use alternative method to name patched fonts (default=1)', const=1, choices=range(-1, 6 + 1)) + parser.add_argument('--mono', '-s', dest='forcemono', default=False, action='count', help='Create monospaced font, existing and added glyphs are single-width (implies --single-width-glyphs)') + parser.add_argument('--outputdir', '-out', dest='outputdir', default=".", type=str, help='The directory to output the patched font file to') + parser.add_argument('--quiet', '-q', dest='quiet', default=False, action='store_true', help='Do not generate verbose output') + parser.add_argument('--single-width-glyphs', dest='single', default=False, action='store_true', help='Whether to generate the glyphs as single-width not double-width (default is double-width) (Nerd Font Mono)') + parser.add_argument('--use-single-width-glyphs', dest='forcemono', default=False, action='count', help=argparse.SUPPRESS) + parser.add_argument('--variable-width-glyphs', dest='nonmono', default=False, action='store_true', help='Do not adjust advance width (no "overhang") (Nerd Font Propo)') + parser.add_argument('--version', '-v', action='version', version=projectName + ': %(prog)s (' + version + ')', help='Show program\'s version number and exit') + # --makegroup has an additional undocumented numeric specifier. '--makegroup' is in fact '--makegroup 1'. + # Original font name: Hugo Sans Mono ExtraCondensed Light Italic + # NF Fam agg. + # -1 no renaming at all (keep old names and versions etc) --- --- --- + # 0 turned off, use old naming scheme [-] [-] [-] + # 1 HugoSansMono Nerd Font ExtraCondensed Light Italic [ ] [ ] [ ] + # 2 HugoSansMono Nerd Font ExtCn Light Italic [ ] [X] [ ] + # 3 HugoSansMono Nerd Font XCn Lt It [ ] [X] [X] + # 4 HugoSansMono NF ExtraCondensed Light Italic [X] [ ] [ ] + # 5 HugoSansMono NF ExtCn Light Italic [X] [X] [ ] + # 6 HugoSansMono NF XCn Lt It [X] [X] [X] + + sym_font_group = parser.add_argument_group('Symbol Fonts') + sym_font_group.add_argument('--complete', '-c', dest='complete', default=False, action='store_true', help='Add all available Glyphs') + sym_font_group.add_argument('--codicons', dest='codicons', default=False, action='store_true', help='Add Codicons Glyphs (https://github.com/microsoft/vscode-codicons)') + sym_font_group.add_argument('--fontawesome', dest='fontawesome', default=False, action='store_true', help='Add Font Awesome Glyphs (http://fontawesome.io/)') + sym_font_group.add_argument('--fontawesomeext', dest='fontawesomeextension', default=False, action='store_true', help='Add Font Awesome Extension Glyphs (https://andrelzgava.github.io/font-awesome-extension/)') + sym_font_group.add_argument('--fontlogos', dest='fontlogos', default=False, action='store_true', help='Add Font Logos Glyphs (https://github.com/Lukas-W/font-logos)') + sym_font_group.add_argument('--material', '--mdi', dest='material', default=False, action='store_true', help='Add Material Design Icons (https://github.com/templarian/MaterialDesign)') + sym_font_group.add_argument('--octicons', dest='octicons', default=False, action='store_true', help='Add Octicons Glyphs (https://octicons.github.com)') + sym_font_group.add_argument('--pomicons', dest='pomicons', default=False, action='store_true', help='Add Pomicon Glyphs (https://github.com/gabrielelana/pomicons)') + sym_font_group.add_argument('--powerline', dest='powerline', default=False, action='store_true', help='Add Powerline Glyphs') + sym_font_group.add_argument('--powerlineextra', dest='powerlineextra', default=False, action='store_true', help='Add Powerline Extra Glyphs (https://github.com/ryanoasis/powerline-extra-symbols)') + sym_font_group.add_argument('--powersymbols', dest='powersymbols', default=False, action='store_true', help='Add IEC Power Symbols (https://unicodepowersymbol.com/)') + sym_font_group.add_argument('--weather', dest='weather', default=False, action='store_true', help='Add Weather Icons (https://github.com/erikflowers/weather-icons)') + + expert_group = parser.add_argument_group('Expert Options') + expert_group.add_argument('--adjust-line-height', '-l', dest='adjustLineHeight', default=False, action='store_true', help='Whether to adjust line heights (attempt to center powerline separators more evenly)') + expert_group.add_argument('--boxdrawing', dest='forcebox', default=False, action='store_true', help='Force patching in (over existing) box drawing glyphs') + expert_group.add_argument('--cell', dest='cellopt', default=None, type=str, help='Adjust or query the cell size, e.g. use "0:1000:-200:800" or "?"') + expert_group.add_argument('--configfile', dest='configfile', default=False, type=str, help='Specify a file path for configuration file (see sample: src/config.sample.cfg)') + expert_group.add_argument('--custom', dest='custom', default=False, type=str, help='Specify a custom symbol font, all glyphs will be copied; absolute path suggested') + expert_group.add_argument('--dry', dest='dry_run', default=False, action='store_true', help='Do neither patch nor store the font, to check naming') + expert_group.add_argument('--glyphdir', dest='glyphdir', default=__dir__ + "/src/glyphs/", type=str, help='Path to glyphs to be used for patching') + expert_group.add_argument('--has-no-italic', dest='noitalic', default=False, action='store_true', help='Font family does not have Italic (but Oblique), to help create correct RIBBI set') + expert_group.add_argument('--metrics', dest='metrics', default=None, choices=get_metrics_names(), help='Select vertical metrics source (for problematic cases)') + expert_group.add_argument('--name', dest='force_name', default=None, type=str, help='Specify naming source (\'full\', \'postscript\', \'filename\', or concrete free name-string)') + expert_group.add_argument('--postprocess', dest='postprocess', default=False, type=str, help='Specify a Script for Post Processing') + progressbars_group_parser = expert_group.add_mutually_exclusive_group(required=False) + expert_group.add_argument('--removeligs', '--removeligatures', dest='removeligatures', default=False, action='store_true', help='Removes ligatures specified in configuration file (needs --configfile)') + expert_group.add_argument('--xavgcharwidth', dest='xavgwidth', default=None, type=int, nargs='?', help='Adjust xAvgCharWidth (optional: concrete value)', const=True) + # --xavgcharwidth for compatibility with old applications like notepad and non-latin fonts + # Possible values with examples: + # - copy from sourcefont (default) + # 0 - calculate from font according to OS/2-version-2 + # 500 - set to 500 + + # progress bar arguments - https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse + progressbars_group_parser.add_argument('--progressbars', dest='progressbars', action='store_true', help='Show percentage completion progress bars per Glyph Set (default)') + progressbars_group_parser.add_argument('--no-progressbars', dest='progressbars', action='store_false', help='Don\'t show percentage completion progress bars per Glyph Set') + expert_group.set_defaults(progressbars=True) + + args = parser.parse_args() + setup_global_logger(args) + + # if we have a config file: fetch commandline arguments from there and process again with all arguments + config = configparser.ConfigParser(empty_lines_in_values=False, allow_no_value=True) + if args.configfile: + if not os.path.isfile(args.configfile): + logger.critical("Configfile does not exist: %s", args.configfile) + sys.exit(1) + if not os.access(args.configfile, os.R_OK): + logger.critical("Can not open configfile for reading: %s", args.configfile) + sys.exit(1) + config.read(args.configfile) + extraflags = config.get("Config", "commandline", fallback='') + if len(extraflags): + logger.info("Adding config commandline options: %s", extraflags) + extraflags += ' ' + args.font # Need to re-add the mandatory argument + args = parser.parse_args(extraflags.split(), args) + + if args.makegroups > 0 and not FontnameParserOK: + logger.critical("FontnameParser module missing (bin/scripts/name_parser/Fontname*), specify --makegroups 0") + sys.exit(1) + + # if you add a new font, set it to True here inside the if condition + if args.complete: + args.fontawesome = True + args.fontawesomeextension = True + args.fontlogos = True + args.octicons = True + args.codicons = True + args.powersymbols = True + args.pomicons = True + args.powerline = True + args.powerlineextra = True + args.material = True + args.weather = True + + if not args.complete: + sym_font_args = [] + # add the list of arguments for each symbol font to the list sym_font_args + for action in sym_font_group._group_actions: + sym_font_args.append(action.__dict__['option_strings']) + + # determine whether or not all symbol fonts are to be used + font_complete = True + for sym_font_arg_aliases in sym_font_args: + found = False + for alias in sym_font_arg_aliases: + if alias in sys.argv: + found = True + if not found: + font_complete = False + args.complete = font_complete + + if args.forcemono: + args.single = True + if args.nonmono and args.single: + logger.warning("Specified contradicting --variable-width-glyphs together with --mono or --single-width-glyphs. Ignoring --variable-width-glyphs.") + args.nonmono = False + + if args.cellopt: + if args.cellopt != '?': + try: + parts = [ int(v) for v in args.cellopt.split(':') ] + if len(parts) != 4: + raise + except: + logger.critical("Parameter for --cell is not 4 colon separated integer numbers: '%s'", args.cellopt) + sys.exit(2) + if parts[0] >= parts[1] or parts[2] >= parts[3]: + logger.critical("Parameter for --cell do not result in positive cell size: %d x %d", + parts[1] - parts[0], parts[3] - parts[2]) + sys.exit(2) + if parts[0] != 0: + logger.warn("First parameter for --cell should be zero, this is probably not working") + args.cellopt = parts + + make_sure_path_exists(args.outputdir) + if not os.path.isfile(args.font): + logger.critical("Font file does not exist: %s", args.font) + sys.exit(1) + if not os.access(args.font, os.R_OK): + logger.critical("Can not open font file for reading: %s", args.font) + sys.exit(1) + is_ttc = len(fontforge.fontsInFile(args.font)) > 1 + try: + source_font_test = TableHEADWriter(args.font) + args.is_variable = source_font_test.find_table([b'avar', b'cvar', b'fvar', b'gvarb', b'HVAR', b'MVAR', b'VVAR'], 0) + if args.is_variable: + logger.warning("Source font is a variable open type font (VF), opening might fail...") + except: + args.is_variable = False + finally: + try: + source_font_test.close() + except: + pass + + if args.extension == "": + args.extension = os.path.splitext(args.font)[1] + else: + args.extension = '.' + args.extension + if re.match(r'\.ttc$', args.extension, re.IGNORECASE): + if not is_ttc: + logger.critical("Can not create True Type Collections from single font files") + sys.exit(1) + else: + if is_ttc: + logger.critical("Can not create single font files from True Type Collections") + sys.exit(1) + + # The if might look ridiculous, but isinstance(False, int) is True! + if isinstance(args.xavgwidth, int) and not isinstance(args.xavgwidth, bool): + if args.xavgwidth < 0: + logger.critical("--xavgcharwidth takes no negative numbers") + sys.exit(2) + if args.xavgwidth > 16384: + logger.critical("--xavgcharwidth takes only numbers up to 16384") + sys.exit(2) + + return (args, config) + +def setup_global_logger(args): + """ Set up the logger and take options into account """ + global logger + logger = logging.getLogger(os.path.basename(args.font)) + logger.setLevel(logging.DEBUG) + log_to_file = (args.debugmode & 1 == 1) + if log_to_file: + try: + f_handler = logging.FileHandler('font-patcher-log.txt') + f_handler.setFormatter(logging.Formatter('%(levelname)s: %(name)s %(message)s')) + logger.addHandler(f_handler) + except: + log_to_file = False + logger.debug(allversions) + logger.debug("Options %s", repr(sys.argv[1:])) + c_handler = logging.StreamHandler(stream=sys.stdout) + c_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) + if not (args.debugmode & 2 == 2): + c_handler.setLevel(logging.INFO) + logger.addHandler(c_handler) + if (args.debugmode & 1 == 1) and not log_to_file: + logger.info("Can not write logfile, disabling") + +def main(): + global logger + logger = logging.getLogger("start") # Use start logger until we can set up something sane + s_handler = logging.StreamHandler(stream=sys.stdout) + s_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) + logger.addHandler(s_handler) + + global version + git_version = check_version_with_git(version) + global allversions + allversions = "Patcher v{} ({}) (ff {})".format( + git_version if git_version else version, script_version, fontforge.version()) + print("{} {}".format(projectName, allversions)) + if git_version: + version = git_version + check_fontforge_min_version() + (args, conf) = setup_arguments() + logger.debug("Naming mode %d", args.makegroups) + + patcher = font_patcher(args, conf) + + sourceFonts = [] + all_fonts = fontforge.fontsInFile(args.font) + if not all_fonts: + if re.match(".*\\.woff2?", args.font, re.I): + all_fonts=[ "" ] + else: + logger.critical("Can not find any fonts in '%s'", args.font) + sys.exit(1) + for i, subfont in enumerate(all_fonts): + if len(all_fonts) > 1: + print("\n") + logger.info("Processing %s (%d/%d)", subfont, i + 1, len(all_fonts)) + try: + sourceFonts.append(fontforge.open("{}({})".format(args.font, i), 1)) # 1 = ("fstypepermitted",)) + except Exception: + logger.critical("Can not open font '%s', try to open with fontforge interactively to get more information", + subfont) + sys.exit(1) + + patcher.setup_name_backup(sourceFonts[-1]) + patcher.patch(sourceFonts[-1]) + + print("Done with Patch Sets, generating font...") + for f in sourceFonts: + patcher.setup_font_names(f) + patcher.generate(sourceFonts) + + for f in sourceFonts: + f.close() + + +if __name__ == "__main__": + __dir__ = os.path.dirname(os.path.abspath(__file__)) + main()