react-native-gtkx 0.3.0-alpha.1 → 0.4.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/adw/index.d.ts +3 -2
- package/dist/adw/index.js +21 -4
- package/dist/adw/index.js.map +1 -1
- package/dist/adw/widgets.generated.d.ts +1 -1
- package/dist/adw/widgets.generated.js +2 -2
- package/dist/adw/widgets.generated.js.map +1 -1
- package/dist/animated/create-animated.d.ts +2 -0
- package/dist/animated/create-animated.js +2 -0
- package/dist/animated/create-animated.js.map +1 -1
- package/dist/animated/event.d.ts +15 -0
- package/dist/animated/event.js +80 -0
- package/dist/animated/event.js.map +1 -0
- package/dist/animated/index.d.ts +4 -0
- package/dist/animated/index.js +8 -0
- package/dist/animated/index.js.map +1 -1
- package/dist/animated/spring.d.ts +10 -0
- package/dist/animated/spring.js +20 -6
- package/dist/animated/spring.js.map +1 -1
- package/dist/animated/timing.d.ts +10 -0
- package/dist/animated/timing.js +21 -13
- package/dist/animated/timing.js.map +1 -1
- package/dist/apis/host.gtkx.js +70 -11
- package/dist/apis/host.gtkx.js.map +1 -1
- package/dist/common/navigation-stack.d.ts +6 -3
- package/dist/common/navigation-stack.js +8 -1
- package/dist/common/navigation-stack.js.map +1 -1
- package/dist/common/widget.js +2 -11
- package/dist/common/widget.js.map +1 -1
- package/dist/components/animated.d.ts +1 -0
- package/dist/components/animated.js +28 -4
- package/dist/components/animated.js.map +1 -1
- package/dist/components/app-registry.js +32 -8
- package/dist/components/app-registry.js.map +1 -1
- package/dist/components/request-animation-frame.d.ts +33 -0
- package/dist/components/request-animation-frame.js +83 -0
- package/dist/components/request-animation-frame.js.map +1 -0
- package/dist/components/scroll-view.js +60 -2
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/virtualized-list.js +1 -4
- package/dist/components/virtualized-list.js.map +1 -1
- package/dist/dnd/autoscroll.d.ts +44 -0
- package/dist/dnd/autoscroll.js +176 -0
- package/dist/dnd/autoscroll.js.map +1 -0
- package/dist/dnd/grid-order.d.ts +45 -0
- package/dist/dnd/grid-order.js +151 -0
- package/dist/dnd/grid-order.js.map +1 -0
- package/dist/dnd/grid.d.ts +44 -0
- package/dist/dnd/grid.js +397 -0
- package/dist/dnd/grid.js.map +1 -0
- package/dist/dnd/gtk-controllers.d.ts +16 -2
- package/dist/dnd/gtk-controllers.js +23 -3
- package/dist/dnd/gtk-controllers.js.map +1 -1
- package/dist/dnd/index.d.ts +4 -2
- package/dist/dnd/index.js +9 -2
- package/dist/dnd/index.js.map +1 -1
- package/dist/dnd/order-state.d.ts +14 -0
- package/dist/dnd/order-state.js +55 -0
- package/dist/dnd/order-state.js.map +1 -0
- package/dist/dnd/order.d.ts +19 -0
- package/dist/dnd/order.js +19 -0
- package/dist/dnd/order.js.map +1 -1
- package/dist/dnd/sortable.d.ts +29 -4
- package/dist/dnd/sortable.js +308 -115
- package/dist/dnd/sortable.js.map +1 -1
- package/dist/dnd/types.d.ts +236 -14
- package/dist/dnd/types.js +30 -0
- package/dist/dnd/types.js.map +1 -1
- package/dist/gesture-handler-compat/attach-context.d.ts +29 -0
- package/dist/gesture-handler-compat/attach-context.js +90 -0
- package/dist/gesture-handler-compat/attach-context.js.map +1 -0
- package/dist/gesture-handler-compat/detector-runtime.d.ts +14 -3
- package/dist/gesture-handler-compat/detector-runtime.js +15 -5
- package/dist/gesture-handler-compat/detector-runtime.js.map +1 -1
- package/dist/gesture-handler-compat/detector.js +57 -2
- package/dist/gesture-handler-compat/detector.js.map +1 -1
- package/dist/gesture-handler-compat/gesture-state-manager.d.ts +5 -0
- package/dist/gesture-handler-compat/gesture-state-manager.js +77 -0
- package/dist/gesture-handler-compat/gesture-state-manager.js.map +1 -0
- package/dist/gesture-handler-compat/index.d.ts +2 -2
- package/dist/gesture-handler-compat/index.js +38 -33
- package/dist/gesture-handler-compat/index.js.map +1 -1
- package/dist/gesture-handler-compat/recognizer.d.ts +12 -1
- package/dist/gesture-handler-compat/recognizer.js +23 -9
- package/dist/gesture-handler-compat/recognizer.js.map +1 -1
- package/dist/gesture-handler-compat/tag-registry.d.ts +14 -0
- package/dist/gesture-handler-compat/tag-registry.js +19 -0
- package/dist/gesture-handler-compat/tag-registry.js.map +1 -0
- package/dist/globals/index.d.ts +47 -0
- package/dist/globals/index.js +181 -0
- package/dist/globals/index.js.map +1 -0
- package/dist/globals/install.d.ts +1 -0
- package/dist/globals/install.js +14 -0
- package/dist/globals/install.js.map +1 -0
- package/dist/gtkx/bridge/adw-namespace.d.ts +2 -0
- package/dist/gtkx/bridge/adw-namespace.js +26 -0
- package/dist/gtkx/bridge/adw-namespace.js.map +1 -0
- package/dist/gtkx/bridge/adw.d.ts +23 -0
- package/dist/gtkx/bridge/adw.js +93 -0
- package/dist/gtkx/bridge/adw.js.map +1 -0
- package/dist/gtkx/bridge/color-scheme-parse.d.ts +11 -0
- package/dist/gtkx/bridge/color-scheme-parse.js +42 -0
- package/dist/gtkx/bridge/color-scheme-parse.js.map +1 -0
- package/dist/gtkx/bridge/color-scheme-portal.d.ts +24 -0
- package/dist/gtkx/bridge/color-scheme-portal.js +172 -0
- package/dist/gtkx/bridge/color-scheme-portal.js.map +1 -0
- package/dist/gtkx/bridge/core.d.ts +25 -0
- package/dist/gtkx/bridge/core.js +69 -0
- package/dist/gtkx/bridge/core.js.map +1 -0
- package/dist/gtkx/bridge/drag-layer.d.ts +27 -0
- package/dist/gtkx/bridge/drag-layer.js +177 -0
- package/dist/gtkx/bridge/drag-layer.js.map +1 -0
- package/dist/gtkx/bridge/index.d.ts +1 -27
- package/dist/gtkx/bridge/index.js +12 -71
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/widgets.generated.adw.d.ts +1 -0
- package/dist/gtkx/bridge/widgets.generated.adw.js +16 -0
- package/dist/gtkx/bridge/widgets.generated.adw.js.map +1 -0
- package/dist/gtkx/bridge/widgets.generated.d.ts +0 -1
- package/dist/gtkx/bridge/widgets.generated.js +3 -3
- package/dist/gtkx/bridge/widgets.generated.js.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/data/generated.d.ts +41 -20
- package/dist/mcp/data/generated.js +46 -20
- package/dist/mcp/data/generated.js.map +1 -1
- package/dist/metro/index.d.ts +1 -0
- package/dist/metro/index.js +12 -0
- package/dist/metro/index.js.map +1 -1
- package/dist/navigation/sidebar.js +2 -45
- package/dist/navigation/sidebar.js.map +1 -1
- package/dist/reanimated-compat/animatable-value.d.ts +158 -0
- package/dist/reanimated-compat/animatable-value.js +316 -0
- package/dist/reanimated-compat/animatable-value.js.map +1 -0
- package/dist/reanimated-compat/animation.d.ts +34 -13
- package/dist/reanimated-compat/animation.js +97 -25
- package/dist/reanimated-compat/animation.js.map +1 -1
- package/dist/reanimated-compat/mutable.js +6 -6
- package/dist/reanimated-compat/mutable.js.map +1 -1
- package/dist/reanimated-compat/updater-animations.js +32 -12
- package/dist/reanimated-compat/updater-animations.js.map +1 -1
- package/dist/runner/host-dev.js +5 -1
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +9 -1
- package/dist/runner/host.js.map +1 -1
- package/dist/vite/index.js +130 -0
- package/dist/vite/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/gtkx/bridge/theme.d.ts +0 -4
- package/dist/gtkx/bridge/theme.js +0 -5
- package/dist/gtkx/bridge/theme.js.map +0 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// The plain-GTK profile's color-scheme source — see
|
|
2
|
+
// .claude/epics/adw-optional/004.md. Two mechanisms, same as the task:
|
|
3
|
+
//
|
|
4
|
+
// 1. org.freedesktop.appearance's "color-scheme" key on the XDG desktop
|
|
5
|
+
// portal (org.freedesktop.portal.Settings, over D-Bus) — the
|
|
6
|
+
// cross-desktop standard GNOME, KDE and others implement, with live
|
|
7
|
+
// updates via its SettingChanged signal. This is what makes the plain
|
|
8
|
+
// profile report the real system scheme on KDE too, not just GNOME.
|
|
9
|
+
// 2. Gtk.Settings' gtk-application-prefer-dark-theme when the portal never
|
|
10
|
+
// answers (no xdg-desktop-portal running at all, or it timed out) — the
|
|
11
|
+
// only other lever plain GTK has, and also the ONLY thing
|
|
12
|
+
// setPlainColorScheme can honestly write (see its own doc below).
|
|
13
|
+
//
|
|
14
|
+
// The parsing half (unwrapping the portal's double-boxed variant, mapping
|
|
15
|
+
// its uint32 onto "light"/"dark") lives in ./color-scheme-parse instead,
|
|
16
|
+
// which has no @gtkx/gi imports at all — this file is the GTK/D-Bus glue
|
|
17
|
+
// around it, and is NOT unit-testable on its own (constructing a real
|
|
18
|
+
// Gio.DBusProxy needs a real GTK/GLib runtime); see that file's own doc and
|
|
19
|
+
// tests/unit/gtkx/color-scheme-parse.test.ts for what actually is.
|
|
20
|
+
//
|
|
21
|
+
// Deliberately hand-rolled rather than reading GTK's own newer
|
|
22
|
+
// Gtk.Settings:gtk-interface-color-scheme (added in GTK 4.16, and itself
|
|
23
|
+
// backed by this exact same portal internally): that property does not
|
|
24
|
+
// exist before 4.16, silently raising this profile's real minimum past the
|
|
25
|
+
// GTK >= 4.10 baseline Alert's Gtk.AlertDialog fallback already commits to,
|
|
26
|
+
// and — because it is GTK's own opaque internal client — gives us nothing
|
|
27
|
+
// to unit-test if the portal itself can never be reached in this repo's
|
|
28
|
+
// headless test session.
|
|
29
|
+
import * as Gio from "@gtkx/gi/gio";
|
|
30
|
+
import * as GLib from "@gtkx/gi/glib";
|
|
31
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
32
|
+
import { parsePortalReadReply, parseSettingChangedValue, } from "./color-scheme-parse";
|
|
33
|
+
const PORTAL_BUS_NAME = "org.freedesktop.portal.Desktop";
|
|
34
|
+
const PORTAL_OBJECT_PATH = "/org/freedesktop/portal/desktop";
|
|
35
|
+
const PORTAL_SETTINGS_INTERFACE = "org.freedesktop.portal.Settings";
|
|
36
|
+
const APPEARANCE_NAMESPACE = "org.freedesktop.appearance";
|
|
37
|
+
const COLOR_SCHEME_KEY = "color-scheme";
|
|
38
|
+
// Bounded so a session with no portal at all (this repo's own headless-sway
|
|
39
|
+
// GTK test session included — see color-scheme-portal.gtk.test.tsx in
|
|
40
|
+
// spike/plain-gtk) fails fast instead of riding D-Bus's own ~25s default
|
|
41
|
+
// method-call timeout. Generous next to a real portal's actual answer time
|
|
42
|
+
// (single-digit milliseconds locally in every manual check during this task).
|
|
43
|
+
const PORTAL_TIMEOUT_MSEC = 2000;
|
|
44
|
+
const settingsDefault = () => Gtk.Settings.getDefault();
|
|
45
|
+
const effectiveScheme = () => settingsDefault()?.gtkApplicationPreferDarkTheme ? "dark" : "light";
|
|
46
|
+
const applyToGtkSettings = (scheme) => {
|
|
47
|
+
const settings = settingsDefault();
|
|
48
|
+
if (settings) {
|
|
49
|
+
// Writing fires notify::gtk-application-prefer-dark-theme (a no-op,
|
|
50
|
+
// GObject-property-setter style, when the value does not actually
|
|
51
|
+
// change) — the ONE signal onPlainColorSchemeChange listens on, so this
|
|
52
|
+
// is also how both setPlainColorScheme and an incoming portal update
|
|
53
|
+
// reach subscribers, with no separate notify path to keep in sync.
|
|
54
|
+
settings.gtkApplicationPreferDarkTheme = scheme === "dark";
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
// null = "follow the system" (this profile's equivalent of Adw's
|
|
58
|
+
// ColorScheme.DEFAULT); "light"/"dark" = an explicit local override (this
|
|
59
|
+
// profile's equivalent of Adw's FORCE_LIGHT/FORCE_DARK) — same tri-state
|
|
60
|
+
// shape as AdwStyleManager's own, so getPlainColorScheme/
|
|
61
|
+
// setPlainColorScheme stay consistent with each other exactly the way
|
|
62
|
+
// AdwStyleManager already is (see host.gtkx.ts's setColorScheme/
|
|
63
|
+
// colorScheme(), which both go through the one manager instance).
|
|
64
|
+
let forced = null;
|
|
65
|
+
// The last value this process actually learned FROM the portal, kept even
|
|
66
|
+
// while forced !== null so un-forcing (setPlainColorScheme(null)) can
|
|
67
|
+
// re-apply it immediately rather than waiting for the next SettingChanged.
|
|
68
|
+
let lastPortalScheme = null;
|
|
69
|
+
const applySystemUpdate = (scheme) => {
|
|
70
|
+
lastPortalScheme = scheme;
|
|
71
|
+
if (forced === null) {
|
|
72
|
+
applyToGtkSettings(scheme);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
let probeStarted = false;
|
|
76
|
+
// One-time, synchronous, memoized — mirrors gtkx/bridge/adw.ts's own
|
|
77
|
+
// probe-once cached shape. Synchronous (not a dynamic import/async probe
|
|
78
|
+
// like adw.ts's) because getPlainColorScheme must answer synchronously on
|
|
79
|
+
// every call per the Host contract (AppearanceHost.getColorScheme is not a
|
|
80
|
+
// Promise) — this is the one place that pays the D-Bus round trip, once,
|
|
81
|
+
// bounded by PORTAL_TIMEOUT_MSEC, the first time appearance is actually
|
|
82
|
+
// touched (not at module load, so an app that never reads/writes
|
|
83
|
+
// Appearance never pays for it at all).
|
|
84
|
+
const ensurePortalProbed = () => {
|
|
85
|
+
if (probeStarted) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
probeStarted = true;
|
|
89
|
+
try {
|
|
90
|
+
const proxy = Gio.DBusProxy.newForBusSync(Gio.BusType.SESSION,
|
|
91
|
+
// Skips the constructor's own synchronous property-cache GetAll call
|
|
92
|
+
// (the Settings portal interface has none we care about) — without
|
|
93
|
+
// this, construction itself can block on bus activation before ever
|
|
94
|
+
// reaching the bounded callSync below.
|
|
95
|
+
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES, null, PORTAL_BUS_NAME, PORTAL_OBJECT_PATH, PORTAL_SETTINGS_INTERFACE, null);
|
|
96
|
+
const reply = proxy.callSync("Read", GLib.Variant.newTuple([
|
|
97
|
+
GLib.Variant.newString(APPEARANCE_NAMESPACE),
|
|
98
|
+
GLib.Variant.newString(COLOR_SCHEME_KEY),
|
|
99
|
+
]), Gio.DBusCallFlags.NONE, PORTAL_TIMEOUT_MSEC, null);
|
|
100
|
+
applySystemUpdate(parsePortalReadReply(reply.getChildValue(0)));
|
|
101
|
+
proxy.on("g-signal", (_sender, signalName, parameters) => {
|
|
102
|
+
if (signalName !== "SettingChanged") {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const namespace = parameters.getChildValue(0).getString()[0];
|
|
106
|
+
const key = parameters.getChildValue(1).getString()[0];
|
|
107
|
+
if (namespace !== APPEARANCE_NAMESPACE || key !== COLOR_SCHEME_KEY) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
applySystemUpdate(parseSettingChangedValue(parameters.getChildValue(2)));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// No session bus, no portal owning org.freedesktop.portal.Desktop, or
|
|
115
|
+
// it didn't answer inside PORTAL_TIMEOUT_MSEC — Gtk.Settings' own
|
|
116
|
+
// current value (its GTK/theme default, absent anything else to set it)
|
|
117
|
+
// is the only honest source left. Not retried: matches adwAvailable()'s
|
|
118
|
+
// own probe-once verdict, and a portal that is not there at process
|
|
119
|
+
// start is not expected to appear mid-session either.
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
/** Always "light" | "dark" — see the module doc for how it is sourced. */
|
|
123
|
+
export const getPlainColorScheme = () => {
|
|
124
|
+
ensurePortalProbed();
|
|
125
|
+
return effectiveScheme();
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* The plain profile's setColorScheme. What Adw's setColorScheme forces is
|
|
129
|
+
* already only ever an app-local override — AdwStyleManager is per-process,
|
|
130
|
+
* never a system-wide write — so writing Gtk.Settings'
|
|
131
|
+
* gtk-application-prefer-dark-theme here (also strictly app-local: it never
|
|
132
|
+
* reaches outside this process either) is not a lesser feature, just the
|
|
133
|
+
* plain-GTK lever that does the same job. There is no honest way to make
|
|
134
|
+
* this profile change the DESKTOP's own preference — no portal write API
|
|
135
|
+
* exists (the portal is read + notify only, by design) — so "local-only" is
|
|
136
|
+
* the whole story, not a fallback for a system-wide write that almost
|
|
137
|
+
* worked.
|
|
138
|
+
*
|
|
139
|
+
* null ("follow the system") re-applies the last value actually observed
|
|
140
|
+
* from the portal, if any. With no portal reachable at all there is no
|
|
141
|
+
* other system source to revert to, so it is a deliberate no-op — staying
|
|
142
|
+
* at whatever the toggle already reads rather than guessing a default.
|
|
143
|
+
*/
|
|
144
|
+
export const setPlainColorScheme = (scheme) => {
|
|
145
|
+
ensurePortalProbed();
|
|
146
|
+
forced = scheme;
|
|
147
|
+
applyToGtkSettings(scheme ?? lastPortalScheme ?? effectiveScheme());
|
|
148
|
+
};
|
|
149
|
+
let settingsListenerAttached = false;
|
|
150
|
+
const listeners = new Set();
|
|
151
|
+
const attachSettingsListener = () => {
|
|
152
|
+
if (settingsListenerAttached) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const settings = settingsDefault();
|
|
156
|
+
if (!settings) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
settingsListenerAttached = true;
|
|
160
|
+
settings.on("notify::gtk-application-prefer-dark-theme", () => {
|
|
161
|
+
for (const listener of listeners) {
|
|
162
|
+
listener();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
export const onPlainColorSchemeChange = (notify) => {
|
|
167
|
+
ensurePortalProbed();
|
|
168
|
+
attachSettingsListener();
|
|
169
|
+
listeners.add(notify);
|
|
170
|
+
return { remove: () => listeners.delete(notify) };
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=color-scheme-portal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-scheme-portal.js","sourceRoot":"","sources":["../../../src/gtkx/bridge/color-scheme-portal.ts"],"names":[],"mappings":"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","sourcesContent":["// The plain-GTK profile's color-scheme source — see\n// .claude/epics/adw-optional/004.md. Two mechanisms, same as the task:\n//\n// 1. org.freedesktop.appearance's \"color-scheme\" key on the XDG desktop\n// portal (org.freedesktop.portal.Settings, over D-Bus) — the\n// cross-desktop standard GNOME, KDE and others implement, with live\n// updates via its SettingChanged signal. This is what makes the plain\n// profile report the real system scheme on KDE too, not just GNOME.\n// 2. Gtk.Settings' gtk-application-prefer-dark-theme when the portal never\n// answers (no xdg-desktop-portal running at all, or it timed out) — the\n// only other lever plain GTK has, and also the ONLY thing\n// setPlainColorScheme can honestly write (see its own doc below).\n//\n// The parsing half (unwrapping the portal's double-boxed variant, mapping\n// its uint32 onto \"light\"/\"dark\") lives in ./color-scheme-parse instead,\n// which has no @gtkx/gi imports at all — this file is the GTK/D-Bus glue\n// around it, and is NOT unit-testable on its own (constructing a real\n// Gio.DBusProxy needs a real GTK/GLib runtime); see that file's own doc and\n// tests/unit/gtkx/color-scheme-parse.test.ts for what actually is.\n//\n// Deliberately hand-rolled rather than reading GTK's own newer\n// Gtk.Settings:gtk-interface-color-scheme (added in GTK 4.16, and itself\n// backed by this exact same portal internally): that property does not\n// exist before 4.16, silently raising this profile's real minimum past the\n// GTK >= 4.10 baseline Alert's Gtk.AlertDialog fallback already commits to,\n// and — because it is GTK's own opaque internal client — gives us nothing\n// to unit-test if the portal itself can never be reached in this repo's\n// headless test session.\nimport * as Gio from \"@gtkx/gi/gio\"\nimport * as GLib from \"@gtkx/gi/glib\"\nimport * as Gtk from \"@gtkx/gi/gtk\"\nimport type { SubscriptionHandle } from \"../../contracts\"\nimport {\n parsePortalReadReply,\n parseSettingChangedValue,\n type ColorScheme,\n} from \"./color-scheme-parse\"\n\nexport type { ColorScheme }\n\nconst PORTAL_BUS_NAME = \"org.freedesktop.portal.Desktop\"\nconst PORTAL_OBJECT_PATH = \"/org/freedesktop/portal/desktop\"\nconst PORTAL_SETTINGS_INTERFACE = \"org.freedesktop.portal.Settings\"\nconst APPEARANCE_NAMESPACE = \"org.freedesktop.appearance\"\nconst COLOR_SCHEME_KEY = \"color-scheme\"\n\n// Bounded so a session with no portal at all (this repo's own headless-sway\n// GTK test session included — see color-scheme-portal.gtk.test.tsx in\n// spike/plain-gtk) fails fast instead of riding D-Bus's own ~25s default\n// method-call timeout. Generous next to a real portal's actual answer time\n// (single-digit milliseconds locally in every manual check during this task).\nconst PORTAL_TIMEOUT_MSEC = 2000\n\nconst settingsDefault = (): Gtk.Settings | null => Gtk.Settings.getDefault()\n\nconst effectiveScheme = (): ColorScheme =>\n settingsDefault()?.gtkApplicationPreferDarkTheme ? \"dark\" : \"light\"\n\nconst applyToGtkSettings = (scheme: ColorScheme): void => {\n const settings = settingsDefault()\n if (settings) {\n // Writing fires notify::gtk-application-prefer-dark-theme (a no-op,\n // GObject-property-setter style, when the value does not actually\n // change) — the ONE signal onPlainColorSchemeChange listens on, so this\n // is also how both setPlainColorScheme and an incoming portal update\n // reach subscribers, with no separate notify path to keep in sync.\n settings.gtkApplicationPreferDarkTheme = scheme === \"dark\"\n }\n}\n\n// null = \"follow the system\" (this profile's equivalent of Adw's\n// ColorScheme.DEFAULT); \"light\"/\"dark\" = an explicit local override (this\n// profile's equivalent of Adw's FORCE_LIGHT/FORCE_DARK) — same tri-state\n// shape as AdwStyleManager's own, so getPlainColorScheme/\n// setPlainColorScheme stay consistent with each other exactly the way\n// AdwStyleManager already is (see host.gtkx.ts's setColorScheme/\n// colorScheme(), which both go through the one manager instance).\nlet forced: ColorScheme | null = null\n// The last value this process actually learned FROM the portal, kept even\n// while forced !== null so un-forcing (setPlainColorScheme(null)) can\n// re-apply it immediately rather than waiting for the next SettingChanged.\nlet lastPortalScheme: ColorScheme | null = null\n\nconst applySystemUpdate = (scheme: ColorScheme): void => {\n lastPortalScheme = scheme\n if (forced === null) {\n applyToGtkSettings(scheme)\n }\n}\n\nlet probeStarted = false\n\n// One-time, synchronous, memoized — mirrors gtkx/bridge/adw.ts's own\n// probe-once cached shape. Synchronous (not a dynamic import/async probe\n// like adw.ts's) because getPlainColorScheme must answer synchronously on\n// every call per the Host contract (AppearanceHost.getColorScheme is not a\n// Promise) — this is the one place that pays the D-Bus round trip, once,\n// bounded by PORTAL_TIMEOUT_MSEC, the first time appearance is actually\n// touched (not at module load, so an app that never reads/writes\n// Appearance never pays for it at all).\nconst ensurePortalProbed = (): void => {\n if (probeStarted) {\n return\n }\n probeStarted = true\n try {\n const proxy = Gio.DBusProxy.newForBusSync(\n Gio.BusType.SESSION,\n // Skips the constructor's own synchronous property-cache GetAll call\n // (the Settings portal interface has none we care about) — without\n // this, construction itself can block on bus activation before ever\n // reaching the bounded callSync below.\n Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES,\n null,\n PORTAL_BUS_NAME,\n PORTAL_OBJECT_PATH,\n PORTAL_SETTINGS_INTERFACE,\n null,\n )\n const reply = proxy.callSync(\n \"Read\",\n GLib.Variant.newTuple([\n GLib.Variant.newString(APPEARANCE_NAMESPACE),\n GLib.Variant.newString(COLOR_SCHEME_KEY),\n ]),\n Gio.DBusCallFlags.NONE,\n PORTAL_TIMEOUT_MSEC,\n null,\n )\n applySystemUpdate(parsePortalReadReply(reply.getChildValue(0)))\n proxy.on(\"g-signal\", (_sender, signalName, parameters) => {\n if (signalName !== \"SettingChanged\") {\n return\n }\n const namespace = parameters.getChildValue(0).getString()[0]\n const key = parameters.getChildValue(1).getString()[0]\n if (namespace !== APPEARANCE_NAMESPACE || key !== COLOR_SCHEME_KEY) {\n return\n }\n applySystemUpdate(parseSettingChangedValue(parameters.getChildValue(2)))\n })\n } catch {\n // No session bus, no portal owning org.freedesktop.portal.Desktop, or\n // it didn't answer inside PORTAL_TIMEOUT_MSEC — Gtk.Settings' own\n // current value (its GTK/theme default, absent anything else to set it)\n // is the only honest source left. Not retried: matches adwAvailable()'s\n // own probe-once verdict, and a portal that is not there at process\n // start is not expected to appear mid-session either.\n }\n}\n\n/** Always \"light\" | \"dark\" — see the module doc for how it is sourced. */\nexport const getPlainColorScheme = (): ColorScheme => {\n ensurePortalProbed()\n return effectiveScheme()\n}\n\n/**\n * The plain profile's setColorScheme. What Adw's setColorScheme forces is\n * already only ever an app-local override — AdwStyleManager is per-process,\n * never a system-wide write — so writing Gtk.Settings'\n * gtk-application-prefer-dark-theme here (also strictly app-local: it never\n * reaches outside this process either) is not a lesser feature, just the\n * plain-GTK lever that does the same job. There is no honest way to make\n * this profile change the DESKTOP's own preference — no portal write API\n * exists (the portal is read + notify only, by design) — so \"local-only\" is\n * the whole story, not a fallback for a system-wide write that almost\n * worked.\n *\n * null (\"follow the system\") re-applies the last value actually observed\n * from the portal, if any. With no portal reachable at all there is no\n * other system source to revert to, so it is a deliberate no-op — staying\n * at whatever the toggle already reads rather than guessing a default.\n */\nexport const setPlainColorScheme = (scheme: ColorScheme | null): void => {\n ensurePortalProbed()\n forced = scheme\n applyToGtkSettings(scheme ?? lastPortalScheme ?? effectiveScheme())\n}\n\nlet settingsListenerAttached = false\nconst listeners = new Set<() => void>()\n\nconst attachSettingsListener = (): void => {\n if (settingsListenerAttached) {\n return\n }\n const settings = settingsDefault()\n if (!settings) {\n return\n }\n settingsListenerAttached = true\n settings.on(\"notify::gtk-application-prefer-dark-theme\", () => {\n for (const listener of listeners) {\n listener()\n }\n })\n}\n\nexport const onPlainColorSchemeChange = (\n notify: () => void,\n): SubscriptionHandle => {\n ensurePortalProbed()\n attachSettingsListener()\n listeners.add(notify)\n return { remove: () => listeners.delete(notify) }\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as Gdk from "@gtkx/gi/gdk";
|
|
2
|
+
import * as Gio from "@gtkx/gi/gio";
|
|
3
|
+
import * as GLib from "@gtkx/gi/glib";
|
|
4
|
+
import * as GObject from "@gtkx/gi/gobject";
|
|
5
|
+
import * as Graphene from "@gtkx/gi/graphene";
|
|
6
|
+
import * as Gsk from "@gtkx/gi/gsk";
|
|
7
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
8
|
+
import * as Pango from "@gtkx/gi/pango";
|
|
9
|
+
export { Gdk, Gio, GLib, GObject, Graphene, Gsk, Gtk, Pango };
|
|
10
|
+
export { GtkApplication, GtkGestureClick } from "@gtkx/jsx/gtk";
|
|
11
|
+
export { GMenu, GSimpleAction } from "@gtkx/jsx/gio";
|
|
12
|
+
export { GtkAdjustment, GtkDragSource, GtkDropControllerMotion, GtkDropTarget, GtkShortcut, GtkShortcutController, GtkTextBuffer, } from "@gtkx/jsx/gtk";
|
|
13
|
+
export * from "./widgets.generated";
|
|
14
|
+
export { createPortal, createRoot, quit, rootElement, useApplication, useBindSetting, useParentWindow, useProperty, useSetting, type Root, type RootElement, } from "@gtkx/react";
|
|
15
|
+
export type { SettingsSchema, SettingsSchemaKeys, SettingValue, } from "@gtkx/react/internal";
|
|
16
|
+
export { useSignal } from "./use-signal";
|
|
17
|
+
export { css, cx, injectGlobal } from "@gtkx/css";
|
|
18
|
+
export { createWidgetCss, type WidgetCss } from "./widget-css";
|
|
19
|
+
export { createTextProbe, measureWidget, toNumber } from "./measure";
|
|
20
|
+
export { computePointIn, computePointInWindow, type Point } from "./geometry";
|
|
21
|
+
export { beginDragLayer, type DragLayerHandle } from "./drag-layer";
|
|
22
|
+
export { createSlotPortal } from "./slot-portal";
|
|
23
|
+
export { cacheChildOrder, getViewBoxComponent, invalidateZOrder, setBoxOnly, setBoxPassthrough, setHitSlop, setPaintOnlyLeaf, setPointerTarget, setZIndex, type HitSlop, } from "./view-box";
|
|
24
|
+
export { getSvgNodeComponent, getSvgNodeDescriptor, queueSvgRedraw, resolveSvgColor, resolveSvgPaint, setSvgNodeDescriptor, type SvgDefsDescriptor, type SvgGradientUnits, type SvgGroupDescriptor, type SvgLinearGradientDescriptor, type SvgNodeDescriptor, type SvgPaintSpec, type SvgRadialGradientDescriptor, type SvgShapeDescriptor, type SvgStopDescriptor, type SvgSvgDescriptor, } from "./svg-node";
|
|
25
|
+
export { allocateChild, attachRnLayout, detachRnLayout, queueAllocate, queueResize, type RnLayoutHooks, type RnLayoutOrientation, } from "./layout-manager";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// The core door onto gtkx: everything the RN core (components, APIs,
|
|
2
|
+
// gesture-handler, reanimated, dnd) needs, and NOTHING from @gtkx/gi/adw or
|
|
3
|
+
// @gtkx/jsx/adw — see .claude/epics/adw-optional/001.md. This is what makes
|
|
4
|
+
// `libraries: ["Gtk-4.0"]` alone buildable: an app that never declares
|
|
5
|
+
// "Adw-1" has no "./adw" entry in either package's codegen store at all, so
|
|
6
|
+
// a static import of either specifier fails the whole build regardless of
|
|
7
|
+
// whether it is ever reached at runtime. ./adw.ts is the one place that
|
|
8
|
+
// still reaches for them, behind a probe (adwAvailable()); its absence
|
|
9
|
+
// surfaces as a named throw, not a build failure.
|
|
10
|
+
//
|
|
11
|
+
// Caveats baked into this surface (catalogued in docs/gtkx-rc4-notes.md):
|
|
12
|
+
// - 64-bit FFI values arrive as BigInt → normalize with toNumber() at this boundary
|
|
13
|
+
// import-then-export (not `export * as`): the latter is the one syntax the
|
|
14
|
+
// stock @react-native/babel-preset cannot transform — this form keeps
|
|
15
|
+
// consumer apps on their unmodified RN Babel config.
|
|
16
|
+
import * as Gdk from "@gtkx/gi/gdk";
|
|
17
|
+
import * as Gio from "@gtkx/gi/gio";
|
|
18
|
+
import * as GLib from "@gtkx/gi/glib";
|
|
19
|
+
import * as GObject from "@gtkx/gi/gobject";
|
|
20
|
+
import * as Graphene from "@gtkx/gi/graphene";
|
|
21
|
+
import * as Gsk from "@gtkx/gi/gsk";
|
|
22
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
23
|
+
import * as Pango from "@gtkx/gi/pango";
|
|
24
|
+
export { Gdk, Gio, GLib, GObject, Graphene, Gsk, Gtk, Pango };
|
|
25
|
+
// GtkApplication and GtkGestureClick are not Gtk.Widget subclasses (an
|
|
26
|
+
// application object and an event controller, respectively), so the widget
|
|
27
|
+
// surface generator never sees them — kept here by hand, same as before it
|
|
28
|
+
// existed.
|
|
29
|
+
export { GtkApplication, GtkGestureClick } from "@gtkx/jsx/gtk";
|
|
30
|
+
// Auxiliary gtkx JSX elements that are not Gtk.Widget subclasses either,
|
|
31
|
+
// same reason as the pair above — scripts/generate-widget-surface.ts only
|
|
32
|
+
// classifies widgets, so these fall into its "notAWidget" bucket (see
|
|
33
|
+
// scripts/widget-surface/classification.json) and are otherwise
|
|
34
|
+
// unreachable through react-native-gtkx/gtk. Every one of these is a real,
|
|
35
|
+
// necessary building block for a real app: actions and menus (Gio), a text
|
|
36
|
+
// buffer and an adjustment (the model objects GtkTextView/GtkSpinRow etc.
|
|
37
|
+
// bind to), keyboard shortcuts, and the two drag-and-drop controllers.
|
|
38
|
+
// Adwaita's own auxiliary elements (AdwBreakpoint, AdwToggle, the
|
|
39
|
+
// AdwShortcutsDialog leaves) live in ./adw instead.
|
|
40
|
+
export { GMenu, GSimpleAction } from "@gtkx/jsx/gio";
|
|
41
|
+
export { GtkAdjustment, GtkDragSource, GtkDropControllerMotion, GtkDropTarget, GtkShortcut, GtkShortcutController, GtkTextBuffer, } from "@gtkx/jsx/gtk";
|
|
42
|
+
// The full GTK widget surface — every GTK class gtkx binds that derives
|
|
43
|
+
// Gtk.Widget, raw. src/gtk/widgets.generated wraps most of them with
|
|
44
|
+
// wrapReactNative; this file is where @gtkx/jsx is still allowed to be
|
|
45
|
+
// imported directly (see the eslint carve-out for src/gtkx/bridge/**), so it
|
|
46
|
+
// pulls the raw widgets from here rather than from @gtkx/jsx itself.
|
|
47
|
+
// Adwaita's raw widgets are the sibling generated file, widgets.generated.adw.ts,
|
|
48
|
+
// exported only from ./adw — see that file's header for why the two cannot
|
|
49
|
+
// share one module.
|
|
50
|
+
export * from "./widgets.generated";
|
|
51
|
+
export { createPortal, createRoot, quit, rootElement, useApplication, useBindSetting, useParentWindow, useProperty, useSetting, } from "@gtkx/react";
|
|
52
|
+
// useSignal comes from ./use-signal, not @gtkx/react — see the workaround note
|
|
53
|
+
// there (rc.3 delivers a stale handler).
|
|
54
|
+
export { useSignal } from "./use-signal";
|
|
55
|
+
export { css, cx, injectGlobal } from "@gtkx/css";
|
|
56
|
+
// The imperative counterpart of `css`: a private provider on one widget,
|
|
57
|
+
// for values that change per frame and must not enter the shared stylesheet.
|
|
58
|
+
export { createWidgetCss } from "./widget-css";
|
|
59
|
+
export { createTextProbe, measureWidget, toNumber } from "./measure";
|
|
60
|
+
export { computePointIn, computePointInWindow } from "./geometry";
|
|
61
|
+
export { beginDragLayer } from "./drag-layer";
|
|
62
|
+
// A portal into a NAMED slot of a remote object (the window's action map,
|
|
63
|
+
// its controllers) rather than into its default child slot — see the file
|
|
64
|
+
// for why gtkx's own createPortal is not enough on its own.
|
|
65
|
+
export { createSlotPortal } from "./slot-portal";
|
|
66
|
+
export { cacheChildOrder, getViewBoxComponent, invalidateZOrder, setBoxOnly, setBoxPassthrough, setHitSlop, setPaintOnlyLeaf, setPointerTarget, setZIndex, } from "./view-box";
|
|
67
|
+
export { getSvgNodeComponent, getSvgNodeDescriptor, queueSvgRedraw, resolveSvgColor, resolveSvgPaint, setSvgNodeDescriptor, } from "./svg-node";
|
|
68
|
+
export { allocateChild, attachRnLayout, detachRnLayout, queueAllocate, queueResize, } from "./layout-manager";
|
|
69
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/gtkx/bridge/core.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,4EAA4E;AAC5E,4EAA4E;AAC5E,uEAAuE;AACvE,4EAA4E;AAC5E,0EAA0E;AAC1E,wEAAwE;AACxE,uEAAuE;AACvE,kDAAkD;AAClD,EAAE;AACF,0EAA0E;AAC1E,oFAAoF;AAEpF,2EAA2E;AAC3E,sEAAsE;AACtE,qDAAqD;AACrD,OAAO,KAAK,GAAG,MAAM,cAAc,CAAA;AACnC,OAAO,KAAK,GAAG,MAAM,cAAc,CAAA;AACnC,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,GAAG,MAAM,cAAc,CAAA;AACnC,OAAO,KAAK,GAAG,MAAM,cAAc,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAA;AAEvC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAA;AAE7D,uEAAuE;AACvE,2EAA2E;AAC3E,2EAA2E;AAC3E,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/D,yEAAyE;AACzE,0EAA0E;AAC1E,sEAAsE;AACtE,gEAAgE;AAChE,2EAA2E;AAC3E,2EAA2E;AAC3E,0EAA0E;AAC1E,uEAAuE;AACvE,kEAAkE;AAClE,oDAAoD;AACpD,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,aAAa,EACb,WAAW,EACX,qBAAqB,EACrB,aAAa,GACd,MAAM,eAAe,CAAA;AAEtB,wEAAwE;AACxE,qEAAqE;AACrE,uEAAuE;AACvE,6EAA6E;AAC7E,qEAAqE;AACrE,kFAAkF;AAClF,2EAA2E;AAC3E,oBAAoB;AACpB,cAAc,qBAAqB,CAAA;AAEnC,OAAO,EACL,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,WAAW,EACX,cAAc,EACd,cAAc,EACd,eAAe,EACf,WAAW,EACX,UAAU,GAGX,MAAM,aAAa,CAAA;AAcpB,+EAA+E;AAC/E,yCAAyC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAExC,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAEjD,yEAAyE;AACzE,6EAA6E;AAC7E,OAAO,EAAE,eAAe,EAAkB,MAAM,cAAc,CAAA;AAE9D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAc,MAAM,YAAY,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAwB,MAAM,cAAc,CAAA;AACnE,0EAA0E;AAC1E,0EAA0E;AAC1E,4DAA4D;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,SAAS,GAEV,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,eAAe,EACf,oBAAoB,GAWrB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,aAAa,EACb,cAAc,EACd,cAAc,EACd,aAAa,EACb,WAAW,GAGZ,MAAM,kBAAkB,CAAA","sourcesContent":["// The core door onto gtkx: everything the RN core (components, APIs,\n// gesture-handler, reanimated, dnd) needs, and NOTHING from @gtkx/gi/adw or\n// @gtkx/jsx/adw — see .claude/epics/adw-optional/001.md. This is what makes\n// `libraries: [\"Gtk-4.0\"]` alone buildable: an app that never declares\n// \"Adw-1\" has no \"./adw\" entry in either package's codegen store at all, so\n// a static import of either specifier fails the whole build regardless of\n// whether it is ever reached at runtime. ./adw.ts is the one place that\n// still reaches for them, behind a probe (adwAvailable()); its absence\n// surfaces as a named throw, not a build failure.\n//\n// Caveats baked into this surface (catalogued in docs/gtkx-rc4-notes.md):\n// - 64-bit FFI values arrive as BigInt → normalize with toNumber() at this boundary\n\n// import-then-export (not `export * as`): the latter is the one syntax the\n// stock @react-native/babel-preset cannot transform — this form keeps\n// consumer apps on their unmodified RN Babel config.\nimport * as Gdk from \"@gtkx/gi/gdk\"\nimport * as Gio from \"@gtkx/gi/gio\"\nimport * as GLib from \"@gtkx/gi/glib\"\nimport * as GObject from \"@gtkx/gi/gobject\"\nimport * as Graphene from \"@gtkx/gi/graphene\"\nimport * as Gsk from \"@gtkx/gi/gsk\"\nimport * as Gtk from \"@gtkx/gi/gtk\"\nimport * as Pango from \"@gtkx/gi/pango\"\n\nexport { Gdk, Gio, GLib, GObject, Graphene, Gsk, Gtk, Pango }\n\n// GtkApplication and GtkGestureClick are not Gtk.Widget subclasses (an\n// application object and an event controller, respectively), so the widget\n// surface generator never sees them — kept here by hand, same as before it\n// existed.\nexport { GtkApplication, GtkGestureClick } from \"@gtkx/jsx/gtk\"\n\n// Auxiliary gtkx JSX elements that are not Gtk.Widget subclasses either,\n// same reason as the pair above — scripts/generate-widget-surface.ts only\n// classifies widgets, so these fall into its \"notAWidget\" bucket (see\n// scripts/widget-surface/classification.json) and are otherwise\n// unreachable through react-native-gtkx/gtk. Every one of these is a real,\n// necessary building block for a real app: actions and menus (Gio), a text\n// buffer and an adjustment (the model objects GtkTextView/GtkSpinRow etc.\n// bind to), keyboard shortcuts, and the two drag-and-drop controllers.\n// Adwaita's own auxiliary elements (AdwBreakpoint, AdwToggle, the\n// AdwShortcutsDialog leaves) live in ./adw instead.\nexport { GMenu, GSimpleAction } from \"@gtkx/jsx/gio\"\nexport {\n GtkAdjustment,\n GtkDragSource,\n GtkDropControllerMotion,\n GtkDropTarget,\n GtkShortcut,\n GtkShortcutController,\n GtkTextBuffer,\n} from \"@gtkx/jsx/gtk\"\n\n// The full GTK widget surface — every GTK class gtkx binds that derives\n// Gtk.Widget, raw. src/gtk/widgets.generated wraps most of them with\n// wrapReactNative; this file is where @gtkx/jsx is still allowed to be\n// imported directly (see the eslint carve-out for src/gtkx/bridge/**), so it\n// pulls the raw widgets from here rather than from @gtkx/jsx itself.\n// Adwaita's raw widgets are the sibling generated file, widgets.generated.adw.ts,\n// exported only from ./adw — see that file's header for why the two cannot\n// share one module.\nexport * from \"./widgets.generated\"\n\nexport {\n createPortal,\n createRoot,\n quit,\n rootElement,\n useApplication,\n useBindSetting,\n useParentWindow,\n useProperty,\n useSetting,\n type Root,\n type RootElement,\n} from \"@gtkx/react\"\n\n// rc.4 moved the settings-schema types off the public entry point into\n// /internal, with no replacement on `@gtkx/react` — `useSetting`/\n// `useBindSetting` are still public and still typed by them, so a consumer\n// that wants to name the type of a setting has no supported import for it.\n// We re-export them from here, which is the whole point of the bridge; the\n// ask to put them back is filed in docs/upstream-gtkx.md.\nexport type {\n SettingsSchema,\n SettingsSchemaKeys,\n SettingValue,\n} from \"@gtkx/react/internal\"\n\n// useSignal comes from ./use-signal, not @gtkx/react — see the workaround note\n// there (rc.3 delivers a stale handler).\nexport { useSignal } from \"./use-signal\"\n\nexport { css, cx, injectGlobal } from \"@gtkx/css\"\n\n// The imperative counterpart of `css`: a private provider on one widget,\n// for values that change per frame and must not enter the shared stylesheet.\nexport { createWidgetCss, type WidgetCss } from \"./widget-css\"\n\nexport { createTextProbe, measureWidget, toNumber } from \"./measure\"\nexport { computePointIn, computePointInWindow, type Point } from \"./geometry\"\nexport { beginDragLayer, type DragLayerHandle } from \"./drag-layer\"\n// A portal into a NAMED slot of a remote object (the window's action map,\n// its controllers) rather than into its default child slot — see the file\n// for why gtkx's own createPortal is not enough on its own.\nexport { createSlotPortal } from \"./slot-portal\"\nexport {\n cacheChildOrder,\n getViewBoxComponent,\n invalidateZOrder,\n setBoxOnly,\n setBoxPassthrough,\n setHitSlop,\n setPaintOnlyLeaf,\n setPointerTarget,\n setZIndex,\n type HitSlop,\n} from \"./view-box\"\nexport {\n getSvgNodeComponent,\n getSvgNodeDescriptor,\n queueSvgRedraw,\n resolveSvgColor,\n resolveSvgPaint,\n setSvgNodeDescriptor,\n type SvgDefsDescriptor,\n type SvgGradientUnits,\n type SvgGroupDescriptor,\n type SvgLinearGradientDescriptor,\n type SvgNodeDescriptor,\n type SvgPaintSpec,\n type SvgRadialGradientDescriptor,\n type SvgShapeDescriptor,\n type SvgStopDescriptor,\n type SvgSvgDescriptor,\n} from \"./svg-node\"\nexport {\n allocateChild,\n attachRnLayout,\n detachRnLayout,\n queueAllocate,\n queueResize,\n type RnLayoutHooks,\n type RnLayoutOrientation,\n} from \"./layout-manager\"\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
export type DragLayerHandle = {
|
|
3
|
+
/** Called on every `GtkDropControllerMotion` "motion", already in the
|
|
4
|
+
* OVERLAY's own coordinates — no per-call translation, because the
|
|
5
|
+
* picture is that overlay's own child. Zero React involvement: a widget
|
|
6
|
+
* property write per axis, nothing else. */
|
|
7
|
+
move: (x: number, y: number) => void;
|
|
8
|
+
/** The pointer (re)entered this window mid-drag: reveal the ghost and
|
|
9
|
+
* place it before the next motion arrives. */
|
|
10
|
+
show: (x: number, y: number) => void;
|
|
11
|
+
/** The pointer left this window: nothing further tracks it here, so
|
|
12
|
+
* hide rather than leave it stuck at the edge. */
|
|
13
|
+
hide: () => void;
|
|
14
|
+
/** The drag ended (dropped or cancelled): remove the ghost and restore
|
|
15
|
+
* the original's opacity. */
|
|
16
|
+
end: () => void;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Starts the window-level ghost for a drag that just began on `widget`,
|
|
20
|
+
* grabbed at `(grabX, grabY)` in `widget`'s own coordinates — the same pair
|
|
21
|
+
* `GtkDragSource.onPrepare` already reports and already feeds `setIcon()`.
|
|
22
|
+
*
|
|
23
|
+
* Returns `null` when `widget` has no window yet (nothing to escape) or
|
|
24
|
+
* shares no transform with it (unrealized) — the same failure mode
|
|
25
|
+
* `computePointIn` documents for `measure()`.
|
|
26
|
+
*/
|
|
27
|
+
export declare const beginDragLayer: (widget: Gtk.Widget, grabX: number, grabY: number) => DragLayerHandle | null;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// A window-level drag layer: a non-interactive `Gtk.Picture` positioned by
|
|
2
|
+
// pixel margins inside a `Gtk.Overlay` wrapped once around each window's real
|
|
3
|
+
// content, showing a live `Gtk.WidgetPaintable` of whatever is being dragged.
|
|
4
|
+
//
|
|
5
|
+
// Why this exists NEXT TO `GtkDragSource`'s own icon (gtk-controllers.tsx
|
|
6
|
+
// already sets one via `setIcon`): that icon is a compositor-owned surface —
|
|
7
|
+
// real, and already unclipped by this process's own widget tree, but also
|
|
8
|
+
// outside it, so nothing in this process can read its geometry or its
|
|
9
|
+
// pixels. A dragged item escaping an `overflow: hidden` ancestor needs a
|
|
10
|
+
// widget IN OUR OWN TREE to prove that with — geometry a test can measure,
|
|
11
|
+
// pixels a screenshot can read. This is that widget: a second, deliberately
|
|
12
|
+
// redundant representation, added at window level (an `Overlay` child, so no
|
|
13
|
+
// ancestor's clip reaches it) for as long as the drag is over this window,
|
|
14
|
+
// and removed the moment the drag ends. `setIcon`'s own icon is untouched —
|
|
15
|
+
// a drag that leaves this window for another still shows it.
|
|
16
|
+
//
|
|
17
|
+
// REPARENTING THE DRAGGED WIDGET ITSELF was tried first and refused: moving
|
|
18
|
+
// the real node into a different container re-triggers ITS OWN size
|
|
19
|
+
// negotiation under a parent with different constraints (measured: a
|
|
20
|
+
// 100×100 card came out 800×600), and an unmount mid-flight strands the
|
|
21
|
+
// widget outside the tree React still thinks it owns. A `WidgetPaintable`
|
|
22
|
+
// sidesteps both — it is a live VIEW of the widget, not the widget, so the
|
|
23
|
+
// original never moves and never leaves the component tree React manages.
|
|
24
|
+
//
|
|
25
|
+
// Ghosting the original is `Gtk.Widget.setOpacity()`, restored to whatever it
|
|
26
|
+
// was before (not hardcoded to 1), so this composes with an app's own
|
|
27
|
+
// animated or static opacity rather than fighting it. Because
|
|
28
|
+
// `Gtk.WidgetPaintable` renders the widget it observes LIVE, `setIcon`'s own
|
|
29
|
+
// compositor icon and this overlay copy dim along with the original — the
|
|
30
|
+
// three are one underlying render, not three independent ones. Documented in
|
|
31
|
+
// docs/api.md rather than fought: decoupling them would need a frozen
|
|
32
|
+
// texture snapshot taken before the fade, not a live paintable, and a frozen
|
|
33
|
+
// snapshot is not what the spike validated or what this measures.
|
|
34
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
35
|
+
import { computePointIn } from "./geometry";
|
|
36
|
+
// Dim, not hidden: RN dnd libraries commonly leave the dragged row at
|
|
37
|
+
// reduced rather than zero opacity (e.g. `react-native-draggable-flatlist`'s
|
|
38
|
+
// `activeOpacity`), and a fully transparent original would take the ghost's
|
|
39
|
+
// own coupled render with it, per the note above.
|
|
40
|
+
const GHOST_OPACITY = 0.35;
|
|
41
|
+
const overlaysByRoot = new WeakMap();
|
|
42
|
+
const asAdwApplicationWindow = (root) => {
|
|
43
|
+
const candidate = root;
|
|
44
|
+
return typeof candidate.setContent === "function" &&
|
|
45
|
+
typeof candidate.getContent === "function"
|
|
46
|
+
? candidate
|
|
47
|
+
: null;
|
|
48
|
+
};
|
|
49
|
+
const setWindowContent = (root, content) => {
|
|
50
|
+
const adwWindow = asAdwApplicationWindow(root);
|
|
51
|
+
if (adwWindow) {
|
|
52
|
+
adwWindow.setContent(content);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
;
|
|
56
|
+
root.setChild(content);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Detaches the window's current content and hands it back, rather than
|
|
61
|
+
* leaving it parented. `Gtk.Overlay.setChild()` asserts its argument is
|
|
62
|
+
* unparented (or already its own child, or null) — it will not steal a
|
|
63
|
+
* widget from another parent — so the content has to be unparented BEFORE
|
|
64
|
+
* the overlay can adopt it, not after.
|
|
65
|
+
*/
|
|
66
|
+
const detachWindowContent = (root) => {
|
|
67
|
+
const adwWindow = asAdwApplicationWindow(root);
|
|
68
|
+
const current = adwWindow
|
|
69
|
+
? adwWindow.getContent()
|
|
70
|
+
: root.getChild();
|
|
71
|
+
if (current) {
|
|
72
|
+
setWindowContent(root, null);
|
|
73
|
+
}
|
|
74
|
+
return current;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The overlay for `root`, wrapping its real content the first time any drag
|
|
78
|
+
* asks for it and reused for the window's whole lifetime after that — a
|
|
79
|
+
* one-time structural change, not a per-drag one, because reparenting a
|
|
80
|
+
* whole app's content is not something to repeat every time a finger moves.
|
|
81
|
+
*/
|
|
82
|
+
const getOverlayEntry = (root) => {
|
|
83
|
+
const existing = overlaysByRoot.get(root);
|
|
84
|
+
if (existing) {
|
|
85
|
+
return existing;
|
|
86
|
+
}
|
|
87
|
+
const current = detachWindowContent(root);
|
|
88
|
+
const overlay = Gtk.Overlay.new();
|
|
89
|
+
overlay.setChild(current);
|
|
90
|
+
setWindowContent(root, overlay);
|
|
91
|
+
const entry = { overlay, active: null };
|
|
92
|
+
overlaysByRoot.set(root, entry);
|
|
93
|
+
// One motion controller per WINDOW rather than per drag or per provider:
|
|
94
|
+
// GDK stops delivering to the drag source after `drag-begin` (the
|
|
95
|
+
// compositor owns the pointer from there), and `GtkDropControllerMotion`
|
|
96
|
+
// is the widget-level replacement `dnd/context.tsx` already relies on, at
|
|
97
|
+
// provider scope, for the same reason. This is that same technique at
|
|
98
|
+
// window scope, so the ghost tracks the pointer regardless of which
|
|
99
|
+
// `DropProvider` — if any — the drag started under.
|
|
100
|
+
const motion = Gtk.DropControllerMotion.new();
|
|
101
|
+
motion.connect("motion", (x, y) => {
|
|
102
|
+
entry.active?.move(x, y);
|
|
103
|
+
});
|
|
104
|
+
motion.connect("enter", (x, y) => {
|
|
105
|
+
entry.active?.show(x, y);
|
|
106
|
+
});
|
|
107
|
+
motion.connect("leave", () => {
|
|
108
|
+
entry.active?.hide();
|
|
109
|
+
});
|
|
110
|
+
overlay.addController(motion);
|
|
111
|
+
return entry;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Starts the window-level ghost for a drag that just began on `widget`,
|
|
115
|
+
* grabbed at `(grabX, grabY)` in `widget`'s own coordinates — the same pair
|
|
116
|
+
* `GtkDragSource.onPrepare` already reports and already feeds `setIcon()`.
|
|
117
|
+
*
|
|
118
|
+
* Returns `null` when `widget` has no window yet (nothing to escape) or
|
|
119
|
+
* shares no transform with it (unrealized) — the same failure mode
|
|
120
|
+
* `computePointIn` documents for `measure()`.
|
|
121
|
+
*/
|
|
122
|
+
export const beginDragLayer = (widget, grabX, grabY) => {
|
|
123
|
+
const root = widget.getRoot();
|
|
124
|
+
if (!root) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const entry = getOverlayEntry(root);
|
|
128
|
+
const origin = computePointIn(widget, entry.overlay, 0, 0);
|
|
129
|
+
const grab = computePointIn(widget, entry.overlay, grabX, grabY);
|
|
130
|
+
if (!origin || !grab) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
// Constant for the drag's lifetime: how far the pointer sits from the
|
|
134
|
+
// widget's own top-left, in the overlay's coordinate space. Every later
|
|
135
|
+
// motion subtracts it back off — the same arithmetic `DropProvider`'s
|
|
136
|
+
// `onDragging` already does for `tx`/`ty`, one level up.
|
|
137
|
+
const offsetX = grab.x - origin.x;
|
|
138
|
+
const offsetY = grab.y - origin.y;
|
|
139
|
+
const picture = Gtk.Picture.newForPaintable(Gtk.WidgetPaintable.new(widget));
|
|
140
|
+
picture.setCanTarget(false);
|
|
141
|
+
picture.setCanFocus(false);
|
|
142
|
+
picture.setHalign(Gtk.Align.START);
|
|
143
|
+
picture.setValign(Gtk.Align.START);
|
|
144
|
+
picture.setMarginStart(Math.round(origin.x));
|
|
145
|
+
picture.setMarginTop(Math.round(origin.y));
|
|
146
|
+
entry.overlay.addOverlay(picture);
|
|
147
|
+
// Neither should ever be true for a floating ghost, but both default open
|
|
148
|
+
// on a plain overlay child — set explicitly rather than trusted, since
|
|
149
|
+
// either one being true would let the ghost resize the window it is
|
|
150
|
+
// supposed to float over (measure) or vanish at its own edge (clip) the
|
|
151
|
+
// moment it demonstrates the fix this exists for.
|
|
152
|
+
entry.overlay.setMeasureOverlay(picture, false);
|
|
153
|
+
entry.overlay.setClipOverlay(picture, false);
|
|
154
|
+
const previousOpacity = widget.getOpacity();
|
|
155
|
+
widget.setOpacity(GHOST_OPACITY);
|
|
156
|
+
const handle = {
|
|
157
|
+
move: (x, y) => {
|
|
158
|
+
picture.setMarginStart(Math.round(x - offsetX));
|
|
159
|
+
picture.setMarginTop(Math.round(y - offsetY));
|
|
160
|
+
},
|
|
161
|
+
show: (x, y) => {
|
|
162
|
+
picture.setVisible(true);
|
|
163
|
+
handle.move(x, y);
|
|
164
|
+
},
|
|
165
|
+
hide: () => picture.setVisible(false),
|
|
166
|
+
end: () => {
|
|
167
|
+
entry.overlay.removeOverlay(picture);
|
|
168
|
+
widget.setOpacity(previousOpacity);
|
|
169
|
+
if (entry.active === handle) {
|
|
170
|
+
entry.active = null;
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
entry.active = handle;
|
|
175
|
+
return handle;
|
|
176
|
+
};
|
|
177
|
+
//# sourceMappingURL=drag-layer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drag-layer.js","sourceRoot":"","sources":["../../../src/gtkx/bridge/drag-layer.ts"],"names":[],"mappings":"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","sourcesContent":["// A window-level drag layer: a non-interactive `Gtk.Picture` positioned by\n// pixel margins inside a `Gtk.Overlay` wrapped once around each window's real\n// content, showing a live `Gtk.WidgetPaintable` of whatever is being dragged.\n//\n// Why this exists NEXT TO `GtkDragSource`'s own icon (gtk-controllers.tsx\n// already sets one via `setIcon`): that icon is a compositor-owned surface —\n// real, and already unclipped by this process's own widget tree, but also\n// outside it, so nothing in this process can read its geometry or its\n// pixels. A dragged item escaping an `overflow: hidden` ancestor needs a\n// widget IN OUR OWN TREE to prove that with — geometry a test can measure,\n// pixels a screenshot can read. This is that widget: a second, deliberately\n// redundant representation, added at window level (an `Overlay` child, so no\n// ancestor's clip reaches it) for as long as the drag is over this window,\n// and removed the moment the drag ends. `setIcon`'s own icon is untouched —\n// a drag that leaves this window for another still shows it.\n//\n// REPARENTING THE DRAGGED WIDGET ITSELF was tried first and refused: moving\n// the real node into a different container re-triggers ITS OWN size\n// negotiation under a parent with different constraints (measured: a\n// 100×100 card came out 800×600), and an unmount mid-flight strands the\n// widget outside the tree React still thinks it owns. A `WidgetPaintable`\n// sidesteps both — it is a live VIEW of the widget, not the widget, so the\n// original never moves and never leaves the component tree React manages.\n//\n// Ghosting the original is `Gtk.Widget.setOpacity()`, restored to whatever it\n// was before (not hardcoded to 1), so this composes with an app's own\n// animated or static opacity rather than fighting it. Because\n// `Gtk.WidgetPaintable` renders the widget it observes LIVE, `setIcon`'s own\n// compositor icon and this overlay copy dim along with the original — the\n// three are one underlying render, not three independent ones. Documented in\n// docs/api.md rather than fought: decoupling them would need a frozen\n// texture snapshot taken before the fade, not a live paintable, and a frozen\n// snapshot is not what the spike validated or what this measures.\nimport * as Gtk from \"@gtkx/gi/gtk\"\nimport { computePointIn } from \"./geometry\"\n\n// Dim, not hidden: RN dnd libraries commonly leave the dragged row at\n// reduced rather than zero opacity (e.g. `react-native-draggable-flatlist`'s\n// `activeOpacity`), and a fully transparent original would take the ghost's\n// own coupled render with it, per the note above.\nconst GHOST_OPACITY = 0.35\n\nexport type DragLayerHandle = {\n /** Called on every `GtkDropControllerMotion` \"motion\", already in the\n * OVERLAY's own coordinates — no per-call translation, because the\n * picture is that overlay's own child. Zero React involvement: a widget\n * property write per axis, nothing else. */\n move: (x: number, y: number) => void\n /** The pointer (re)entered this window mid-drag: reveal the ghost and\n * place it before the next motion arrives. */\n show: (x: number, y: number) => void\n /** The pointer left this window: nothing further tracks it here, so\n * hide rather than leave it stuck at the edge. */\n hide: () => void\n /** The drag ended (dropped or cancelled): remove the ghost and restore\n * the original's opacity. */\n end: () => void\n}\n\ntype OverlayEntry = {\n overlay: Gtk.Overlay\n /** At most one drag is ever in flight per window — GDK serialises drag\n * sessions on a seat — so one slot, not a set. */\n active: DragLayerHandle | null\n}\n\nconst overlaysByRoot = new WeakMap<Gtk.Root, OverlayEntry>()\n\n// `Adw.ApplicationWindow` names its own slot \"content\" and manages Adwaita's\n// toolbar/toast chrome INSIDE the `Gtk.Window` child slot it inherits —\n// writing that slot directly would replace Adwaita's internal structure\n// instead of the app's content. Anything else `AppRegistry.tsx` builds\n// (`Gtk.ApplicationWindow`) is a plain `Gtk.Window`, whose own `child` slot\n// IS the app's content, so `getChild`/`setChild` is right for it.\n//\n// Told apart by DUCK TYPING (does it have setContent/getContent?) rather\n// than `instanceof Adw.ApplicationWindow`: this file backs the RN core's\n// drag-and-drop (react-native-gtkx/dnd), which must build without Adw-1 at\n// all (see .claude/epics/adw-optional/001.md) — `@gtkx/gi/adw` is not\n// something this module can import even just to compare against it. A\n// plain Gtk.Window/GtkApplicationWindow never has these methods, so the\n// check is exactly as precise as the instanceof it replaces.\ntype AdwApplicationWindowLike = {\n setContent: (content: Gtk.Widget | null) => void\n getContent: () => Gtk.Widget | null\n}\n\nconst asAdwApplicationWindow = (\n root: Gtk.Root,\n): AdwApplicationWindowLike | null => {\n const candidate = root as unknown as Partial<AdwApplicationWindowLike>\n return typeof candidate.setContent === \"function\" &&\n typeof candidate.getContent === \"function\"\n ? (candidate as AdwApplicationWindowLike)\n : null\n}\n\nconst setWindowContent = (root: Gtk.Root, content: Gtk.Widget | null): void => {\n const adwWindow = asAdwApplicationWindow(root)\n if (adwWindow) {\n adwWindow.setContent(content)\n } else {\n ;(root as unknown as Gtk.Window).setChild(content)\n }\n}\n\n/**\n * Detaches the window's current content and hands it back, rather than\n * leaving it parented. `Gtk.Overlay.setChild()` asserts its argument is\n * unparented (or already its own child, or null) — it will not steal a\n * widget from another parent — so the content has to be unparented BEFORE\n * the overlay can adopt it, not after.\n */\nconst detachWindowContent = (root: Gtk.Root): Gtk.Widget | null => {\n const adwWindow = asAdwApplicationWindow(root)\n const current = adwWindow\n ? adwWindow.getContent()\n : (root as unknown as Gtk.Window).getChild()\n if (current) {\n setWindowContent(root, null)\n }\n return current\n}\n\n/**\n * The overlay for `root`, wrapping its real content the first time any drag\n * asks for it and reused for the window's whole lifetime after that — a\n * one-time structural change, not a per-drag one, because reparenting a\n * whole app's content is not something to repeat every time a finger moves.\n */\nconst getOverlayEntry = (root: Gtk.Root): OverlayEntry => {\n const existing = overlaysByRoot.get(root)\n if (existing) {\n return existing\n }\n\n const current = detachWindowContent(root)\n const overlay = Gtk.Overlay.new()\n overlay.setChild(current)\n setWindowContent(root, overlay)\n\n const entry: OverlayEntry = { overlay, active: null }\n overlaysByRoot.set(root, entry)\n\n // One motion controller per WINDOW rather than per drag or per provider:\n // GDK stops delivering to the drag source after `drag-begin` (the\n // compositor owns the pointer from there), and `GtkDropControllerMotion`\n // is the widget-level replacement `dnd/context.tsx` already relies on, at\n // provider scope, for the same reason. This is that same technique at\n // window scope, so the ghost tracks the pointer regardless of which\n // `DropProvider` — if any — the drag started under.\n const motion = Gtk.DropControllerMotion.new()\n motion.connect(\"motion\", (x: number, y: number) => {\n entry.active?.move(x, y)\n })\n motion.connect(\"enter\", (x: number, y: number) => {\n entry.active?.show(x, y)\n })\n motion.connect(\"leave\", () => {\n entry.active?.hide()\n })\n overlay.addController(motion)\n\n return entry\n}\n\n/**\n * Starts the window-level ghost for a drag that just began on `widget`,\n * grabbed at `(grabX, grabY)` in `widget`'s own coordinates — the same pair\n * `GtkDragSource.onPrepare` already reports and already feeds `setIcon()`.\n *\n * Returns `null` when `widget` has no window yet (nothing to escape) or\n * shares no transform with it (unrealized) — the same failure mode\n * `computePointIn` documents for `measure()`.\n */\nexport const beginDragLayer = (\n widget: Gtk.Widget,\n grabX: number,\n grabY: number,\n): DragLayerHandle | null => {\n const root = widget.getRoot()\n if (!root) {\n return null\n }\n const entry = getOverlayEntry(root)\n\n const origin = computePointIn(widget, entry.overlay, 0, 0)\n const grab = computePointIn(widget, entry.overlay, grabX, grabY)\n if (!origin || !grab) {\n return null\n }\n // Constant for the drag's lifetime: how far the pointer sits from the\n // widget's own top-left, in the overlay's coordinate space. Every later\n // motion subtracts it back off — the same arithmetic `DropProvider`'s\n // `onDragging` already does for `tx`/`ty`, one level up.\n const offsetX = grab.x - origin.x\n const offsetY = grab.y - origin.y\n\n const picture = Gtk.Picture.newForPaintable(Gtk.WidgetPaintable.new(widget))\n picture.setCanTarget(false)\n picture.setCanFocus(false)\n picture.setHalign(Gtk.Align.START)\n picture.setValign(Gtk.Align.START)\n picture.setMarginStart(Math.round(origin.x))\n picture.setMarginTop(Math.round(origin.y))\n\n entry.overlay.addOverlay(picture)\n // Neither should ever be true for a floating ghost, but both default open\n // on a plain overlay child — set explicitly rather than trusted, since\n // either one being true would let the ghost resize the window it is\n // supposed to float over (measure) or vanish at its own edge (clip) the\n // moment it demonstrates the fix this exists for.\n entry.overlay.setMeasureOverlay(picture, false)\n entry.overlay.setClipOverlay(picture, false)\n\n const previousOpacity = widget.getOpacity()\n widget.setOpacity(GHOST_OPACITY)\n\n const handle: DragLayerHandle = {\n move: (x, y) => {\n picture.setMarginStart(Math.round(x - offsetX))\n picture.setMarginTop(Math.round(y - offsetY))\n },\n show: (x, y) => {\n picture.setVisible(true)\n handle.move(x, y)\n },\n hide: () => picture.setVisible(false),\n end: () => {\n entry.overlay.removeOverlay(picture)\n widget.setOpacity(previousOpacity)\n if (entry.active === handle) {\n entry.active = null\n }\n },\n }\n entry.active = handle\n return handle\n}\n"]}
|
|
@@ -1,27 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as Gdk from "@gtkx/gi/gdk";
|
|
3
|
-
import * as Gio from "@gtkx/gi/gio";
|
|
4
|
-
import * as GLib from "@gtkx/gi/glib";
|
|
5
|
-
import * as GObject from "@gtkx/gi/gobject";
|
|
6
|
-
import * as Graphene from "@gtkx/gi/graphene";
|
|
7
|
-
import * as Gsk from "@gtkx/gi/gsk";
|
|
8
|
-
import * as Gtk from "@gtkx/gi/gtk";
|
|
9
|
-
import * as Pango from "@gtkx/gi/pango";
|
|
10
|
-
export { Adw, Gdk, Gio, GLib, GObject, Graphene, Gsk, Gtk, Pango };
|
|
11
|
-
export { GtkApplication, GtkGestureClick } from "@gtkx/jsx/gtk";
|
|
12
|
-
export { GMenu, GSimpleAction } from "@gtkx/jsx/gio";
|
|
13
|
-
export { AdwBreakpoint, AdwShortcutsItem, AdwShortcutsSection, AdwToggle, } from "@gtkx/jsx/adw";
|
|
14
|
-
export { GtkAdjustment, GtkDragSource, GtkDropControllerMotion, GtkDropTarget, GtkShortcut, GtkShortcutController, GtkTextBuffer, } from "@gtkx/jsx/gtk";
|
|
15
|
-
export * from "./widgets.generated";
|
|
16
|
-
export { createPortal, createRoot, quit, rootElement, useApplication, useBindSetting, useParentWindow, useProperty, useSetting, type Root, type RootElement, } from "@gtkx/react";
|
|
17
|
-
export type { SettingsSchema, SettingsSchemaKeys, SettingValue, } from "@gtkx/react/internal";
|
|
18
|
-
export { useSignal } from "./use-signal";
|
|
19
|
-
export { css, cx, injectGlobal } from "@gtkx/css";
|
|
20
|
-
export { createWidgetCss, type WidgetCss } from "./widget-css";
|
|
21
|
-
export { createTextProbe, measureWidget, toNumber } from "./measure";
|
|
22
|
-
export { computePointIn, computePointInWindow, type Point } from "./geometry";
|
|
23
|
-
export { createSlotPortal } from "./slot-portal";
|
|
24
|
-
export { cacheChildOrder, getViewBoxComponent, invalidateZOrder, setBoxOnly, setBoxPassthrough, setHitSlop, setPaintOnlyLeaf, setPointerTarget, setZIndex, type HitSlop, } from "./view-box";
|
|
25
|
-
export { getSvgNodeComponent, getSvgNodeDescriptor, queueSvgRedraw, resolveSvgColor, resolveSvgPaint, setSvgNodeDescriptor, type SvgDefsDescriptor, type SvgGradientUnits, type SvgGroupDescriptor, type SvgLinearGradientDescriptor, type SvgNodeDescriptor, type SvgPaintSpec, type SvgRadialGradientDescriptor, type SvgShapeDescriptor, type SvgStopDescriptor, type SvgSvgDescriptor, } from "./svg-node";
|
|
26
|
-
export { allocateChild, attachRnLayout, detachRnLayout, queueAllocate, queueResize, type RnLayoutHooks, type RnLayoutOrientation, } from "./layout-manager";
|
|
27
|
-
export { colorScheme, styleManager } from "./theme";
|
|
1
|
+
export * from "./core";
|