Commit080e1c1bRecorded20 Sep 2026Repositorysigil-app

Rename to sigil-desktop 0.10.0: (sigil desktop), a C surface, a Guix+Nix resolver

Message

The package is sigil-desktop, the library (sigil desktop); (sigil app) stays for this release as a plain re-export and goes in 0.11. app.c is desktop.c ((sigil desktop), SIGIL_DESKTOP_ variables, sigil-desktop: log prefix); vendor/sokol and the sapp_ compatibility file are gone, nothing sokol remains here.

include/sigil-desktop.h gives sibling packages the framebuffer size, a GL proc loader (glfwGetProcAddress) and the platform name; sigil-graphics 0.11.4 builds its swapchain and GL loader on it and stops linking libGL.

dl-search.c is table-driven and walks every row on every machine (Guix and Nix coexist): SIGIL_LIBRARY_PATH, then the active environment ($GUIX_ENVIRONMENT/lib, nix-shell's buildInputs and nativeBuildInputs each + /lib under IN_NIX_SHELL, $NIX_LD_LIBRARY_PATH), then the user profiles (~/.guix-home/profile/lib, ~/.guix-profile/lib, ~/.nix-profile/lib, /etc/profiles/per-user/$USER/lib), then the system ones (/run/current-system/profile/lib, /run/current-system/sw/lib). First hit wins; the trace names the row and whether /gnu/store and /nix/store exist. test/dl-search-test.sh proves it against fake Guix and Nix profiles in a temp HOME (and went red when two rows were swapped).

README (new) and the 0.10.0 CHANGELOG entry.

Changed
 CHANGELOG.md                                 |    65 +
 README.md                                    |   103 ++
 include/sigil-desktop.h                      |    34 +
 package.sgl                                  |    49 +-
 src/c/{app-internal.h => desktop-internal.h} |    45 +-
 src/c/{app.c => desktop.c}                   |   285 +--
 src/c/dl-search.c                            |   190 +-
 src/c/sokol-compat.c                         |    60 -
 src/sigil/app.sgl                            |    92 +-
 src/sigil/desktop.sgl                        |    93 +
 test/dl-search-probe.c                       |    23 +
 test/dl-search-test.sh                       |    56 +
 vendor/sokol/sokol_app.h                     | 14047 -------------------------------------------------------------------------------------------------------------------------------------------------
 vendor/sokol/sokol_log.h                     |   334 ----
 vendor/sokol/sokol_time.h                    |   319 ----
 15 files changed, 727 insertions(+), 15068 deletions(-)
Diff
CHANGELOG.mdmodified
@@ -7,6 +7,71 @@ All notable changes to this project will be documented in this file.
7
The format is based on [Keep a Changelog](https://keepachangelog.com/),
8
and this project adheres to [Semantic Versioning](https://semver.org/).
9
+10
## [0.10.0] - unreleased
+11
+12
The package is now **sigil-desktop**, and the window is GLFW instead of
+13
sokol_app.
+14
+15
### Changed
+16
+17
- **Native Wayland on Linux.** GLFW 3.5.1 is vendored as source under
+18
`vendor/glfw` (no local patches, `VENDOR.md` has the pin and inventory).
+19
One binary runs as a Wayland client or under X11, picked at startup;
+20
`SIGIL_DESKTOP_PLATFORM=wayland|x11` forces it. Under sokol_app the
+21
Linux window was always X11 (XWayland on a Wayland desktop).
+22
- **No platform libraries linked.** GLFW loads libwayland-client,
+23
libxkbcommon, libX11 and friends, libEGL and libGL at run time; the
+24
Linux `link-flags` are empty (were `-lX11 -lXi -lXcursor`). A game's
+25
NEEDED list loses those three.
+26
- **Framebuffer pixels follow the output scale.** On a Wayland output at
+27
scale 2 a window asked for at 800x600 has a 1600x1200 framebuffer;
+28
`frame-width`/`frame-height` report it and `mouse-x`/`mouse-y` are in the
+29
same pixels. Fractional scales work. A program with hard-coded pixel
+30
coordinates should lay out from `frame-width` and `frame-height`. On X11
+31
nothing changes.
+32
- The library is `(sigil desktop)`. `(sigil app)` remains as a re-export
+33
for this release only.
+34
- `app-run` raises `app-run: could not open a window` (exit 1) when no
+35
display platform or GL context is available; sokol_app aborted.
+36
- `(quit-requested?)` answers `#t` inside the frame the close button was
+37
pressed in, not only in cleanup.
+38
- The frame clock restarts after the init procedure, so a long asset load
+39
is not the first frame's delta time.
+40
- GL 4.3 core is requested on Linux and Windows and 4.1 on macOS, as
+41
before; the window has no default icon (sokol_app drew one).
+42
+43
### Added
+44
+45
- `include/sigil-desktop.h`: `sigil_desktop_framebuffer_size`,
+46
`sigil_desktop_gl_get_proc_address`, `sigil_desktop_platform`, the C
+47
surface sigil-graphics builds its swapchain and GL loader on.
+48
- `src/c/dl-search.c`: a `dlopen` that finds runtime libraries in Guix and
+49
Nix profile directories (`SIGIL_LIBRARY_PATH`, `$GUIX_ENVIRONMENT/lib`,
+50
nix-shell inputs, `$NIX_LD_LIBRARY_PATH`, the user and system profiles),
+51
with `test/dl-search-test.sh`.
+52
- `guix/run-wayland.scm`, `guix/run-x11.scm`, `guix/build.scm`.
+53
- `SIGIL_DESKTOP_VERBOSE=1` for startup, resize and library-resolution
+54
diagnostics.
+55
+56
### Removed
+57
+58
- `vendor/sokol` (sokol_app, sokol_time, sokol_log) and the `sapp_*`
+59
symbols. sigil-graphics 0.11.4 no longer links them.
+60
+61
### Requires
+62
+63
- Sigil 0.20+ as before. Building on Guix needs the X11 and Wayland headers
+64
in `guix/build.scm` (libx11, libxcursor, libxrandr, libxinerama, libxi,
+65
libxext, xorgproto, wayland, libxkbcommon).
+66
+67
### Upgrade notes
+68
+69
- Relock to `^0.10.0`, delete the consumer's `build/` once (a stale
+70
`sokol-app.o` otherwise stays in the archive), then rename `(sigil app)`
+71
imports to `(sigil desktop)` before 0.11.
+72
- The Codeberg repository is renamed `sigil/sigil-app` to
+73
`sigil/sigil-desktop`; the old URL redirects.
+74
75
## [0.9.0] - 2026-06-25
76
77
### Changed
README.mdadded
@@ -0,0 +1,103 @@
+1
# sigil-desktop
+2
+3
The desktop host layer for Sigil games and interactive programs: a window
+4
with an OpenGL context, keyboard and mouse state, a frame clock, and a
+5
quit request, behind the `(sigil desktop)` library. Drawing is
+6
[sigil-graphics](https://codeberg.org/sigil/sigil-graphics), which builds
+7
on this package; sound is
+8
[sigil-audio](https://codeberg.org/sigil/sigil-audio).
+9
+10
The window comes from [GLFW](https://www.glfw.org) 3.5.1, vendored as
+11
source under `vendor/glfw` (no local patches; see `vendor/glfw/VENDOR.md`).
+12
On Linux one binary runs as a native Wayland client or under X11, picked
+13
when the program starts; on Windows it is a Win32 window; the macOS files
+14
are vendored and not yet built. Every platform library (libwayland-client,
+15
libxkbcommon, libX11, libEGL, libGL, ...) is loaded at run time by GLFW,
+16
so a game links none of them.
+17
+18
This package was `sigil-app` through 0.9.x, when the window was sokol_app
+19
(X11 only on Linux). The `(sigil app)` library still exists in 0.10 as a
+20
re-export of `(sigil desktop)` so a consumer can relock first and rename
+21
its imports second; it goes away in 0.11.
+22
+23
## Use
+24
+25
```scheme
+26
(import (sigil desktop) (sigil graphics))
+27
+28
(define (game)
+29
(gfx-setup)
+30
(let loop ()
+31
(let ((dt (wait-frame)))
+32
(begin-frame)
+33
(clear-screen 0.0 0.0 0.0)
+34
;; draw with (frame-width) x (frame-height) pixels to work with
+35
(end-frame)
+36
(cond ((key-pressed? 'escape) (request-quit))
+37
((quit-requested?) #t)
+38
(else (loop)))))
+39
(gfx-shutdown))
+40
+41
(run-game "My Game" 960 720 game)
+42
```
+43
+44
`run-game` runs the thunk in a coroutine; `(wait-frame)` yields to the
+45
host and returns the frame's delta time in seconds when the next frame
+46
starts. Below it, `app-run` takes init, frame and cleanup procedures
+47
directly.
+48
+49
The exports: `app-run`, `run-game`, `wait-frame`, `frame-width`,
+50
`frame-height`, `frame-time`, `time-elapsed`, `mouse-x`, `mouse-y`,
+51
`mouse-down?`, `mouse-pressed?`, `mouse-released?`, `key-down?`,
+52
`key-pressed?`, `key-released?`, `quit-requested?`, `request-quit`.
+53
+54
Sizes and positions are framebuffer pixels: on a scaled Wayland output a
+55
window asked for at 960x720 has a framebuffer of 1920x1440 at scale 2 (or
+56
1440x1080 at 1.5), `frame-width` says so, and `mouse-x`/`mouse-y` are in
+57
the same pixels. Key symbols: `a`..`z`, `0`..`9`, `space`, `return` (or
+58
`enter`), `escape` (or `esc`), `tab`, `backspace`, `left`, `right`, `up`,
+59
`down`, `shift`, `ctrl` (or `control`), `alt`. Mouse buttons: `left`,
+60
`right`, `middle`. `key-pressed?` is true for the one frame after the key
+61
went down (a held key repeating does not re-fire it); `key-down?` reports
+62
the state after that frame's events.
+63
+64
## Environment
+65
+66
- `SIGIL_DESKTOP_PLATFORM=wayland|x11|win32|cocoa` forces the platform.
+67
Otherwise GLFW follows `XDG_SESSION_TYPE` and `WAYLAND_DISPLAY`/`DISPLAY`,
+68
trying Wayland before X11.
+69
- `SIGIL_DESKTOP_VERBOSE=1` prints the platform, window and framebuffer
+70
sizes and content scale on startup and on every resize, and which
+71
directory each runtime library was found in when the loader needed help.
+72
- `SIGIL_LIBRARY_PATH=dir:dir` adds directories the runtime loader looks in
+73
for the platform libraries (see below).
+74
+75
## Guix and Nix
+76
+77
GLFW loads its platform libraries by bare soname, and on Guix and Nix a
+78
profile's `lib/` is on no default loader path. `src/c/dl-search.c`
+79
defines `dlopen` in the executable: it tries the name as the loader would,
+80
and only when that fails looks under, in order, `SIGIL_LIBRARY_PATH`,
+81
`$GUIX_ENVIRONMENT/lib`, `$buildInputs`/`$nativeBuildInputs` (each `/lib`,
+82
inside a nix-shell), `$NIX_LD_LIBRARY_PATH`, `~/.guix-home/profile/lib`,
+83
`~/.guix-profile/lib`, `~/.nix-profile/lib`,
+84
`/etc/profiles/per-user/$USER/lib`, `/run/current-system/profile/lib`,
+85
`/run/current-system/sw/lib`. Every row is walked on every machine (Guix
+86
and Nix can coexist); the first hit wins and `SIGIL_DESKTOP_VERBOSE` says
+87
which. `test/dl-search-test.sh` exercises it against fake profiles.
+88
+89
Manifests under `guix/`: `run-wayland.scm` (mesa, wayland, libxkbcommon)
+90
and `run-x11.scm` (mesa, libx11) are what a game needs at run time;
+91
`build.scm` is the headers a build needs. Keep `libglvnd` out of a run
+92
manifest: Guix's mesa is built without it and a vendorless `libGLX.so.0`
+93
breaks GLX.
+94
+95
## Building
+96
+97
```sh
+98
guix shell -m guix/build.scm -- sh -c 'CPATH=$GUIX_ENVIRONMENT/include sigil build'
+99
sigil build --config windows-amd64 # cross, through zig
+100
```
+101
+102
The C surface other packages use is `include/sigil-desktop.h`
+103
(framebuffer size, GL proc loader, platform name).
include/sigil-desktop.hadded
@@ -0,0 +1,34 @@
+1
/*
+2
* sigil-desktop.h - the C surface of sigil-desktop for sibling packages
+3
*
+4
* sigil-graphics builds its sokol_gfx environment and swapchain from
+5
* these, and loads GL through the proc loader instead of linking libGL.
+6
* Everything here is valid only while app-run is running (between the
+7
* init callback and the cleanup callback).
+8
*/
+9
+10
#ifndef SIGIL_DESKTOP_H
+11
#define SIGIL_DESKTOP_H
+12
+13
#ifdef __cplusplus
+14
extern "C" {
+15
#endif
+16
+17
/* The window's framebuffer size in pixels: what GL draws into and what
+18
* frame-width / frame-height report. 1x1 before the window exists. */
+19
void sigil_desktop_framebuffer_size(int *width, int *height);
+20
+21
/* The address of a GL or GL extension function for the current context
+22
* (glfwGetProcAddress), or NULL. Valid once the window exists; GL is
+23
* loaded by GLFW at run time, nothing links it. */
+24
void *sigil_desktop_gl_get_proc_address(const char *name);
+25
+26
/* The platform GLFW picked: "wayland", "x11", "win32", "cocoa", or
+27
* "none" before app-run. */
+28
const char *sigil_desktop_platform(void);
+29
+30
#ifdef __cplusplus
+31
}
+32
#endif
+33
+34
#endif /* SIGIL_DESKTOP_H */
package.sglmodified
@@ -1,4 +1,6 @@
−1
;;; sigil-app - Desktop host layer for Sigil
+1
;;; sigil-desktop - Desktop host layer for Sigil (window, GL context, input,
+2
;;; frame clock, quit). Named sigil-app through 0.9.x, when it wrapped
+3
;;; sokol_app.
4
;;;
5
;;; Window, GL context, input, frame clock and quit for interactive
6
;;; applications, over GLFW (vendored under vendor/glfw). On Linux one
@@ -68,15 +70,15 @@
70
(else '())))
71
72
;; dl-search.c interposes dlopen so GLFW's runtime loading finds libraries
−71
;; in Guix profile directories; it is Linux-only by design (see the file).
−72
(define (app-sources os)
−73
(append '("src/c/app.c" "src/c/sokol-compat.c")
+73
;; in Guix and Nix profile directories; Linux-only by design (see the file).
+74
(define (desktop-sources os)
+75
(append '("src/c/desktop.c")
76
(if (eq? os 'linux) '("src/c/dl-search.c") '())))
77
−76
(define app-include-dirs
−77
'("vendor/glfw/include" "vendor/sokol" "src/c"))
+78
(define desktop-include-dirs
+79
'("include" "vendor/glfw/include"))
80
−79
(define app-flags
+81
(define desktop-flags
82
'("-std=c99" "-D_GNU_SOURCE" "-Wno-unused-parameter"))
83
84
;; GLFW's own warning set is -Wall; its sources are compiled as they
@@ -95,11 +97,11 @@
97
;; defines follow the config's target rather than the host (the same
98
;; reason link-flags below is a lambda). Both steps register their
99
;; objects on the context; create-static-library archives them all.
−98
(define (compile-app ctx)
+100
(define (compile-desktop ctx)
101
((compile-c-sources
−100
sources: (app-sources (target-os ctx))
−101
include-dirs: app-include-dirs
−102
flags: (with-sigil-c-flags app-flags))
+102
sources: (desktop-sources (target-os ctx))
+103
include-dirs: desktop-include-dirs
+104
flags: (with-sigil-c-flags desktop-flags))
105
ctx))
106
107
(define (compile-glfw ctx)
@@ -111,11 +113,14 @@
113
ctx)))
114
115
(package
−114
name: "sigil-app"
−115
version: "0.9.0"
+116
name: "sigil-desktop"
+117
version: "0.10.0"
118
sigil: "0.20"
119
description: "Desktop host layer for Sigil (window, GL context, input, frame clock) over GLFW"
−118
url: "https://codeberg.org/sigil/sigil-app"
+120
;; The repository is being renamed sigil/sigil-app -> sigil/sigil-desktop on
+121
;; Codeberg (in place; the old name redirects). Until then consumers keep
+122
;; from-git url: "codeberg:sigil/sigil-app".
+123
url: "https://codeberg.org/sigil/sigil-desktop"
124
license: "BSD-3-Clause"
125
authors: (list "David Wilson <david@daviwil.com>")
126
@@ -149,14 +154,14 @@
154
155
libraries: (list
156
(library
−152
name: 'sigil-app
+157
name: 'sigil-desktop
158
;; sigil-build reads this list only as a "has native code" test and
159
;; for the include dirs; the build task below compiles the real,
−155
;; target-dependent list (these two plus dl-search.c on Linux plus
+160
;; target-dependent list (this plus dl-search.c on Linux plus
161
;; the GLFW backend files). Keep it to files every target compiles.
−157
c-sources: '("src/c/app.c" "src/c/sokol-compat.c")
−158
c-include-dirs: '("vendor/glfw/include" "vendor/sokol" "src/c")
−159
native-init: "sigil__init_sigil_app_module"
+162
c-sources: '("src/c/desktop.c")
+163
c-include-dirs: '("include" "vendor/glfw/include")
+164
native-init: "sigil__init_sigil_desktop_module"
165
;; Platform linker flags.
166
;;
167
;; Linux: none. GLFW dlopens libwayland-client, libwayland-egl,
@@ -181,10 +186,10 @@
186
tasks: (list
187
(task
188
name: 'build
−184
description: "Build sigil-app"
+189
description: "Build sigil-desktop"
190
steps: (list
−186
compile-app
+191
compile-desktop
192
compile-glfw
−188
(create-static-library name: "sigil-app")
+193
(create-static-library name: "sigil-desktop")
194
(compile-sigil-modules sources: "src/**/*.sgl"
195
output-dir: (config-output-subdir "lib"))))))
src/c/app-internal.h → src/c/desktop-internal.hrenamed
@@ -1,5 +1,5 @@
1
/*
−2
* app-internal.h - Internal header for the Sigil desktop host layer
+2
* desktop-internal.h - Internal header for the Sigil desktop host layer
3
*
4
* Application state for the window, GL context, input, frame clock and
5
* quit handling. The host is GLFW (vendored under vendor/glfw); the
@@ -7,16 +7,16 @@
7
* and every platform library is loaded at runtime by GLFW itself.
8
*/
9
−10
#ifndef SIGIL_APP_INTERNAL_H
−11
#define SIGIL_APP_INTERNAL_H
+10
#ifndef SIGIL_DESKTOP_INTERNAL_H
+11
#define SIGIL_DESKTOP_INTERNAL_H
12
13
#include <sigil/sigil.h>
14
#include <stdbool.h>
15
16
/* GLFW_KEY_LAST is 348; sokol_app's table was 512 and the key symbols
17
* only ever map into the GLFW range, so the same size is kept. */
−18
#define SIGIL_APP_MAX_KEYS 512
−19
#define SIGIL_APP_MAX_MOUSE_BUTTONS 3
+18
#define SIGIL_DESKTOP_MAX_KEYS 512
+19
#define SIGIL_DESKTOP_MAX_MOUSE_BUTTONS 3
20
21
struct GLFWwindow;
22
@@ -49,13 +49,13 @@ typedef struct {
49
double time_elapsed; /* Seconds since app start */
50
51
/* Input state - current frame */
−52
bool keys_down[SIGIL_APP_MAX_KEYS];
−53
bool keys_pressed[SIGIL_APP_MAX_KEYS];
−54
bool keys_released[SIGIL_APP_MAX_KEYS];
+52
bool keys_down[SIGIL_DESKTOP_MAX_KEYS];
+53
bool keys_pressed[SIGIL_DESKTOP_MAX_KEYS];
+54
bool keys_released[SIGIL_DESKTOP_MAX_KEYS];
55
−56
bool mouse_buttons[SIGIL_APP_MAX_MOUSE_BUTTONS];
−57
bool mouse_pressed[SIGIL_APP_MAX_MOUSE_BUTTONS];
−58
bool mouse_released[SIGIL_APP_MAX_MOUSE_BUTTONS];
+56
bool mouse_buttons[SIGIL_DESKTOP_MAX_MOUSE_BUTTONS];
+57
bool mouse_pressed[SIGIL_DESKTOP_MAX_MOUSE_BUTTONS];
+58
bool mouse_released[SIGIL_DESKTOP_MAX_MOUSE_BUTTONS];
59
/* Cursor position in window (screen) units as GLFW reports it;
60
* mouse-x / mouse-y scale it into framebuffer pixels on read. */
61
double cursor_x;
@@ -63,27 +63,26 @@ typedef struct {
63
64
/* Quit handling */
65
bool quit_requested;
−66
} AppState;
+66
} DesktopState;
67
68
/* Global state - initialized by app module */
−69
extern AppState *g_app;
+69
extern DesktopState *g_desktop;
70
71
/* Initialize/shutdown app state */
−72
void sigil_app_state_init(SigilVM *vm);
−73
void sigil_app_state_shutdown(void);
+72
void sigil_desktop_state_init(SigilVM *vm);
+73
void sigil_desktop_state_shutdown(void);
74
75
/* Input handling helpers */
−76
void sigil_app_clear_frame_input(void);
−77
int sigil_app_key_code_from_symbol(SigilVM *vm, Value sym);
+76
void sigil_desktop_clear_frame_input(void);
+77
int sigil_desktop_key_code_from_symbol(SigilVM *vm, Value sym);
78
−79
/* Framebuffer size in pixels (1x1 before the window exists), for the
−80
* sokol_app compatibility shim in sokol-compat.c. */
−81
int sigil_app_framebuffer_width(void);
−82
int sigil_app_framebuffer_height(void);
+79
/* Framebuffer size in pixels (1x1 before the window exists). */
+80
int sigil_desktop_framebuffer_width(void);
+81
int sigil_desktop_framebuffer_height(void);
82
83
#if defined(__linux__)
84
/* dl-search.c: the directories the interposed dlopen falls back to. */
−86
const char *sigil_app_dlopen_search_summary(void);
+85
const char *sigil_desktop_dlopen_search_summary(void);
86
#endif
87
−89
#endif /* SIGIL_APP_INTERNAL_H */
+88
#endif /* SIGIL_DESKTOP_INTERNAL_H */
src/c/app.c → src/c/desktop.crenamed
@@ -1,5 +1,5 @@
1
/*
−2
* app.c - Sigil App Module
+2
* desktop.c - the (sigil desktop) module
3
*
4
* The desktop host layer: window, GL context, input, frame clock and quit,
5
* over GLFW (vendored under vendor/glfw). One binary runs as a native
@@ -7,11 +7,12 @@
7
* platform libraries (libwayland-client, libxkbcommon, libX11, libGL/EGL,
8
* ...) with dlopen, so nothing platform-specific is linked.
9
*
−10
* The exported Sigil API is the one sokol_app provided before: app-run,
+10
* The exported Sigil API is the one (sigil app) had over sokol_app: app-run,
11
* frame-*, mouse-*, key-*, quit-requested?, request-quit.
12
*/
13
−14
#include "app-internal.h"
+14
#include "desktop-internal.h"
+15
#include "sigil-desktop.h"
16
#include "sigil-internal.h"
17
18
/* No GL header: this layer never calls GL itself; sokol_gfx (in
@@ -24,54 +25,54 @@
25
#include <string.h>
26
27
/* Global app state */
−27
AppState *g_app = NULL;
+28
DesktopState *g_desktop = NULL;
29
30
/*
31
* Initialize app state
32
*/
−32
void sigil_app_state_init(SigilVM *vm)
+33
void sigil_desktop_state_init(SigilVM *vm)
34
{
−34
if (g_app) return;
+35
if (g_desktop) return;
36
−36
g_app = calloc(1, sizeof(AppState));
−37
g_app->vm = vm;
−38
g_app->init_callback = SIGIL_FALSE;
−39
g_app->frame_callback = SIGIL_FALSE;
−40
g_app->cleanup_callback = SIGIL_FALSE;
−41
g_app->fb_width = 1;
−42
g_app->fb_height = 1;
−43
g_app->win_width = 1;
−44
g_app->win_height = 1;
+37
g_desktop = calloc(1, sizeof(DesktopState));
+38
g_desktop->vm = vm;
+39
g_desktop->init_callback = SIGIL_FALSE;
+40
g_desktop->frame_callback = SIGIL_FALSE;
+41
g_desktop->cleanup_callback = SIGIL_FALSE;
+42
g_desktop->fb_width = 1;
+43
g_desktop->fb_height = 1;
+44
g_desktop->win_width = 1;
+45
g_desktop->win_height = 1;
46
}
47
−47
void sigil_app_state_shutdown(void)
+48
void sigil_desktop_state_shutdown(void)
49
{
−49
if (g_app) {
−50
free(g_app);
−51
g_app = NULL;
+50
if (g_desktop) {
+51
free(g_desktop);
+52
g_desktop = NULL;
53
}
54
}
55
56
/*
57
* Clear per-frame input state
58
*/
−58
void sigil_app_clear_frame_input(void)
+59
void sigil_desktop_clear_frame_input(void)
60
{
−60
if (!g_app) return;
−61
memset(g_app->keys_pressed, 0, sizeof(g_app->keys_pressed));
−62
memset(g_app->keys_released, 0, sizeof(g_app->keys_released));
−63
memset(g_app->mouse_pressed, 0, sizeof(g_app->mouse_pressed));
−64
memset(g_app->mouse_released, 0, sizeof(g_app->mouse_released));
+61
if (!g_desktop) return;
+62
memset(g_desktop->keys_pressed, 0, sizeof(g_desktop->keys_pressed));
+63
memset(g_desktop->keys_released, 0, sizeof(g_desktop->keys_released));
+64
memset(g_desktop->mouse_pressed, 0, sizeof(g_desktop->mouse_pressed));
+65
memset(g_desktop->mouse_released, 0, sizeof(g_desktop->mouse_released));
66
}
67
−67
int sigil_app_framebuffer_width(void)
+68
int sigil_desktop_framebuffer_width(void)
69
{
−69
return (g_app && g_app->fb_width > 0) ? g_app->fb_width : 1;
+70
return (g_desktop && g_desktop->fb_width > 0) ? g_desktop->fb_width : 1;
71
}
72
−72
int sigil_app_framebuffer_height(void)
+73
int sigil_desktop_framebuffer_height(void)
74
{
−74
return (g_app && g_app->fb_height > 0) ? g_app->fb_height : 1;
+75
return (g_desktop && g_desktop->fb_height > 0) ? g_desktop->fb_height : 1;
76
}
77
78
/*
@@ -80,7 +81,7 @@ int sigil_app_framebuffer_height(void)
81
* digits, space, return/enter, escape/esc, tab, backspace, the arrows,
82
* shift, ctrl/control, alt.
83
*/
−83
int sigil_app_key_code_from_symbol(SigilVM *vm, Value sym)
+84
int sigil_desktop_key_code_from_symbol(SigilVM *vm, Value sym)
85
{
86
(void)vm;
87
if (!sigil_is_symbol(sym)) return GLFW_KEY_UNKNOWN;
@@ -144,93 +145,93 @@ static int mouse_button_from_symbol(SigilVM *vm, Value sym)
145
/* Check for VM errors and print them */
146
static void check_vm_error(const char *context)
147
{
−147
if (!g_app) return;
−148
const char *err = sigil_error_message(g_app->vm);
+148
if (!g_desktop) return;
+149
const char *err = sigil_error_message(g_desktop->vm);
150
if (err) {
151
fprintf(stderr, "Scheme error in %s: %s\n", context, err);
−151
sigil_error_clear(g_app->vm);
−152
g_app->quit_requested = true;
−153
if (g_app->window) glfwSetWindowShouldClose(g_app->window, GLFW_TRUE);
+152
sigil_error_clear(g_desktop->vm);
+153
g_desktop->quit_requested = true;
+154
if (g_desktop->window) glfwSetWindowShouldClose(g_desktop->window, GLFW_TRUE);
155
}
156
}
157
158
static void glfw_error_callback(int code, const char *description)
159
{
−159
fprintf(stderr, "sigil-app: GLFW error 0x%X: %s\n", code, description);
+160
fprintf(stderr, "sigil-desktop: GLFW error 0x%X: %s\n", code, description);
161
}
162
163
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
164
{
165
(void)window; (void)scancode; (void)mods;
−165
if (!g_app) return;
−166
if (key < 0 || key >= SIGIL_APP_MAX_KEYS) return;
+166
if (!g_desktop) return;
+167
if (key < 0 || key >= SIGIL_DESKTOP_MAX_KEYS) return;
168
169
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
170
/* A repeat is a held key, not a new press: pressed? fires once. */
−170
if (!g_app->keys_down[key]) {
−171
g_app->keys_pressed[key] = true;
+171
if (!g_desktop->keys_down[key]) {
+172
g_desktop->keys_pressed[key] = true;
173
}
−173
g_app->keys_down[key] = true;
+174
g_desktop->keys_down[key] = true;
175
} else if (action == GLFW_RELEASE) {
−175
g_app->keys_down[key] = false;
−176
g_app->keys_released[key] = true;
+176
g_desktop->keys_down[key] = false;
+177
g_desktop->keys_released[key] = true;
178
}
179
}
180
181
static void mouse_button_callback(GLFWwindow *window, int button, int action, int mods)
182
{
183
(void)window; (void)mods;
−183
if (!g_app) return;
−184
if (button < 0 || button >= SIGIL_APP_MAX_MOUSE_BUTTONS) return;
+184
if (!g_desktop) return;
+185
if (button < 0 || button >= SIGIL_DESKTOP_MAX_MOUSE_BUTTONS) return;
186
187
if (action == GLFW_PRESS) {
−187
if (!g_app->mouse_buttons[button]) {
−188
g_app->mouse_pressed[button] = true;
+188
if (!g_desktop->mouse_buttons[button]) {
+189
g_desktop->mouse_pressed[button] = true;
190
}
−190
g_app->mouse_buttons[button] = true;
+191
g_desktop->mouse_buttons[button] = true;
192
} else if (action == GLFW_RELEASE) {
−192
g_app->mouse_buttons[button] = false;
−193
g_app->mouse_released[button] = true;
+193
g_desktop->mouse_buttons[button] = false;
+194
g_desktop->mouse_released[button] = true;
195
}
196
}
197
198
static void cursor_pos_callback(GLFWwindow *window, double x, double y)
199
{
200
(void)window;
−200
if (!g_app) return;
−201
g_app->cursor_x = x;
−202
g_app->cursor_y = y;
+201
if (!g_desktop) return;
+202
g_desktop->cursor_x = x;
+203
g_desktop->cursor_y = y;
204
}
205
206
static void window_close_callback(GLFWwindow *window)
207
{
208
(void)window;
−208
if (!g_app) return;
+209
if (!g_desktop) return;
210
/* The window manager asked; the game sees (quit-requested?) => #t
211
* and the loop ends after this frame, as with sokol_app's
212
* QUIT_REQUESTED event. */
−212
g_app->quit_requested = true;
+213
g_desktop->quit_requested = true;
214
}
215
216
static void framebuffer_size_callback(GLFWwindow *window, int width, int height)
217
{
−217
if (!g_app) return;
−218
g_app->fb_width = width;
−219
g_app->fb_height = height;
−220
if (getenv("SIGIL_APP_VERBOSE")) {
+218
if (!g_desktop) return;
+219
g_desktop->fb_width = width;
+220
g_desktop->fb_height = height;
+221
if (getenv("SIGIL_DESKTOP_VERBOSE")) {
222
float sx = 1.0f, sy = 1.0f;
223
glfwGetWindowContentScale(window, &sx, &sy);
−223
fprintf(stderr, "sigil-app: framebuffer=%dx%d window=%dx%d content-scale=%.2fx%.2f\n",
−224
width, height, g_app->win_width, g_app->win_height, sx, sy);
+224
fprintf(stderr, "sigil-desktop: framebuffer=%dx%d window=%dx%d content-scale=%.2fx%.2f\n",
+225
width, height, g_desktop->win_width, g_desktop->win_height, sx, sy);
226
}
227
}
228
229
static void window_size_callback(GLFWwindow *window, int width, int height)
230
{
231
(void)window;
−231
if (!g_app) return;
−232
g_app->win_width = width;
−233
g_app->win_height = height;
+232
if (!g_desktop) return;
+233
g_desktop->win_width = width;
+234
g_desktop->win_height = height;
235
}
236
237
/* Cursor position scaled from window units into framebuffer pixels, so
@@ -238,14 +239,14 @@ static void window_size_callback(GLFWwindow *window, int width, int height)
239
* system whatever the output scale is. */
240
static double cursor_to_fb_x(void)
241
{
−241
if (!g_app || g_app->win_width <= 0) return 0.0;
−242
return g_app->cursor_x * ((double)g_app->fb_width / (double)g_app->win_width);
+242
if (!g_desktop || g_desktop->win_width <= 0) return 0.0;
+243
return g_desktop->cursor_x * ((double)g_desktop->fb_width / (double)g_desktop->win_width);
244
}
245
246
static double cursor_to_fb_y(void)
247
{
−247
if (!g_app || g_app->win_height <= 0) return 0.0;
−248
return g_app->cursor_y * ((double)g_app->fb_height / (double)g_app->win_height);
+248
if (!g_desktop || g_desktop->win_height <= 0) return 0.0;
+249
return g_desktop->cursor_y * ((double)g_desktop->fb_height / (double)g_desktop->win_height);
250
}
251
252
/* ============================================================
@@ -255,13 +256,13 @@ static double cursor_to_fb_y(void)
256
/*
257
* GLFW picks Wayland when XDG_SESSION_TYPE=wayland and WAYLAND_DISPLAY is
258
* set, X11 when XDG_SESSION_TYPE=x11 and DISPLAY is set, and otherwise
−258
* tries Wayland then X11. SIGIL_APP_PLATFORM=wayland|x11 forces one, for
+259
* tries Wayland then X11. SIGIL_DESKTOP_PLATFORM=wayland|x11 forces one, for
260
* tests that run under a private compositor or X server and for users
261
* whose session variables lie.
262
*/
263
static void apply_platform_hint(void)
264
{
−264
const char *want = getenv("SIGIL_APP_PLATFORM");
+265
const char *want = getenv("SIGIL_DESKTOP_PLATFORM");
266
if (!want || !*want) return;
267
if (strcmp(want, "wayland") == 0) {
268
glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND);
@@ -272,7 +273,7 @@ static void apply_platform_hint(void)
273
} else if (strcmp(want, "cocoa") == 0) {
274
glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_COCOA);
275
} else {
−275
fprintf(stderr, "sigil-app: SIGIL_APP_PLATFORM=%s is not one of wayland, x11, win32, cocoa; ignored\n", want);
+276
fprintf(stderr, "sigil-desktop: SIGIL_DESKTOP_PLATFORM=%s is not one of wayland, x11, win32, cocoa; ignored\n", want);
277
}
278
}
279
@@ -288,6 +289,28 @@ static const char *platform_name(int platform)
289
}
290
}
291
+292
/* ============================================================
+293
* PUBLIC C SURFACE (include/sigil-desktop.h)
+294
* ============================================================ */
+295
+296
void sigil_desktop_framebuffer_size(int *width, int *height)
+297
{
+298
if (width) *width = sigil_desktop_framebuffer_width();
+299
if (height) *height = sigil_desktop_framebuffer_height();
+300
}
+301
+302
void *sigil_desktop_gl_get_proc_address(const char *name)
+303
{
+304
if (!g_desktop || !g_desktop->window || !name) return NULL;
+305
return (void *)glfwGetProcAddress(name);
+306
}
+307
+308
const char *sigil_desktop_platform(void)
+309
{
+310
if (!g_desktop || !g_desktop->window) return "none";
+311
return platform_name(glfwGetPlatform());
+312
}
+313
314
/* ============================================================
315
* MAIN LOOP
316
* ============================================================ */
@@ -300,7 +323,7 @@ static bool run_main_loop(const char *title, int width, int height)
323
apply_platform_hint();
324
325
if (!glfwInit()) {
−303
fprintf(stderr, "sigil-app: glfwInit failed; no usable display platform\n");
+326
fprintf(stderr, "sigil-desktop: glfwInit failed; no usable display platform\n");
327
return false;
328
}
329
@@ -327,31 +350,31 @@ static bool run_main_loop(const char *title, int width, int height)
350
351
GLFWwindow *window = glfwCreateWindow(width, height, title, NULL, NULL);
352
if (!window) {
−330
fprintf(stderr, "sigil-app: window creation failed (platform %s)\n",
+353
fprintf(stderr, "sigil-desktop: window creation failed (platform %s)\n",
354
platform_name(glfwGetPlatform()));
355
glfwTerminate();
356
return false;
357
}
−335
g_app->window = window;
+358
g_desktop->window = window;
359
360
glfwMakeContextCurrent(window);
361
glfwSwapInterval(1);
362
−340
glfwGetFramebufferSize(window, &g_app->fb_width, &g_app->fb_height);
−341
glfwGetWindowSize(window, &g_app->win_width, &g_app->win_height);
−342
glfwGetCursorPos(window, &g_app->cursor_x, &g_app->cursor_y);
+363
glfwGetFramebufferSize(window, &g_desktop->fb_width, &g_desktop->fb_height);
+364
glfwGetWindowSize(window, &g_desktop->win_width, &g_desktop->win_height);
+365
glfwGetCursorPos(window, &g_desktop->cursor_x, &g_desktop->cursor_y);
366
−344
if (getenv("SIGIL_APP_VERBOSE")) {
+367
if (getenv("SIGIL_DESKTOP_VERBOSE")) {
368
float sx = 1.0f, sy = 1.0f;
369
glfwGetWindowContentScale(window, &sx, &sy);
−347
fprintf(stderr, "sigil-app: platform=%s window=%dx%d framebuffer=%dx%d content-scale=%.2fx%.2f gl=%d.%d\n",
+370
fprintf(stderr, "sigil-desktop: platform=%s window=%dx%d framebuffer=%dx%d content-scale=%.2fx%.2f gl=%d.%d\n",
371
platform_name(glfwGetPlatform()),
−349
g_app->win_width, g_app->win_height,
−350
g_app->fb_width, g_app->fb_height, sx, sy,
+372
g_desktop->win_width, g_desktop->win_height,
+373
g_desktop->fb_width, g_desktop->fb_height, sx, sy,
374
glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR),
375
glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR));
376
#if defined(__linux__)
−354
fprintf(stderr, "sigil-app: dlopen fallback dirs: %s\n", sigil_app_dlopen_search_summary());
+377
fprintf(stderr, "sigil-desktop: dlopen fallback dirs: %s\n", sigil_desktop_dlopen_search_summary());
378
#endif
379
}
380
@@ -363,26 +386,26 @@ static bool run_main_loop(const char *title, int width, int height)
386
glfwSetWindowSizeCallback(window, window_size_callback);
387
388
/* init */
−366
g_app->last_time = glfwGetTime();
−367
if (!sigil_is_false(g_app->init_callback)) {
−368
sigil_apply0(g_app->vm, g_app->init_callback);
+389
g_desktop->last_time = glfwGetTime();
+390
if (!sigil_is_false(g_desktop->init_callback)) {
+391
sigil_apply0(g_desktop->vm, g_desktop->init_callback);
392
check_vm_error("init");
393
}
394
395
/* frames; the clock restarts after init so a long asset load is not
396
* frame 1's dt (sokol_app handed the load time to the first frame). */
−374
g_app->last_time = glfwGetTime();
+397
g_desktop->last_time = glfwGetTime();
398
while (!glfwWindowShouldClose(window)) {
399
glfwPollEvents();
400
401
double now = glfwGetTime();
−379
g_app->frame_time = now - g_app->last_time;
−380
g_app->time_elapsed += g_app->frame_time;
−381
g_app->last_time = now;
+402
g_desktop->frame_time = now - g_desktop->last_time;
+403
g_desktop->time_elapsed += g_desktop->frame_time;
+404
g_desktop->last_time = now;
405
−383
if (!sigil_is_false(g_app->frame_callback)) {
−384
Value dt = sigil_flonum(g_app->frame_time);
−385
sigil_apply1(g_app->vm, g_app->frame_callback, dt);
+406
if (!sigil_is_false(g_desktop->frame_callback)) {
+407
Value dt = sigil_flonum(g_desktop->frame_time);
+408
sigil_apply1(g_desktop->vm, g_desktop->frame_callback, dt);
409
check_vm_error("frame");
410
}
411
@@ -390,16 +413,16 @@ static bool run_main_loop(const char *title, int width, int height)
413
glfwSwapBuffers(window);
414
415
/* Clear per-frame input state for next frame */
−393
sigil_app_clear_frame_input();
+416
sigil_desktop_clear_frame_input();
417
}
418
419
/* cleanup */
−397
if (!sigil_is_false(g_app->cleanup_callback)) {
−398
sigil_apply0(g_app->vm, g_app->cleanup_callback);
+420
if (!sigil_is_false(g_desktop->cleanup_callback)) {
+421
sigil_apply0(g_desktop->vm, g_desktop->cleanup_callback);
422
check_vm_error("cleanup");
423
}
424
−402
g_app->window = NULL;
+425
g_desktop->window = NULL;
426
glfwDestroyWindow(window);
427
glfwTerminate();
428
return true;
@@ -425,16 +448,16 @@ static Value native_app_run(SigilVM *vm, int argc, Value *args)
448
}
449
450
/* Initialize app state */
−428
sigil_app_state_init(vm);
−429
if (g_app->window) {
+451
sigil_desktop_state_init(vm);
+452
if (g_desktop->window) {
453
sigil__vm_error(vm, SIGIL_ERR_RUNTIME, "app-run: already running; app-run does not nest");
454
return SIGIL_UNDEFINED;
455
}
456
457
/* Store callbacks */
−435
g_app->init_callback = args[0];
−436
g_app->frame_callback = args[1];
−437
g_app->cleanup_callback = args[2];
+458
g_desktop->init_callback = args[0];
+459
g_desktop->frame_callback = args[1];
+460
g_desktop->cleanup_callback = args[2];
461
462
/* Parse optional arguments */
463
const char *title = "Sigil App";
@@ -458,11 +481,11 @@ static Value native_app_run(SigilVM *vm, int argc, Value *args)
481
bool ran = run_main_loop(title, width, height);
482
483
/* Cleanup */
−461
sigil_app_state_shutdown();
+484
sigil_desktop_state_shutdown();
485
486
if (!ran) {
487
sigil__vm_error(vm, SIGIL_ERR_RUNTIME,
−465
"app-run: could not open a window (see the sigil-app: lines above)");
+488
"app-run: could not open a window (see the sigil-desktop: lines above)");
489
return SIGIL_UNDEFINED;
490
}
491
return SIGIL_NIL;
@@ -474,7 +497,7 @@ static Value native_app_run(SigilVM *vm, int argc, Value *args)
497
static Value native_frame_width(SigilVM *vm, int argc, Value *args)
498
{
499
(void)vm; (void)argc; (void)args;
−477
return sigil_fixnum(sigil_app_framebuffer_width());
+500
return sigil_fixnum(sigil_desktop_framebuffer_width());
501
}
502
503
/*
@@ -483,7 +506,7 @@ static Value native_frame_width(SigilVM *vm, int argc, Value *args)
506
static Value native_frame_height(SigilVM *vm, int argc, Value *args)
507
{
508
(void)vm; (void)argc; (void)args;
−486
return sigil_fixnum(sigil_app_framebuffer_height());
+509
return sigil_fixnum(sigil_desktop_framebuffer_height());
510
}
511
512
/*
@@ -492,8 +515,8 @@ static Value native_frame_height(SigilVM *vm, int argc, Value *args)
515
static Value native_frame_time(SigilVM *vm, int argc, Value *args)
516
{
517
(void)vm; (void)argc; (void)args;
−495
if (!g_app) return sigil_flonum(0.0);
−496
return sigil_flonum(g_app->frame_time);
+518
if (!g_desktop) return sigil_flonum(0.0);
+519
return sigil_flonum(g_desktop->frame_time);
520
}
521
522
/*
@@ -502,8 +525,8 @@ static Value native_frame_time(SigilVM *vm, int argc, Value *args)
525
static Value native_time_elapsed(SigilVM *vm, int argc, Value *args)
526
{
527
(void)vm; (void)argc; (void)args;
−505
if (!g_app) return sigil_flonum(0.0);
−506
return sigil_flonum(g_app->time_elapsed);
+528
if (!g_desktop) return sigil_flonum(0.0);
+529
return sigil_flonum(g_desktop->time_elapsed);
530
}
531
532
/*
@@ -531,8 +554,8 @@ static Value native_mouse_down(SigilVM *vm, int argc, Value *args)
554
{

Showing the first 500 of 606 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

src/c/dl-search.cmodified
@@ -4,33 +4,28 @@
4
* GLFW loads every platform library at run time by bare soname:
5
* dlopen("libwayland-client.so.0"), dlopen("libX11.so.6"), dlopen("libEGL.so.1").
6
* The dynamic loader finds such a name through LD_LIBRARY_PATH, the
−7
* caller's RUNPATH and the system default directories. On Guix none of
−8
* those name a profile's lib directory: a Guix profile does not set
−9
* LD_LIBRARY_PATH, and Guix's own packages are patched to dlopen absolute
−10
* store paths, which a user's binary cannot be.
+7
* caller's RUNPATH and the system default directories. On Guix and Nix none
+8
* of those name a profile's lib directory: the profile sets no
+9
* LD_LIBRARY_PATH, and the distribution's own packages are patched to
+10
* dlopen absolute store paths, which a user's binary cannot be.
11
*
12
* This file defines dlopen in the executable. The executable's symbols come
13
* first in the lookup order, so every dlopen in the process (GLFW's in
14
* posix_module.c, and any other loader compiled into the program) resolves
15
* here. It tries the name as given first, so on a system where the loader
16
* already finds the library nothing changes. When that fails and the name
−17
* is a bare soname (no slash), it retries the name joined to each directory
−18
* of:
−19
*
−20
* SIGIL_LIBRARY_PATH colon separated, the user's override
−21
* $GUIX_ENVIRONMENT/lib set by `guix shell`
−22
* $HOME/.guix-home/profile/lib Guix Home
−23
* $HOME/.guix-profile/lib the user profile
−24
* /run/current-system/profile/lib Guix System
−25
*
−26
* The real dlopen is reached with dlsym(RTLD_NEXT, "dlopen"). A library
−27
* found this way loads its own dependencies through its RUNPATH, which on
−28
* Guix names their store paths, so one absolute path is enough.
+17
* is a bare soname (no slash), it retries the name under each entry of the
+18
* table below, in order. The real dlopen is reached with
+19
* dlsym(RTLD_NEXT, "dlopen"). A library found this way loads its own
+20
* dependencies through its RUNPATH, which on Guix and Nix names their
+21
* store paths, so one absolute path is enough.
22
*
23
* A NEEDED entry (a library linked with -l) is resolved by the loader
24
* before main runs and cannot be helped here; only dlopen is covered.
25
*
−33
* SIGIL_APP_VERBOSE=1 prints every fallback that succeeds.
+26
* SIGIL_DESKTOP_VERBOSE=1 prints, for every fallback that succeeds, the
+27
* soname, the table entry and the path, and whether /gnu/store and
+28
* /nix/store exist on this machine.
29
*
30
* Linux only: on macOS the two-level namespace binds libraries to
31
* libSystem's dlopen, and on Windows LoadLibrary has its own search order.
@@ -44,6 +39,54 @@
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
+42
#include <sys/stat.h>
+43
+44
/* ---- the search table ------------------------------------------------ */
+45
+46
typedef enum {
+47
ENTRY_ENV_COLON_DIRS, /* env var: colon-separated directories */
+48
ENTRY_ENV_SPACE_ROOTS, /* env var: space-separated roots, suffix appended */
+49
ENTRY_ENV_ROOT, /* env var: one root, suffix appended */
+50
ENTRY_HOME, /* $HOME + suffix */
+51
ENTRY_USER, /* prefix + $USER + suffix */
+52
ENTRY_DIR /* a fixed directory */
+53
} entry_kind;
+54
+55
typedef struct {
+56
entry_kind kind;
+57
const char *name; /* env var, prefix, or the directory itself */
+58
const char *suffix; /* appended to each root (may be "") */
+59
const char *only_if; /* env var that must be set for the row to apply, or NULL */
+60
} search_entry;
+61
+62
/* One row per source of library directories; adding a distribution is a
+63
* row. Every row is walked on every machine (Guix and Nix coexist: David
+64
* runs Nix inside Guix), so there is no "which distro" branch and a
+65
* library may come from a Nix profile while its own dependency, resolved
+66
* by RUNPATH, comes from a Guix one. Order: the user's explicit override,
+67
* the active environment (guix shell, nix-shell, nix-ld), then the user
+68
* profiles, then the system profiles, Guix and Nix interleaved. When two
+69
* rows offer the same soname the first hit wins and the trace names it. */
+70
static const search_entry SEARCH_TABLE[] = {
+71
/* explicit override */
+72
{ ENTRY_ENV_COLON_DIRS, "SIGIL_LIBRARY_PATH", "", NULL },
+73
/* the active environment */
+74
{ ENTRY_ENV_ROOT, "GUIX_ENVIRONMENT", "/lib", NULL }, /* guix shell */
+75
{ ENTRY_ENV_SPACE_ROOTS, "buildInputs", "/lib", "IN_NIX_SHELL" }, /* nix-shell */
+76
{ ENTRY_ENV_SPACE_ROOTS, "nativeBuildInputs", "/lib", "IN_NIX_SHELL" },
+77
{ ENTRY_ENV_COLON_DIRS, "NIX_LD_LIBRARY_PATH", "", NULL }, /* nix-ld */
+78
/* user profiles */
+79
{ ENTRY_HOME, "", "/.guix-home/profile/lib", NULL }, /* Guix Home */
+80
{ ENTRY_HOME, "", "/.guix-profile/lib", NULL }, /* guix package */
+81
{ ENTRY_HOME, "", "/.nix-profile/lib", NULL }, /* nix-env, nix profile */
+82
{ ENTRY_USER, "/etc/profiles/per-user/", "/lib", NULL }, /* NixOS per-user */
+83
/* system profiles */
+84
{ ENTRY_DIR, "/run/current-system/profile/lib", "", NULL }, /* Guix System */
+85
{ ENTRY_DIR, "/run/current-system/sw/lib", "", NULL }, /* NixOS */
+86
};
+87
#define SEARCH_TABLE_LEN (sizeof SEARCH_TABLE / sizeof SEARCH_TABLE[0])
+88
+89
/* ---- the real dlopen ------------------------------------------------- */
90
91
typedef void *(*sigil_dlopen_fn)(const char *, int);
92
@@ -54,79 +97,120 @@ static sigil_dlopen_fn real_dlopen(void)
97
return fn;
98
}
99
−57
static void *try_dir(sigil_dlopen_fn real, const char *dir, size_t dirlen,
+100
static int dir_exists(const char *path)
+101
{
+102
struct stat st;
+103
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
+104
}
+105
+106
static void trace_found(const search_entry *e, const char *name, const char *path)
+107
{
+108
if (!getenv("SIGIL_DESKTOP_VERBOSE")) return;
+109
const char *label = (e->kind == ENTRY_DIR) ? e->name
+110
: (e->kind == ENTRY_HOME) ? "HOME"
+111
: (e->kind == ENTRY_USER) ? "USER"
+112
: e->name;
+113
fprintf(stderr, "sigil-desktop: dlopen %s: found via %s%s as %s (/gnu/store %s, /nix/store %s)\n",
+114
name, label, e->suffix, path,
+115
dir_exists("/gnu/store") ? "present" : "absent",
+116
dir_exists("/nix/store") ? "present" : "absent");
+117
}
+118
+119
/* dir[0..dirlen) + suffix + "/" + name, through the real dlopen */
+120
static void *try_dir(sigil_dlopen_fn real, const search_entry *e,
+121
const char *dir, size_t dirlen, const char *suffix,
122
const char *name, int flags)
123
{
124
char path[PATH_MAX];
−61
size_t namelen = strlen(name);
−62
if (dirlen == 0 || dirlen + 1 + namelen + 1 > sizeof path) return NULL;
+125
size_t sufflen = strlen(suffix), namelen = strlen(name);
+126
if (dirlen == 0 || dirlen + sufflen + 1 + namelen + 1 > sizeof path) return NULL;
127
memcpy(path, dir, dirlen);
−64
path[dirlen] = '/';
−65
memcpy(path + dirlen + 1, name, namelen + 1);
+128
memcpy(path + dirlen, suffix, sufflen);
+129
path[dirlen + sufflen] = '/';
+130
memcpy(path + dirlen + sufflen + 1, name, namelen + 1);
131
void *h = real(path, flags);
−67
if (h && getenv("SIGIL_APP_VERBOSE")) {
−68
fprintf(stderr, "sigil-app: dlopen %s: found as %s\n", name, path);
−69
}
+132
if (h) trace_found(e, name, path);
133
return h;
134
}
135
−73
/* dir may be a colon-separated list */
−74
static void *try_list(sigil_dlopen_fn real, const char *list, const char *name, int flags)
+136
/* every item of a separated list */
+137
static void *try_list(sigil_dlopen_fn real, const search_entry *e, const char *list,
+138
char sep, const char *name, int flags)
139
{
140
if (!list) return NULL;
141
while (*list) {
−78
const char *colon = strchr(list, ':');
−79
size_t len = colon ? (size_t)(colon - list) : strlen(list);
−80
void *h = try_dir(real, list, len, name, flags);
+142
const char *end = strchr(list, sep);
+143
size_t len = end ? (size_t)(end - list) : strlen(list);
+144
void *h = try_dir(real, e, list, len, e->suffix, name, flags);
145
if (h) return h;
−82
if (!colon) break;
−83
list = colon + 1;
+146
if (!end) break;
+147
list = end + 1;
148
}
149
return NULL;
150
}
151
−88
static void *try_under(sigil_dlopen_fn real, const char *base, const char *suffix,
−89
const char *name, int flags)
+152
static void *try_entry(sigil_dlopen_fn real, const search_entry *e, const char *name, int flags)
153
{
−91
char dir[PATH_MAX];
−92
if (!base || !*base) return NULL;
−93
int n = snprintf(dir, sizeof dir, "%s%s", base, suffix);
−94
if (n <= 0 || (size_t)n >= sizeof dir) return NULL;
−95
return try_dir(real, dir, (size_t)n, name, flags);
+154
if (e->only_if && !getenv(e->only_if)) return NULL;
+155
const char *v;
+156
switch (e->kind) {
+157
case ENTRY_ENV_COLON_DIRS:
+158
return try_list(real, e, getenv(e->name), ':', name, flags);
+159
case ENTRY_ENV_SPACE_ROOTS:
+160
return try_list(real, e, getenv(e->name), ' ', name, flags);
+161
case ENTRY_ENV_ROOT:
+162
v = getenv(e->name);
+163
return v ? try_dir(real, e, v, strlen(v), e->suffix, name, flags) : NULL;
+164
case ENTRY_HOME:
+165
v = getenv("HOME");
+166
return v ? try_dir(real, e, v, strlen(v), e->suffix, name, flags) : NULL;
+167
case ENTRY_USER: {
+168
v = getenv("USER");
+169
if (!v || !*v) return NULL;
+170
char root[PATH_MAX];
+171
int n = snprintf(root, sizeof root, "%s%s", e->name, v);
+172
if (n <= 0 || (size_t)n >= sizeof root) return NULL;
+173
return try_dir(real, e, root, (size_t)n, e->suffix, name, flags);
+174
}
+175
case ENTRY_DIR:
+176
return try_dir(real, e, e->name, strlen(e->name), e->suffix, name, flags);
+177
}
+178
return NULL;
179
}
180
+181
/* ---- the interposed dlopen ------------------------------------------- */
+182
183
void *dlopen(const char *name, int flags)
184
{
185
sigil_dlopen_fn real = real_dlopen();
186
if (!real) {
187
/* No next dlopen: only a fully static link gets here; say so, since
188
* GLFW then reports the library as missing. */
−104
fprintf(stderr, "sigil-app: dlopen(%s): no underlying dlopen (static link?)\n", name ? name : "(null)");
+189
fprintf(stderr, "sigil-desktop: dlopen(%s): no underlying dlopen (static link?)\n",
+190
name ? name : "(null)");
191
return NULL;
192
}
193
194
void *h = real(name, flags);
195
if (h || !name || strchr(name, '/')) return h;
196
−111
/* A bare soname the loader could not find: the profile directories. */
−112
const char *home = getenv("HOME");
−113
h = try_list(real, getenv("SIGIL_LIBRARY_PATH"), name, flags);
−114
if (!h) h = try_under(real, getenv("GUIX_ENVIRONMENT"), "/lib", name, flags);
−115
if (!h) h = try_under(real, home, "/.guix-home/profile/lib", name, flags);
−116
if (!h) h = try_under(real, home, "/.guix-profile/lib", name, flags);
−117
if (!h) h = try_dir(real, "/run/current-system/profile/lib",
−118
strlen("/run/current-system/profile/lib"), name, flags);
−119
if (h) return h;
+197
/* A bare soname the loader could not find: the table, in order. */
+198
for (size_t i = 0; i < SEARCH_TABLE_LEN; i++) {
+199
h = try_entry(real, &SEARCH_TABLE[i], name, flags);
+200
if (h) return h;
+201
}
202
203
/* Nothing found: repeat the plain call so dlerror() names the soname
204
* the caller asked for, not the last directory tried. */
205
return real(name, flags);
206
}
207
−126
/* Referenced from app.c so this object is always linked ahead of libc,
+208
/* Referenced from desktop.c so this object is always linked ahead of libc,
209
* whatever order the linker meets the archive members in. */
−128
const char *sigil_app_dlopen_search_summary(void)
+210
const char *sigil_desktop_dlopen_search_summary(void)
211
{
−130
return "SIGIL_LIBRARY_PATH, $GUIX_ENVIRONMENT/lib, ~/.guix-home/profile/lib, "
−131
"~/.guix-profile/lib, /run/current-system/profile/lib";
+212
return "SIGIL_LIBRARY_PATH; $GUIX_ENVIRONMENT/lib; $buildInputs/*/lib and "
+213
"$nativeBuildInputs/*/lib under IN_NIX_SHELL; $NIX_LD_LIBRARY_PATH; ~/.guix-home/profile/lib; "
+214
"~/.guix-profile/lib; ~/.nix-profile/lib; /etc/profiles/per-user/$USER/lib; "
+215
"/run/current-system/profile/lib; /run/current-system/sw/lib";
216
}
src/c/sokol-compat.cdeleted
@@ -1,60 +0,0 @@
−1
/*
−2
* sokol-compat.c - the sokol_app symbols sigil-graphics still links against
−3
*
−4
* The window no longer comes from sokol_app (see app.c: it is GLFW now), but
−5
* sigil-graphics' vendored sokol_glue.h calls sapp_get_environment() and
−6
* sapp_get_swapchain(), its graphics.c calls sapp_width()/sapp_height(), and
−7
* every sokol_gfx logger points at slog_func from sokol_log.h. This file
−8
* implements exactly those five symbols over the GLFW host state so a
−9
* consumer relocks sigil-app and nothing else changes. The types come from
−10
* the vendored sokol_app.h, included for declarations only (no SOKOL_IMPL),
−11
* so the struct layouts match what sigil-graphics compiled against.
−12
*
−13
* The values are the ones sokol_app's GL backend reported: RGBA8 colour,
−14
* a combined depth-stencil buffer (GLFW's default framebuffer is 24/8), no
−15
* MSAA, GL framebuffer 0.
−16
*/
−17
−18
#include "app-internal.h"
−19
#include <string.h>
−20
−21
/* Order is load-bearing: sokol_log.h with its IMPL defines SOKOL_API_IMPL,
−22
* which the sapp_* definitions below use; sokol_app.h then contributes
−23
* declarations only. */
−24
#define SOKOL_LOG_IMPL
−25
#include "sokol_log.h"
−26
−27
#include "sokol_app.h"
−28
−29
SOKOL_API_IMPL int sapp_width(void)
−30
{
−31
return sigil_app_framebuffer_width();
−32
}
−33
−34
SOKOL_API_IMPL int sapp_height(void)
−35
{
−36
return sigil_app_framebuffer_height();
−37
}
−38
−39
SOKOL_API_IMPL sapp_environment sapp_get_environment(void)
−40
{
−41
sapp_environment env;
−42
memset(&env, 0, sizeof(env));
−43
env.defaults.color_format = SAPP_PIXELFORMAT_RGBA8;
−44
env.defaults.depth_format = SAPP_PIXELFORMAT_DEPTH_STENCIL;
−45
env.defaults.sample_count = 1;
−46
return env;
−47
}
−48
−49
SOKOL_API_IMPL sapp_swapchain sapp_get_swapchain(void)
−50
{
−51
sapp_swapchain sc;
−52
memset(&sc, 0, sizeof(sc));
−53
sc.width = sigil_app_framebuffer_width();
−54
sc.height = sigil_app_framebuffer_height();
−55
sc.sample_count = 1;
−56
sc.color_format = SAPP_PIXELFORMAT_RGBA8;
−57
sc.depth_format = SAPP_PIXELFORMAT_DEPTH_STENCIL;
−58
sc.gl.framebuffer = 0;
−59
return sc;
−60
}
src/sigil/app.sglmodified
@@ -1,18 +1,21 @@
−1
;;; (sigil app) - Application Framework
+1
;;; (sigil app) - the old name of (sigil desktop)
2
;;;
−3
;;; Provides windowing, input handling, and application lifecycle management.
−4
;;; Native functions are registered by app.c, this module provides re-exports
−5
;;; and higher-level utilities.
+3
;;; DEPRECATED since sigil-desktop 0.10.0 and kept for one release so a
+4
;;; consumer can relock first and rename its imports second. Every binding
+5
;;; is (sigil desktop)'s; nothing lives here. Change
6
;;;
−7
;;; The frame-loop macro provides a coroutine-based game loop where Scheme
−8
;;; appears to own the main loop while C (Sokol) actually controls execution.
+7
;;; (import (sigil app))
+8
;;;
+9
;;; to
+10
;;;
+11
;;; (import (sigil desktop))
+12
;;;
+13
;;; before 0.11.0, when this library goes away.
14
15
(define-library (sigil app)
−11
(import (sigil core)
−12
(sigil coroutines))
+16
(import (sigil desktop))
17
18
(export
−15
;; Native functions (re-exported)
19
app-run
20
frame-width frame-height
21
frame-time time-elapsed
@@ -20,74 +23,5 @@
23
mouse-down? mouse-pressed? mouse-released?
24
key-down? key-pressed? key-released?
25
quit-requested? request-quit
−23
−24
;; Cooperative frame scheduling
26
run-game
−26
wait-frame)
−27
−28
(begin
−29
;; Native functions are automatically available after native module init.
−30
−31
;; ========== Cooperative Frame Scheduler ==========
−32
;;;
−33
;;; The frame-loop pattern inverts control so Scheme code reads naturally:
−34
;;;
−35
;;; (run-game "My Game" 800 600
−36
;;; (lambda ()
−37
;;; ;; init code here
−38
;;; (let loop ()
−39
;;; (let ((dt (wait-frame)))
−40
;;; ;; frame code here using dt
−41
;;; (unless (quit-requested?)
−42
;;; (loop))))))
−43
;;;
−44
;;; Behind the scenes, (wait-frame) yields to C, which resumes the
−45
;;; coroutine on the next frame with the delta time.
−46
−47
;; Global coroutine for the current game loop
−48
(define *game-coroutine* #f)
−49
−50
;; Yield point - returns delta time when resumed
−51
(define (wait-frame)
−52
(: -> number?)
−53
(send 'frame-complete))
−54
−55
;; Internal frame callback - resumes the game coroutine
−56
(define (frame-tick dt)
−57
(when *game-coroutine*
−58
(if (coroutine-done? *game-coroutine*)
−59
(request-quit)
−60
(coroutine-send *game-coroutine* dt))))
−61
−62
;; Stored game thunk - will be converted to coroutine in init callback
−63
(define *game-thunk* #f)
−64
−65
;; Internal init callback - creates and starts the game coroutine
−66
(define (game-init)
−67
(when *game-thunk*
−68
;; Create the game coroutine now that Sokol is initialized
−69
(set! *game-coroutine*
−70
(coroutine
−71
;; Call the user's game thunk
−72
(*game-thunk*)
−73
;; When thunk returns, game is done
−74
'game-finished))
−75
;; Run init code up to first (wait-frame)
−76
(when (not (coroutine-done? *game-coroutine*))
−77
(coroutine-send *game-coroutine* 0.0))))
−78
−79
;; Run a game with the coroutine-based loop
−80
;; game-thunk is called inside a coroutine and can use (wait-frame)
−81
(define (run-game title width height game-thunk)
−82
(: string? integer? integer? procedure? -> void?)
−83
;; Store the thunk for the init callback
−84
(set! *game-thunk* game-thunk)
−85
−86
;; Run the app - init callback will start the coroutine
−87
(app-run
−88
game-init ; init - creates and starts coroutine
−89
frame-tick ; frame - resumes coroutine
−90
(lambda () ; cleanup
−91
(set! *game-coroutine* #f)
−92
(set! *game-thunk* #f))
−93
title width height))))
+27
wait-frame))
src/sigil/desktop.sgladded
@@ -0,0 +1,93 @@
+1
;;; (sigil desktop) - the desktop host layer
+2
;;;
+3
;;; Provides windowing, input handling, and application lifecycle management.
+4
;;; Native functions are registered by desktop.c (over GLFW), this module provides re-exports
+5
;;; and higher-level utilities.
+6
;;;
+7
;;; The frame-loop macro provides a coroutine-based game loop where Scheme
+8
;;; appears to own the main loop while C (GLFW) actually controls execution.
+9
+10
(define-library (sigil desktop)
+11
(import (sigil core)
+12
(sigil coroutines))
+13
+14
(export
+15
;; Native functions (re-exported)
+16
app-run
+17
frame-width frame-height
+18
frame-time time-elapsed
+19
mouse-x mouse-y
+20
mouse-down? mouse-pressed? mouse-released?
+21
key-down? key-pressed? key-released?
+22
quit-requested? request-quit
+23
+24
;; Cooperative frame scheduling
+25
run-game
+26
wait-frame)
+27
+28
(begin
+29
;; Native functions are automatically available after native module init.
+30
+31
;; ========== Cooperative Frame Scheduler ==========
+32
;;;
+33
;;; The frame-loop pattern inverts control so Scheme code reads naturally:
+34
;;;
+35
;;; (run-game "My Game" 800 600
+36
;;; (lambda ()
+37
;;; ;; init code here
+38
;;; (let loop ()
+39
;;; (let ((dt (wait-frame)))
+40
;;; ;; frame code here using dt
+41
;;; (unless (quit-requested?)
+42
;;; (loop))))))
+43
;;;
+44
;;; Behind the scenes, (wait-frame) yields to C, which resumes the
+45
;;; coroutine on the next frame with the delta time.
+46
+47
;; Global coroutine for the current game loop
+48
(define *game-coroutine* #f)
+49
+50
;; Yield point - returns delta time when resumed
+51
(define (wait-frame)
+52
(: -> number?)
+53
(send 'frame-complete))
+54
+55
;; Internal frame callback - resumes the game coroutine
+56
(define (frame-tick dt)
+57
(when *game-coroutine*
+58
(if (coroutine-done? *game-coroutine*)
+59
(request-quit)
+60
(coroutine-send *game-coroutine* dt))))
+61
+62
;; Stored game thunk - will be converted to coroutine in init callback
+63
(define *game-thunk* #f)
+64
+65
;; Internal init callback - creates and starts the game coroutine
+66
(define (game-init)
+67
(when *game-thunk*
+68
;; Create the game coroutine now that the window is up
+69
(set! *game-coroutine*
+70
(coroutine
+71
;; Call the user's game thunk
+72
(*game-thunk*)
+73
;; When thunk returns, game is done
+74
'game-finished))
+75
;; Run init code up to first (wait-frame)
+76
(when (not (coroutine-done? *game-coroutine*))
+77
(coroutine-send *game-coroutine* 0.0))))
+78
+79
;; Run a game with the coroutine-based loop
+80
;; game-thunk is called inside a coroutine and can use (wait-frame)
+81
(define (run-game title width height game-thunk)
+82
(: string? integer? integer? procedure? -> void?)
+83
;; Store the thunk for the init callback
+84
(set! *game-thunk* game-thunk)
+85
+86
;; Run the app - init callback will start the coroutine
+87
(app-run
+88
game-init ; init - creates and starts coroutine
+89
frame-tick ; frame - resumes coroutine
+90
(lambda () ; cleanup
+91
(set! *game-coroutine* #f)
+92
(set! *game-thunk* #f))
+93
title width height))))
test/dl-search-probe.cadded
@@ -0,0 +1,23 @@
+1
/* dl-search-probe.c - links dl-search.c and reports which file a soname
+2
* resolved to. Driven by test/dl-search-test.sh.
+3
* usage: dl-search-probe <soname> exit 0 and print the path on success */
+4
#ifndef _GNU_SOURCE
+5
#define _GNU_SOURCE
+6
#endif
+7
#include <dlfcn.h>
+8
#include <link.h>
+9
#include <stdio.h>
+10
+11
const char *sigil_desktop_dlopen_search_summary(void);
+12
+13
int main(int argc, char **argv)
+14
{
+15
if (argc != 2) { fprintf(stderr, "usage: %s <soname>\n", argv[0]); return 2; }
+16
void *h = dlopen(argv[1], RTLD_NOW | RTLD_LOCAL);
+17
if (!h) { printf("UNRESOLVED %s: %s\n", argv[1], dlerror()); return 1; }
+18
struct link_map *lm = NULL;
+19
if (dlinfo(h, RTLD_DI_LINKMAP, &lm) == 0 && lm) printf("RESOLVED %s -> %s\n", argv[1], lm->l_name);
+20
else printf("RESOLVED %s\n", argv[1]);
+21
(void)sigil_desktop_dlopen_search_summary;
+22
return 0;
+23
}
test/dl-search-test.shadded
@@ -0,0 +1,56 @@
+1
#!/bin/sh
+2
# dl-search-test.sh - the interposed dlopen against fake Guix and Nix profiles.
+3
#
+4
# Builds a probe from src/c/dl-search.c, a throwaway shared object, and a
+5
# temp HOME holding an empty ~/.guix-home/profile/lib and a
+6
# ~/.nix-profile/lib that has the object; then asserts, in order:
+7
# 1. the plain loader cannot find the soname (the control: the fallback
+8
# is what resolves it, not LD_LIBRARY_PATH or the cache)
+9
# 2. it resolves, from the Nix profile, with the Guix row walked first
+10
# and empty (both distributions' rows are live at once)
+11
# 3. with a copy in the Guix profile too, the Guix row wins (first hit)
+12
# and the trace names it
+13
# 4. IN_NIX_SHELL + buildInputs resolves ahead of every profile
+14
# 5. SIGIL_LIBRARY_PATH resolves ahead of everything
+15
# Any assertion failing exits 1. Needs a C compiler: $CC, or the pinned
+16
# zig under ~/.sigil/toolchain/zig, or cc.
+17
set -u
+18
cd "$(dirname "$0")/.." || exit 2
+19
if [ -n "${CC:-}" ]; then :
+20
elif [ -x "$HOME/.sigil/toolchain/zig/zig" ]; then CC="$HOME/.sigil/toolchain/zig/zig cc"
+21
elif command -v cc >/dev/null 2>&1; then CC=cc
+22
else echo "SETUP-FAILED: no C compiler (set CC)"; exit 2; fi
+23
T=$(mktemp -d) || exit 2
+24
trap 'rm -rf "$T"' EXIT
+25
FAKE=libsigildlsearchfake.so.7
+26
printf 'int sigil_fake_answer(void) { return 42; }\n' > "$T/fake.c"
+27
$CC -shared -fPIC -o "$T/$FAKE" "$T/fake.c" || { echo "SETUP-FAILED: cannot build the fake library"; exit 2; }
+28
$CC -o "$T/probe" test/dl-search-probe.c src/c/dl-search.c -ldl || { echo "SETUP-FAILED: cannot build the probe"; exit 2; }
+29
H="$T/home"; mkdir -p "$H/.guix-home/profile/lib" "$H/.nix-profile/lib" "$T/nixstore/foo-1.0/lib"
+30
cp "$T/$FAKE" "$H/.nix-profile/lib/"
+31
fails=0
+32
pass() { echo "PASS $1: $2"; }
+33
fail() { echo "FAIL $1: $2"; fails=$((fails + 1)); }
+34
run() { # name, expected-substring-of-stdout, env assignments...
+35
name=$1; want=$2; shift 2
+36
out=$(env -i HOME="$H" USER=sigiltest SIGIL_DESKTOP_VERBOSE=1 "$@" "$T/probe" "$FAKE" 2>&1)
+37
case "$out" in *"$want"*) pass "$name" "$want";; *) fail "$name" "wanted [$want], got: $out";; esac
+38
}
+39
# 1. control: HOME with no profile dirs at all
+40
mkdir -p "$T/emptyhome"
+41
run control "UNRESOLVED $FAKE" HOME="$T/emptyhome"
+42
# 2. Nix profile only (the Guix row exists and is empty)
+43
run nix-profile "found via HOME/.nix-profile/lib as $H/.nix-profile/lib/$FAKE"
+44
# 3. both: Guix Home first
+45
cp "$T/$FAKE" "$H/.guix-home/profile/lib/"
+46
run first-hit-wins "found via HOME/.guix-home/profile/lib as $H/.guix-home/profile/lib/$FAKE"
+47
# 4. nix-shell inputs beat the profiles
+48
cp "$T/$FAKE" "$T/nixstore/foo-1.0/lib/"
+49
run nix-shell "found via buildInputs/lib as $T/nixstore/foo-1.0/lib/$FAKE" IN_NIX_SHELL=impure buildInputs="$T/nixstore/bar-2.0 $T/nixstore/foo-1.0"
+50
# 5. the override beats everything
+51
mkdir -p "$T/override"; cp "$T/$FAKE" "$T/override/"
+52
run override "found via SIGIL_LIBRARY_PATH as $T/override/$FAKE" SIGIL_LIBRARY_PATH="/nonexistent:$T/override" IN_NIX_SHELL=impure buildInputs="$T/nixstore/foo-1.0"
+53
# the trace names the stores present on this machine
+54
out=$(env -i HOME="$H" USER=sigiltest SIGIL_DESKTOP_VERBOSE=1 "$T/probe" "$FAKE" 2>&1)
+55
case "$out" in *"(/gnu/store "*", /nix/store "*")"*) pass trace-stores "$(echo "$out" | grep -o '(/gnu/store [a-z]*, /nix/store [a-z]*)' | head -1)";; *) fail trace-stores "no store note in: $out";; esac
+56
if [ $fails -eq 0 ]; then echo "GREEN: dl-search"; exit 0; else echo "RED: $fails failed"; exit 1; fi
vendor/sokol/sokol_app.hdeleted
@@ -1,14047 +0,0 @@
−1
#if defined(SOKOL_IMPL) && !defined(SOKOL_APP_IMPL)
−2
#define SOKOL_APP_IMPL
−3
#endif
−4
#ifndef SOKOL_APP_INCLUDED
−5
/*
−6
sokol_app.h -- cross-platform application wrapper
−7
−8
Project URL: https://github.com/floooh/sokol
−9
−10
Do this:
−11
#define SOKOL_IMPL or
−12
#define SOKOL_APP_IMPL
−13
before you include this file in *one* C or C++ file to create the
−14
implementation.
−15
−16
In the same place define one of the following to select the 3D-API
−17
which should be initialized by sokol_app.h (this must also match
−18
the backend selected for sokol_gfx.h if both are used in the same
−19
project):
−20
−21
#define SOKOL_GLCORE
−22
#define SOKOL_GLES3
−23
#define SOKOL_D3D11
−24
#define SOKOL_METAL
−25
#define SOKOL_WGPU
−26
#define SOKOL_NOAPI
−27
−28
Optionally provide the following defines with your own implementations:
−29
−30
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
−31
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
−32
SOKOL_WIN32_FORCE_MAIN - define this on Win32 to add a main() entry point
−33
SOKOL_WIN32_FORCE_WINMAIN - define this on Win32 to add a WinMain() entry point (enabled by default unless
−34
SOKOL_WIN32_FORCE_MAIN or SOKOL_NO_ENTRY is defined)
−35
SOKOL_NO_ENTRY - define this if sokol_app.h shouldn't "hijack" the main() function
−36
SOKOL_APP_API_DECL - public function declaration prefix (default: extern)
−37
SOKOL_API_DECL - same as SOKOL_APP_API_DECL
−38
SOKOL_API_IMPL - public function implementation prefix (default: -)
−39
−40
Optionally define the following to force debug checks and validations
−41
even in release mode:
−42
−43
SOKOL_DEBUG - by default this is defined if NDEBUG is not defined
−44
−45
If sokol_app.h is compiled as a DLL, define the following before
−46
including the declaration or implementation:
−47
−48
SOKOL_DLL
−49
−50
On Windows, SOKOL_DLL will define SOKOL_APP_API_DECL as __declspec(dllexport)
−51
or __declspec(dllimport) as needed.
−52
−53
if SOKOL_WIN32_FORCE_MAIN and SOKOL_WIN32_FORCE_WINMAIN are both defined,
−54
it is up to the developer to define the desired subsystem.
−55
−56
On Linux, SOKOL_GLCORE can use either GLX or EGL.
−57
GLX is default, set SOKOL_FORCE_EGL to override.
−58
−59
For example code, see https://github.com/floooh/sokol-samples/tree/master/sapp
−60
−61
Portions of the Windows and Linux GL initialization, event-, icon- etc... code
−62
have been taken from GLFW (http://www.glfw.org/).
−63
−64
iOS onscreen keyboard support 'inspired' by libgdx.
−65
−66
Link with the following system libraries:
−67
−68
- on macOS:
−69
- all backends: Foundation, Cocoa, QuartzCore
−70
- with SOKOL_METAL: Metal, MetalKit
−71
- with SOKOL_GLCORE: OpenGL
−72
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
−73
- on iOS:
−74
- all backends: Foundation, UIKit
−75
- with SOKOL_METAL: Metal, MetalKit
−76
- with SOKOL_GLES3: OpenGLES, GLKit
−77
- on Linux:
−78
- all backends: X11, Xi, Xcursor, dl, pthread, m
−79
- with SOKOL_GLCORE: GL
−80
- with SOKOL_GLES3: GLESv2
−81
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
−82
- with EGL: EGL
−83
- on Android: GLESv3, EGL, log, android
−84
- on Windows:
−85
- with MSVC or Clang: library dependencies are defined via `#pragma comment`
−86
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
−87
- with MINGW/MSYS2 gcc:
−88
- compile with '-mwin32' so that _WIN32 is defined
−89
- link with the following libs: -lkernel32 -luser32 -lshell32
−90
- additionally with the GL backend: -lgdi32
−91
- additionally with the D3D11 backend: -ld3d11 -ldxgi
−92
−93
On Linux, you also need to use the -pthread compiler and linker option, otherwise weird
−94
things will happen, see here for details: https://github.com/floooh/sokol/issues/376
−95
−96
On macOS and iOS, the implementation must be compiled as Objective-C.
−97
−98
On Emscripten:
−99
- for WebGL2: add the linker option `-s USE_WEBGL2=1`
−100
- for WebGPU: compile and link with `--use-port=emdawnwebgpu`
−101
(for more exotic situations read: https://dawn.googlesource.com/dawn/+/refs/heads/main/src/emdawnwebgpu/pkg/README.md)
−102
−103
FEATURE OVERVIEW
−104
================
−105
sokol_app.h provides a minimalistic cross-platform API which
−106
implements the 'application-wrapper' parts of a 3D application:
−107
−108
- a common application entry function
−109
- creates a window and 3D-API context/device with a swapchain
−110
surface, depth-stencil-buffer surface and optionally MSAA surface
−111
- makes the rendered frame visible
−112
- provides keyboard-, mouse- and low-level touch-events
−113
- platforms: MacOS, iOS, HTML5, Win32, Linux/RaspberryPi, Android
−114
- 3D-APIs: Metal, D3D11, GL4.1, GL4.3, GLES3, WebGL2, WebGPU, NOAPI
−115
−116
FEATURE/PLATFORM MATRIX
−117
=======================
−118
| Windows | macOS | Linux | iOS | Android | HTML5
−119
--------------------+---------+-------+-------+-------+---------+--------
−120
gl 4.x | YES | YES | YES | --- | --- | ---
−121
gles3/webgl2 | --- | --- | YES(2)| YES | YES | YES
−122
metal | --- | YES | --- | YES | --- | ---
−123
d3d11 | YES | --- | --- | --- | --- | ---
−124
webgpu | YES(4) | YES(4)| YES(4)| NO | NO | YES
−125
noapi | YES | TODO | TODO | --- | TODO | ---
−126
KEY_DOWN | YES | YES | YES | SOME | TODO | YES
−127
KEY_UP | YES | YES | YES | SOME | TODO | YES
−128
CHAR | YES | YES | YES | YES | TODO | YES
−129
MOUSE_DOWN | YES | YES | YES | --- | --- | YES
−130
MOUSE_UP | YES | YES | YES | --- | --- | YES
−131
MOUSE_SCROLL | YES | YES | YES | --- | --- | YES
−132
MOUSE_MOVE | YES | YES | YES | --- | --- | YES
−133
MOUSE_ENTER | YES | YES | YES | --- | --- | YES
−134
MOUSE_LEAVE | YES | YES | YES | --- | --- | YES
−135
TOUCHES_BEGAN | --- | --- | --- | YES | YES | YES
−136
TOUCHES_MOVED | --- | --- | --- | YES | YES | YES
−137
TOUCHES_ENDED | --- | --- | --- | YES | YES | YES
−138
TOUCHES_CANCELLED | --- | --- | --- | YES | YES | YES
−139
RESIZED | YES | YES | YES | YES | YES | YES
−140
ICONIFIED | YES | YES | YES | --- | --- | ---
−141
RESTORED | YES | YES | YES | --- | --- | ---
−142
FOCUSED | YES | YES | YES | --- | --- | YES
−143
UNFOCUSED | YES | YES | YES | --- | --- | YES
−144
SUSPENDED | --- | --- | --- | YES | YES | TODO
−145
RESUMED | --- | --- | --- | YES | YES | TODO
−146
QUIT_REQUESTED | YES | YES | YES | --- | --- | YES
−147
IME | TODO | TODO? | TODO | ??? | TODO | ???
−148
key repeat flag | YES | YES | YES | --- | --- | YES
−149
windowed | YES | YES | YES | --- | --- | YES
−150
fullscreen | YES | YES | YES | YES | YES | YES(3)
−151
mouse hide | YES | YES | YES | --- | --- | YES
−152
mouse lock | YES | YES | YES | --- | --- | YES
−153
set cursor type | YES | YES | YES | --- | --- | YES
−154
screen keyboard | --- | --- | --- | YES | TODO | YES
−155
swap interval | YES | YES | YES | YES | TODO | YES
−156
high-dpi | YES | YES | TODO | YES | YES | YES
−157
clipboard | YES | YES | YES | --- | --- | YES
−158
MSAA | YES | YES | YES | YES | YES | YES
−159
drag'n'drop | YES | YES | YES | --- | --- | YES
−160
window icon | YES | YES(1)| YES | --- | --- | YES
−161
−162
(1) macOS has no regular window icons, instead the dock icon is changed
−163
(2) supported with EGL only (not GLX)
−164
(3) fullscreen in the browser not supported on iphones
−165
(4) WebGPU on native desktop platforms should be considered experimental
−166
and mainly useful for debugging and benchmarking
−167
−168
STEP BY STEP
−169
============
−170
--- Add a sokol_main() function to your code which returns a sapp_desc structure
−171
with initialization parameters and callback function pointers. This
−172
function is called very early, usually at the start of the
−173
platform's entry function (e.g. main or WinMain). You should do as
−174
little as possible here, since the rest of your code might be called
−175
from another thread (this depends on the platform):
−176
−177
sapp_desc sokol_main(int argc, char* argv[]) {
−178
return (sapp_desc) {
−179
.width = 640,
−180
.height = 480,
−181
.init_cb = my_init_func,
−182
.frame_cb = my_frame_func,
−183
.cleanup_cb = my_cleanup_func,
−184
.event_cb = my_event_func,
−185
...
−186
};
−187
}
−188
−189
To get any logging output in case of errors you need to provide a log
−190
callback. The easiest way is via sokol_log.h:
−191
−192
#include "sokol_log.h"
−193
−194
sapp_desc sokol_main(int argc, char* argv[]) {
−195
return (sapp_desc) {
−196
...
−197
.logger.func = slog_func,
−198
};
−199
}
−200
−201
There are many more setup parameters, but these are the most important.
−202
For a complete list search for the sapp_desc structure declaration
−203
below.
−204
−205
DO NOT call any sokol-app function from inside sokol_main(), since
−206
sokol-app will not be initialized at this point.
−207
−208
The .width and .height parameters are the preferred size of the 3D
−209
rendering canvas. The actual size may differ from this depending on
−210
platform and other circumstances. Also the canvas size may change at
−211
any time (for instance when the user resizes the application window,
−212
or rotates the mobile device). You can just keep .width and .height
−213
zero-initialized to open a default-sized window (what "default-size"
−214
exactly means is platform-specific, but usually it's a size that covers
−215
most of, but not all, of the display).
−216
−217
All provided function callbacks will be called from the same thread,
−218
but this may be different from the thread where sokol_main() was called.
−219
−220
.init_cb (void (*)(void))
−221
This function is called once after the application window,
−222
3D rendering context and swap chain have been created. The
−223
function takes no arguments and has no return value.
−224
.frame_cb (void (*)(void))
−225
This is the per-frame callback, which is usually called 60
−226
times per second. This is where your application would update
−227
most of its state and perform all rendering.
−228
.cleanup_cb (void (*)(void))
−229
The cleanup callback is called once right before the application
−230
quits.
−231
.event_cb (void (*)(const sapp_event* event))
−232
The event callback is mainly for input handling, but is also
−233
used to communicate other types of events to the application. Keep the
−234
event_cb struct member zero-initialized if your application doesn't require
−235
event handling.
−236
−237
As you can see, those 'standard callbacks' don't have a user_data
−238
argument, so any data that needs to be preserved between callbacks
−239
must live in global variables. If keeping state in global variables
−240
is not an option, there's an alternative set of callbacks with
−241
an additional user_data pointer argument:
−242
−243
.user_data (void*)
−244
The user-data argument for the callbacks below
−245
.init_userdata_cb (void (*)(void* user_data))
−246
.frame_userdata_cb (void (*)(void* user_data))
−247
.cleanup_userdata_cb (void (*)(void* user_data))
−248
.event_userdata_cb (void(*)(const sapp_event* event, void* user_data))
−249
−250
The function sapp_userdata() can be used to query the user_data
−251
pointer provided in the sapp_desc struct.
−252
−253
You can also call sapp_query_desc() to get a copy of the
−254
original sapp_desc structure.
−255
−256
NOTE that there's also an alternative compile mode where sokol_app.h
−257
doesn't "hijack" the main() function. Search below for SOKOL_NO_ENTRY.
−258
−259
--- Implement the initialization callback function (init_cb), this is called
−260
once after the rendering surface, 3D API and swap chain have been
−261
initialized by sokol_app. All sokol-app functions can be called
−262
from inside the initialization callback, the most useful functions
−263
at this point are:
−264
−265
int sapp_width(void)
−266
int sapp_height(void)
−267
Returns the current width and height of the default framebuffer in pixels,
−268
this may change from one frame to the next, and it may be different
−269
from the initial size provided in the sapp_desc struct.
−270
−271
float sapp_widthf(void)
−272
float sapp_heightf(void)
−273
These are alternatives to sapp_width() and sapp_height() which return
−274
the default framebuffer size as float values instead of integer. This
−275
may help to prevent casting back and forth between int and float
−276
in more strongly typed languages than C and C++.
−277
−278
double sapp_frame_duration(void)
−279
Returns the frame duration in seconds averaged over a number of
−280
frames to smooth out any jittering spikes.
−281
−282
int sapp_color_format(void)
−283
int sapp_depth_format(void)
−284
The color and depth-stencil pixelformats of the default framebuffer,
−285
as integer values which are compatible with sokol-gfx's
−286
sg_pixel_format enum (so that they can be plugged directly in places
−287
where sg_pixel_format is expected). Possible values are:
−288
−289
23 == SG_PIXELFORMAT_RGBA8
−290
28 == SG_PIXELFORMAT_BGRA8
−291
42 == SG_PIXELFORMAT_DEPTH
−292
43 == SG_PIXELFORMAT_DEPTH_STENCIL
−293
−294
int sapp_sample_count(void)
−295
Return the MSAA sample count of the default framebuffer.
−296
−297
const void* sapp_metal_get_device(void)
−298
const void* sapp_metal_get_current_drawable(void)
−299
const void* sapp_metal_get_depth_stencil_texture(void)
−300
const void* sapp_metal_get_msaa_color_texture(void)
−301
If the Metal backend has been selected, these functions return pointers
−302
to various Metal API objects required for rendering, otherwise
−303
they return a null pointer. These void pointers are actually
−304
Objective-C ids converted with a (ARC) __bridge cast so that
−305
the ids can be tunneled through C code. Also note that the returned
−306
pointers may change from one frame to the next, only the Metal device
−307
object is guaranteed to stay the same.
−308
−309
const void* sapp_macos_get_window(void)
−310
On macOS, get the NSWindow object pointer, otherwise a null pointer.
−311
Before being used as Objective-C object, the void* must be converted
−312
back with a (ARC) __bridge cast.
−313
−314
const void* sapp_ios_get_window(void)
−315
On iOS, get the UIWindow object pointer, otherwise a null pointer.
−316
Before being used as Objective-C object, the void* must be converted
−317
back with a (ARC) __bridge cast.
−318
−319
const void* sapp_d3d11_get_device(void)
−320
const void* sapp_d3d11_get_device_context(void)
−321
const void* sapp_d3d11_get_render_view(void)
−322
const void* sapp_d3d11_get_resolve_view(void);
−323
const void* sapp_d3d11_get_depth_stencil_view(void)
−324
Similar to the sapp_metal_* functions, the sapp_d3d11_* functions
−325
return pointers to D3D11 API objects required for rendering,
−326
only if the D3D11 backend has been selected. Otherwise they
−327
return a null pointer. Note that the returned pointers to the
−328
render-target-view and depth-stencil-view may change from one
−329
frame to the next!
−330
−331
const void* sapp_win32_get_hwnd(void)
−332
On Windows, get the window's HWND, otherwise a null pointer. The
−333
HWND has been cast to a void pointer in order to be tunneled
−334
through code which doesn't include Windows.h.
−335
−336
const void* sapp_x11_get_window(void)
−337
On Linux, get the X11 Window, otherwise a null pointer. The
−338
Window has been cast to a void pointer in order to be tunneled
−339
through code which doesn't include X11/Xlib.h.
−340
−341
const void* sapp_x11_get_display(void)
−342
On Linux, get the X11 Display, otherwise a null pointer. The
−343
Display has been cast to a void pointer in order to be tunneled
−344
through code which doesn't include X11/Xlib.h.
−345
−346
const void* sapp_wgpu_get_device(void)
−347
const void* sapp_wgpu_get_render_view(void)
−348
const void* sapp_wgpu_get_resolve_view(void)
−349
const void* sapp_wgpu_get_depth_stencil_view(void)
−350
These are the WebGPU-specific functions to get the WebGPU
−351
objects and values required for rendering. If sokol_app.h
−352
is not compiled with SOKOL_WGPU, these functions return null.
−353
−354
uint32_t sapp_gl_get_framebuffer(void)
−355
This returns the 'default framebuffer' of the GL context.
−356
Typically this will be zero.
−357
−358
int sapp_gl_get_major_version(void)
−359
int sapp_gl_get_minor_version(void)
−360
bool sapp_gl_is_gles(void)
−361
Returns the major and minor version of the GL context and
−362
whether the GL context is a GLES context
−363
−364
const void* sapp_android_get_native_activity(void);
−365
On Android, get the native activity ANativeActivity pointer, otherwise
−366
a null pointer.
−367
−368
--- Implement the frame-callback function, this function will be called
−369
on the same thread as the init callback, but might be on a different
−370
thread than the sokol_main() function. Note that the size of
−371
the rendering framebuffer might have changed since the frame callback
−372
was called last. Call the functions sapp_width() and sapp_height()
−373
each frame to get the current size.
−374
−375
--- Optionally implement the event-callback to handle input events.
−376
sokol-app provides the following type of input events:
−377
- a 'virtual key' was pressed down or released
−378
- a single text character was entered (provided as UTF-32 encoded
−379
UNICODE code point)
−380
- a mouse button was pressed down or released (left, right, middle)
−381
- mouse-wheel or 2D scrolling events
−382
- the mouse was moved
−383
- the mouse has entered or left the application window boundaries
−384
- low-level, portable multi-touch events (began, moved, ended, cancelled)
−385
- the application window was resized, iconified or restored
−386
- the application was suspended or restored (on mobile platforms)
−387
- the user or application code has asked to quit the application
−388
- a string was pasted to the system clipboard
−389
- one or more files have been dropped onto the application window
−390
−391
To explicitly 'consume' an event and prevent that the event is
−392
forwarded for further handling to the operating system, call
−393
sapp_consume_event() from inside the event handler (NOTE that
−394
this behaviour is currently only implemented for some HTML5
−395
events, support for other platforms and event types will
−396
be added as needed, please open a GitHub ticket and/or provide
−397
a PR if needed).
−398
−399
NOTE: Do *not* call any 3D API rendering functions in the event
−400
callback function, since the 3D API context may not be active when the
−401
event callback is called (it may work on some platforms and 3D APIs,
−402
but not others, and the exact behaviour may change between
−403
sokol-app versions).
−404
−405
--- Implement the cleanup-callback function, this is called once
−406
after the user quits the application (see the section
−407
"APPLICATION QUIT" for detailed information on quitting
−408
behaviour, and how to intercept a pending quit - for instance to show a
−409
"Really Quit?" dialog box). Note that the cleanup-callback isn't
−410
guaranteed to be called on the web and mobile platforms.
−411
−412
MOUSE CURSOR TYPE AND VISIBILITY
−413
================================
−414
You can show and hide the mouse cursor with
−415
−416
void sapp_show_mouse(bool show)
−417
−418
And to get the current shown status:
−419
−420
bool sapp_mouse_shown(void)
−421
−422
NOTE that hiding the mouse cursor is different and independent from
−423
the MOUSE/POINTER LOCK feature which will also hide the mouse pointer when
−424
active (MOUSE LOCK is described below).
−425
−426
To change the mouse cursor to one of several predefined types, call
−427
the function:
−428
−429
void sapp_set_mouse_cursor(sapp_mouse_cursor cursor)
−430
−431
Setting the default mouse cursor SAPP_MOUSECURSOR_DEFAULT will restore
−432
the standard look.
−433
−434
To get the currently active mouse cursor type, call:
−435
−436
sapp_mouse_cursor sapp_get_mouse_cursor(void)
−437
−438
MOUSE LOCK (AKA POINTER LOCK, AKA MOUSE CAPTURE)
−439
================================================
−440
In normal mouse mode, no mouse movement events are reported when the
−441
mouse leaves the windows client area or hits the screen border (whether
−442
it's one or the other depends on the platform), and the mouse move events
−443
(SAPP_EVENTTYPE_MOUSE_MOVE) contain absolute mouse positions in
−444
framebuffer pixels in the sapp_event items mouse_x and mouse_y, and
−445
relative movement in framebuffer pixels in the sapp_event items mouse_dx
−446
and mouse_dy.
−447
−448
To get continuous mouse movement (also when the mouse leaves the window
−449
client area or hits the screen border), activate mouse-lock mode
−450
by calling:
−451
−452
sapp_lock_mouse(true)
−453
−454
When mouse lock is activated, the mouse pointer is hidden, the
−455
reported absolute mouse position (sapp_event.mouse_x/y) appears
−456
frozen, and the relative mouse movement in sapp_event.mouse_dx/dy
−457
no longer has a direct relation to framebuffer pixels but instead
−458
uses "raw mouse input" (what "raw mouse input" exactly means also
−459
differs by platform).
−460
−461
To deactivate mouse lock and return to normal mouse mode, call
−462
−463
sapp_lock_mouse(false)
−464
−465
And finally, to check if mouse lock is currently active, call
−466
−467
if (sapp_mouse_locked()) { ... }
−468
−469
Note that mouse-lock state may not change immediately after sapp_lock_mouse(true/false)
−470
is called, instead on some platforms the actual state switch may be delayed
−471
to the end of the current frame or even to a later frame.
−472
−473
The mouse may also be unlocked automatically without calling sapp_lock_mouse(false),
−474
most notably when the application window becomes inactive.
−475
−476
On the web platform there are further restrictions to be aware of, caused
−477
by the limitations of the HTML5 Pointer Lock API:
−478
−479
- sapp_lock_mouse(true) can be called at any time, but it will
−480
only take effect in a 'short-lived input event handler of a specific
−481
type', meaning when one of the following events happens:
−482
- SAPP_EVENTTYPE_MOUSE_DOWN
−483
- SAPP_EVENTTYPE_MOUSE_UP
−484
- SAPP_EVENTTYPE_MOUSE_SCROLL
−485
- SAPP_EVENTTYPE_KEY_UP
−486
- SAPP_EVENTTYPE_KEY_DOWN
−487
- The mouse lock/unlock action on the web platform is asynchronous,
−488
this means that sapp_mouse_locked() won't immediately return
−489
the new status after calling sapp_lock_mouse(), instead the
−490
reported status will only change when the pointer lock has actually
−491
been activated or deactivated in the browser.
−492
- On the web, mouse lock can be deactivated by the user at any time
−493
by pressing the Esc key. When this happens, sokol_app.h behaves
−494
the same as if sapp_lock_mouse(false) is called.
−495
−496
For things like camera manipulation it's most straightforward to lock
−497
and unlock the mouse right from the sokol_app.h event handler, for
−498
instance the following code enters and leaves mouse lock when the
−499
left mouse button is pressed and released, and then uses the relative

Showing the first 500 of 14048 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

vendor/sokol/sokol_log.hdeleted
@@ -1,334 +0,0 @@
−1
#if defined(SOKOL_IMPL) && !defined(SOKOL_LOG_IMPL)
−2
#define SOKOL_LOG_IMPL
−3
#endif
−4
#ifndef SOKOL_LOG_INCLUDED
−5
/*
−6
sokol_log.h -- common logging callback for sokol headers
−7
−8
Project URL: https://github.com/floooh/sokol
−9
−10
Example code: https://github.com/floooh/sokol-samples
−11
−12
Do this:
−13
#define SOKOL_IMPL or
−14
#define SOKOL_LOG_IMPL
−15
before you include this file in *one* C or C++ file to create the
−16
implementation.
−17
−18
Optionally provide the following defines when building the implementation:
−19
−20
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
−21
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
−22
SOKOL_LOG_API_DECL - public function declaration prefix (default: extern)
−23
SOKOL_API_DECL - same as SOKOL_GFX_API_DECL
−24
SOKOL_API_IMPL - public function implementation prefix (default: -)
−25
−26
Optionally define the following for verbose output:
−27
−28
SOKOL_DEBUG - by default this is defined if NDEBUG is not defined
−29
−30
−31
OVERVIEW
−32
========
−33
sokol_log.h provides a default logging callback for other sokol headers.
−34
−35
To use the default log callback, just include sokol_log.h and provide
−36
a function pointer to the 'slog_func' function when setting up the
−37
sokol library:
−38
−39
For instance with sokol_audio.h:
−40
−41
#include "sokol_log.h"
−42
...
−43
saudio_setup(&(saudio_desc){ .logger.func = slog_func });
−44
−45
Logging output goes to stderr and/or a platform specific logging subsystem
−46
(which means that in some scenarios you might see logging messages duplicated):
−47
−48
- Windows: stderr + OutputDebugStringA()
−49
- macOS/iOS/Linux: stderr + syslog()
−50
- Emscripten: console.info()/warn()/error()
−51
- Android: __android_log_write()
−52
−53
On Windows with sokol_app.h also note the runtime config items to make
−54
stdout/stderr output visible on the console for WinMain() applications
−55
via sapp_desc.win32.console_attach or sapp_desc.win32.console_create,
−56
however when running in a debugger on Windows, the logging output should
−57
show up on the debug output UI panel.
−58
−59
In debug mode, a log message might look like this:
−60
−61
[sspine][error][id:12] /Users/floh/projects/sokol/util/sokol_spine.h:3472:0:
−62
SKELETON_DESC_NO_ATLAS: no atlas object provided in sspine_skeleton_desc.atlas
−63
−64
The source path and line number is formatted like compiler errors, in some IDEs (like VSCode)
−65
such error messages are clickable.
−66
−67
In release mode, logging is less verbose as to not bloat the executable with string data, but you still get
−68
enough information to identify the type and location of an error:
−69
−70
[sspine][error][id:12][line:3472]
−71
−72
RULES FOR WRITING YOUR OWN LOGGING FUNCTION
−73
===========================================
−74
- must be re-entrant because it might be called from different threads
−75
- must treat **all** provided string pointers as optional (can be null)
−76
- don't store the string pointers, copy the string data instead
−77
- must not return for log level panic
−78
−79
LICENSE
−80
=======
−81
zlib/libpng license
−82
−83
Copyright (c) 2023 Andre Weissflog
−84
−85
This software is provided 'as-is', without any express or implied warranty.
−86
In no event will the authors be held liable for any damages arising from the
−87
use of this software.
−88
−89
Permission is granted to anyone to use this software for any purpose,
−90
including commercial applications, and to alter it and redistribute it
−91
freely, subject to the following restrictions:
−92
−93
1. The origin of this software must not be misrepresented; you must not
−94
claim that you wrote the original software. If you use this software in a
−95
product, an acknowledgment in the product documentation would be
−96
appreciated but is not required.
−97
−98
2. Altered source versions must be plainly marked as such, and must not
−99
be misrepresented as being the original software.
−100
−101
3. This notice may not be removed or altered from any source
−102
distribution.
−103
*/
−104
#define SOKOL_LOG_INCLUDED (1)
−105
#include <stdint.h>
−106
−107
#if defined(SOKOL_API_DECL) && !defined(SOKOL_LOG_API_DECL)
−108
#define SOKOL_LOG_API_DECL SOKOL_API_DECL
−109
#endif
−110
#ifndef SOKOL_LOG_API_DECL
−111
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_LOG_IMPL)
−112
#define SOKOL_LOG_API_DECL __declspec(dllexport)
−113
#elif defined(_WIN32) && defined(SOKOL_DLL)
−114
#define SOKOL_LOG_API_DECL __declspec(dllimport)
−115
#else
−116
#define SOKOL_LOG_API_DECL extern
−117
#endif
−118
#endif
−119
−120
#ifdef __cplusplus
−121
extern "C" {
−122
#endif
−123
−124
/*
−125
Plug this function into the 'logger.func' struct item when initializing any of the sokol
−126
headers. For instance for sokol_audio.h it would look like this:
−127
−128
saudio_setup(&(saudio_desc){
−129
.logger = {
−130
.func = slog_func
−131
}
−132
});
−133
*/
−134
SOKOL_LOG_API_DECL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data);
−135
−136
#ifdef __cplusplus
−137
} // extern "C"
−138
#endif
−139
#endif // SOKOL_LOG_INCLUDED
−140
−141
// ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██
−142
// ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██
−143
// ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██
−144
// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
−145
// ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████
−146
//
−147
// >>implementation
−148
#ifdef SOKOL_LOG_IMPL
−149
#define SOKOL_LOG_IMPL_INCLUDED (1)
−150
−151
#ifndef SOKOL_API_IMPL
−152
#define SOKOL_API_IMPL
−153
#endif
−154
#ifndef SOKOL_DEBUG
−155
#ifndef NDEBUG
−156
#define SOKOL_DEBUG
−157
#endif
−158
#endif
−159
#ifndef SOKOL_ASSERT
−160
#include <assert.h>
−161
#define SOKOL_ASSERT(c) assert(c)
−162
#endif
−163
−164
#ifndef _SOKOL_PRIVATE
−165
#if defined(__GNUC__) || defined(__clang__)
−166
#define _SOKOL_PRIVATE __attribute__((unused)) static
−167
#else
−168
#define _SOKOL_PRIVATE static
−169
#endif
−170
#endif
−171
−172
#ifndef _SOKOL_UNUSED
−173
#define _SOKOL_UNUSED(x) (void)(x)
−174
#endif
−175
−176
// platform detection
−177
#if defined(__APPLE__)
−178
#define _SLOG_APPLE (1)
−179
#elif defined(__EMSCRIPTEN__)
−180
#define _SLOG_EMSCRIPTEN (1)
−181
#elif defined(_WIN32)
−182
#define _SLOG_WINDOWS (1)
−183
#elif defined(__ANDROID__)
−184
#define _SLOG_ANDROID (1)
−185
#elif defined(__linux__) || defined(__unix__)
−186
#define _SLOG_LINUX (1)
−187
#else
−188
#error "sokol_log.h: unknown platform"
−189
#endif
−190
−191
#include <stdlib.h> // abort
−192
#include <stdio.h> // fputs
−193
#include <stddef.h> // size_t
−194
−195
#if defined(_SLOG_EMSCRIPTEN)
−196
#include <emscripten/emscripten.h>
−197
#elif defined(_SLOG_WINDOWS)
−198
#ifndef WIN32_LEAN_AND_MEAN
−199
#define WIN32_LEAN_AND_MEAN
−200
#endif
−201
#ifndef NOMINMAX
−202
#define NOMINMAX
−203
#endif
−204
#include <windows.h>
−205
#elif defined(_SLOG_ANDROID)
−206
#include <android/log.h>
−207
#elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE)
−208
#include <syslog.h>
−209
#endif
−210
−211
// size of line buffer (on stack!) in bytes including terminating zero
−212
#define _SLOG_LINE_LENGTH (512)
−213
−214
_SOKOL_PRIVATE char* _slog_append(const char* str, char* dst, char* end) {
−215
if (str) {
−216
char c;
−217
while (((c = *str++) != 0) && (dst < (end - 1))) {
−218
*dst++ = c;
−219
}
−220
}
−221
*dst = 0;
−222
return dst;
−223
}
−224
−225
_SOKOL_PRIVATE char* _slog_itoa(uint32_t x, char* buf, size_t buf_size) {
−226
const size_t max_digits_and_null = 11;
−227
if (buf_size < max_digits_and_null) {
−228
return 0;
−229
}
−230
char* p = buf + max_digits_and_null;
−231
*--p = 0;
−232
do {
−233
*--p = '0' + (x % 10);
−234
x /= 10;
−235
} while (x != 0);
−236
return p;
−237
}
−238
−239
#if defined(_SLOG_EMSCRIPTEN)
−240
EM_JS(void, slog_js_log, (uint32_t level, const char* c_str), {
−241
const str = UTF8ToString(c_str);
−242
switch (level) {
−243
case 0: console.error(str); break;
−244
case 1: console.error(str); break;
−245
case 2: console.warn(str); break;
−246
default: console.info(str); break;
−247
}
−248
})
−249
#endif
−250
−251
SOKOL_API_IMPL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data) {
−252
_SOKOL_UNUSED(user_data);
−253
−254
const char* log_level_str;
−255
switch (log_level) {
−256
case 0: log_level_str = "panic"; break;
−257
case 1: log_level_str = "error"; break;
−258
case 2: log_level_str = "warning"; break;
−259
default: log_level_str = "info"; break;
−260
}
−261
−262
// build log output line
−263
char line_buf[_SLOG_LINE_LENGTH];
−264
char* str = line_buf;
−265
char* end = line_buf + sizeof(line_buf);
−266
char num_buf[32];
−267
if (tag) {
−268
str = _slog_append("[", str, end);
−269
str = _slog_append(tag, str, end);
−270
str = _slog_append("]", str, end);
−271
}
−272
str = _slog_append("[", str, end);
−273
str = _slog_append(log_level_str, str, end);
−274
str = _slog_append("]", str, end);
−275
str = _slog_append("[id:", str, end);
−276
str = _slog_append(_slog_itoa(log_item, num_buf, sizeof(num_buf)), str, end);
−277
str = _slog_append("]", str, end);
−278
// if a filename is provided, build a clickable log message that's compatible with compiler error messages
−279
if (filename) {
−280
str = _slog_append(" ", str, end);
−281
#if defined(_MSC_VER)
−282
// MSVC compiler error format
−283
str = _slog_append(filename, str, end);
−284
str = _slog_append("(", str, end);
−285
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
−286
str = _slog_append("): ", str, end);
−287
#else
−288
// gcc/clang compiler error format
−289
str = _slog_append(filename, str, end);
−290
str = _slog_append(":", str, end);
−291
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
−292
str = _slog_append(":0: ", str, end);
−293
#endif
−294
}
−295
else {
−296
str = _slog_append("[line:", str, end);
−297
str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end);
−298
str = _slog_append("] ", str, end);
−299
}
−300
if (message) {
−301
str = _slog_append("\n\t", str, end);
−302
str = _slog_append(message, str, end);
−303
}
−304
str = _slog_append("\n\n", str, end);
−305
if (0 == log_level) {
−306
str = _slog_append("ABORTING because of [panic]\n", str, end);
−307
(void)str;
−308
}
−309
−310
// print to stderr?
−311
#if defined(_SLOG_LINUX) || defined(_SLOG_WINDOWS) || defined(_SLOG_APPLE)
−312
fputs(line_buf, stderr);
−313
#endif
−314
−315
// platform specific logging calls
−316
#if defined(_SLOG_WINDOWS)
−317
OutputDebugStringA(line_buf);
−318
#elif defined(_SLOG_ANDROID)
−319
int prio;
−320
switch (log_level) {
−321
case 0: prio = ANDROID_LOG_FATAL; break;
−322
case 1: prio = ANDROID_LOG_ERROR; break;
−323
case 2: prio = ANDROID_LOG_WARN; break;
−324
default: prio = ANDROID_LOG_INFO; break;
−325
}
−326
__android_log_write(prio, "SOKOL", line_buf);
−327
#elif defined(_SLOG_EMSCRIPTEN)
−328
slog_js_log(log_level, line_buf);
−329
#endif
−330
if (0 == log_level) {
−331
abort();
−332
}
−333
}
−334
#endif // SOKOL_LOG_IMPL
vendor/sokol/sokol_time.hdeleted
@@ -1,319 +0,0 @@
−1
#if defined(SOKOL_IMPL) && !defined(SOKOL_TIME_IMPL)
−2
#define SOKOL_TIME_IMPL
−3
#endif
−4
#ifndef SOKOL_TIME_INCLUDED
−5
/*
−6
sokol_time.h -- simple cross-platform time measurement
−7
−8
Project URL: https://github.com/floooh/sokol
−9
−10
Do this:
−11
#define SOKOL_IMPL or
−12
#define SOKOL_TIME_IMPL
−13
before you include this file in *one* C or C++ file to create the
−14
implementation.
−15
−16
Optionally provide the following defines with your own implementations:
−17
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
−18
SOKOL_TIME_API_DECL - public function declaration prefix (default: extern)
−19
SOKOL_API_DECL - same as SOKOL_TIME_API_DECL
−20
SOKOL_API_IMPL - public function implementation prefix (default: -)
−21
−22
If sokol_time.h is compiled as a DLL, define the following before
−23
including the declaration or implementation:
−24
−25
SOKOL_DLL
−26
−27
On Windows, SOKOL_DLL will define SOKOL_TIME_API_DECL as __declspec(dllexport)
−28
or __declspec(dllimport) as needed.
−29
−30
void stm_setup();
−31
Call once before any other functions to initialize sokol_time
−32
(this calls for instance QueryPerformanceFrequency on Windows)
−33
−34
uint64_t stm_now();
−35
Get current point in time in unspecified 'ticks'. The value that
−36
is returned has no relation to the 'wall-clock' time and is
−37
not in a specific time unit, it is only useful to compute
−38
time differences.
−39
−40
uint64_t stm_diff(uint64_t new, uint64_t old);
−41
Computes the time difference between new and old. This will always
−42
return a positive, non-zero value.
−43
−44
uint64_t stm_since(uint64_t start);
−45
Takes the current time, and returns the elapsed time since start
−46
(this is a shortcut for "stm_diff(stm_now(), start)")
−47
−48
uint64_t stm_laptime(uint64_t* last_time);
−49
This is useful for measuring frame time and other recurring
−50
events. It takes the current time, returns the time difference
−51
to the value in last_time, and stores the current time in
−52
last_time for the next call. If the value in last_time is 0,
−53
the return value will be zero (this usually happens on the
−54
very first call).
−55
−56
uint64_t stm_round_to_common_refresh_rate(uint64_t duration)
−57
This oddly named function takes a measured frame time and
−58
returns the closest "nearby" common display refresh rate frame duration
−59
in ticks. If the input duration isn't close to any common display
−60
refresh rate, the input duration will be returned unchanged as a fallback.
−61
The main purpose of this function is to remove jitter/inaccuracies from
−62
measured frame times, and instead use the display refresh rate as
−63
frame duration.
−64
NOTE: for more robust frame timing, consider using the
−65
sokol_app.h function sapp_frame_duration()
−66
−67
Use the following functions to convert a duration in ticks into
−68
useful time units:
−69
−70
double stm_sec(uint64_t ticks);
−71
double stm_ms(uint64_t ticks);
−72
double stm_us(uint64_t ticks);
−73
double stm_ns(uint64_t ticks);
−74
Converts a tick value into seconds, milliseconds, microseconds
−75
or nanoseconds. Note that not all platforms will have nanosecond
−76
or even microsecond precision.
−77
−78
Uses the following time measurement functions under the hood:
−79
−80
Windows: QueryPerformanceFrequency() / QueryPerformanceCounter()
−81
MacOS/iOS: mach_absolute_time()
−82
emscripten: emscripten_get_now()
−83
Linux+others: clock_gettime(CLOCK_MONOTONIC)
−84
−85
zlib/libpng license
−86
−87
Copyright (c) 2018 Andre Weissflog
−88
−89
This software is provided 'as-is', without any express or implied warranty.
−90
In no event will the authors be held liable for any damages arising from the
−91
use of this software.
−92
−93
Permission is granted to anyone to use this software for any purpose,
−94
including commercial applications, and to alter it and redistribute it
−95
freely, subject to the following restrictions:
−96
−97
1. The origin of this software must not be misrepresented; you must not
−98
claim that you wrote the original software. If you use this software in a
−99
product, an acknowledgment in the product documentation would be
−100
appreciated but is not required.
−101
−102
2. Altered source versions must be plainly marked as such, and must not
−103
be misrepresented as being the original software.
−104
−105
3. This notice may not be removed or altered from any source
−106
distribution.
−107
*/
−108
#define SOKOL_TIME_INCLUDED (1)
−109
#include <stdint.h>
−110
−111
#if defined(SOKOL_API_DECL) && !defined(SOKOL_TIME_API_DECL)
−112
#define SOKOL_TIME_API_DECL SOKOL_API_DECL
−113
#endif
−114
#ifndef SOKOL_TIME_API_DECL
−115
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_TIME_IMPL)
−116
#define SOKOL_TIME_API_DECL __declspec(dllexport)
−117
#elif defined(_WIN32) && defined(SOKOL_DLL)
−118
#define SOKOL_TIME_API_DECL __declspec(dllimport)
−119
#else
−120
#define SOKOL_TIME_API_DECL extern
−121
#endif
−122
#endif
−123
−124
#ifdef __cplusplus
−125
extern "C" {
−126
#endif
−127
−128
SOKOL_TIME_API_DECL void stm_setup(void);
−129
SOKOL_TIME_API_DECL uint64_t stm_now(void);
−130
SOKOL_TIME_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks);
−131
SOKOL_TIME_API_DECL uint64_t stm_since(uint64_t start_ticks);
−132
SOKOL_TIME_API_DECL uint64_t stm_laptime(uint64_t* last_time);
−133
SOKOL_TIME_API_DECL uint64_t stm_round_to_common_refresh_rate(uint64_t frame_ticks);
−134
SOKOL_TIME_API_DECL double stm_sec(uint64_t ticks);
−135
SOKOL_TIME_API_DECL double stm_ms(uint64_t ticks);
−136
SOKOL_TIME_API_DECL double stm_us(uint64_t ticks);
−137
SOKOL_TIME_API_DECL double stm_ns(uint64_t ticks);
−138
−139
#ifdef __cplusplus
−140
} /* extern "C" */
−141
#endif
−142
#endif // SOKOL_TIME_INCLUDED
−143
−144
/*-- IMPLEMENTATION ----------------------------------------------------------*/
−145
#ifdef SOKOL_TIME_IMPL
−146
#define SOKOL_TIME_IMPL_INCLUDED (1)
−147
#include <string.h> /* memset */
−148
−149
#ifndef SOKOL_API_IMPL
−150
#define SOKOL_API_IMPL
−151
#endif
−152
#ifndef SOKOL_ASSERT
−153
#include <assert.h>
−154
#define SOKOL_ASSERT(c) assert(c)
−155
#endif
−156
#ifndef _SOKOL_PRIVATE
−157
#if defined(__GNUC__) || defined(__clang__)
−158
#define _SOKOL_PRIVATE __attribute__((unused)) static
−159
#else
−160
#define _SOKOL_PRIVATE static
−161
#endif
−162
#endif
−163
−164
#if defined(_WIN32)
−165
#ifndef WIN32_LEAN_AND_MEAN
−166
#define WIN32_LEAN_AND_MEAN
−167
#endif
−168
#include <windows.h>
−169
typedef struct {
−170
uint32_t initialized;
−171
LARGE_INTEGER freq;
−172
LARGE_INTEGER start;
−173
} _stm_state_t;
−174
#elif defined(__APPLE__) && defined(__MACH__)
−175
#include <mach/mach_time.h>
−176
typedef struct {
−177
uint32_t initialized;
−178
mach_timebase_info_data_t timebase;
−179
uint64_t start;
−180
} _stm_state_t;
−181
#elif defined(__EMSCRIPTEN__)
−182
#include <emscripten/emscripten.h>
−183
typedef struct {
−184
uint32_t initialized;
−185
double start;
−186
} _stm_state_t;
−187
#else /* anything else, this will need more care for non-Linux platforms */
−188
#ifdef ESP8266
−189
// On the ESP8266, clock_gettime ignores the first argument and CLOCK_MONOTONIC isn't defined
−190
#define CLOCK_MONOTONIC 0
−191
#endif
−192
#include <time.h>
−193
typedef struct {
−194
uint32_t initialized;
−195
uint64_t start;
−196
} _stm_state_t;
−197
#endif
−198
static _stm_state_t _stm;
−199
−200
/* prevent 64-bit overflow when computing relative timestamp
−201
see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3
−202
*/
−203
#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__))
−204
_SOKOL_PRIVATE int64_t _stm_int64_muldiv(int64_t value, int64_t numer, int64_t denom) {
−205
int64_t q = value / denom;
−206
int64_t r = value % denom;
−207
return q * numer + r * numer / denom;
−208
}
−209
#endif
−210
−211
SOKOL_API_IMPL void stm_setup(void) {
−212
memset(&_stm, 0, sizeof(_stm));
−213
_stm.initialized = 0xABCDABCD;
−214
#if defined(_WIN32)
−215
QueryPerformanceFrequency(&_stm.freq);
−216
QueryPerformanceCounter(&_stm.start);
−217
#elif defined(__APPLE__) && defined(__MACH__)
−218
mach_timebase_info(&_stm.timebase);
−219
_stm.start = mach_absolute_time();
−220
#elif defined(__EMSCRIPTEN__)
−221
_stm.start = emscripten_get_now();
−222
#else
−223
struct timespec ts;
−224
clock_gettime(CLOCK_MONOTONIC, &ts);
−225
_stm.start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec;
−226
#endif
−227
}
−228
−229
SOKOL_API_IMPL uint64_t stm_now(void) {
−230
SOKOL_ASSERT(_stm.initialized == 0xABCDABCD);
−231
uint64_t now;
−232
#if defined(_WIN32)
−233
LARGE_INTEGER qpc_t;
−234
QueryPerformanceCounter(&qpc_t);
−235
now = (uint64_t) _stm_int64_muldiv(qpc_t.QuadPart - _stm.start.QuadPart, 1000000000, _stm.freq.QuadPart);
−236
#elif defined(__APPLE__) && defined(__MACH__)
−237
const uint64_t mach_now = mach_absolute_time() - _stm.start;
−238
now = (uint64_t) _stm_int64_muldiv((int64_t)mach_now, (int64_t)_stm.timebase.numer, (int64_t)_stm.timebase.denom);
−239
#elif defined(__EMSCRIPTEN__)
−240
double js_now = emscripten_get_now() - _stm.start;
−241
now = (uint64_t) (js_now * 1000000.0);
−242
#else
−243
struct timespec ts;
−244
clock_gettime(CLOCK_MONOTONIC, &ts);
−245
now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm.start;
−246
#endif
−247
return now;
−248
}
−249
−250
SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) {
−251
if (new_ticks > old_ticks) {
−252
return new_ticks - old_ticks;
−253
}
−254
else {
−255
return 1;
−256
}
−257
}
−258
−259
SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) {
−260
return stm_diff(stm_now(), start_ticks);
−261
}
−262
−263
SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) {
−264
SOKOL_ASSERT(last_time);
−265
uint64_t dt = 0;
−266
uint64_t now = stm_now();
−267
if (0 != *last_time) {
−268
dt = stm_diff(now, *last_time);
−269
}
−270
*last_time = now;
−271
return dt;
−272
}
−273
−274
// first number is frame duration in ns, second number is tolerance in ns,
−275
// the resulting min/max values must not overlap!
−276
static const uint64_t _stm_refresh_rates[][2] = {
−277
{ 16666667, 1000000 }, // 60 Hz: 16.6667 +- 1ms
−278
{ 13888889, 250000 }, // 72 Hz: 13.8889 +- 0.25ms
−279
{ 13333333, 250000 }, // 75 Hz: 13.3333 +- 0.25ms
−280
{ 11764706, 250000 }, // 85 Hz: 11.7647 +- 0.25
−281
{ 11111111, 250000 }, // 90 Hz: 11.1111 +- 0.25ms
−282
{ 10000000, 500000 }, // 100 Hz: 10.0000 +- 0.5ms
−283
{ 8333333, 500000 }, // 120 Hz: 8.3333 +- 0.5ms
−284
{ 6944445, 500000 }, // 144 Hz: 6.9445 +- 0.5ms
−285
{ 4166667, 1000000 }, // 240 Hz: 4.1666 +- 1ms
−286
{ 0, 0 }, // keep the last element always at zero
−287
};
−288
−289
SOKOL_API_IMPL uint64_t stm_round_to_common_refresh_rate(uint64_t ticks) {
−290
uint64_t ns;
−291
int i = 0;
−292
while (0 != (ns = _stm_refresh_rates[i][0])) {
−293
uint64_t tol = _stm_refresh_rates[i][1];
−294
if ((ticks > (ns - tol)) && (ticks < (ns + tol))) {
−295
return ns;
−296
}
−297
i++;
−298
}
−299
// fallthrough: didn't fit into any buckets
−300
return ticks;
−301
}
−302
−303
SOKOL_API_IMPL double stm_sec(uint64_t ticks) {
−304
return (double)ticks / 1000000000.0;
−305
}
−306
−307
SOKOL_API_IMPL double stm_ms(uint64_t ticks) {
−308
return (double)ticks / 1000000.0;
−309
}
−310
−311
SOKOL_API_IMPL double stm_us(uint64_t ticks) {
−312
return (double)ticks / 1000.0;
−313
}
−314
−315
SOKOL_API_IMPL double stm_ns(uint64_t ticks) {
−316
return (double)ticks;
−317
}
−318
#endif /* SOKOL_TIME_IMPL */
−319