diff --git a/src/app.rs b/src/app.rs index b47f4a67..88b05819 100644 --- a/src/app.rs +++ b/src/app.rs @@ -197,6 +197,14 @@ impl App { ), &["s"], ), + ( + format!( + "{}.{}", + browser.window.action.id, + browser.window.action.source.gobject.name() + ), + &["u"], + ), ( format!( "{}.{}", diff --git a/src/app/browser/window.rs b/src/app/browser/window.rs index 579b11f0..56d2b2f1 100644 --- a/src/app/browser/window.rs +++ b/src/app/browser/window.rs @@ -86,6 +86,11 @@ impl Window { move |position| tab.save_as(position) }); + action.source.connect_activate({ + let tab = tab.clone(); + move |position| tab.source(position) + }); + action.history_back.connect_activate({ let tab = tab.clone(); move |position| { diff --git a/src/app/browser/window/action.rs b/src/app/browser/window/action.rs index a99847b0..58a96d1d 100644 --- a/src/app/browser/window/action.rs +++ b/src/app/browser/window/action.rs @@ -8,6 +8,7 @@ mod home; mod pin; mod reload; mod save_as; +mod source; use append::Append; use bookmark::Bookmark; @@ -19,6 +20,7 @@ use home::Home; use pin::Pin; use reload::Reload; use save_as::SaveAs; +use source::Source; use gtk::{ gio::SimpleActionGroup, @@ -42,6 +44,7 @@ pub struct Action { pub pin: Rc, pub reload: Rc, pub save_as: Rc, + pub source: Rc, // Group pub id: GString, pub gobject: SimpleActionGroup, @@ -63,6 +66,7 @@ impl Action { let pin = Rc::new(Pin::new()); let reload = Rc::new(Reload::new()); let save_as = Rc::new(SaveAs::new()); + let source = Rc::new(Source::new()); // Generate unique group ID let id = uuid_string_random(); @@ -81,6 +85,7 @@ impl Action { gobject.add_action(&pin.gobject); gobject.add_action(&reload.gobject); gobject.add_action(&save_as.gobject); + gobject.add_action(&source.gobject); // Done Self { @@ -94,6 +99,7 @@ impl Action { pin, reload, save_as, + source, id, gobject, } diff --git a/src/app/browser/window/action/source.rs b/src/app/browser/window/action/source.rs new file mode 100644 index 00000000..f612620c --- /dev/null +++ b/src/app/browser/window/action/source.rs @@ -0,0 +1,64 @@ +use gtk::{ + gio::SimpleAction, + glib::uuid_string_random, + prelude::{ActionExt, ToVariant}, +}; + +// Defaults + +/// C-compatible variant type +const DEFAULT_STATE: i32 = -1; + +/// [SimpleAction](https://docs.gtk.org/gio/class.SimpleAction.html) wrapper for `Source` action of `Window` group +pub struct Source { + pub gobject: SimpleAction, +} + +impl Source { + // Constructors + + /// Create new `Self` + pub fn new() -> Self { + Self { + gobject: SimpleAction::new_stateful( + &uuid_string_random(), + None, + &DEFAULT_STATE.to_variant(), + ), + } + } + + // Actions + + /// Change action [state](https://docs.gtk.org/gio/method.SimpleAction.set_state.html) + /// * set `DEFAULT_STATE` on `None` + pub fn change_state(&self, state: Option) { + self.gobject.change_state( + &match state { + Some(value) => value, + None => DEFAULT_STATE, + } + .to_variant(), + ) + } + + // Events + + /// Define callback function for + /// [SimpleAction::activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal + pub fn connect_activate(&self, callback: impl Fn(Option) + 'static) { + self.gobject.connect_activate(move |this, _| { + let state = this + .state() + .expect("State value required") + .get::() + .expect("Parameter type does not match `i32`"); + + callback(if state == DEFAULT_STATE { + None + } else { + Some(state) + }) + }); + } +} diff --git a/src/app/browser/window/header/bar/menu.rs b/src/app/browser/window/header/bar/menu.rs index 99f4886d..a9a39ec4 100644 --- a/src/app/browser/window/header/bar/menu.rs +++ b/src/app/browser/window/header/bar/menu.rs @@ -59,6 +59,17 @@ impl Menu { main_page.append_section(None, &main_page_mark); + // Main > Page > Tools + let main_page_tools = gio::Menu::new(); + + main_page_tools.append(Some("Source"), Some(&format!( + "{}.{}", + window_action.id, + window_action.source.gobject.name() + ))); + + main_page.append_section(None, &main_page_tools); + // Main > Page > Navigation let main_page_navigation = gio::Menu::new(); diff --git a/src/app/browser/window/tab.rs b/src/app/browser/window/tab.rs index 386a375d..4affeb17 100644 --- a/src/app/browser/window/tab.rs +++ b/src/app/browser/window/tab.rs @@ -60,6 +60,7 @@ impl Tab { action.pin.change_state(state); action.reload.change_state(state); action.save_as.change_state(state); + action.source.change_state(state); } }); @@ -161,6 +162,14 @@ impl Tab { } } + // View source for page at given `position`, `None` to use selected page (if available) + pub fn source(&self, page_position: Option) { + if let Some(item) = self.item(page_position) { + item.page.navigation.request.to_source(); + item.page.load(true); + } + } + /// Toggle `Bookmark` in current `Profile` for `Page` at given `position` (current page on `None`) /// * return `true` on bookmark created, `false` on deleted; `Error` otherwise. pub fn bookmark(&self, page_position: Option) -> Result { diff --git a/src/app/browser/window/tab/item/page/navigation/request.rs b/src/app/browser/window/tab/item/page/navigation/request.rs index 35ac13a7..ed47b292 100644 --- a/src/app/browser/window/tab/item/page/navigation/request.rs +++ b/src/app/browser/window/tab/item/page/navigation/request.rs @@ -94,6 +94,10 @@ impl Request { self.widget.entry.set_text(&self.download()); } + pub fn to_source(&self) { + self.widget.entry.set_text(&self.source()); + } + // Getters pub fn uri(&self) -> Option { @@ -120,6 +124,10 @@ impl Request { pub fn download(&self) -> GString { gformat!("download:{}", self.strip_prefix()) } + + pub fn source(&self) -> GString { + gformat!("source:{}", self.strip_prefix()) + } } // Tools diff --git a/src/app/browser/window/tab/menu.rs b/src/app/browser/window/tab/menu.rs index a533da1a..9e67abf7 100644 --- a/src/app/browser/window/tab/menu.rs +++ b/src/app/browser/window/tab/menu.rs @@ -56,6 +56,19 @@ impl Menu { main.append_section(None, &main_mark); + let main_tools = gtk::gio::Menu::new(); + + main_tools.append( + Some("Source"), + Some(&format!( + "{}.{}", + window_action.id, + window_action.source.gobject.name() + )), + ); + + main.append_section(None, &main_tools); + let navigation = gtk::gio::Menu::new(); navigation.append(