Skip to content

Commit 6b5dd36

Browse files
committed
try make work on gnome
1 parent fc01c78 commit 6b5dd36

6 files changed

Lines changed: 103 additions & 58 deletions

File tree

AGENTS.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Repository Guidelines
2+
3+
## Project Structure & Module Organization
4+
- Root crate: `Cargo.toml`, library entry at `src/lib.rs` (public `Webview` API).
5+
- FFI layer: `fltk-webview-sys/` with `build.rs` and platform helpers (`cocoa_helper.m`, `gtk_helper.c`).
6+
- Examples: `examples/*.rs` (e.g., `basic.rs`, `dispatch.rs`, `markdown.rs`).
7+
- CI: `.github/workflows/rust.yml` builds on Windows, macOS, and Linux.
8+
- Assets: `screenshots/` used in the README.
9+
10+
## Build, Test, and Development Commands
11+
- Build: `cargo build` (add `--features fltk/fltk-bundled` to use bundled FLTK like CI).
12+
- Run example: `cargo run --example basic` (replace `basic` with any file in `examples/`).
13+
- Lint: `cargo clippy --all-targets -- -D warnings` (treat warnings as errors).
14+
- Format: `cargo fmt --all` (required before PRs).
15+
- Docs: `cargo doc --open` (browse crate docs, README is included).
16+
- Test: `cargo test` (add tests as described below; currently minimal).
17+
18+
Linux note: install `libwebkit2gtk-4.1-dev` and common X11 deps (see workflow). Windows/macOS need no extra packages.
19+
20+
## Coding Style & Naming Conventions
21+
- Rust style with `rustfmt` (4-space indent, max line width per default config).
22+
- Naming: `snake_case` for functions/modules, `CamelCase` for types/traits, `SCREAMING_SNAKE_CASE` for consts.
23+
- Keep platform-specific code behind `cfg` gates and isolate FFI in `fltk-webview-sys`.
24+
25+
## Testing Guidelines
26+
- Prefer small unit tests co-located with modules (`#[cfg(test)] mod tests { ... }`) or `tests/` for integration.
27+
- Name tests after behavior, e.g., `creates_webview_from_fltk_window`.
28+
- Run with `cargo test`; avoid platform GUI assumptions—mock or guard with `#[cfg]`.
29+
30+
## Commit & Pull Request Guidelines
31+
- Commits: imperative present, concise, scoped. Example: `fix: correct SetFocus usage on Windows` or `docs: expand usage section`.
32+
- PRs must include: summary, rationale, affected platforms, screenshots if UI-visible, and any linked issues.
33+
- CI must pass on all platforms; run `cargo fmt`, `cargo clippy`, and build examples locally where feasible.
34+
- For Linux changes, note any new `apt`/`dnf` packages or `pkg-config` requirements.
35+

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ fn main() {
3737
## Dependencies
3838
- fltk-rs's dependencies, which can be found [here](https://github.com/fltk-rs/fltk-rs#dependencies).
3939
- On Windows: No other dependencies.
40-
- On MacOS: No other dependencies.
41-
- On X11/wayland platforms, webkit2gtk:
42-
- Debian-based distros: `sudo apt-get install libwebkit2gtk-4.1-dev`.
43-
- RHEL-based distros: `sudo dnf install webkit2gtk3-devel`.
44-
45-
## Known Issues
46-
The situation on linux is quite bad. It depends on whether you're running X11 or wayland. On wayland, this will use xwayland. On X11, I can't get embedding to work on Gnome's mutter window manager, which keeps fighting for ownership of the webview window, causing flickering or a blank screen!D=x11 environment variable for webkit2gtk to work properly.
40+
- On macOS: No other dependencies.
41+
- On Linux (X11 only): WebKitGTK and X11 dev packages.
42+
- Debian-based distros: `sudo apt-get install libwebkit2gtk-4.1-dev libx11-dev`.
43+
- RHEL-based distros: `sudo dnf install webkit2gtk3-devel libX11-devel`.
44+
45+
## Linux Notes
46+
- This crate supports X11 only on Linux. On GNOME or Wayland sessions, force X11: `GDK_BACKEND=x11`.
47+
- GNOME/Mutter can interfere with embedded toplevels; the X11 path mitigates this by making the webview unmanaged.
48+
- If you see blanking, try: `WEBKIT_DISABLE_COMPOSITING_MODE=1`.
4749

4850
![alt_test](screenshots/ex.jpg)
4951

examples/basic2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use fltk::{app, prelude::*, group, input, window};
1+
use fltk::{app, group, input, prelude::*, window};
22
use fltk_webview::*;
33

44
fn main() {

examples/bind.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,5 @@ fn main() {
5050
wv.return_(seq, 0, &format!("\"Hello {}\"", val));
5151
});
5252

53-
5453
app.run().unwrap();
5554
}

fltk-webview-sys/src/gtk_helper.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,22 @@ GdkWindow *my_get_win(GtkWindow *win) {
1212
}
1313

1414
void x_init(Display *disp, Window child, Window parent) {
15-
XMoveWindow(disp, child, 0, 0);
15+
// Make the child unmanaged (override-redirect) to avoid WM interference (e.g., Mutter)
16+
XUnmapWindow(disp, child);
17+
XSetWindowAttributes attrs;
18+
attrs.override_redirect = True;
19+
XChangeWindowAttributes(disp, child, CWOverrideRedirect, &attrs);
1620

21+
// Position and reparent under the FLTK window
22+
XMoveWindow(disp, child, 0, 0);
1723
XReparentWindow(disp, child, parent, 0, 0);
1824

25+
// Ensure the child remains mapped with the parent
1926
XFixesChangeSaveSet(disp, child, SetModeInsert, SaveSetRoot, SaveSetUnmap);
27+
XMapWindow(disp, child);
28+
XSync(disp, False);
2029

30+
// Send a synthetic ConfigureNotify to ensure size is correct
2131
XEvent client_event;
2232
XWindowAttributes childAttributes;
2333
XWindowAttributes parentAttributes;
@@ -29,6 +39,8 @@ void x_init(Display *disp, Window child, Window parent) {
2939
client_event.xconfigure.display = disp;
3040
client_event.xconfigure.event = child;
3141
client_event.xconfigure.window = child;
42+
client_event.xconfigure.x = 0;
43+
client_event.xconfigure.y = 0;
3244
client_event.xconfigure.width = childAttributes.width;
3345
client_event.xconfigure.height = childAttributes.height;
3446
client_event.xconfigure.border_width = 0;
@@ -37,3 +49,9 @@ void x_init(Display *disp, Window child, Window parent) {
3749

3850
XSendEvent(disp, child, False, StructureNotifyMask, &client_event);
3951
}
52+
53+
void x_focus(Display *disp, Window child) {
54+
XSetInputFocus(disp, child, RevertToParent, CurrentTime);
55+
}
56+
57+
int my_gtk_events_pending() { return gtk_events_pending(); }

src/lib.rs

Lines changed: 39 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(clippy::needless_doctest_main)]
12
#![doc = include_str!("../README.md")]
23

34
use fltk::{
@@ -6,39 +7,11 @@ use fltk::{
67
window,
78
};
89
use fltk_webview_sys as wv;
9-
pub use wv::Webview;
10+
use std::{os::raw, sync::Arc};
1011
pub use wv::SizeHint;
11-
use std::{
12-
os::raw,
13-
sync::Arc,
14-
};
12+
pub use wv::Webview;
1513

16-
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
17-
fn win_manager(prog: &str) -> bool {
18-
let sm = std::env::var("SESSION_MANAGER");
19-
if let Ok(sm) = sm {
20-
let pid = sm.split("/").last();
21-
if let Some(pid) = pid {
22-
match std::process::Command::new("ps")
23-
.args(&["-p", pid, "-o", "comm="])
24-
.output()
25-
{
26-
Ok(out) => {
27-
if String::from_utf8_lossy(&out.stdout).contains(prog) {
28-
true
29-
} else {
30-
false
31-
}
32-
}
33-
_ => false,
34-
}
35-
} else {
36-
false
37-
}
38-
} else {
39-
false
40-
}
41-
}
14+
// Linux path is unified under X11; Wayland embedding is not supported.
4215

4316
pub trait FromFltkWindow {
4417
fn create(debug: bool, win: &mut window::Window) -> Webview;
@@ -75,15 +48,19 @@ impl FromFltkWindow for Webview {
7548
fltk::enums::Event::Push => {
7649
SetFocus(w.raw_handle() as _);
7750
true
78-
},
79-
_ => false
51+
}
52+
_ => false,
8053
});
8154
}
8255
#[cfg(target_os = "macos")]
8356
{
8457
pub enum NSWindow {}
8558
extern "C" {
86-
pub fn make_delegate(child: *mut NSWindow, parent: *mut NSWindow, add_menu: i32);
59+
pub fn make_delegate(
60+
child: *mut NSWindow,
61+
parent: *mut NSWindow,
62+
add_menu: i32,
63+
);
8764
pub fn my_close_win(win: *mut NSWindow);
8865
}
8966
let handle = win.raw_handle();
@@ -107,9 +84,11 @@ impl FromFltkWindow for Webview {
10784
pub enum Display {}
10885
extern "C" {
10986
pub fn gtk_init(argc: *mut i32, argv: *mut *mut raw::c_char);
87+
pub fn my_gtk_events_pending() -> i32;
11088
pub fn my_get_win(wid: *mut GtkWindow) -> *mut GdkWindow;
11189
pub fn my_get_xid(w: *mut GdkWindow) -> u64;
11290
pub fn x_init(disp: *mut Display, child: u64, parent: u64);
91+
pub fn x_focus(disp: *mut Display, child: u64);
11392
pub fn gtk_main_iteration_do(blocking: bool);
11493
}
11594
gtk_init(&mut 0, std::ptr::null_mut());
@@ -121,25 +100,37 @@ impl FromFltkWindow for Webview {
121100
assert!(!temp.is_null());
122101
let xid = my_get_xid(temp as _);
123102
let flxid = win.raw_handle();
124-
if win_manager("gnome-session") {
125-
win.draw(move |w| {
126-
x_init(app::display() as _, xid, flxid);
127-
app::sleep(0.03);
128-
wv::webview_set_size(inner, w.w(), w.h(), 0);
129-
});
130-
win.flush();
131-
} else {
132-
x_init(app::display() as _, xid, flxid);
133-
win.draw(move |w| wv::webview_set_size(inner, w.w(), w.h(), 0));
134-
}
135103

136-
app::add_timeout3(0.001, |handle| {
137-
gtk_main_iteration_do(false);
138-
app::repeat_timeout3(0.001, handle);
104+
// Unified X11 path: make child unmanaged and reparent into FLTK window
105+
x_init(app::display() as _, xid, flxid);
106+
// Ensure input focus goes to the embedded child when shown
107+
x_focus(app::display() as _, xid);
108+
109+
win.draw(move |w| wv::webview_set_size(inner, w.w(), w.h(), 0));
110+
111+
// Set focus to child on mouse press to ensure keystrokes reach WebKit
112+
let xid_for_focus = xid;
113+
win.handle(move |_, ev| {
114+
if ev == enums::Event::Push {
115+
x_focus(app::display() as _, xid_for_focus);
116+
true
117+
} else {
118+
false
119+
}
120+
});
121+
122+
app::add_timeout3(0.016, |handle| {
123+
let mut spins = 0;
124+
while my_gtk_events_pending() != 0 && spins < 4 {
125+
gtk_main_iteration_do(false);
126+
spins += 1;
127+
}
128+
app::repeat_timeout3(0.016, handle);
139129
});
140130
}
141131
}
142132
assert!(!inner.is_null());
133+
#[allow(clippy::arc_with_non_send_sync)]
143134
let inner = Arc::new(inner);
144135
Webview::from_raw(inner)
145136
}

0 commit comments

Comments
 (0)