roxane 0.0.1 → 0.0.3
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.
- checksums.yaml +4 -4
- data/README.md +9 -0
- data/lib/roxane/ffi.rb +7 -0
- data/lib/roxane/gtk.rb +29 -0
- data/lib/roxane/version.rb +1 -1
- data/lib/roxane/webkit.rb +40 -0
- data/lib/roxane/window.rb +77 -1
- data/lib/roxane.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 949821f1324cd761b172fc4b4f7519459b3d70c3a53db0bc9ba3ad694ffe3e80
|
|
4
|
+
data.tar.gz: dd6ea3c05680732a4c6d8cb08702626735675b2035d6cdc1c7822a08e43fac93
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: edbfde719e7560dcd6f2e68c8509be66d44118035fe02009f6d285482583abf14c5f6bcdfc8bb577c62f60db7cd615c720b9ca18f13c7259269fb8bb52b341bf
|
|
7
|
+
data.tar.gz: c70573dc5ad95b1d59ab06ed5714dd88a420410857e5c3fcad2c974834429f19a8679a85b2933408a40f821374064ea675d6f3980e3f7f93a9d720797fdaf243
|
data/README.md
CHANGED
|
@@ -65,6 +65,15 @@ rake test # host: unit tests only (the asset server); the windowed
|
|
|
65
65
|
# smoke test self-skips unless ROXANE_INTEGRATION=1
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
## Linux / Wayland note (window size)
|
|
69
|
+
|
|
70
|
+
On GTK3, upstream `libwebview` implements `WEBVIEW_HINT_NONE` with
|
|
71
|
+
`gtk_window_resize`. Under Wayland that does **not** set the initial xdg
|
|
72
|
+
geometry, so floating compositors (e.g. Hyprland) often map the window at a
|
|
73
|
+
tiny 200×200 square; GNOME hides the same bug. Roxane compensates on Linux by
|
|
74
|
+
calling `gtk_window_set_default_size` and briefly pinning a size-request through
|
|
75
|
+
first map (then releasing it so the window stays resizable).
|
|
76
|
+
|
|
68
77
|
## Status
|
|
69
78
|
|
|
70
79
|
Early but working. The runtime (window + system webview + invoke/emit bridge +
|
data/lib/roxane/ffi.rb
CHANGED
|
@@ -15,6 +15,12 @@ module Roxane
|
|
|
15
15
|
HINT_MAX = 2
|
|
16
16
|
HINT_FIXED = 3
|
|
17
17
|
|
|
18
|
+
# webview_native_handle_kind_t — BROWSER_CONTROLLER is the engine view
|
|
19
|
+
# (WebKitWebView* on GTK), the door to engine calls webview doesn't wrap.
|
|
20
|
+
NATIVE_HANDLE_UI_WINDOW = 0
|
|
21
|
+
NATIVE_HANDLE_UI_WIDGET = 1
|
|
22
|
+
NATIVE_HANDLE_BROWSER_CONTROLLER = 2
|
|
23
|
+
|
|
18
24
|
begin
|
|
19
25
|
ffi_lib Roxane.library_path
|
|
20
26
|
|
|
@@ -31,6 +37,7 @@ module Roxane
|
|
|
31
37
|
attach_function :webview_set_html, [:pointer, :string], :int
|
|
32
38
|
attach_function :webview_init, [:pointer, :string], :int
|
|
33
39
|
attach_function :webview_eval, [:pointer, :string], :int
|
|
40
|
+
attach_function :webview_get_native_handle, [:pointer, :int], :pointer
|
|
34
41
|
|
|
35
42
|
callback :bind_fn, [:string, :string, :pointer], :void
|
|
36
43
|
attach_function :webview_bind, [:pointer, :string, :bind_fn, :pointer], :int
|
data/lib/roxane/gtk.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Roxane
|
|
4
|
+
# Direct GTK3 bindings for window-size affordances the webview C API gets wrong
|
|
5
|
+
# on Wayland. libwebview 0.12 (GTK3) implements WEBVIEW_HINT_NONE with
|
|
6
|
+
# gtk_window_resize only; on Wayland that does not set the initial xdg
|
|
7
|
+
# geometry, so the client commits 200×200 and floating compositors (Hyprland,
|
|
8
|
+
# etc.) keep the tiny square. GNOME/Mutter is more forgiving, which hides the
|
|
9
|
+
# bug there. GTK4 webview already uses gtk_window_set_default_size — we do the
|
|
10
|
+
# same from Ruby, plus a brief size-request so the first map advertises the
|
|
11
|
+
# right min/geometry, then release it so the window stays user-resizable.
|
|
12
|
+
#
|
|
13
|
+
# Where libgtk-3 isn't loadable (macOS/Windows — their backends are separate),
|
|
14
|
+
# AVAILABLE is false and callers no-op.
|
|
15
|
+
module Gtk
|
|
16
|
+
extend ::FFI::Library
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
ffi_lib "libgtk-3.so.0"
|
|
20
|
+
attach_function :gtk_window_set_default_size, [:pointer, :int, :int], :void
|
|
21
|
+
attach_function :gtk_window_resize, [:pointer, :int, :int], :void
|
|
22
|
+
attach_function :gtk_widget_set_size_request, [:pointer, :int, :int], :void
|
|
23
|
+
attach_function :gtk_widget_get_realized, [:pointer], :int
|
|
24
|
+
AVAILABLE = true
|
|
25
|
+
rescue LoadError, ::FFI::NotFoundError
|
|
26
|
+
AVAILABLE = false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/roxane/version.rb
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Roxane
|
|
4
|
+
# Direct WebKitGTK bindings for the few affordances the webview C API doesn't
|
|
5
|
+
# wrap (today: full-content zoom). On Linux the library is already linked into
|
|
6
|
+
# the process by libwebview — we bind the soname libwebview itself links (4.1,
|
|
7
|
+
# falling back to 4.0). Where neither loads (macOS/Windows — their engines get
|
|
8
|
+
# their own bindings later), AVAILABLE is false and callers no-op gracefully.
|
|
9
|
+
module WebKit
|
|
10
|
+
extend ::FFI::Library
|
|
11
|
+
|
|
12
|
+
begin
|
|
13
|
+
ffi_lib ["libwebkit2gtk-4.1.so.0", "libwebkit2gtk-4.0.so.37"]
|
|
14
|
+
attach_function :webkit_web_view_set_zoom_level, [:pointer, :double], :void
|
|
15
|
+
attach_function :webkit_web_view_get_zoom_level, [:pointer], :double
|
|
16
|
+
AVAILABLE = true
|
|
17
|
+
rescue LoadError, ::FFI::NotFoundError
|
|
18
|
+
AVAILABLE = false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# GLib main-loop scheduling. g_idle_add / g_timeout_add are thread-safe and
|
|
23
|
+
# run the callback as a TOP-LEVEL main-loop iteration — a clean stack, never
|
|
24
|
+
# nested inside a webview dispatch callback (layout-triggering WebKit calls
|
|
25
|
+
# made from inside one can reenter the engine and crash; see the zoom work,
|
|
26
|
+
# 2026-07-03).
|
|
27
|
+
module GLib
|
|
28
|
+
extend ::FFI::Library
|
|
29
|
+
|
|
30
|
+
begin
|
|
31
|
+
ffi_lib "libglib-2.0.so.0"
|
|
32
|
+
callback :g_source_func, [:pointer], :int
|
|
33
|
+
attach_function :g_idle_add, [:g_source_func, :pointer], :uint
|
|
34
|
+
attach_function :g_timeout_add, [:uint, :g_source_func, :pointer], :uint
|
|
35
|
+
AVAILABLE = true
|
|
36
|
+
rescue LoadError, ::FFI::NotFoundError
|
|
37
|
+
AVAILABLE = false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/roxane/window.rb
CHANGED
|
@@ -26,6 +26,7 @@ module Roxane
|
|
|
26
26
|
@on_close = nil
|
|
27
27
|
@server = nil
|
|
28
28
|
@ui_queue = Queue.new # procs to run on the UI thread
|
|
29
|
+
@zoom = 1.0
|
|
29
30
|
|
|
30
31
|
@w = FFI.webview_create(debug ? 1 : 0, nil)
|
|
31
32
|
raise Error, "could not create webview" if @w.null?
|
|
@@ -83,6 +84,31 @@ module Roxane
|
|
|
83
84
|
self
|
|
84
85
|
end
|
|
85
86
|
|
|
87
|
+
# Full-content zoom, like a browser's Ctrl+± (1.0 = natural size). Backed by
|
|
88
|
+
# the engine's native zoom (WebKitGTK today); where that binding isn't
|
|
89
|
+
# available the setter no-ops and the reader reports the last requested
|
|
90
|
+
# level. Safe from any thread: scheduled with g_idle_add, which runs on the
|
|
91
|
+
# UI thread as a TOP-LEVEL loop iteration — never nested inside a webview
|
|
92
|
+
# dispatch callback, where a layout-triggering WebKit call can reenter the
|
|
93
|
+
# engine mid-resolve and crash it. Rapid calls coalesce (each application
|
|
94
|
+
# reads the latest requested level; extra idles are harmless).
|
|
95
|
+
def zoom
|
|
96
|
+
@zoom
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def zoom=(factor)
|
|
100
|
+
@zoom = Float(factor)
|
|
101
|
+
return unless WebKit::AVAILABLE && GLib::AVAILABLE
|
|
102
|
+
|
|
103
|
+
@apply_zoom ||= ::FFI::Function.new(:int, [:pointer]) do |_data|
|
|
104
|
+
view = FFI.webview_get_native_handle(@w, FFI::NATIVE_HANDLE_BROWSER_CONTROLLER)
|
|
105
|
+
WebKit.webkit_web_view_set_zoom_level(view, @zoom) unless view.null?
|
|
106
|
+
0 # G_SOURCE_REMOVE
|
|
107
|
+
end
|
|
108
|
+
@callbacks << @apply_zoom unless @callbacks.include?(@apply_zoom)
|
|
109
|
+
GLib.g_idle_add(@apply_zoom, nil)
|
|
110
|
+
end
|
|
111
|
+
|
|
86
112
|
def on_close(&block)
|
|
87
113
|
@on_close = block
|
|
88
114
|
self
|
|
@@ -106,9 +132,59 @@ module Roxane
|
|
|
106
132
|
private
|
|
107
133
|
|
|
108
134
|
def apply_size(size, min_size, resizable)
|
|
109
|
-
width, height = size
|
|
135
|
+
width, height = Integer(size[0]), Integer(size[1])
|
|
110
136
|
FFI.webview_set_size(@w, width, height, resizable ? FFI::HINT_NONE : FFI::HINT_FIXED)
|
|
111
137
|
FFI.webview_set_size(@w, min_size[0], min_size[1], FFI::HINT_MIN) if min_size && resizable
|
|
138
|
+
# GTK3/Wayland: compensate for libwebview using gtk_window_resize (ignored
|
|
139
|
+
# as initial geometry). No-ops on macOS/Windows where Gtk is unavailable.
|
|
140
|
+
apply_gtk_wayland_size(width, height, min_size, resizable)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# See Roxane::Gtk — set_default_size + a temporary size-request so the first
|
|
144
|
+
# xdg configure isn't 200×200 under floating Wayland compositors.
|
|
145
|
+
def apply_gtk_wayland_size(width, height, min_size, resizable)
|
|
146
|
+
return unless Gtk::AVAILABLE && GLib::AVAILABLE
|
|
147
|
+
|
|
148
|
+
handle = FFI.webview_get_native_handle(@w, FFI::NATIVE_HANDLE_UI_WINDOW)
|
|
149
|
+
return if handle.null?
|
|
150
|
+
|
|
151
|
+
Gtk.gtk_window_set_default_size(handle, width, height)
|
|
152
|
+
return unless resizable
|
|
153
|
+
|
|
154
|
+
# Pin geometry through the first map, then release so the user can shrink.
|
|
155
|
+
# (Non-resizable windows keep webview's FIXED size-request permanently.)
|
|
156
|
+
Gtk.gtk_widget_set_size_request(handle, width, height)
|
|
157
|
+
release_initial_gtk_size_request(width, height, min_size)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Poll until the GtkWindow is realized (shown), then drop the temporary
|
|
161
|
+
# size-request. Scheduled from construction — safe if run() is delayed;
|
|
162
|
+
# continues until realize or the window is destroyed.
|
|
163
|
+
def release_initial_gtk_size_request(width, height, min_size)
|
|
164
|
+
state = { seen_realized: false }
|
|
165
|
+
cb = ::FFI::Function.new(:int, [:pointer]) do |_data|
|
|
166
|
+
handle = FFI.webview_get_native_handle(@w, FFI::NATIVE_HANDLE_UI_WINDOW)
|
|
167
|
+
if handle.null?
|
|
168
|
+
0 # G_SOURCE_REMOVE — window gone
|
|
169
|
+
elsif Gtk.gtk_widget_get_realized(handle) == 0
|
|
170
|
+
1 # G_SOURCE_CONTINUE — not mapped yet
|
|
171
|
+
elsif !state[:seen_realized]
|
|
172
|
+
# One extra tick after realize so the compositor has acked min_size.
|
|
173
|
+
state[:seen_realized] = true
|
|
174
|
+
1
|
|
175
|
+
else
|
|
176
|
+
if min_size
|
|
177
|
+
Gtk.gtk_widget_set_size_request(handle, Integer(min_size[0]), Integer(min_size[1]))
|
|
178
|
+
else
|
|
179
|
+
Gtk.gtk_widget_set_size_request(handle, -1, -1)
|
|
180
|
+
end
|
|
181
|
+
Gtk.gtk_window_set_default_size(handle, width, height)
|
|
182
|
+
Gtk.gtk_window_resize(handle, width, height)
|
|
183
|
+
0 # G_SOURCE_REMOVE
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
@callbacks << cb
|
|
187
|
+
GLib.g_timeout_add(50, cb, nil)
|
|
112
188
|
end
|
|
113
189
|
|
|
114
190
|
# One persistent dispatch callback drains a queue of procs on the UI thread —
|
data/lib/roxane.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: roxane
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- BKK Riese
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|
|
@@ -39,8 +39,10 @@ files:
|
|
|
39
39
|
- assets/bridge.js
|
|
40
40
|
- lib/roxane.rb
|
|
41
41
|
- lib/roxane/ffi.rb
|
|
42
|
+
- lib/roxane/gtk.rb
|
|
42
43
|
- lib/roxane/static_server.rb
|
|
43
44
|
- lib/roxane/version.rb
|
|
45
|
+
- lib/roxane/webkit.rb
|
|
44
46
|
- lib/roxane/window.rb
|
|
45
47
|
homepage: https://github.com/quarterstack/roxane
|
|
46
48
|
licenses:
|