From 21bc4af3c93c920d61bfb7bfede85a7883d0f6ab Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 4 Jan 2022 15:12:40 -0500 Subject: [PATCH] connect handler for new window and quit all from dock menu --- examples/dock/dock_item/mod.rs | 1 + examples/dock/dock_popover/imp.rs | 1 + examples/dock/dock_popover/mod.rs | 70 ++++++++++++++++++++++++++++--- examples/dock/main.rs | 11 ++++- examples/dock/style.css | 24 +++++------ 5 files changed, 88 insertions(+), 19 deletions(-) diff --git a/examples/dock/dock_item/mod.rs b/examples/dock/dock_item/mod.rs index c06e3dbb..19776f5b 100644 --- a/examples/dock/dock_item/mod.rs +++ b/examples/dock/dock_item/mod.rs @@ -35,6 +35,7 @@ impl DockItem { let item_box = Box::new(Orientation::Vertical, 0); self_.set_child(Some(&item_box)); + self_.add_css_class("dock_item"); let image = cascade! { Image::new(); diff --git a/examples/dock/dock_popover/imp.rs b/examples/dock/dock_popover/imp.rs index 8d1eec41..9e234dcf 100644 --- a/examples/dock/dock_popover/imp.rs +++ b/examples/dock/dock_popover/imp.rs @@ -11,6 +11,7 @@ use crate::dock_object::DockObject; pub struct DockPopover { pub menu_handle: Rc>, pub all_windows_item_revealer: Rc>, + pub all_windows_item_header: Rc>, pub window_list: Rc>, pub launch_new_item: Rc>, pub favorite_item: Rc>, diff --git a/examples/dock/dock_popover/mod.rs b/examples/dock/dock_popover/mod.rs index 08c5c3af..f8001b81 100644 --- a/examples/dock/dock_popover/mod.rs +++ b/examples/dock/dock_popover/mod.rs @@ -1,12 +1,14 @@ use cascade::cascade; -use gtk4::ffi::gtk_window_close; +use gio::DesktopAppInfo; use gtk4::subclass::prelude::*; use gtk4::{gio, glib}; use gtk4::{prelude::*, Label}; -use gtk4::{Box, Button, Image, ListBox, Orientation, Revealer}; +use gtk4::{Box, Button, Image, ListBox, Orientation, Revealer, Window}; -use crate::dock_object::DockObject; +use crate::dock_object::{self, DockObject}; use crate::utils::BoxedWindowList; +use crate::Event; +use crate::TX; mod imp; @@ -88,6 +90,7 @@ impl DockPopover { ..set_pixel_size(16); }; all_windows_item_header_box.append(&all_windows_item_header_icon); + imp.all_windows_item_header.replace(all_windows_item_header); if let Ok(window_list) = dock_object .property("active") @@ -99,7 +102,7 @@ impl DockPopover { } else { let window_list_revealer = cascade! { Revealer::new(); - ..set_reveal_child(true); + ..set_reveal_child(false); ..set_transition_type(gtk4::RevealerTransitionType::SlideDown); }; all_windows_item_container.append(&window_list_revealer); @@ -129,6 +132,8 @@ impl DockPopover { window_box.append(&window_image); window_box.append(&window_title); } + imp.all_windows_item_revealer.replace(window_list_revealer); + imp.window_list.replace(window_listbox); } } @@ -142,11 +147,13 @@ impl DockPopover { Button::with_label("New Window"); }; launch_item_container.append(&launch_new_item); + imp.launch_new_item.replace(launch_new_item); let favorite_item = cascade! { Button::with_label(if dock_object.property("saved").unwrap().get::().unwrap() {"Remove from Favorites"} else {"Add to Favorites"}); }; menu_handle.append(&favorite_item); + imp.favorite_item.replace(favorite_item); if let Ok(window_list) = dock_object .property("active") @@ -158,6 +165,7 @@ impl DockPopover { Button::with_label(format!("Quit {} Windows", window_list.0.len()).as_str()); }; menu_handle.append(&quit_all_item); + imp.quit_all_item.replace(quit_all_item); } else { let quit_all_item = cascade! { Button::with_label("Quit"); @@ -166,6 +174,7 @@ impl DockPopover { if window_list.0.len() == 0 { quit_all_item.hide(); } + imp.quit_all_item.replace(quit_all_item); } } self.setup_handlers(); @@ -184,6 +193,57 @@ impl DockPopover { } fn setup_handlers(&self) { - // todo!(); + let imp = imp::DockPopover::from_instance(&self); + let dock_object = imp.dock_object.borrow(); + let launch_new_item = imp.launch_new_item.borrow(); + let favorite_item = imp.favorite_item.borrow(); + let quit_all_item = imp.quit_all_item.borrow(); + let window_listbox = imp.window_list.borrow(); + let all_windows_header = imp.all_windows_item_header.borrow(); + let revealer = &imp.all_windows_item_revealer; + + if let Some(dock_object) = dock_object.as_ref() { + println!("setting up popover menu handlers"); + launch_new_item.connect_clicked(glib::clone!(@weak dock_object => move |self_| { + let app_info = dock_object.property("appinfo").expect("DockObject must have appinfo property").get::>().expect("Failed to convert value to DesktopAppInfo").unwrap(); + + let window = self_.root().unwrap().downcast::().unwrap(); + let context = window.display().app_launch_context(); + if let Err(err) = app_info.launch(&[], Some(&context)) { + gtk4::MessageDialog::builder() + .text(&format!("Failed to start {}", app_info.name())) + .secondary_text(&err.to_string()) + .message_type(gtk4::MessageType::Error) + .modal(true) + .transient_for(&window) + .build() + .show(); + } + })); + + quit_all_item.connect_clicked(glib::clone!(@weak dock_object => move |self_| { + let active = dock_object.property("active").expect("DockObject must have active property").get::().expect("Failed to convert value to WindowList").0; + for w in active { + let entity = w.entity.clone(); + glib::MainContext::default().spawn_local(async move { + if let Some(tx) = TX.get() { + let _ = tx.send(Event::Close(entity)).await; + } + }); + } + })); + + favorite_item.connect_clicked(glib::clone!(@weak dock_object => move |self_| { + println!("handling favorite"); + })); + + all_windows_header.connect_clicked( + glib::clone!(@weak dock_object, @weak revealer => move |self_| { + dbg!(dock_object); + let revealer = revealer.borrow(); + revealer.set_reveal_child(!revealer.reveals_child()) + }), + ); + } } } diff --git a/examples/dock/main.rs b/examples/dock/main.rs index 7bb668a8..bccdee98 100644 --- a/examples/dock/main.rs +++ b/examples/dock/main.rs @@ -41,6 +41,7 @@ static X11_CONN: OnceCell = OnceCell::new(); pub enum Event { WindowList(Vec), Activate((u32, u32)), + Close((u32, u32)), RefreshFromCache, } @@ -52,7 +53,7 @@ pub struct Item { desktop_entry: String, } -fn spawn_launcher(tx: mpsc::Sender) -> Connection { +fn spawn_zbus(tx: mpsc::Sender) -> Connection { let connection = block_on(Connection::session()).unwrap(); let sender = tx.clone(); @@ -110,7 +111,7 @@ fn main() { app.connect_activate(move |app| { let (tx, mut rx) = mpsc::channel(100); - let zbus_conn = spawn_launcher(tx.clone()); + let zbus_conn = spawn_zbus(tx.clone()); if TX.set(tx).is_err() { println!("failed to set global Sender. Exiting"); std::process::exit(1); @@ -136,6 +137,12 @@ fn main() { .await .expect("Failed to focus selected window"); } + Event::Close(e) => { + let _activate_window = zbus_conn + .call_method(Some(DEST), PATH, Some(DEST), "WindowQuit", &((e,))) + .await + .expect("Failed to close selected window"); + } Event::RefreshFromCache => { // println!("refreshing model from cache"); let cached_results = cached_results.as_ref(); diff --git a/examples/dock/style.css b/examples/dock/style.css index 5fc8085d..db8d7c9a 100644 --- a/examples/dock/style.css +++ b/examples/dock/style.css @@ -16,6 +16,18 @@ listview row { padding: 0px; } +button.dock_item:hover { + background: #888888; + border-radius: 12px; + border-width: 0px; +} + +button.dock_item { + background: #333333; + border-radius: 12px; + border-width: 0px; +} + list { border-radius: 12px; background: #333333; @@ -34,18 +46,6 @@ list row { padding: 0px; } -button:hover { - background: #888888; - border-radius: 12px; - border-width: 0px; -} - -button { - background: #333333; - border-radius: 12px; - border-width: 0px; -} - box.dock { border-radius: 12px; background: #333333;