Complete engine rewrite - now featuring Gecko!
This commit is contained in:
parent
d6b604639d
commit
b1be74adb8
20 changed files with 4069 additions and 2309 deletions
164
src/webkit/popup.rs
Normal file
164
src/webkit/popup.rs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
//! Real popup windows for Linux/WebKitGTK content views.
|
||||
//!
|
||||
//! wry does not connect WebKitGTK's `create` signal, so new-window requests
|
||||
//! would never produce a window with a live `window.opener`. That breaks
|
||||
//! popup-based logins ("Sign in with Google" and friends). Here we attach the
|
||||
//! signal to the raw `WebKitWebView` and build proper related-view popups.
|
||||
|
||||
use super::{NavKind, NewWindowDecision, UserEvent, decide_new_window};
|
||||
use gtk::prelude::*;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use tao::event_loop::EventLoopProxy;
|
||||
use webkit2gtk::{URIRequestExt, UserContentManagerExt, WebViewExt};
|
||||
|
||||
pub struct PopupHub {
|
||||
pub proxy: EventLoopProxy<UserEvent>,
|
||||
pub adblock_enabled: Cell<bool>,
|
||||
pub popups: RefCell<Vec<gtk::glib::WeakRef<webkit2gtk::WebView>>>,
|
||||
}
|
||||
|
||||
impl PopupHub {
|
||||
pub fn new(proxy: EventLoopProxy<UserEvent>, adblock_enabled: bool) -> Self {
|
||||
Self {
|
||||
proxy,
|
||||
adblock_enabled: Cell::new(adblock_enabled),
|
||||
popups: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hook the `create` signal of a content webview.
|
||||
pub fn attach(view: &webkit2gtk::WebView, hub: &Rc<PopupHub>) {
|
||||
let hub = hub.clone();
|
||||
view.connect_create(move |view, action| handle_create(view, action, &hub));
|
||||
}
|
||||
|
||||
/// Push the adblock toggle into popup pages that are already open.
|
||||
pub fn set_popup_adblock(hub: &PopupHub, enabled: bool) {
|
||||
hub.adblock_enabled.set(enabled);
|
||||
let script = format!(
|
||||
"window.__rustywolfSetAdblockEnabled && window.__rustywolfSetAdblockEnabled({enabled});"
|
||||
);
|
||||
|
||||
let mut alive = Vec::new();
|
||||
for weak in hub.popups.borrow_mut().drain(..) {
|
||||
if let Some(view) = weak.upgrade() {
|
||||
view.evaluate_javascript(&script, None, None, None::<>k::gio::Cancellable>, |_| {});
|
||||
alive.push(view.downgrade());
|
||||
}
|
||||
}
|
||||
*hub.popups.borrow_mut() = alive;
|
||||
}
|
||||
|
||||
fn handle_create(
|
||||
view: &webkit2gtk::WebView,
|
||||
action: &webkit2gtk::NavigationAction,
|
||||
hub: &Rc<PopupHub>,
|
||||
) -> Option<gtk::Widget> {
|
||||
let url = action
|
||||
.request()
|
||||
.and_then(|request| request.uri())
|
||||
.map(|uri| uri.to_string())
|
||||
.unwrap_or_default();
|
||||
let user_gesture = action.is_user_gesture();
|
||||
let nav = match action.navigation_type() {
|
||||
webkit2gtk::NavigationType::LinkClicked => NavKind::Link,
|
||||
webkit2gtk::NavigationType::FormSubmitted | webkit2gtk::NavigationType::FormResubmitted => {
|
||||
NavKind::Form
|
||||
}
|
||||
_ => NavKind::Other,
|
||||
};
|
||||
|
||||
match decide_new_window(&url, nav, user_gesture) {
|
||||
NewWindowDecision::Deny => None,
|
||||
NewWindowDecision::Tab => {
|
||||
let _ = hub.proxy.send_event(UserEvent::NewWindow { url });
|
||||
None
|
||||
}
|
||||
NewWindowDecision::Ask => {
|
||||
let _ = hub.proxy.send_event(UserEvent::NewWindowAsk { url });
|
||||
None
|
||||
}
|
||||
NewWindowDecision::Popup => create_popup(view, &url, hub),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_popup(
|
||||
opener: &webkit2gtk::WebView,
|
||||
url: &str,
|
||||
hub: &Rc<PopupHub>,
|
||||
) -> Option<gtk::Widget> {
|
||||
let view = webkit2gtk::WebView::with_related_view(opener);
|
||||
if let Some(settings) = WebViewExt::settings(opener) {
|
||||
view.set_settings(&settings);
|
||||
}
|
||||
install_scripts(&view, hub.adblock_enabled.get());
|
||||
|
||||
let title = url::Url::parse(url)
|
||||
.ok()
|
||||
.and_then(|parsed| parsed.host_str().map(ToString::to_string))
|
||||
.unwrap_or_else(|| "RustyWolf".to_string());
|
||||
let window = gtk::Window::new(gtk::WindowType::Toplevel);
|
||||
window.set_title(&title);
|
||||
window.set_default_size(960, 700);
|
||||
window.set_position(gtk::WindowPosition::Center);
|
||||
window.add(&view);
|
||||
|
||||
// Popups can spawn popups (SSO hand-offs often do).
|
||||
let nested_hub = hub.clone();
|
||||
view.connect_create(move |view, action| handle_create(view, action, &nested_hub));
|
||||
|
||||
// Keep the window title in sync with the page.
|
||||
let window_weak = window.downgrade();
|
||||
view.connect_title_notify(move |view| {
|
||||
if let Some(window) = window_weak.upgrade()
|
||||
&& let Some(title) = view.title()
|
||||
{
|
||||
window.set_title(&title);
|
||||
}
|
||||
});
|
||||
|
||||
// Minimal popup shortcuts: Ctrl+W closes, F5 / Ctrl+R reload.
|
||||
let view_weak = view.downgrade();
|
||||
window.connect_key_press_event(move |window, event| {
|
||||
use gtk::gdk::keys::constants as key;
|
||||
let ctrl = event.state().contains(gtk::gdk::ModifierType::CONTROL_MASK);
|
||||
let keyval = event.keyval();
|
||||
if ctrl && keyval == key::w {
|
||||
window.close();
|
||||
return gtk::glib::Propagation::Stop;
|
||||
}
|
||||
if keyval == key::F5 || (ctrl && keyval == key::r) {
|
||||
if let Some(view) = view_weak.upgrade() {
|
||||
view.reload();
|
||||
}
|
||||
return gtk::glib::Propagation::Stop;
|
||||
}
|
||||
gtk::glib::Propagation::Proceed
|
||||
});
|
||||
|
||||
window.show_all();
|
||||
hub.popups.borrow_mut().push(view.downgrade());
|
||||
Some(window.upcast())
|
||||
}
|
||||
|
||||
fn install_scripts(view: &webkit2gtk::WebView, adblock_enabled: bool) {
|
||||
let Some(manager) = view.user_content_manager() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let source = format!(
|
||||
"{}\nwindow.__rustywolfAdblockInitEnabled = {adblock_enabled};\n{}",
|
||||
super::js::PRIVACY_JS,
|
||||
super::js::ADBLOCK_JS
|
||||
);
|
||||
let script = webkit2gtk::UserScript::new(
|
||||
&source,
|
||||
webkit2gtk::UserContentInjectedFrames::AllFrames,
|
||||
webkit2gtk::UserScriptInjectionTime::Start,
|
||||
&[],
|
||||
&[],
|
||||
);
|
||||
manager.add_script(&script);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue