Merge branch 'main' into ssh-integration
commit
f242c6b5c4
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
153
build.zig
153
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
|
||||
|
|
|
|||
|
|
@ -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 = .{
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -5,3 +5,5 @@
|
|||
#include <freetype/ftoutln.h>
|
||||
#include <freetype/ftsnames.h>
|
||||
#include <freetype/ttnameid.h>
|
||||
#include <freetype/ftbitmap.h>
|
||||
#include <freetype/ftbbox.h>
|
||||
|
|
|
|||
|
|
@ -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 | Yes<sup>1</sup> | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
|
||||
/// | `.resize_nesw` | Yes | Yes<sup>1</sup> | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
|
||||
/// | `.resize_all` | Yes | Yes | Yes | Yes |
|
||||
/// | `.not_allowed` | Yes | Yes | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
|
||||
///
|
||||
/// 1. This uses a private system API and may fail in the future.
|
||||
/// 2. This uses a newer standard that not all cursor themes support.
|
||||
///
|
||||
/// If the requested shape is not available, this function emits a CursorUnavailable error
|
||||
/// Possible errors include glfw.ErrorCode.PlatformError and glfw.ErrorCode.CursorUnavailable.
|
||||
/// null is returned in the event of an error.
|
||||
///
|
||||
/// thread_safety: This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: cursor_object, glfwCreateCursor
|
||||
pub inline fn createStandard(shape: Shape) ?Cursor {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwCreateStandardCursor(@as(c_int, @intCast(@intFromEnum(shape))))) |cursor| return Cursor{ .ptr = cursor };
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Destroys a cursor.
|
||||
///
|
||||
/// This function destroys a cursor previously created with glfw.Cursor.create. Any remaining
|
||||
/// cursors will be destroyed by glfw.terminate.
|
||||
///
|
||||
/// If the specified cursor is current for any window, that window will be reverted to the default
|
||||
/// cursor. This does not affect the cursor mode.
|
||||
///
|
||||
/// Possible errors include glfw.ErrorCode.PlatformError.
|
||||
///
|
||||
/// @reentrancy This function must not be called from a callback.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: cursor_object, glfw.createCursor
|
||||
pub inline fn destroy(self: Cursor) void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwDestroyCursor(self.ptr);
|
||||
}
|
||||
|
||||
test "create" {
|
||||
const allocator = testing.allocator;
|
||||
|
||||
const glfw = @import("main.zig");
|
||||
defer glfw.clearError(); // clear any error we generate
|
||||
if (!glfw.init(.{})) {
|
||||
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
|
||||
std.process.exit(1);
|
||||
}
|
||||
defer glfw.terminate();
|
||||
|
||||
const image = try Image.init(allocator, 32, 32, 32 * 32 * 4);
|
||||
defer image.deinit(allocator);
|
||||
|
||||
const cursor = glfw.Cursor.create(image, 0, 0);
|
||||
if (cursor) |cur| cur.destroy();
|
||||
}
|
||||
|
||||
test "createStandard" {
|
||||
const glfw = @import("main.zig");
|
||||
defer glfw.clearError(); // clear any error we generate
|
||||
if (!glfw.init(.{})) {
|
||||
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
|
||||
std.process.exit(1);
|
||||
}
|
||||
defer glfw.terminate();
|
||||
|
||||
const cursor = glfw.Cursor.createStandard(.ibeam);
|
||||
if (cursor) |cur| cur.destroy();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
3551
pkg/glfw/Window.zig
3551
pkg/glfw/Window.zig
File diff suppressed because it is too large
Load Diff
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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);
|
||||
|
|
@ -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",
|
||||
};
|
||||
|
|
@ -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" },
|
||||
},
|
||||
}
|
||||
|
|
@ -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");
|
||||
});
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
100
pkg/glfw/hat.zig
100
pkg/glfw/hat.zig
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
266
pkg/glfw/key.zig
266
pkg/glfw/key.zig
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
167
pkg/glfw/mod.zig
167
pkg/glfw/mod.zig
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
extern const struct wl_interface wp_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,
|
||||
};
|
||||
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#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
|
||||
* <pre>
|
||||
*
|
||||
* 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.
|
||||
* </pre>
|
||||
*/
|
||||
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
|
||||
|
|
@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
extern const struct wl_interface zwp_idle_inhibitor_v1_interface;
|
||||
|
||||
static const struct wl_interface *idle_inhibit_unstable_v1_types[] = {
|
||||
&zwp_idle_inhibitor_v1_interface,
|
||||
&wl_surface_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_idle_inhibit_manager_v1_requests[] = {
|
||||
{ "destroy", "", idle_inhibit_unstable_v1_types + 0 },
|
||||
{ "create_inhibitor", "no", idle_inhibit_unstable_v1_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zwp_idle_inhibit_manager_v1_interface = {
|
||||
"zwp_idle_inhibit_manager_v1", 1,
|
||||
2, zwp_idle_inhibit_manager_v1_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_idle_inhibitor_v1_requests[] = {
|
||||
{ "destroy", "", idle_inhibit_unstable_v1_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zwp_idle_inhibitor_v1_interface = {
|
||||
"zwp_idle_inhibitor_v1", 1,
|
||||
1, zwp_idle_inhibitor_v1_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page page_idle_inhibit_unstable_v1 The idle_inhibit_unstable_v1 protocol
|
||||
* @section page_ifaces_idle_inhibit_unstable_v1 Interfaces
|
||||
* - @subpage page_iface_zwp_idle_inhibit_manager_v1 - control behavior when display idles
|
||||
* - @subpage page_iface_zwp_idle_inhibitor_v1 - context object for inhibiting idle behavior
|
||||
* @section page_copyright_idle_inhibit_unstable_v1 Copyright
|
||||
* <pre>
|
||||
*
|
||||
* Copyright © 2015 Samsung Electronics Co., Ltd
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
* </pre>
|
||||
*/
|
||||
struct wl_surface;
|
||||
struct zwp_idle_inhibit_manager_v1;
|
||||
struct zwp_idle_inhibitor_v1;
|
||||
|
||||
#ifndef ZWP_IDLE_INHIBIT_MANAGER_V1_INTERFACE
|
||||
#define ZWP_IDLE_INHIBIT_MANAGER_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_idle_inhibit_manager_v1 zwp_idle_inhibit_manager_v1
|
||||
* @section page_iface_zwp_idle_inhibit_manager_v1_desc Description
|
||||
*
|
||||
* This interface permits inhibiting the idle behavior such as screen
|
||||
* blanking, locking, and screensaving. The client binds the idle manager
|
||||
* globally, then creates idle-inhibitor objects for each surface.
|
||||
*
|
||||
* Warning! The protocol described in this file is experimental and
|
||||
* backward incompatible changes may be made. Backward compatible changes
|
||||
* may be added together with the corresponding interface version bump.
|
||||
* Backward incompatible changes are done by bumping the version number in
|
||||
* the protocol and interface names and resetting the interface version.
|
||||
* Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
* version number in the protocol and interface names are removed and the
|
||||
* interface version number is reset.
|
||||
* @section page_iface_zwp_idle_inhibit_manager_v1_api API
|
||||
* See @ref iface_zwp_idle_inhibit_manager_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_idle_inhibit_manager_v1 The zwp_idle_inhibit_manager_v1 interface
|
||||
*
|
||||
* This interface permits inhibiting the idle behavior such as screen
|
||||
* blanking, locking, and screensaving. The client binds the idle manager
|
||||
* globally, then creates idle-inhibitor objects for each surface.
|
||||
*
|
||||
* Warning! The protocol described in this file is experimental and
|
||||
* backward incompatible changes may be made. Backward compatible changes
|
||||
* may be added together with the corresponding interface version bump.
|
||||
* Backward incompatible changes are done by bumping the version number in
|
||||
* the protocol and interface names and resetting the interface version.
|
||||
* Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
* version number in the protocol and interface names are removed and the
|
||||
* interface version number is reset.
|
||||
*/
|
||||
extern const struct wl_interface zwp_idle_inhibit_manager_v1_interface;
|
||||
#endif
|
||||
#ifndef ZWP_IDLE_INHIBITOR_V1_INTERFACE
|
||||
#define ZWP_IDLE_INHIBITOR_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_idle_inhibitor_v1 zwp_idle_inhibitor_v1
|
||||
* @section page_iface_zwp_idle_inhibitor_v1_desc Description
|
||||
*
|
||||
* An idle inhibitor prevents the output that the associated surface is
|
||||
* visible on from being set to a state where it is not visually usable due
|
||||
* to lack of user interaction (e.g. blanked, dimmed, locked, set to power
|
||||
* save, etc.) Any screensaver processes are also blocked from displaying.
|
||||
*
|
||||
* If the surface is destroyed, unmapped, becomes occluded, loses
|
||||
* visibility, or otherwise becomes not visually relevant for the user, the
|
||||
* idle inhibitor will not be honored by the compositor; if the surface
|
||||
* subsequently regains visibility the inhibitor takes effect once again.
|
||||
* Likewise, the inhibitor isn't honored if the system was already idled at
|
||||
* the time the inhibitor was established, although if the system later
|
||||
* de-idles and re-idles the inhibitor will take effect.
|
||||
* @section page_iface_zwp_idle_inhibitor_v1_api API
|
||||
* See @ref iface_zwp_idle_inhibitor_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_idle_inhibitor_v1 The zwp_idle_inhibitor_v1 interface
|
||||
*
|
||||
* An idle inhibitor prevents the output that the associated surface is
|
||||
* visible on from being set to a state where it is not visually usable due
|
||||
* to lack of user interaction (e.g. blanked, dimmed, locked, set to power
|
||||
* save, etc.) Any screensaver processes are also blocked from displaying.
|
||||
*
|
||||
* If the surface is destroyed, unmapped, becomes occluded, loses
|
||||
* visibility, or otherwise becomes not visually relevant for the user, the
|
||||
* idle inhibitor will not be honored by the compositor; if the surface
|
||||
* subsequently regains visibility the inhibitor takes effect once again.
|
||||
* Likewise, the inhibitor isn't honored if the system was already idled at
|
||||
* the time the inhibitor was established, although if the system later
|
||||
* de-idles and re-idles the inhibitor will take effect.
|
||||
*/
|
||||
extern const struct wl_interface zwp_idle_inhibitor_v1_interface;
|
||||
#endif
|
||||
|
||||
#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY 0
|
||||
#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR 1
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_idle_inhibit_manager_v1
|
||||
*/
|
||||
#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_idle_inhibit_manager_v1
|
||||
*/
|
||||
#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_idle_inhibit_manager_v1 */
|
||||
static inline void
|
||||
zwp_idle_inhibit_manager_v1_set_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_idle_inhibit_manager_v1 */
|
||||
static inline void *
|
||||
zwp_idle_inhibit_manager_v1_get_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_idle_inhibit_manager_v1_get_version(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_idle_inhibit_manager_v1
|
||||
*
|
||||
* Destroy the inhibit manager.
|
||||
*/
|
||||
static inline void
|
||||
zwp_idle_inhibit_manager_v1_destroy(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibit_manager_v1,
|
||||
ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_idle_inhibit_manager_v1
|
||||
*
|
||||
* Create a new inhibitor object associated with the given surface.
|
||||
*/
|
||||
static inline struct zwp_idle_inhibitor_v1 *
|
||||
zwp_idle_inhibit_manager_v1_create_inhibitor(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, struct wl_surface *surface)
|
||||
{
|
||||
struct wl_proxy *id;
|
||||
|
||||
id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibit_manager_v1,
|
||||
ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR, &zwp_idle_inhibitor_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1), 0, NULL, surface);
|
||||
|
||||
return (struct zwp_idle_inhibitor_v1 *) id;
|
||||
}
|
||||
|
||||
#define ZWP_IDLE_INHIBITOR_V1_DESTROY 0
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_idle_inhibitor_v1
|
||||
*/
|
||||
#define ZWP_IDLE_INHIBITOR_V1_DESTROY_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_idle_inhibitor_v1 */
|
||||
static inline void
|
||||
zwp_idle_inhibitor_v1_set_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_idle_inhibitor_v1 */
|
||||
static inline void *
|
||||
zwp_idle_inhibitor_v1_get_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_idle_inhibitor_v1_get_version(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_idle_inhibitor_v1
|
||||
*
|
||||
* Remove the inhibitor effect from the associated wl_surface.
|
||||
*/
|
||||
static inline void
|
||||
zwp_idle_inhibitor_v1_destroy(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_idle_inhibitor_v1,
|
||||
ZWP_IDLE_INHIBITOR_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_pointer_interface;
|
||||
extern const struct wl_interface wl_region_interface;
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
extern const struct wl_interface zwp_confined_pointer_v1_interface;
|
||||
extern const struct wl_interface zwp_locked_pointer_v1_interface;
|
||||
|
||||
static const struct wl_interface *pointer_constraints_unstable_v1_types[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
&zwp_locked_pointer_v1_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_pointer_interface,
|
||||
&wl_region_interface,
|
||||
NULL,
|
||||
&zwp_confined_pointer_v1_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_pointer_interface,
|
||||
&wl_region_interface,
|
||||
NULL,
|
||||
&wl_region_interface,
|
||||
&wl_region_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_pointer_constraints_v1_requests[] = {
|
||||
{ "destroy", "", pointer_constraints_unstable_v1_types + 0 },
|
||||
{ "lock_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 2 },
|
||||
{ "confine_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 7 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zwp_pointer_constraints_v1_interface = {
|
||||
"zwp_pointer_constraints_v1", 1,
|
||||
3, zwp_pointer_constraints_v1_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_locked_pointer_v1_requests[] = {
|
||||
{ "destroy", "", pointer_constraints_unstable_v1_types + 0 },
|
||||
{ "set_cursor_position_hint", "ff", pointer_constraints_unstable_v1_types + 0 },
|
||||
{ "set_region", "?o", pointer_constraints_unstable_v1_types + 12 },
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_locked_pointer_v1_events[] = {
|
||||
{ "locked", "", pointer_constraints_unstable_v1_types + 0 },
|
||||
{ "unlocked", "", pointer_constraints_unstable_v1_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zwp_locked_pointer_v1_interface = {
|
||||
"zwp_locked_pointer_v1", 1,
|
||||
3, zwp_locked_pointer_v1_requests,
|
||||
2, zwp_locked_pointer_v1_events,
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_confined_pointer_v1_requests[] = {
|
||||
{ "destroy", "", pointer_constraints_unstable_v1_types + 0 },
|
||||
{ "set_region", "?o", pointer_constraints_unstable_v1_types + 13 },
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_confined_pointer_v1_events[] = {
|
||||
{ "confined", "", pointer_constraints_unstable_v1_types + 0 },
|
||||
{ "unconfined", "", pointer_constraints_unstable_v1_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zwp_confined_pointer_v1_interface = {
|
||||
"zwp_confined_pointer_v1", 1,
|
||||
2, zwp_confined_pointer_v1_requests,
|
||||
2, zwp_confined_pointer_v1_events,
|
||||
};
|
||||
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page page_pointer_constraints_unstable_v1 The pointer_constraints_unstable_v1 protocol
|
||||
* protocol for constraining pointer motions
|
||||
*
|
||||
* @section page_desc_pointer_constraints_unstable_v1 Description
|
||||
*
|
||||
* This protocol specifies a set of interfaces used for adding constraints to
|
||||
* the motion of a pointer. Possible constraints include confining pointer
|
||||
* motions to a given region, or locking it to its current position.
|
||||
*
|
||||
* In order to constrain the pointer, a client must first bind the global
|
||||
* interface "wp_pointer_constraints" which, if a compositor supports pointer
|
||||
* constraints, is exposed by the registry. Using the bound global object, the
|
||||
* client uses the request that corresponds to the type of constraint it wants
|
||||
* to make. See wp_pointer_constraints for more details.
|
||||
*
|
||||
* Warning! The protocol described in this file is experimental and backward
|
||||
* incompatible changes may be made. Backward compatible changes may be added
|
||||
* together with the corresponding interface version bump. Backward
|
||||
* incompatible changes are done by bumping the version number in the protocol
|
||||
* and interface names and resetting the interface version. Once the protocol
|
||||
* is to be declared stable, the 'z' prefix and the version number in the
|
||||
* protocol and interface names are removed and the interface version number is
|
||||
* reset.
|
||||
*
|
||||
* @section page_ifaces_pointer_constraints_unstable_v1 Interfaces
|
||||
* - @subpage page_iface_zwp_pointer_constraints_v1 - constrain the movement of a pointer
|
||||
* - @subpage page_iface_zwp_locked_pointer_v1 - receive relative pointer motion events
|
||||
* - @subpage page_iface_zwp_confined_pointer_v1 - confined pointer object
|
||||
* @section page_copyright_pointer_constraints_unstable_v1 Copyright
|
||||
* <pre>
|
||||
*
|
||||
* Copyright © 2014 Jonas Ådahl
|
||||
* Copyright © 2015 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
* </pre>
|
||||
*/
|
||||
struct wl_pointer;
|
||||
struct wl_region;
|
||||
struct wl_surface;
|
||||
struct zwp_confined_pointer_v1;
|
||||
struct zwp_locked_pointer_v1;
|
||||
struct zwp_pointer_constraints_v1;
|
||||
|
||||
#ifndef ZWP_POINTER_CONSTRAINTS_V1_INTERFACE
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_pointer_constraints_v1 zwp_pointer_constraints_v1
|
||||
* @section page_iface_zwp_pointer_constraints_v1_desc Description
|
||||
*
|
||||
* The global interface exposing pointer constraining functionality. It
|
||||
* exposes two requests: lock_pointer for locking the pointer to its
|
||||
* position, and confine_pointer for locking the pointer to a region.
|
||||
*
|
||||
* The lock_pointer and confine_pointer requests create the objects
|
||||
* wp_locked_pointer and wp_confined_pointer respectively, and the client can
|
||||
* use these objects to interact with the lock.
|
||||
*
|
||||
* For any surface, only one lock or confinement may be active across all
|
||||
* wl_pointer objects of the same seat. If a lock or confinement is requested
|
||||
* when another lock or confinement is active or requested on the same surface
|
||||
* and with any of the wl_pointer objects of the same seat, an
|
||||
* 'already_constrained' error will be raised.
|
||||
* @section page_iface_zwp_pointer_constraints_v1_api API
|
||||
* See @ref iface_zwp_pointer_constraints_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_pointer_constraints_v1 The zwp_pointer_constraints_v1 interface
|
||||
*
|
||||
* The global interface exposing pointer constraining functionality. It
|
||||
* exposes two requests: lock_pointer for locking the pointer to its
|
||||
* position, and confine_pointer for locking the pointer to a region.
|
||||
*
|
||||
* The lock_pointer and confine_pointer requests create the objects
|
||||
* wp_locked_pointer and wp_confined_pointer respectively, and the client can
|
||||
* use these objects to interact with the lock.
|
||||
*
|
||||
* For any surface, only one lock or confinement may be active across all
|
||||
* wl_pointer objects of the same seat. If a lock or confinement is requested
|
||||
* when another lock or confinement is active or requested on the same surface
|
||||
* and with any of the wl_pointer objects of the same seat, an
|
||||
* 'already_constrained' error will be raised.
|
||||
*/
|
||||
extern const struct wl_interface zwp_pointer_constraints_v1_interface;
|
||||
#endif
|
||||
#ifndef ZWP_LOCKED_POINTER_V1_INTERFACE
|
||||
#define ZWP_LOCKED_POINTER_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_locked_pointer_v1 zwp_locked_pointer_v1
|
||||
* @section page_iface_zwp_locked_pointer_v1_desc Description
|
||||
*
|
||||
* The wp_locked_pointer interface represents a locked pointer state.
|
||||
*
|
||||
* While the lock of this object is active, the wl_pointer objects of the
|
||||
* associated seat will not emit any wl_pointer.motion events.
|
||||
*
|
||||
* This object will send the event 'locked' when the lock is activated.
|
||||
* Whenever the lock is activated, it is guaranteed that the locked surface
|
||||
* will already have received pointer focus and that the pointer will be
|
||||
* within the region passed to the request creating this object.
|
||||
*
|
||||
* To unlock the pointer, send the destroy request. This will also destroy
|
||||
* the wp_locked_pointer object.
|
||||
*
|
||||
* If the compositor decides to unlock the pointer the unlocked event is
|
||||
* sent. See wp_locked_pointer.unlock for details.
|
||||
*
|
||||
* When unlocking, the compositor may warp the cursor position to the set
|
||||
* cursor position hint. If it does, it will not result in any relative
|
||||
* motion events emitted via wp_relative_pointer.
|
||||
*
|
||||
* If the surface the lock was requested on is destroyed and the lock is not
|
||||
* yet activated, the wp_locked_pointer object is now defunct and must be
|
||||
* destroyed.
|
||||
* @section page_iface_zwp_locked_pointer_v1_api API
|
||||
* See @ref iface_zwp_locked_pointer_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_locked_pointer_v1 The zwp_locked_pointer_v1 interface
|
||||
*
|
||||
* The wp_locked_pointer interface represents a locked pointer state.
|
||||
*
|
||||
* While the lock of this object is active, the wl_pointer objects of the
|
||||
* associated seat will not emit any wl_pointer.motion events.
|
||||
*
|
||||
* This object will send the event 'locked' when the lock is activated.
|
||||
* Whenever the lock is activated, it is guaranteed that the locked surface
|
||||
* will already have received pointer focus and that the pointer will be
|
||||
* within the region passed to the request creating this object.
|
||||
*
|
||||
* To unlock the pointer, send the destroy request. This will also destroy
|
||||
* the wp_locked_pointer object.
|
||||
*
|
||||
* If the compositor decides to unlock the pointer the unlocked event is
|
||||
* sent. See wp_locked_pointer.unlock for details.
|
||||
*
|
||||
* When unlocking, the compositor may warp the cursor position to the set
|
||||
* cursor position hint. If it does, it will not result in any relative
|
||||
* motion events emitted via wp_relative_pointer.
|
||||
*
|
||||
* If the surface the lock was requested on is destroyed and the lock is not
|
||||
* yet activated, the wp_locked_pointer object is now defunct and must be
|
||||
* destroyed.
|
||||
*/
|
||||
extern const struct wl_interface zwp_locked_pointer_v1_interface;
|
||||
#endif
|
||||
#ifndef ZWP_CONFINED_POINTER_V1_INTERFACE
|
||||
#define ZWP_CONFINED_POINTER_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_confined_pointer_v1 zwp_confined_pointer_v1
|
||||
* @section page_iface_zwp_confined_pointer_v1_desc Description
|
||||
*
|
||||
* The wp_confined_pointer interface represents a confined pointer state.
|
||||
*
|
||||
* This object will send the event 'confined' when the confinement is
|
||||
* activated. Whenever the confinement is activated, it is guaranteed that
|
||||
* the surface the pointer is confined to will already have received pointer
|
||||
* focus and that the pointer will be within the region passed to the request
|
||||
* creating this object. It is up to the compositor to decide whether this
|
||||
* requires some user interaction and if the pointer will warp to within the
|
||||
* passed region if outside.
|
||||
*
|
||||
* To unconfine the pointer, send the destroy request. This will also destroy
|
||||
* the wp_confined_pointer object.
|
||||
*
|
||||
* If the compositor decides to unconfine the pointer the unconfined event is
|
||||
* sent. The wp_confined_pointer object is at this point defunct and should
|
||||
* be destroyed.
|
||||
* @section page_iface_zwp_confined_pointer_v1_api API
|
||||
* See @ref iface_zwp_confined_pointer_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_confined_pointer_v1 The zwp_confined_pointer_v1 interface
|
||||
*
|
||||
* The wp_confined_pointer interface represents a confined pointer state.
|
||||
*
|
||||
* This object will send the event 'confined' when the confinement is
|
||||
* activated. Whenever the confinement is activated, it is guaranteed that
|
||||
* the surface the pointer is confined to will already have received pointer
|
||||
* focus and that the pointer will be within the region passed to the request
|
||||
* creating this object. It is up to the compositor to decide whether this
|
||||
* requires some user interaction and if the pointer will warp to within the
|
||||
* passed region if outside.
|
||||
*
|
||||
* To unconfine the pointer, send the destroy request. This will also destroy
|
||||
* the wp_confined_pointer object.
|
||||
*
|
||||
* If the compositor decides to unconfine the pointer the unconfined event is
|
||||
* sent. The wp_confined_pointer object is at this point defunct and should
|
||||
* be destroyed.
|
||||
*/
|
||||
extern const struct wl_interface zwp_confined_pointer_v1_interface;
|
||||
#endif
|
||||
|
||||
#ifndef ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
|
||||
/**
|
||||
* @ingroup iface_zwp_pointer_constraints_v1
|
||||
* wp_pointer_constraints error values
|
||||
*
|
||||
* These errors can be emitted in response to wp_pointer_constraints
|
||||
* requests.
|
||||
*/
|
||||
enum zwp_pointer_constraints_v1_error {
|
||||
/**
|
||||
* pointer constraint already requested on that surface
|
||||
*/
|
||||
ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED = 1,
|
||||
};
|
||||
#endif /* ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM */
|
||||
|
||||
#ifndef ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
|
||||
/**
|
||||
* @ingroup iface_zwp_pointer_constraints_v1
|
||||
* constraint lifetime
|
||||
*
|
||||
* These values represent different lifetime semantics. They are passed
|
||||
* as arguments to the factory requests to specify how the constraint
|
||||
* lifetimes should be managed.
|
||||
*/
|
||||
enum zwp_pointer_constraints_v1_lifetime {
|
||||
/**
|
||||
* the pointer constraint is defunct once deactivated
|
||||
*
|
||||
* A oneshot pointer constraint will never reactivate once it has
|
||||
* been deactivated. See the corresponding deactivation event
|
||||
* (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined)
|
||||
* for details.
|
||||
*/
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT = 1,
|
||||
/**
|
||||
* the pointer constraint may reactivate
|
||||
*
|
||||
* A persistent pointer constraint may again reactivate once it
|
||||
* has been deactivated. See the corresponding deactivation event
|
||||
* (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined)
|
||||
* for details.
|
||||
*/
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT = 2,
|
||||
};
|
||||
#endif /* ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM */
|
||||
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY 0
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER 1
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER 2
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_pointer_constraints_v1
|
||||
*/
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_pointer_constraints_v1
|
||||
*/
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_pointer_constraints_v1
|
||||
*/
|
||||
#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_pointer_constraints_v1 */
|
||||
static inline void
|
||||
zwp_pointer_constraints_v1_set_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_pointer_constraints_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_pointer_constraints_v1 */
|
||||
static inline void *
|
||||
zwp_pointer_constraints_v1_get_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_pointer_constraints_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_pointer_constraints_v1_get_version(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_pointer_constraints_v1
|
||||
*
|
||||
* Used by the client to notify the server that it will no longer use this
|
||||
* pointer constraints object.
|
||||
*/
|
||||
static inline void
|
||||
zwp_pointer_constraints_v1_destroy(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_pointer_constraints_v1
|
||||
*
|
||||
* The lock_pointer request lets the client request to disable movements of
|
||||
* the virtual pointer (i.e. the cursor), effectively locking the pointer
|
||||
* to a position. This request may not take effect immediately; in the
|
||||
* future, when the compositor deems implementation-specific constraints
|
||||
* are satisfied, the pointer lock will be activated and the compositor
|
||||
* sends a locked event.
|
||||
*
|
||||
* The protocol provides no guarantee that the constraints are ever
|
||||
* satisfied, and does not require the compositor to send an error if the
|
||||
* constraints cannot ever be satisfied. It is thus possible to request a
|
||||
* lock that will never activate.
|
||||
*
|
||||
* There may not be another pointer constraint of any kind requested or
|
||||
* active on the surface for any of the wl_pointer objects of the seat of
|
||||
* the passed pointer when requesting a lock. If there is, an error will be
|
||||
* raised. See general pointer lock documentation for more details.
|
||||
*
|
||||
* The intersection of the region passed with this request and the input
|
||||
* region of the surface is used to determine where the pointer must be
|
||||
* in order for the lock to activate. It is up to the compositor whether to
|
||||
* warp the pointer or require some kind of user interaction for the lock
|
||||
* to activate. If the region is null the surface input region is used.
|
||||
*
|
||||
* A surface may receive pointer focus without the lock being activated.
|
||||
*
|
||||
* The request creates a new object wp_locked_pointer which is used to
|
||||
* interact with the lock as well as receive updates about its state. See
|
||||
* the the description of wp_locked_pointer for further information.
|
||||
*
|
||||
* Note that while a pointer is locked, the wl_pointer objects of the
|
||||
* corresponding seat will not emit any wl_pointer.motion events, but
|
||||
* relative motion events will still be emitted via wp_relative_pointer
|
||||
* objects of the same seat. wl_pointer.axis and wl_pointer.button events
|
||||
* are unaffected.
|
||||
*/
|
||||
static inline struct zwp_locked_pointer_v1 *
|
||||
zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
|
||||
{
|
||||
struct wl_proxy *id;
|
||||
|
||||
id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER, &zwp_locked_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), 0, NULL, surface, pointer, region, lifetime);
|
||||
|
||||
return (struct zwp_locked_pointer_v1 *) id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_pointer_constraints_v1
|
||||
*
|
||||
* The confine_pointer request lets the client request to confine the
|
||||
* pointer cursor to a given region. This request may not take effect
|
||||
* immediately; in the future, when the compositor deems implementation-
|
||||
* specific constraints are satisfied, the pointer confinement will be
|
||||
* activated and the compositor sends a confined event.
|
||||
*
|
||||
* The intersection of the region passed with this request and the input
|
||||
* region of the surface is used to determine where the pointer must be
|
||||
* in order for the confinement to activate. It is up to the compositor
|
||||
* whether to warp the pointer or require some kind of user interaction for
|
||||
* the confinement to activate. If the region is null the surface input
|
||||
* region is used.
|
||||
*
|
||||
* The request will create a new object wp_confined_pointer which is used
|
||||
* to interact with the confinement as well as receive updates about its
|
||||
* state. See the the description of wp_confined_pointer for further
|
||||
* information.
|
||||
*/
|
||||
static inline struct zwp_confined_pointer_v1 *
|
||||
zwp_pointer_constraints_v1_confine_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
|
||||
{
|
||||
struct wl_proxy *id;
|
||||
|
||||
id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_pointer_constraints_v1,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER, &zwp_confined_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1), 0, NULL, surface, pointer, region, lifetime);
|
||||
|
||||
return (struct zwp_confined_pointer_v1 *) id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
* @struct zwp_locked_pointer_v1_listener
|
||||
*/
|
||||
struct zwp_locked_pointer_v1_listener {
|
||||
/**
|
||||
* lock activation event
|
||||
*
|
||||
* Notification that the pointer lock of the seat's pointer is
|
||||
* activated.
|
||||
*/
|
||||
void (*locked)(void *data,
|
||||
struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
|
||||
/**
|
||||
* lock deactivation event
|
||||
*
|
||||
* Notification that the pointer lock of the seat's pointer is no
|
||||
* longer active. If this is a oneshot pointer lock (see
|
||||
* wp_pointer_constraints.lifetime) this object is now defunct and
|
||||
* should be destroyed. If this is a persistent pointer lock (see
|
||||
* wp_pointer_constraints.lifetime) this pointer lock may again
|
||||
* reactivate in the future.
|
||||
*/
|
||||
void (*unlocked)(void *data,
|
||||
struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*/
|
||||
static inline int
|
||||
zwp_locked_pointer_v1_add_listener(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1,
|
||||
const struct zwp_locked_pointer_v1_listener *listener, void *data)
|
||||
{
|
||||
return wl_proxy_add_listener((struct wl_proxy *) zwp_locked_pointer_v1,
|
||||
(void (**)(void)) listener, data);
|
||||
}
|
||||
|
||||
#define ZWP_LOCKED_POINTER_V1_DESTROY 0
|
||||
#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT 1
|
||||
#define ZWP_LOCKED_POINTER_V1_SET_REGION 2
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*/
|
||||
#define ZWP_LOCKED_POINTER_V1_LOCKED_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*/
|
||||
#define ZWP_LOCKED_POINTER_V1_UNLOCKED_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*/
|
||||
#define ZWP_LOCKED_POINTER_V1_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*/
|
||||
#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*/
|
||||
#define ZWP_LOCKED_POINTER_V1_SET_REGION_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_locked_pointer_v1 */
|
||||
static inline void
|
||||
zwp_locked_pointer_v1_set_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_locked_pointer_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_locked_pointer_v1 */
|
||||
static inline void *
|
||||
zwp_locked_pointer_v1_get_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_locked_pointer_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_locked_pointer_v1_get_version(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*
|
||||
* Destroy the locked pointer object. If applicable, the compositor will
|
||||
* unlock the pointer.
|
||||
*/
|
||||
static inline void
|
||||
zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
|
||||
ZWP_LOCKED_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*
|
||||
* Set the cursor position hint relative to the top left corner of the
|
||||
* surface.
|
||||
*
|
||||
* If the client is drawing its own cursor, it should update the position
|
||||
* hint to the position of its own cursor. A compositor may use this
|
||||
* information to warp the pointer upon unlock in order to avoid pointer
|
||||
* jumps.
|
||||
*
|
||||
* The cursor position hint is double buffered. The new hint will only take
|
||||
* effect when the associated surface gets it pending state applied. See
|
||||
* wl_surface.commit for details.
|
||||
*/
|
||||
static inline void
|
||||
zwp_locked_pointer_v1_set_cursor_position_hint(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
|
||||
ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), 0, surface_x, surface_y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_locked_pointer_v1
|
||||
*
|
||||
* Set a new region used to lock the pointer.
|
||||
*
|
||||
* The new lock region is double-buffered. The new lock region will
|
||||
* only take effect when the associated surface gets its pending state
|
||||
* applied. See wl_surface.commit for details.
|
||||
*
|
||||
* For details about the lock region, see wp_locked_pointer.
|
||||
*/
|
||||
static inline void
|
||||
zwp_locked_pointer_v1_set_region(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, struct wl_region *region)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_locked_pointer_v1,
|
||||
ZWP_LOCKED_POINTER_V1_SET_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1), 0, region);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_confined_pointer_v1
|
||||
* @struct zwp_confined_pointer_v1_listener
|
||||
*/
|
||||
struct zwp_confined_pointer_v1_listener {
|
||||
/**
|
||||
* pointer confined
|
||||
*
|
||||
* Notification that the pointer confinement of the seat's
|
||||
* pointer is activated.
|
||||
*/
|
||||
void (*confined)(void *data,
|
||||
struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
|
||||
/**
|
||||
* pointer unconfined
|
||||
*
|
||||
* Notification that the pointer confinement of the seat's
|
||||
* pointer is no longer active. If this is a oneshot pointer
|
||||
* confinement (see wp_pointer_constraints.lifetime) this object is
|
||||
* now defunct and should be destroyed. If this is a persistent
|
||||
* pointer confinement (see wp_pointer_constraints.lifetime) this
|
||||
* pointer confinement may again reactivate in the future.
|
||||
*/
|
||||
void (*unconfined)(void *data,
|
||||
struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_confined_pointer_v1
|
||||
*/
|
||||
static inline int
|
||||
zwp_confined_pointer_v1_add_listener(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1,
|
||||
const struct zwp_confined_pointer_v1_listener *listener, void *data)
|
||||
{
|
||||
return wl_proxy_add_listener((struct wl_proxy *) zwp_confined_pointer_v1,
|
||||
(void (**)(void)) listener, data);
|
||||
}
|
||||
|
||||
#define ZWP_CONFINED_POINTER_V1_DESTROY 0
|
||||
#define ZWP_CONFINED_POINTER_V1_SET_REGION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_confined_pointer_v1
|
||||
*/
|
||||
#define ZWP_CONFINED_POINTER_V1_CONFINED_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_confined_pointer_v1
|
||||
*/
|
||||
#define ZWP_CONFINED_POINTER_V1_UNCONFINED_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_confined_pointer_v1
|
||||
*/
|
||||
#define ZWP_CONFINED_POINTER_V1_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_confined_pointer_v1
|
||||
*/
|
||||
#define ZWP_CONFINED_POINTER_V1_SET_REGION_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_confined_pointer_v1 */
|
||||
static inline void
|
||||
zwp_confined_pointer_v1_set_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_confined_pointer_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_confined_pointer_v1 */
|
||||
static inline void *
|
||||
zwp_confined_pointer_v1_get_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_confined_pointer_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_confined_pointer_v1_get_version(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_confined_pointer_v1
|
||||
*
|
||||
* Destroy the confined pointer object. If applicable, the compositor will
|
||||
* unconfine the pointer.
|
||||
*/
|
||||
static inline void
|
||||
zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_confined_pointer_v1,
|
||||
ZWP_CONFINED_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_confined_pointer_v1
|
||||
*
|
||||
* Set a new region used to confine the pointer.
|
||||
*
|
||||
* The new confine region is double-buffered. The new confine region will
|
||||
* only take effect when the associated surface gets its pending state
|
||||
* applied. See wl_surface.commit for details.
|
||||
*
|
||||
* If the confinement is active when the new confinement region is applied
|
||||
* and the pointer ends up outside of newly applied region, the pointer may
|
||||
* warped to a position within the new confinement region. If warped, a
|
||||
* wl_pointer.motion event will be emitted, but no
|
||||
* wp_relative_pointer.relative_motion event.
|
||||
*
|
||||
* The compositor may also, instead of using the new region, unconfine the
|
||||
* pointer.
|
||||
*
|
||||
* For details about the confine region, see wp_confined_pointer.
|
||||
*/
|
||||
static inline void
|
||||
zwp_confined_pointer_v1_set_region(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, struct wl_region *region)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_confined_pointer_v1,
|
||||
ZWP_CONFINED_POINTER_V1_SET_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1), 0, region);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_pointer_interface;
|
||||
extern const struct wl_interface zwp_relative_pointer_v1_interface;
|
||||
|
||||
static const struct wl_interface *relative_pointer_unstable_v1_types[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&zwp_relative_pointer_v1_interface,
|
||||
&wl_pointer_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_relative_pointer_manager_v1_requests[] = {
|
||||
{ "destroy", "", relative_pointer_unstable_v1_types + 0 },
|
||||
{ "get_relative_pointer", "no", relative_pointer_unstable_v1_types + 6 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zwp_relative_pointer_manager_v1_interface = {
|
||||
"zwp_relative_pointer_manager_v1", 1,
|
||||
2, zwp_relative_pointer_manager_v1_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_relative_pointer_v1_requests[] = {
|
||||
{ "destroy", "", relative_pointer_unstable_v1_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message zwp_relative_pointer_v1_events[] = {
|
||||
{ "relative_motion", "uuffff", relative_pointer_unstable_v1_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zwp_relative_pointer_v1_interface = {
|
||||
"zwp_relative_pointer_v1", 1,
|
||||
1, zwp_relative_pointer_v1_requests,
|
||||
1, zwp_relative_pointer_v1_events,
|
||||
};
|
||||
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page page_relative_pointer_unstable_v1 The relative_pointer_unstable_v1 protocol
|
||||
* protocol for relative pointer motion events
|
||||
*
|
||||
* @section page_desc_relative_pointer_unstable_v1 Description
|
||||
*
|
||||
* This protocol specifies a set of interfaces used for making clients able to
|
||||
* receive relative pointer events not obstructed by barriers (such as the
|
||||
* monitor edge or other pointer barriers).
|
||||
*
|
||||
* To start receiving relative pointer events, a client must first bind the
|
||||
* global interface "wp_relative_pointer_manager" which, if a compositor
|
||||
* supports relative pointer motion events, is exposed by the registry. After
|
||||
* having created the relative pointer manager proxy object, the client uses
|
||||
* it to create the actual relative pointer object using the
|
||||
* "get_relative_pointer" request given a wl_pointer. The relative pointer
|
||||
* motion events will then, when applicable, be transmitted via the proxy of
|
||||
* the newly created relative pointer object. See the documentation of the
|
||||
* relative pointer interface for more details.
|
||||
*
|
||||
* Warning! The protocol described in this file is experimental and backward
|
||||
* incompatible changes may be made. Backward compatible changes may be added
|
||||
* together with the corresponding interface version bump. Backward
|
||||
* incompatible changes are done by bumping the version number in the protocol
|
||||
* and interface names and resetting the interface version. Once the protocol
|
||||
* is to be declared stable, the 'z' prefix and the version number in the
|
||||
* protocol and interface names are removed and the interface version number is
|
||||
* reset.
|
||||
*
|
||||
* @section page_ifaces_relative_pointer_unstable_v1 Interfaces
|
||||
* - @subpage page_iface_zwp_relative_pointer_manager_v1 - get relative pointer objects
|
||||
* - @subpage page_iface_zwp_relative_pointer_v1 - relative pointer object
|
||||
* @section page_copyright_relative_pointer_unstable_v1 Copyright
|
||||
* <pre>
|
||||
*
|
||||
* Copyright © 2014 Jonas Ådahl
|
||||
* Copyright © 2015 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
* </pre>
|
||||
*/
|
||||
struct wl_pointer;
|
||||
struct zwp_relative_pointer_manager_v1;
|
||||
struct zwp_relative_pointer_v1;
|
||||
|
||||
#ifndef ZWP_RELATIVE_POINTER_MANAGER_V1_INTERFACE
|
||||
#define ZWP_RELATIVE_POINTER_MANAGER_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_relative_pointer_manager_v1 zwp_relative_pointer_manager_v1
|
||||
* @section page_iface_zwp_relative_pointer_manager_v1_desc Description
|
||||
*
|
||||
* A global interface used for getting the relative pointer object for a
|
||||
* given pointer.
|
||||
* @section page_iface_zwp_relative_pointer_manager_v1_api API
|
||||
* See @ref iface_zwp_relative_pointer_manager_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_relative_pointer_manager_v1 The zwp_relative_pointer_manager_v1 interface
|
||||
*
|
||||
* A global interface used for getting the relative pointer object for a
|
||||
* given pointer.
|
||||
*/
|
||||
extern const struct wl_interface zwp_relative_pointer_manager_v1_interface;
|
||||
#endif
|
||||
#ifndef ZWP_RELATIVE_POINTER_V1_INTERFACE
|
||||
#define ZWP_RELATIVE_POINTER_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zwp_relative_pointer_v1 zwp_relative_pointer_v1
|
||||
* @section page_iface_zwp_relative_pointer_v1_desc Description
|
||||
*
|
||||
* A wp_relative_pointer object is an extension to the wl_pointer interface
|
||||
* used for emitting relative pointer events. It shares the same focus as
|
||||
* wl_pointer objects of the same seat and will only emit events when it has
|
||||
* focus.
|
||||
* @section page_iface_zwp_relative_pointer_v1_api API
|
||||
* See @ref iface_zwp_relative_pointer_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zwp_relative_pointer_v1 The zwp_relative_pointer_v1 interface
|
||||
*
|
||||
* A wp_relative_pointer object is an extension to the wl_pointer interface
|
||||
* used for emitting relative pointer events. It shares the same focus as
|
||||
* wl_pointer objects of the same seat and will only emit events when it has
|
||||
* focus.
|
||||
*/
|
||||
extern const struct wl_interface zwp_relative_pointer_v1_interface;
|
||||
#endif
|
||||
|
||||
#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY 0
|
||||
#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER 1
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_manager_v1
|
||||
*/
|
||||
#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_manager_v1
|
||||
*/
|
||||
#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_relative_pointer_manager_v1 */
|
||||
static inline void
|
||||
zwp_relative_pointer_manager_v1_set_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_relative_pointer_manager_v1 */
|
||||
static inline void *
|
||||
zwp_relative_pointer_manager_v1_get_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_relative_pointer_manager_v1_get_version(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_manager_v1
|
||||
*
|
||||
* Used by the client to notify the server that it will no longer use this
|
||||
* relative pointer manager object.
|
||||
*/
|
||||
static inline void
|
||||
zwp_relative_pointer_manager_v1_destroy(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_manager_v1,
|
||||
ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_manager_v1
|
||||
*
|
||||
* Create a relative pointer interface given a wl_pointer object. See the
|
||||
* wp_relative_pointer interface for more details.
|
||||
*/
|
||||
static inline struct zwp_relative_pointer_v1 *
|
||||
zwp_relative_pointer_manager_v1_get_relative_pointer(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, struct wl_pointer *pointer)
|
||||
{
|
||||
struct wl_proxy *id;
|
||||
|
||||
id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_manager_v1,
|
||||
ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER, &zwp_relative_pointer_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1), 0, NULL, pointer);
|
||||
|
||||
return (struct zwp_relative_pointer_v1 *) id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_v1
|
||||
* @struct zwp_relative_pointer_v1_listener
|
||||
*/
|
||||
struct zwp_relative_pointer_v1_listener {
|
||||
/**
|
||||
* relative pointer motion
|
||||
*
|
||||
* Relative x/y pointer motion from the pointer of the seat
|
||||
* associated with this object.
|
||||
*
|
||||
* A relative motion is in the same dimension as regular wl_pointer
|
||||
* motion events, except they do not represent an absolute
|
||||
* position. For example, moving a pointer from (x, y) to (x', y')
|
||||
* would have the equivalent relative motion (x' - x, y' - y). If a
|
||||
* pointer motion caused the absolute pointer position to be
|
||||
* clipped by for example the edge of the monitor, the relative
|
||||
* motion is unaffected by the clipping and will represent the
|
||||
* unclipped motion.
|
||||
*
|
||||
* This event also contains non-accelerated motion deltas. The
|
||||
* non-accelerated delta is, when applicable, the regular pointer
|
||||
* motion delta as it was before having applied motion acceleration
|
||||
* and other transformations such as normalization.
|
||||
*
|
||||
* Note that the non-accelerated delta does not represent 'raw'
|
||||
* events as they were read from some device. Pointer motion
|
||||
* acceleration is device- and configuration-specific and
|
||||
* non-accelerated deltas and accelerated deltas may have the same
|
||||
* value on some devices.
|
||||
*
|
||||
* Relative motions are not coupled to wl_pointer.motion events,
|
||||
* and can be sent in combination with such events, but also
|
||||
* independently. There may also be scenarios where
|
||||
* wl_pointer.motion is sent, but there is no relative motion. The
|
||||
* order of an absolute and relative motion event originating from
|
||||
* the same physical motion is not guaranteed.
|
||||
*
|
||||
* If the client needs button events or focus state, it can receive
|
||||
* them from a wl_pointer object of the same seat that the
|
||||
* wp_relative_pointer object is associated with.
|
||||
* @param utime_hi high 32 bits of a 64 bit timestamp with microsecond granularity
|
||||
* @param utime_lo low 32 bits of a 64 bit timestamp with microsecond granularity
|
||||
* @param dx the x component of the motion vector
|
||||
* @param dy the y component of the motion vector
|
||||
* @param dx_unaccel the x component of the unaccelerated motion vector
|
||||
* @param dy_unaccel the y component of the unaccelerated motion vector
|
||||
*/
|
||||
void (*relative_motion)(void *data,
|
||||
struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
|
||||
uint32_t utime_hi,
|
||||
uint32_t utime_lo,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t dx_unaccel,
|
||||
wl_fixed_t dy_unaccel);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_v1
|
||||
*/
|
||||
static inline int
|
||||
zwp_relative_pointer_v1_add_listener(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
|
||||
const struct zwp_relative_pointer_v1_listener *listener, void *data)
|
||||
{
|
||||
return wl_proxy_add_listener((struct wl_proxy *) zwp_relative_pointer_v1,
|
||||
(void (**)(void)) listener, data);
|
||||
}
|
||||
|
||||
#define ZWP_RELATIVE_POINTER_V1_DESTROY 0
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_v1
|
||||
*/
|
||||
#define ZWP_RELATIVE_POINTER_V1_RELATIVE_MOTION_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_v1
|
||||
*/
|
||||
#define ZWP_RELATIVE_POINTER_V1_DESTROY_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zwp_relative_pointer_v1 */
|
||||
static inline void
|
||||
zwp_relative_pointer_v1_set_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zwp_relative_pointer_v1 */
|
||||
static inline void *
|
||||
zwp_relative_pointer_v1_get_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zwp_relative_pointer_v1_get_version(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zwp_relative_pointer_v1
|
||||
*/
|
||||
static inline void
|
||||
zwp_relative_pointer_v1_destroy(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zwp_relative_pointer_v1,
|
||||
ZWP_RELATIVE_POINTER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
extern const struct wl_interface wp_viewport_interface;
|
||||
|
||||
static const struct wl_interface *viewporter_types[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wp_viewport_interface,
|
||||
&wl_surface_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message wp_viewporter_requests[] = {
|
||||
{ "destroy", "", viewporter_types + 0 },
|
||||
{ "get_viewport", "no", viewporter_types + 4 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wp_viewporter_interface = {
|
||||
"wp_viewporter", 1,
|
||||
2, wp_viewporter_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message wp_viewport_requests[] = {
|
||||
{ "destroy", "", viewporter_types + 0 },
|
||||
{ "set_source", "ffff", viewporter_types + 0 },
|
||||
{ "set_destination", "ii", viewporter_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wp_viewport_interface = {
|
||||
"wp_viewport", 1,
|
||||
3, wp_viewport_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
|
|
@ -1,398 +0,0 @@
|
|||
/* Generated by wayland-scanner 1.23.1 */
|
||||
|
||||
#ifndef VIEWPORTER_CLIENT_PROTOCOL_H
|
||||
#define VIEWPORTER_CLIENT_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page page_viewporter The viewporter protocol
|
||||
* @section page_ifaces_viewporter Interfaces
|
||||
* - @subpage page_iface_wp_viewporter - surface cropping and scaling
|
||||
* - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface
|
||||
* @section page_copyright_viewporter Copyright
|
||||
* <pre>
|
||||
*
|
||||
* Copyright © 2013-2016 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
* </pre>
|
||||
*/
|
||||
struct wl_surface;
|
||||
struct wp_viewport;
|
||||
struct wp_viewporter;
|
||||
|
||||
#ifndef WP_VIEWPORTER_INTERFACE
|
||||
#define WP_VIEWPORTER_INTERFACE
|
||||
/**
|
||||
* @page page_iface_wp_viewporter wp_viewporter
|
||||
* @section page_iface_wp_viewporter_desc Description
|
||||
*
|
||||
* The global interface exposing surface cropping and scaling
|
||||
* capabilities is used to instantiate an interface extension for a
|
||||
* wl_surface object. This extended interface will then allow
|
||||
* cropping and scaling the surface contents, effectively
|
||||
* disconnecting the direct relationship between the buffer and the
|
||||
* surface size.
|
||||
* @section page_iface_wp_viewporter_api API
|
||||
* See @ref iface_wp_viewporter.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_wp_viewporter The wp_viewporter interface
|
||||
*
|
||||
* The global interface exposing surface cropping and scaling
|
||||
* capabilities is used to instantiate an interface extension for a
|
||||
* wl_surface object. This extended interface will then allow
|
||||
* cropping and scaling the surface contents, effectively
|
||||
* disconnecting the direct relationship between the buffer and the
|
||||
* surface size.
|
||||
*/
|
||||
extern const struct wl_interface wp_viewporter_interface;
|
||||
#endif
|
||||
#ifndef WP_VIEWPORT_INTERFACE
|
||||
#define WP_VIEWPORT_INTERFACE
|
||||
/**
|
||||
* @page page_iface_wp_viewport wp_viewport
|
||||
* @section page_iface_wp_viewport_desc Description
|
||||
*
|
||||
* An additional interface to a wl_surface object, which allows the
|
||||
* client to specify the cropping and scaling of the surface
|
||||
* contents.
|
||||
*
|
||||
* This interface works with two concepts: the source rectangle (src_x,
|
||||
* src_y, src_width, src_height), and the destination size (dst_width,
|
||||
* dst_height). The contents of the source rectangle are scaled to the
|
||||
* destination size, and content outside the source rectangle is ignored.
|
||||
* This state is double-buffered, and is applied on the next
|
||||
* wl_surface.commit.
|
||||
*
|
||||
* The two parts of crop and scale state are independent: the source
|
||||
* rectangle, and the destination size. Initially both are unset, that
|
||||
* is, no scaling is applied. The whole of the current wl_buffer is
|
||||
* used as the source, and the surface size is as defined in
|
||||
* wl_surface.attach.
|
||||
*
|
||||
* If the destination size is set, it causes the surface size to become
|
||||
* dst_width, dst_height. The source (rectangle) is scaled to exactly
|
||||
* this size. This overrides whatever the attached wl_buffer size is,
|
||||
* unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
|
||||
* has no content and therefore no size. Otherwise, the size is always
|
||||
* at least 1x1 in surface local coordinates.
|
||||
*
|
||||
* If the source rectangle is set, it defines what area of the wl_buffer is
|
||||
* taken as the source. If the source rectangle is set and the destination
|
||||
* size is not set, then src_width and src_height must be integers, and the
|
||||
* surface size becomes the source rectangle size. This results in cropping
|
||||
* without scaling. If src_width or src_height are not integers and
|
||||
* destination size is not set, the bad_size protocol error is raised when
|
||||
* the surface state is applied.
|
||||
*
|
||||
* The coordinate transformations from buffer pixel coordinates up to
|
||||
* the surface-local coordinates happen in the following order:
|
||||
* 1. buffer_transform (wl_surface.set_buffer_transform)
|
||||
* 2. buffer_scale (wl_surface.set_buffer_scale)
|
||||
* 3. crop and scale (wp_viewport.set*)
|
||||
* This means, that the source rectangle coordinates of crop and scale
|
||||
* are given in the coordinates after the buffer transform and scale,
|
||||
* i.e. in the coordinates that would be the surface-local coordinates
|
||||
* if the crop and scale was not applied.
|
||||
*
|
||||
* If src_x or src_y are negative, the bad_value protocol error is raised.
|
||||
* Otherwise, if the source rectangle is partially or completely outside of
|
||||
* the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
|
||||
* when the surface state is applied. A NULL wl_buffer does not raise the
|
||||
* out_of_buffer error.
|
||||
*
|
||||
* If the wl_surface associated with the wp_viewport is destroyed,
|
||||
* all wp_viewport requests except 'destroy' raise the protocol error
|
||||
* no_surface.
|
||||
*
|
||||
* If the wp_viewport object is destroyed, the crop and scale
|
||||
* state is removed from the wl_surface. The change will be applied
|
||||
* on the next wl_surface.commit.
|
||||
* @section page_iface_wp_viewport_api API
|
||||
* See @ref iface_wp_viewport.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_wp_viewport The wp_viewport interface
|
||||
*
|
||||
* An additional interface to a wl_surface object, which allows the
|
||||
* client to specify the cropping and scaling of the surface
|
||||
* contents.
|
||||
*
|
||||
* This interface works with two concepts: the source rectangle (src_x,
|
||||
* src_y, src_width, src_height), and the destination size (dst_width,
|
||||
* dst_height). The contents of the source rectangle are scaled to the
|
||||
* destination size, and content outside the source rectangle is ignored.
|
||||
* This state is double-buffered, and is applied on the next
|
||||
* wl_surface.commit.
|
||||
*
|
||||
* The two parts of crop and scale state are independent: the source
|
||||
* rectangle, and the destination size. Initially both are unset, that
|
||||
* is, no scaling is applied. The whole of the current wl_buffer is
|
||||
* used as the source, and the surface size is as defined in
|
||||
* wl_surface.attach.
|
||||
*
|
||||
* If the destination size is set, it causes the surface size to become
|
||||
* dst_width, dst_height. The source (rectangle) is scaled to exactly
|
||||
* this size. This overrides whatever the attached wl_buffer size is,
|
||||
* unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
|
||||
* has no content and therefore no size. Otherwise, the size is always
|
||||
* at least 1x1 in surface local coordinates.
|
||||
*
|
||||
* If the source rectangle is set, it defines what area of the wl_buffer is
|
||||
* taken as the source. If the source rectangle is set and the destination
|
||||
* size is not set, then src_width and src_height must be integers, and the
|
||||
* surface size becomes the source rectangle size. This results in cropping
|
||||
* without scaling. If src_width or src_height are not integers and
|
||||
* destination size is not set, the bad_size protocol error is raised when
|
||||
* the surface state is applied.
|
||||
*
|
||||
* The coordinate transformations from buffer pixel coordinates up to
|
||||
* the surface-local coordinates happen in the following order:
|
||||
* 1. buffer_transform (wl_surface.set_buffer_transform)
|
||||
* 2. buffer_scale (wl_surface.set_buffer_scale)
|
||||
* 3. crop and scale (wp_viewport.set*)
|
||||
* This means, that the source rectangle coordinates of crop and scale
|
||||
* are given in the coordinates after the buffer transform and scale,
|
||||
* i.e. in the coordinates that would be the surface-local coordinates
|
||||
* if the crop and scale was not applied.
|
||||
*
|
||||
* If src_x or src_y are negative, the bad_value protocol error is raised.
|
||||
* Otherwise, if the source rectangle is partially or completely outside of
|
||||
* the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
|
||||
* when the surface state is applied. A NULL wl_buffer does not raise the
|
||||
* out_of_buffer error.
|
||||
*
|
||||
* If the wl_surface associated with the wp_viewport is destroyed,
|
||||
* all wp_viewport requests except 'destroy' raise the protocol error
|
||||
* no_surface.
|
||||
*
|
||||
* If the wp_viewport object is destroyed, the crop and scale
|
||||
* state is removed from the wl_surface. The change will be applied
|
||||
* on the next wl_surface.commit.
|
||||
*/
|
||||
extern const struct wl_interface wp_viewport_interface;
|
||||
#endif
|
||||
|
||||
#ifndef WP_VIEWPORTER_ERROR_ENUM
|
||||
#define WP_VIEWPORTER_ERROR_ENUM
|
||||
enum wp_viewporter_error {
|
||||
/**
|
||||
* the surface already has a viewport object associated
|
||||
*/
|
||||
WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0,
|
||||
};
|
||||
#endif /* WP_VIEWPORTER_ERROR_ENUM */
|
||||
|
||||
#define WP_VIEWPORTER_DESTROY 0
|
||||
#define WP_VIEWPORTER_GET_VIEWPORT 1
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewporter
|
||||
*/
|
||||
#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wp_viewporter
|
||||
*/
|
||||
#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_wp_viewporter */
|
||||
static inline void
|
||||
wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_wp_viewporter */
|
||||
static inline void *
|
||||
wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
wp_viewporter_get_version(struct wp_viewporter *wp_viewporter)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) wp_viewporter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewporter
|
||||
*
|
||||
* Informs the server that the client will not be using this
|
||||
* protocol object anymore. This does not affect any other objects,
|
||||
* wp_viewport objects included.
|
||||
*/
|
||||
static inline void
|
||||
wp_viewporter_destroy(struct wp_viewporter *wp_viewporter)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter,
|
||||
WP_VIEWPORTER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewporter
|
||||
*
|
||||
* Instantiate an interface extension for the given wl_surface to
|
||||
* crop and scale its content. If the given wl_surface already has
|
||||
* a wp_viewport object associated, the viewport_exists
|
||||
* protocol error is raised.
|
||||
*/
|
||||
static inline struct wp_viewport *
|
||||
wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface)
|
||||
{
|
||||
struct wl_proxy *id;
|
||||
|
||||
id = wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter,
|
||||
WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), 0, NULL, surface);
|
||||
|
||||
return (struct wp_viewport *) id;
|
||||
}
|
||||
|
||||
#ifndef WP_VIEWPORT_ERROR_ENUM
|
||||
#define WP_VIEWPORT_ERROR_ENUM
|
||||
enum wp_viewport_error {
|
||||
/**
|
||||
* negative or zero values in width or height
|
||||
*/
|
||||
WP_VIEWPORT_ERROR_BAD_VALUE = 0,
|
||||
/**
|
||||
* destination size is not integer
|
||||
*/
|
||||
WP_VIEWPORT_ERROR_BAD_SIZE = 1,
|
||||
/**
|
||||
* source rectangle extends outside of the content area
|
||||
*/
|
||||
WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2,
|
||||
/**
|
||||
* the wl_surface was destroyed
|
||||
*/
|
||||
WP_VIEWPORT_ERROR_NO_SURFACE = 3,
|
||||
};
|
||||
#endif /* WP_VIEWPORT_ERROR_ENUM */
|
||||
|
||||
#define WP_VIEWPORT_DESTROY 0
|
||||
#define WP_VIEWPORT_SET_SOURCE 1
|
||||
#define WP_VIEWPORT_SET_DESTINATION 2
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*/
|
||||
#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*/
|
||||
#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*/
|
||||
#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_wp_viewport */
|
||||
static inline void
|
||||
wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_wp_viewport */
|
||||
static inline void *
|
||||
wp_viewport_get_user_data(struct wp_viewport *wp_viewport)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
wp_viewport_get_version(struct wp_viewport *wp_viewport)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) wp_viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*
|
||||
* The associated wl_surface's crop and scale state is removed.
|
||||
* The change is applied on the next wl_surface.commit.
|
||||
*/
|
||||
static inline void
|
||||
wp_viewport_destroy(struct wp_viewport *wp_viewport)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
|
||||
WP_VIEWPORT_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*
|
||||
* Set the source rectangle of the associated wl_surface. See
|
||||
* wp_viewport for the description, and relation to the wl_buffer
|
||||
* size.
|
||||
*
|
||||
* If all of x, y, width and height are -1.0, the source rectangle is
|
||||
* unset instead. Any other set of values where width or height are zero
|
||||
* or negative, or x or y are negative, raise the bad_value protocol
|
||||
* error.
|
||||
*
|
||||
* The crop and scale state is double-buffered state, and will be
|
||||
* applied on the next wl_surface.commit.
|
||||
*/
|
||||
static inline void
|
||||
wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
|
||||
WP_VIEWPORT_SET_SOURCE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*
|
||||
* Set the destination size of the associated wl_surface. See
|
||||
* wp_viewport for the description, and relation to the wl_buffer
|
||||
* size.
|
||||
*
|
||||
* If width is -1 and height is -1, the destination size is unset
|
||||
* instead. Any other pair of values for width and height that
|
||||
* contains zero or negative values raises the bad_value protocol
|
||||
* error.
|
||||
*
|
||||
* The crop and scale state is double-buffered state, and will be
|
||||
* applied on the next wl_surface.commit.
|
||||
*/
|
||||
static inline void
|
||||
wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport,
|
||||
WP_VIEWPORT_SET_DESTINATION, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, width, height);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_buffer_interface;
|
||||
extern const struct wl_interface wl_callback_interface;
|
||||
extern const struct wl_interface wl_data_device_interface;
|
||||
extern const struct wl_interface wl_data_offer_interface;
|
||||
extern const struct wl_interface wl_data_source_interface;
|
||||
extern const struct wl_interface wl_keyboard_interface;
|
||||
extern const struct wl_interface wl_output_interface;
|
||||
extern const struct wl_interface wl_pointer_interface;
|
||||
extern const struct wl_interface wl_region_interface;
|
||||
extern const struct wl_interface wl_registry_interface;
|
||||
extern const struct wl_interface wl_seat_interface;
|
||||
extern const struct wl_interface wl_shell_surface_interface;
|
||||
extern const struct wl_interface wl_shm_pool_interface;
|
||||
extern const struct wl_interface wl_subsurface_interface;
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
extern const struct wl_interface wl_touch_interface;
|
||||
|
||||
static const struct wl_interface *wayland_types[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_callback_interface,
|
||||
&wl_registry_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_region_interface,
|
||||
&wl_buffer_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_shm_pool_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_data_source_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
&wl_data_source_interface,
|
||||
NULL,
|
||||
&wl_data_offer_interface,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_data_offer_interface,
|
||||
&wl_data_offer_interface,
|
||||
&wl_data_source_interface,
|
||||
&wl_data_device_interface,
|
||||
&wl_seat_interface,
|
||||
&wl_shell_surface_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_output_interface,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_output_interface,
|
||||
&wl_buffer_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_callback_interface,
|
||||
&wl_region_interface,
|
||||
&wl_region_interface,
|
||||
&wl_output_interface,
|
||||
&wl_output_interface,
|
||||
&wl_pointer_interface,
|
||||
&wl_keyboard_interface,
|
||||
&wl_touch_interface,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_subsurface_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_surface_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_display_requests[] = {
|
||||
{ "sync", "n", wayland_types + 8 },
|
||||
{ "get_registry", "n", wayland_types + 9 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_display_events[] = {
|
||||
{ "error", "ous", wayland_types + 0 },
|
||||
{ "delete_id", "u", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_display_interface = {
|
||||
"wl_display", 1,
|
||||
2, wl_display_requests,
|
||||
2, wl_display_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_registry_requests[] = {
|
||||
{ "bind", "usun", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_registry_events[] = {
|
||||
{ "global", "usu", wayland_types + 0 },
|
||||
{ "global_remove", "u", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_registry_interface = {
|
||||
"wl_registry", 1,
|
||||
1, wl_registry_requests,
|
||||
2, wl_registry_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_callback_events[] = {
|
||||
{ "done", "u", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_callback_interface = {
|
||||
"wl_callback", 1,
|
||||
0, NULL,
|
||||
1, wl_callback_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_compositor_requests[] = {
|
||||
{ "create_surface", "n", wayland_types + 10 },
|
||||
{ "create_region", "n", wayland_types + 11 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_compositor_interface = {
|
||||
"wl_compositor", 6,
|
||||
2, wl_compositor_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_shm_pool_requests[] = {
|
||||
{ "create_buffer", "niiiiu", wayland_types + 12 },
|
||||
{ "destroy", "", wayland_types + 0 },
|
||||
{ "resize", "i", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_shm_pool_interface = {
|
||||
"wl_shm_pool", 1,
|
||||
3, wl_shm_pool_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_shm_requests[] = {
|
||||
{ "create_pool", "nhi", wayland_types + 18 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_shm_events[] = {
|
||||
{ "format", "u", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_shm_interface = {
|
||||
"wl_shm", 1,
|
||||
1, wl_shm_requests,
|
||||
1, wl_shm_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_buffer_requests[] = {
|
||||
{ "destroy", "", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_buffer_events[] = {
|
||||
{ "release", "", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_buffer_interface = {
|
||||
"wl_buffer", 1,
|
||||
1, wl_buffer_requests,
|
||||
1, wl_buffer_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_data_offer_requests[] = {
|
||||
{ "accept", "u?s", wayland_types + 0 },
|
||||
{ "receive", "sh", wayland_types + 0 },
|
||||
{ "destroy", "", wayland_types + 0 },
|
||||
{ "finish", "3", wayland_types + 0 },
|
||||
{ "set_actions", "3uu", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_data_offer_events[] = {
|
||||
{ "offer", "s", wayland_types + 0 },
|
||||
{ "source_actions", "3u", wayland_types + 0 },
|
||||
{ "action", "3u", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_data_offer_interface = {
|
||||
"wl_data_offer", 3,
|
||||
5, wl_data_offer_requests,
|
||||
3, wl_data_offer_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_data_source_requests[] = {
|
||||
{ "offer", "s", wayland_types + 0 },
|
||||
{ "destroy", "", wayland_types + 0 },
|
||||
{ "set_actions", "3u", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_data_source_events[] = {
|
||||
{ "target", "?s", wayland_types + 0 },
|
||||
{ "send", "sh", wayland_types + 0 },
|
||||
{ "cancelled", "", wayland_types + 0 },
|
||||
{ "dnd_drop_performed", "3", wayland_types + 0 },
|
||||
{ "dnd_finished", "3", wayland_types + 0 },
|
||||
{ "action", "3u", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_data_source_interface = {
|
||||
"wl_data_source", 3,
|
||||
3, wl_data_source_requests,
|
||||
6, wl_data_source_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_data_device_requests[] = {
|
||||
{ "start_drag", "?oo?ou", wayland_types + 21 },
|
||||
{ "set_selection", "?ou", wayland_types + 25 },
|
||||
{ "release", "2", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_data_device_events[] = {
|
||||
{ "data_offer", "n", wayland_types + 27 },
|
||||
{ "enter", "uoff?o", wayland_types + 28 },
|
||||
{ "leave", "", wayland_types + 0 },
|
||||
{ "motion", "uff", wayland_types + 0 },
|
||||
{ "drop", "", wayland_types + 0 },
|
||||
{ "selection", "?o", wayland_types + 33 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_data_device_interface = {
|
||||
"wl_data_device", 3,
|
||||
3, wl_data_device_requests,
|
||||
6, wl_data_device_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_data_device_manager_requests[] = {
|
||||
{ "create_data_source", "n", wayland_types + 34 },
|
||||
{ "get_data_device", "no", wayland_types + 35 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_data_device_manager_interface = {
|
||||
"wl_data_device_manager", 3,
|
||||
2, wl_data_device_manager_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_shell_requests[] = {
|
||||
{ "get_shell_surface", "no", wayland_types + 37 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_shell_interface = {
|
||||
"wl_shell", 1,
|
||||
1, wl_shell_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_shell_surface_requests[] = {
|
||||
{ "pong", "u", wayland_types + 0 },
|
||||
{ "move", "ou", wayland_types + 39 },
|
||||
{ "resize", "ouu", wayland_types + 41 },
|
||||
{ "set_toplevel", "", wayland_types + 0 },
|
||||
{ "set_transient", "oiiu", wayland_types + 44 },
|
||||
{ "set_fullscreen", "uu?o", wayland_types + 48 },
|
||||
{ "set_popup", "ouoiiu", wayland_types + 51 },
|
||||
{ "set_maximized", "?o", wayland_types + 57 },
|
||||
{ "set_title", "s", wayland_types + 0 },
|
||||
{ "set_class", "s", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_shell_surface_events[] = {
|
||||
{ "ping", "u", wayland_types + 0 },
|
||||
{ "configure", "uii", wayland_types + 0 },
|
||||
{ "popup_done", "", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_shell_surface_interface = {
|
||||
"wl_shell_surface", 1,
|
||||
10, wl_shell_surface_requests,
|
||||
3, wl_shell_surface_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_surface_requests[] = {
|
||||
{ "destroy", "", wayland_types + 0 },
|
||||
{ "attach", "?oii", wayland_types + 58 },
|
||||
{ "damage", "iiii", wayland_types + 0 },
|
||||
{ "frame", "n", wayland_types + 61 },
|
||||
{ "set_opaque_region", "?o", wayland_types + 62 },
|
||||
{ "set_input_region", "?o", wayland_types + 63 },
|
||||
{ "commit", "", wayland_types + 0 },
|
||||
{ "set_buffer_transform", "2i", wayland_types + 0 },
|
||||
{ "set_buffer_scale", "3i", wayland_types + 0 },
|
||||
{ "damage_buffer", "4iiii", wayland_types + 0 },
|
||||
{ "offset", "5ii", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_surface_events[] = {
|
||||
{ "enter", "o", wayland_types + 64 },
|
||||
{ "leave", "o", wayland_types + 65 },
|
||||
{ "preferred_buffer_scale", "6i", wayland_types + 0 },
|
||||
{ "preferred_buffer_transform", "6u", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_surface_interface = {
|
||||
"wl_surface", 6,
|
||||
11, wl_surface_requests,
|
||||
4, wl_surface_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_seat_requests[] = {
|
||||
{ "get_pointer", "n", wayland_types + 66 },
|
||||
{ "get_keyboard", "n", wayland_types + 67 },
|
||||
{ "get_touch", "n", wayland_types + 68 },
|
||||
{ "release", "5", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_seat_events[] = {
|
||||
{ "capabilities", "u", wayland_types + 0 },
|
||||
{ "name", "2s", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_seat_interface = {
|
||||
"wl_seat", 9,
|
||||
4, wl_seat_requests,
|
||||
2, wl_seat_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_pointer_requests[] = {
|
||||
{ "set_cursor", "u?oii", wayland_types + 69 },
|
||||
{ "release", "3", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_pointer_events[] = {
|
||||
{ "enter", "uoff", wayland_types + 73 },
|
||||
{ "leave", "uo", wayland_types + 77 },
|
||||
{ "motion", "uff", wayland_types + 0 },
|
||||
{ "button", "uuuu", wayland_types + 0 },
|
||||
{ "axis", "uuf", wayland_types + 0 },
|
||||
{ "frame", "5", wayland_types + 0 },
|
||||
{ "axis_source", "5u", wayland_types + 0 },
|
||||
{ "axis_stop", "5uu", wayland_types + 0 },
|
||||
{ "axis_discrete", "5ui", wayland_types + 0 },
|
||||
{ "axis_value120", "8ui", wayland_types + 0 },
|
||||
{ "axis_relative_direction", "9uu", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_pointer_interface = {
|
||||
"wl_pointer", 9,
|
||||
2, wl_pointer_requests,
|
||||
11, wl_pointer_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_keyboard_requests[] = {
|
||||
{ "release", "3", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_keyboard_events[] = {
|
||||
{ "keymap", "uhu", wayland_types + 0 },
|
||||
{ "enter", "uoa", wayland_types + 79 },
|
||||
{ "leave", "uo", wayland_types + 82 },
|
||||
{ "key", "uuuu", wayland_types + 0 },
|
||||
{ "modifiers", "uuuuu", wayland_types + 0 },
|
||||
{ "repeat_info", "4ii", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_keyboard_interface = {
|
||||
"wl_keyboard", 9,
|
||||
1, wl_keyboard_requests,
|
||||
6, wl_keyboard_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_touch_requests[] = {
|
||||
{ "release", "3", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_touch_events[] = {
|
||||
{ "down", "uuoiff", wayland_types + 84 },
|
||||
{ "up", "uui", wayland_types + 0 },
|
||||
{ "motion", "uiff", wayland_types + 0 },
|
||||
{ "frame", "", wayland_types + 0 },
|
||||
{ "cancel", "", wayland_types + 0 },
|
||||
{ "shape", "6iff", wayland_types + 0 },
|
||||
{ "orientation", "6if", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_touch_interface = {
|
||||
"wl_touch", 9,
|
||||
1, wl_touch_requests,
|
||||
7, wl_touch_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_output_requests[] = {
|
||||
{ "release", "3", wayland_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message wl_output_events[] = {
|
||||
{ "geometry", "iiiiissi", wayland_types + 0 },
|
||||
{ "mode", "uiii", wayland_types + 0 },
|
||||
{ "done", "2", wayland_types + 0 },
|
||||
{ "scale", "2i", wayland_types + 0 },
|
||||
{ "name", "4s", wayland_types + 0 },
|
||||
{ "description", "4s", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_output_interface = {
|
||||
"wl_output", 4,
|
||||
1, wl_output_requests,
|
||||
6, wl_output_events,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_region_requests[] = {
|
||||
{ "destroy", "", wayland_types + 0 },
|
||||
{ "add", "iiii", wayland_types + 0 },
|
||||
{ "subtract", "iiii", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_region_interface = {
|
||||
"wl_region", 1,
|
||||
3, wl_region_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_subcompositor_requests[] = {
|
||||
{ "destroy", "", wayland_types + 0 },
|
||||
{ "get_subsurface", "noo", wayland_types + 90 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_subcompositor_interface = {
|
||||
"wl_subcompositor", 1,
|
||||
2, wl_subcompositor_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message wl_subsurface_requests[] = {
|
||||
{ "destroy", "", wayland_types + 0 },
|
||||
{ "set_position", "ii", wayland_types + 0 },
|
||||
{ "place_above", "o", wayland_types + 93 },
|
||||
{ "place_below", "o", wayland_types + 94 },
|
||||
{ "set_sync", "", wayland_types + 0 },
|
||||
{ "set_desync", "", wayland_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wl_subsurface_interface = {
|
||||
"wl_subsurface", 1,
|
||||
6, wl_subsurface_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,85 +0,0 @@
|
|||
/* Generated by wayland-scanner 1.23.1 */
|
||||
|
||||
/*
|
||||
* Copyright © 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
|
||||
* Copyright © 2020 Carlos Garnacho <carlosg@gnome.org>
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_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,
|
||||
};
|
||||
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#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
|
||||
* <pre>
|
||||
*
|
||||
* Copyright © 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
|
||||
* Copyright © 2020 Carlos Garnacho <carlosg@gnome.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
* </pre>
|
||||
*/
|
||||
struct wl_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
|
||||
|
|
@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface xdg_toplevel_interface;
|
||||
extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
|
||||
|
||||
static const struct wl_interface *xdg_decoration_unstable_v1_types[] = {
|
||||
NULL,
|
||||
&zxdg_toplevel_decoration_v1_interface,
|
||||
&xdg_toplevel_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_decoration_manager_v1_requests[] = {
|
||||
{ "destroy", "", xdg_decoration_unstable_v1_types + 0 },
|
||||
{ "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = {
|
||||
"zxdg_decoration_manager_v1", 1,
|
||||
2, zxdg_decoration_manager_v1_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = {
|
||||
{ "destroy", "", xdg_decoration_unstable_v1_types + 0 },
|
||||
{ "set_mode", "u", xdg_decoration_unstable_v1_types + 0 },
|
||||
{ "unset_mode", "", xdg_decoration_unstable_v1_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_toplevel_decoration_v1_events[] = {
|
||||
{ "configure", "u", xdg_decoration_unstable_v1_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = {
|
||||
"zxdg_toplevel_decoration_v1", 1,
|
||||
3, zxdg_toplevel_decoration_v1_requests,
|
||||
1, zxdg_toplevel_decoration_v1_events,
|
||||
};
|
||||
|
||||
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol
|
||||
* @section page_ifaces_xdg_decoration_unstable_v1 Interfaces
|
||||
* - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager
|
||||
* - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface
|
||||
* @section page_copyright_xdg_decoration_unstable_v1 Copyright
|
||||
* <pre>
|
||||
*
|
||||
* Copyright © 2018 Simon Ser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
* </pre>
|
||||
*/
|
||||
struct xdg_toplevel;
|
||||
struct zxdg_decoration_manager_v1;
|
||||
struct zxdg_toplevel_decoration_v1;
|
||||
|
||||
#ifndef ZXDG_DECORATION_MANAGER_V1_INTERFACE
|
||||
#define ZXDG_DECORATION_MANAGER_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1
|
||||
* @section page_iface_zxdg_decoration_manager_v1_desc Description
|
||||
*
|
||||
* This interface allows a compositor to announce support for server-side
|
||||
* decorations.
|
||||
*
|
||||
* A window decoration is a set of window controls as deemed appropriate by
|
||||
* the party managing them, such as user interface components used to move,
|
||||
* resize and change a window's state.
|
||||
*
|
||||
* A client can use this protocol to request being decorated by a supporting
|
||||
* compositor.
|
||||
*
|
||||
* If compositor and client do not negotiate the use of a server-side
|
||||
* decoration using this protocol, clients continue to self-decorate as they
|
||||
* see fit.
|
||||
*
|
||||
* Warning! The protocol described in this file is experimental and
|
||||
* backward incompatible changes may be made. Backward compatible changes
|
||||
* may be added together with the corresponding interface version bump.
|
||||
* Backward incompatible changes are done by bumping the version number in
|
||||
* the protocol and interface names and resetting the interface version.
|
||||
* Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
* version number in the protocol and interface names are removed and the
|
||||
* interface version number is reset.
|
||||
* @section page_iface_zxdg_decoration_manager_v1_api API
|
||||
* See @ref iface_zxdg_decoration_manager_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface
|
||||
*
|
||||
* This interface allows a compositor to announce support for server-side
|
||||
* decorations.
|
||||
*
|
||||
* A window decoration is a set of window controls as deemed appropriate by
|
||||
* the party managing them, such as user interface components used to move,
|
||||
* resize and change a window's state.
|
||||
*
|
||||
* A client can use this protocol to request being decorated by a supporting
|
||||
* compositor.
|
||||
*
|
||||
* If compositor and client do not negotiate the use of a server-side
|
||||
* decoration using this protocol, clients continue to self-decorate as they
|
||||
* see fit.
|
||||
*
|
||||
* Warning! The protocol described in this file is experimental and
|
||||
* backward incompatible changes may be made. Backward compatible changes
|
||||
* may be added together with the corresponding interface version bump.
|
||||
* Backward incompatible changes are done by bumping the version number in
|
||||
* the protocol and interface names and resetting the interface version.
|
||||
* Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
* version number in the protocol and interface names are removed and the
|
||||
* interface version number is reset.
|
||||
*/
|
||||
extern const struct wl_interface zxdg_decoration_manager_v1_interface;
|
||||
#endif
|
||||
#ifndef ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE
|
||||
/**
|
||||
* @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1
|
||||
* @section page_iface_zxdg_toplevel_decoration_v1_desc Description
|
||||
*
|
||||
* The decoration object allows the compositor to toggle server-side window
|
||||
* decorations for a toplevel surface. The client can request to switch to
|
||||
* another mode.
|
||||
*
|
||||
* The xdg_toplevel_decoration object must be destroyed before its
|
||||
* xdg_toplevel.
|
||||
* @section page_iface_zxdg_toplevel_decoration_v1_api API
|
||||
* See @ref iface_zxdg_toplevel_decoration_v1.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface
|
||||
*
|
||||
* The decoration object allows the compositor to toggle server-side window
|
||||
* decorations for a toplevel surface. The client can request to switch to
|
||||
* another mode.
|
||||
*
|
||||
* The xdg_toplevel_decoration object must be destroyed before its
|
||||
* xdg_toplevel.
|
||||
*/
|
||||
extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
|
||||
#endif
|
||||
|
||||
#define ZXDG_DECORATION_MANAGER_V1_DESTROY 0
|
||||
#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_decoration_manager_v1
|
||||
*/
|
||||
#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zxdg_decoration_manager_v1
|
||||
*/
|
||||
#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zxdg_decoration_manager_v1 */
|
||||
static inline void
|
||||
zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zxdg_decoration_manager_v1 */
|
||||
static inline void *
|
||||
zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_decoration_manager_v1
|
||||
*
|
||||
* Destroy the decoration manager. This doesn't destroy objects created
|
||||
* with the manager.
|
||||
*/
|
||||
static inline void
|
||||
zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1,
|
||||
ZXDG_DECORATION_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_decoration_manager_v1
|
||||
*
|
||||
* Create a new decoration object associated with the given toplevel.
|
||||
*
|
||||
* Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
|
||||
* buffer attached or committed is a client error, and any attempts by a
|
||||
* client to attach or manipulate a buffer prior to the first
|
||||
* xdg_toplevel_decoration.configure event must also be treated as
|
||||
* errors.
|
||||
*/
|
||||
static inline struct zxdg_toplevel_decoration_v1 *
|
||||
zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel)
|
||||
{
|
||||
struct wl_proxy *id;
|
||||
|
||||
id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1,
|
||||
ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), 0, NULL, toplevel);
|
||||
|
||||
return (struct zxdg_toplevel_decoration_v1 *) id;
|
||||
}
|
||||
|
||||
#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM
|
||||
enum zxdg_toplevel_decoration_v1_error {
|
||||
/**
|
||||
* xdg_toplevel has a buffer attached before configure
|
||||
*/
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0,
|
||||
/**
|
||||
* xdg_toplevel already has a decoration object
|
||||
*/
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1,
|
||||
/**
|
||||
* xdg_toplevel destroyed before the decoration object
|
||||
*/
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2,
|
||||
};
|
||||
#endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */
|
||||
|
||||
#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
* window decoration modes
|
||||
*
|
||||
* These values describe window decoration modes.
|
||||
*/
|
||||
enum zxdg_toplevel_decoration_v1_mode {
|
||||
/**
|
||||
* no server-side window decoration
|
||||
*/
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1,
|
||||
/**
|
||||
* server-side window decoration
|
||||
*/
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2,
|
||||
};
|
||||
#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
* @struct zxdg_toplevel_decoration_v1_listener
|
||||
*/
|
||||
struct zxdg_toplevel_decoration_v1_listener {
|
||||
/**
|
||||
* suggest a surface change
|
||||
*
|
||||
* The configure event asks the client to change its decoration
|
||||
* mode. The configured state should not be applied immediately.
|
||||
* Clients must send an ack_configure in response to this event.
|
||||
* See xdg_surface.configure and xdg_surface.ack_configure for
|
||||
* details.
|
||||
*
|
||||
* A configure event can be sent at any time. The specified mode
|
||||
* must be obeyed by the client.
|
||||
* @param mode the decoration mode
|
||||
*/
|
||||
void (*configure)(void *data,
|
||||
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
|
||||
uint32_t mode);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
*/
|
||||
static inline int
|
||||
zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
|
||||
const struct zxdg_toplevel_decoration_v1_listener *listener, void *data)
|
||||
{
|
||||
return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1,
|
||||
(void (**)(void)) listener, data);
|
||||
}
|
||||
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
*/
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
*/
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
*/
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
*/
|
||||
#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_zxdg_toplevel_decoration_v1 */
|
||||
static inline void
|
||||
zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_zxdg_toplevel_decoration_v1 */
|
||||
static inline void *
|
||||
zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
*
|
||||
* Switch back to a mode without any server-side decorations at the next
|
||||
* commit.
|
||||
*/
|
||||
static inline void
|
||||
zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
*
|
||||
* Set the toplevel surface decoration mode. This informs the compositor
|
||||
* that the client prefers the provided decoration mode.
|
||||
*
|
||||
* After requesting a decoration mode, the compositor will respond by
|
||||
* emitting an xdg_surface.configure event. The client should then update
|
||||
* its content, drawing it without decorations if the received mode is
|
||||
* server-side decorations. The client must also acknowledge the configure
|
||||
* when committing the new content (see xdg_surface.ack_configure).
|
||||
*
|
||||
* The compositor can decide not to use the client's mode and enforce a
|
||||
* different mode instead.
|
||||
*
|
||||
* Clients whose decoration mode depend on the xdg_toplevel state may send
|
||||
* a set_mode request in response to an xdg_surface.configure event and wait
|
||||
* for the next xdg_surface.configure event to prevent unwanted state.
|
||||
* Such clients are responsible for preventing configure loops and must
|
||||
* make sure not to send multiple successive set_mode requests with the
|
||||
* same decoration mode.
|
||||
*/
|
||||
static inline void
|
||||
zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_zxdg_toplevel_decoration_v1
|
||||
*
|
||||
* Unset the toplevel surface decoration mode. This informs the compositor
|
||||
* that the client doesn't prefer a particular decoration mode.
|
||||
*
|
||||
* This request has the same semantics as set_mode.
|
||||
*/
|
||||
static inline void
|
||||
zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
|
||||
{
|
||||
wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1,
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_output_interface;
|
||||
extern const struct wl_interface wl_seat_interface;
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
extern const struct wl_interface xdg_popup_interface;
|
||||
extern const struct wl_interface xdg_positioner_interface;
|
||||
extern const struct wl_interface xdg_surface_interface;
|
||||
extern const struct wl_interface xdg_toplevel_interface;
|
||||
|
||||
static const struct wl_interface *xdg_shell_types[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&xdg_positioner_interface,
|
||||
&xdg_surface_interface,
|
||||
&wl_surface_interface,
|
||||
&xdg_toplevel_interface,
|
||||
&xdg_popup_interface,
|
||||
&xdg_surface_interface,
|
||||
&xdg_positioner_interface,
|
||||
&xdg_toplevel_interface,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_output_interface,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
&xdg_positioner_interface,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_wm_base_requests[] = {
|
||||
{ "destroy", "", xdg_shell_types + 0 },
|
||||
{ "create_positioner", "n", xdg_shell_types + 4 },
|
||||
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
|
||||
{ "pong", "u", xdg_shell_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_wm_base_events[] = {
|
||||
{ "ping", "u", xdg_shell_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
|
||||
"xdg_wm_base", 6,
|
||||
4, xdg_wm_base_requests,
|
||||
1, xdg_wm_base_events,
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_positioner_requests[] = {
|
||||
{ "destroy", "", xdg_shell_types + 0 },
|
||||
{ "set_size", "ii", xdg_shell_types + 0 },
|
||||
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
|
||||
{ "set_anchor", "u", xdg_shell_types + 0 },
|
||||
{ "set_gravity", "u", xdg_shell_types + 0 },
|
||||
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
|
||||
{ "set_offset", "ii", xdg_shell_types + 0 },
|
||||
{ "set_reactive", "3", xdg_shell_types + 0 },
|
||||
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
|
||||
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
|
||||
"xdg_positioner", 6,
|
||||
10, xdg_positioner_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_surface_requests[] = {
|
||||
{ "destroy", "", xdg_shell_types + 0 },
|
||||
{ "get_toplevel", "n", xdg_shell_types + 7 },
|
||||
{ "get_popup", "n?oo", xdg_shell_types + 8 },
|
||||
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
|
||||
{ "ack_configure", "u", xdg_shell_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_surface_events[] = {
|
||||
{ "configure", "u", xdg_shell_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
|
||||
"xdg_surface", 6,
|
||||
5, xdg_surface_requests,
|
||||
1, xdg_surface_events,
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_toplevel_requests[] = {
|
||||
{ "destroy", "", xdg_shell_types + 0 },
|
||||
{ "set_parent", "?o", xdg_shell_types + 11 },
|
||||
{ "set_title", "s", xdg_shell_types + 0 },
|
||||
{ "set_app_id", "s", xdg_shell_types + 0 },
|
||||
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
|
||||
{ "move", "ou", xdg_shell_types + 16 },
|
||||
{ "resize", "ouu", xdg_shell_types + 18 },
|
||||
{ "set_max_size", "ii", xdg_shell_types + 0 },
|
||||
{ "set_min_size", "ii", xdg_shell_types + 0 },
|
||||
{ "set_maximized", "", xdg_shell_types + 0 },
|
||||
{ "unset_maximized", "", xdg_shell_types + 0 },
|
||||
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
|
||||
{ "unset_fullscreen", "", xdg_shell_types + 0 },
|
||||
{ "set_minimized", "", xdg_shell_types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_toplevel_events[] = {
|
||||
{ "configure", "iia", xdg_shell_types + 0 },
|
||||
{ "close", "", xdg_shell_types + 0 },
|
||||
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
|
||||
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
|
||||
"xdg_toplevel", 6,
|
||||
14, xdg_toplevel_requests,
|
||||
4, xdg_toplevel_events,
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_popup_requests[] = {
|
||||
{ "destroy", "", xdg_shell_types + 0 },
|
||||
{ "grab", "ou", xdg_shell_types + 22 },
|
||||
{ "reposition", "3ou", xdg_shell_types + 24 },
|
||||
};
|
||||
|
||||
static const struct wl_message xdg_popup_events[] = {
|
||||
{ "configure", "iiii", xdg_shell_types + 0 },
|
||||
{ "popup_done", "", xdg_shell_types + 0 },
|
||||
{ "repositioned", "3u", xdg_shell_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
|
||||
"xdg_popup", 6,
|
||||
3, xdg_popup_requests,
|
||||
3, xdg_popup_events,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
1266
src/apprt/glfw.zig
1266
src/apprt/glfw.zig
File diff suppressed because it is too large
Load Diff
|
|
@ -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 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
) },
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
@ -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"<cannot eval: {type(node).__name__}>"
|
||||
|
||||
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")
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue