Skip to content

fix(linux): Port to webkitgtk6 #1530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
598 changes: 458 additions & 140 deletions Cargo.lock

Large diffs are not rendered by default.

27 changes: 8 additions & 19 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,9 @@ protocol = []
devtools = []
transparent = []
fullscreen = []
linux-body = ["webkit2gtk/v2_40", "os-webview"]
linux-body = ["os-webview"]
mac-proxy = []
os-webview = [
"javascriptcore-rs",
"webkit2gtk",
"webkit2gtk-sys",
"dep:gtk",
"soup3",
"x11-dl",
"gdkx11",
]
os-webview = ["soup3", "webkit", "dep:gtk"]
tracing = ["dep:tracing"]

[dependencies]
Expand All @@ -56,16 +48,10 @@ dpi = "0.1"
cookie = "0.18"

[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
javascriptcore-rs = { version = "=1.1.2", features = [
"v2_28",
], optional = true }
webkit2gtk = { version = "=2.0.1", features = ["v2_38"], optional = true }
webkit2gtk-sys = { version = "=2.0.1", optional = true }
gtk = { version = "0.18", optional = true }
soup3 = { version = "0.5", optional = true }
x11-dl = { version = "2.21", optional = true }
gdkx11 = { version = "0.18", optional = true }
soup3 = { version = "0.7", optional = true }
percent-encoding = "2.3"
webkit = { package = "webkit6", version = "0.4", optional = true, features = ["v2_42"]}
gtk = { package = "gtk4", version = "0.9", optional = true, features = ["v4_6"] }

[target."cfg(target_os = \"windows\")".dependencies]
webview2-com = "0.37"
Expand Down Expand Up @@ -207,6 +193,9 @@ getrandom = "0.3"
http-range = "0.1"
percent-encoding = "2.3"

[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dev-dependencies]
x11-dl = { version = "2.21" }

[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = ["cfg(linux)", "cfg(gtk)"]
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,19 +172,19 @@ event_loop.run_app(&mut app).unwrap();
###### Arch Linux / Manjaro:

```bash
sudo pacman -S webkit2gtk-4.1
sudo pacman -S webkitgtk-6.0
```

###### Debian / Ubuntu:

```bash
sudo apt install libwebkit2gtk-4.1-dev
sudo apt install libwebkitgtk-6.0-dev
```

###### Fedora

```bash
sudo dnf install gtk3-devel webkit2gtk4.1-devel
sudo dnf install webkitgtk6.0-devel
```

###### Nix & NixOS
Expand All @@ -197,7 +197,7 @@ let
pkgs = import (fetchTarball("channel:nixpkgs-unstable")) { };
packages = with pkgs; [
pkg-config
webkitgtk_4_1
webkitgtk_6_0
];
in
pkgs.mkShell {
Expand Down Expand Up @@ -288,7 +288,7 @@ Wry uses a set of feature flags to toggle several advanced features.
Avoid this in release build if your app needs to publish to App Store.
libraries and prevent from building documentation on doc.rs fails.
- `linux-body`: Enables body support of custom protocol request on Linux. Requires
webkit2gtk v2.40 or above.
webkitgtk6 v2.42 or above.
- `tracing`: enables [`tracing`] for `evaluate_script`, `ipc_handler` and `custom_protocols.

### Partners
Expand Down
5 changes: 4 additions & 1 deletion examples/custom_titlebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ fn hit_test(window_size: PhysicalSize<u32>, x: i32, y: i32, scale: f64) -> HitTe
let bottom = top + window_size.height as i32;
let right = left + window_size.width as i32;

let x = x * scale as i32;
let y = y * scale as i32;

let inset = (BORDERLESS_RESIZE_INSET * scale) as i32;

#[rustfmt::skip]
Expand Down Expand Up @@ -266,7 +269,7 @@ fn main() -> wry::Result<()> {
builder.build_gtk(vbox)?
};

let mut webview = Some(webview);
let mut webview: Option<wry::WebView> = Some(webview);

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
Expand Down
3 changes: 1 addition & 2 deletions examples/gtk_multiwebview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ fn main() -> wry::Result<()> {
use tao::platform::unix::WindowExtUnix;
let fixed = gtk::Fixed::new();
let vbox = window.default_vbox().unwrap();
vbox.pack_start(&fixed, true, true, 0);
fixed.show_all();
vbox.prepend(&fixed);
fixed
};

Expand Down
5 changes: 3 additions & 2 deletions examples/multiwebview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,9 @@ impl ApplicationHandler for State {
target_os = "openbsd",
))]
{
while gtk::events_pending() {
gtk::main_iteration_do(false);
let context = gtk::glib::MainContext::default();
while context.pending() {
context.iteration(false);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/reparent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn main() -> wry::Result<()> {
target_os = "ios",
target_os = "android"
)))]
let webview = {
let mut webview = {
use tao::platform::unix::WindowExtUnix;
let vbox = window.default_vbox().unwrap();
builder.build_gtk(vbox)?
Expand Down
5 changes: 3 additions & 2 deletions examples/wgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,9 @@ impl ApplicationHandler for State {
target_os = "openbsd",
))]
{
while gtk::events_pending() {
gtk::main_iteration_do(false);
let context = gtk::glib::MainContext::default();
while context.pending() {
context.iteration(false);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions examples/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ impl ApplicationHandler for State {
target_os = "openbsd",
))]
{
while gtk::events_pending() {
gtk::main_iteration_do(false);
let context = gtk::glib::MainContext::default();
while context.pending() {
context.iteration(false);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ pub enum Error {
#[error(transparent)]
GlibBoolError(#[from] gtk::glib::BoolError),
#[cfg(gtk)]
#[error("{0} is not a supported webview parent widget.")]
UnsupportedParentWidget(String),
#[cfg(gtk)]
#[error("Fail to fetch security manager")]
MissingManager,
#[cfg(gtk)]
#[error("Couldn't find X11 Display")]
X11DisplayNotFound,
#[cfg(gtk)]
#[error(transparent)]
XlibError(#[from] x11_dl::error::OpenError),
#[error("Failed to initialize the script")]
InitScriptError,
#[error("Bad RPC request: {0} ((1))")]
Expand Down
30 changes: 15 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,19 +194,19 @@
//! ##### Arch Linux / Manjaro:
//!
//! ```bash
//! sudo pacman -S webkit2gtk-4.1
//! sudo pacman -S webkitgtk-6.0
//! ```
//!
//! ##### Debian / Ubuntu:
//!
//! ```bash
//! sudo apt install libwebkit2gtk-4.1-dev
//! sudo apt install libwebkitgtk-6.0-dev
//! ```
//!
//! ##### Fedora
//!
//! ```bash
//! sudo dnf install gtk3-devel webkit2gtk4.1-devel
//! sudo dnf install gtk3-devel webkitgtk6.0-devel
//! ```
//!
//! ##### Nix & NixOS
Expand All @@ -219,7 +219,7 @@
//! pkgs = import (fetchTarball("channel:nixpkgs-unstable")) { };
//! packages = with pkgs; [
//! pkg-config
//! webkitgtk_4_1
//! webkitgtk_6_0
//! ];
//! in
//! pkgs.mkShell {
Expand Down Expand Up @@ -1701,7 +1701,7 @@ pub trait WebViewBuilderExtUnix<'a> {
/// - Panics if [`gtk::init`] was not called in this thread.
fn build_gtk<W>(self, widget: &'a W) -> Result<WebView>
where
W: gtk::prelude::IsA<gtk::Container>;
W: gtk::prelude::IsA<gtk::Widget>;

/// Set the path from which to load extensions from.
fn with_extensions_path(self, path: impl Into<PathBuf>) -> Self;
Expand All @@ -1717,7 +1717,7 @@ pub trait WebViewBuilderExtUnix<'a> {
impl<'a> WebViewBuilderExtUnix<'a> for WebViewBuilder<'a> {
fn build_gtk<W>(self, widget: &'a W) -> Result<WebView>
where
W: gtk::prelude::IsA<gtk::Container>,
W: gtk::prelude::IsA<gtk::Widget>,
{
let parts = self.inner?;

Expand Down Expand Up @@ -2067,33 +2067,33 @@ pub trait WebViewExtUnix: Sized {
/// - Panics if [`gtk::init`] was not called in this thread.
fn new_gtk<W>(widget: &W) -> Result<Self>
where
W: gtk::prelude::IsA<gtk::Container>;
W: gtk::prelude::IsA<gtk::Widget>;

/// Returns Webkit2gtk Webview handle
fn webview(&self) -> webkit2gtk::WebView;
/// Returns Webkitgtk Webview handle
fn webview(&self) -> webkit::WebView;

/// Attaches this webview to the given Widget and removes it from the current one.
fn reparent<W>(&self, widget: &W) -> Result<()>
fn reparent<W>(&mut self, widget: &W) -> Result<()>
where
W: gtk::prelude::IsA<gtk::Container>;
W: gtk::prelude::IsA<gtk::Widget>;
}

#[cfg(gtk)]
impl WebViewExtUnix for WebView {
fn new_gtk<W>(widget: &W) -> Result<Self>
where
W: gtk::prelude::IsA<gtk::Container>,
W: gtk::prelude::IsA<gtk::Widget>,
{
WebViewBuilder::new().build_gtk(widget)
}

fn webview(&self) -> webkit2gtk::WebView {
fn webview(&self) -> webkit::WebView {
self.webview.webview.clone()
}

fn reparent<W>(&self, widget: &W) -> Result<()>
fn reparent<W>(&mut self, widget: &W) -> Result<()>
where
W: gtk::prelude::IsA<gtk::Container>,
W: gtk::prelude::IsA<gtk::Widget>,
{
self.webview.reparent(widget)
}
Expand Down
78 changes: 47 additions & 31 deletions src/webkitgtk/drag_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ use std::{
rc::Rc,
};

use gtk::{glib::GString, prelude::*};
use webkit2gtk::WebView;
use gtk::{
gdk::{DragAction, FileList},
gio::Cancellable,
prelude::*,
DropTargetAsync,
};
use webkit::WebView;

use crate::DragDropEvent;

Expand Down Expand Up @@ -72,45 +77,63 @@ impl DragDropController {

pub(crate) fn connect_drag_event(webview: &WebView, handler: Box<dyn Fn(DragDropEvent) -> bool>) {
let controller = Rc::new(DragDropController::new(handler));
let drop_target = DropTargetAsync::new(None, DragAction::all());

{
let controller = controller.clone();
webview.connect_drag_data_received(move |_, _, _, _, data, info, _| {
if info == 2 {
let uris = data.uris();
let paths = uris.iter().map(path_buf_from_uri).collect::<Vec<_>>();
controller.enter();
controller.call(DragDropEvent::Enter {
paths: paths.clone(),
position: controller.position.get(),
});
controller.store_paths(paths);
}
let controller: Rc<DragDropController> = controller.clone();
drop_target.connect_accept(move |_, drop| {
let controller = controller.clone();
drop.read_value_async(
FileList::static_type(),
gtk::glib::Priority::DEFAULT,
Cancellable::NONE,
move |result| {
if let Ok(value) = result {
if let Ok(files) = value.get::<FileList>() {
let paths = files
.files()
.iter()
.filter_map(|gfile| gfile.path())
.collect::<Vec<_>>();

controller.enter();
controller.call(DragDropEvent::Enter {
paths: paths.clone(),
position: controller.position.get(),
});
controller.store_paths(paths);
}
}
},
);
true
});
}

{
let controller = controller.clone();
webview.connect_drag_motion(move |_, _, x, y, _| {
drop_target.connect_drag_motion(move |_, _, x, y| {
if controller.state() == DragControllerState::Entered {
controller.call(DragDropEvent::Over { position: (x, y) });
controller.call(DragDropEvent::Over {
position: (x.round() as _, y.round() as _),
});
} else {
controller.store_position((x, y));
controller.store_position((x.round() as _, y.round() as _));
}
false
DragAction::COPY
});
}

{
let controller = controller.clone();
webview.connect_drag_drop(move |_, ctx, x, y, time| {
if controller.state() == DragControllerState::Leaving {
drop_target.connect_drop(move |_, drop, x, y| {
if controller.state() == DragControllerState::Entered {
if let Some(paths) = controller.take_paths() {
ctx.drop_finish(true, time);
drop.finish(DragAction::COPY);
controller.leave();
return controller.call(DragDropEvent::Drop {
paths,
position: (x, y),
position: (x.round() as _, y.round() as _),
});
}
}
Expand All @@ -119,7 +142,7 @@ pub(crate) fn connect_drag_event(webview: &WebView, handler: Box<dyn Fn(DragDrop
});
}

webview.connect_drag_leave(move |_w, _, _| {
drop_target.connect_drag_leave(move |_, _| {
if controller.state() != DragControllerState::Left {
controller.leaving();
let controller = controller.clone();
Expand All @@ -131,13 +154,6 @@ pub(crate) fn connect_drag_event(webview: &WebView, handler: Box<dyn Fn(DragDrop
});
}
});
}

fn path_buf_from_uri(gstr: &GString) -> PathBuf {
let path = gstr.as_str();
let path = path.strip_prefix("file://").unwrap_or(path);
let path = percent_encoding::percent_decode(path.as_bytes())
.decode_utf8_lossy()
.to_string();
PathBuf::from(path)
webview.add_controller(drop_target);
}
Loading