From be9ee81967b96fc695b709321ba0cdfe20d5d9d2 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 27 Dec 2021 18:33:17 -0500 Subject: [PATCH] more cleanup and fix save/restore dock items --- examples/dock/dock_item/imp.rs | 3 - examples/dock/dock_item/mod.rs | 79 +------------------- examples/dock/dock_object/mod.rs | 17 +++-- examples/dock/window/imp.rs | 1 + examples/dock/window/mod.rs | 123 ++++++++++++++++++------------- 5 files changed, 85 insertions(+), 138 deletions(-) diff --git a/examples/dock/dock_item/imp.rs b/examples/dock/dock_item/imp.rs index e3a21286..3b67118c 100644 --- a/examples/dock/dock_item/imp.rs +++ b/examples/dock/dock_item/imp.rs @@ -2,8 +2,6 @@ use gtk::glib; use gtk::prelude::*; use gtk::subclass::prelude::*; use gtk4 as gtk; -use gtk4::DragSource; -use once_cell::sync::OnceCell; use gtk::CompositeTemplate; @@ -14,7 +12,6 @@ pub struct DockItem { pub image: TemplateChild, #[template_child] pub dots: TemplateChild, - pub drag_controller: OnceCell, } #[glib::object_subclass] diff --git a/examples/dock/dock_item/mod.rs b/examples/dock/dock_item/mod.rs index 9523a94b..c6cf8d30 100644 --- a/examples/dock/dock_item/mod.rs +++ b/examples/dock/dock_item/mod.rs @@ -1,12 +1,7 @@ use crate::utils::BoxedWindowList; -use gdk4::ContentProvider; -use gdk4::Display; use gio::DesktopAppInfo; use gio::Icon; -use gio::ListStore; use gtk4 as gtk; -use gtk4::DragSource; -use gtk4::IconTheme; mod imp; use gtk::glib; @@ -28,22 +23,12 @@ impl Default for DockItem { impl DockItem { pub fn new() -> Self { - let mut actions = gdk4::DragAction::MOVE; - actions.insert(gdk4::DragAction::MOVE); - let self_: DockItem = glib::Object::new(&[]).expect("Failed to create DockItem"); self_ } - pub fn drag_controller(&self) -> &DragSource { - let imp = imp::DockItem::from_instance(self); - imp.drag_controller - .get() - .expect("Could not get drag_controller") - } - // refactor to emit event for removing the item? - pub fn set_app_info(&self, dock_object: &DockObject, i: u32, saved_app_model: &ListStore) { + pub fn set_app_info(&self, dock_object: &DockObject) { let self_ = imp::DockItem::from_instance(self); if let Ok(app_info_value) = dock_object.property("appinfo") { if let Ok(Some(app_info)) = app_info_value.get::>() { @@ -54,68 +39,6 @@ impl DockItem { ); self_.image.set_from_gicon(&icon); - if let Some(drag_controller) = self_.drag_controller.get() { - if let Some(file) = app_info.filename() { - let provider = - ContentProvider::for_value(&file.to_string_lossy().to_value()); - drag_controller.set_content(Some(&provider)); - } - drag_controller.connect_drag_cancel( - glib::clone!(@weak saved_app_model, @weak app_info => @default-return true, move |_self, _drag, _delete_data| { - if let Some(item) = saved_app_model.item(i) { - if let Ok(cur_app_info) = item.downcast::() { - if let Ok(Some(cur_app_info)) = cur_app_info.property("appinfo").expect("property appinfo missing from DockObject").get::>() { - // dbg!(cur_app_info.filename()); - if cur_app_info.filename() == app_info.filename() { - saved_app_model.remove(i); - } - } - } - } - true - }), - ); - drag_controller.connect_drag_end( - glib::clone!(@weak saved_app_model, @weak app_info => move |_self, _drag, _delete_data| { - dbg!(i); - dbg!(_delete_data); - if let Some(item) = saved_app_model.item(i) { - if let Ok(cur_app_info) = item.downcast::() { - if let Ok(Some(cur_app_info)) = cur_app_info.property("appinfo").expect("property appinfo missing from DockObject").get::>() { - // dbg!(cur_app_info.filename()); - if cur_app_info.filename() == app_info.filename() { - saved_app_model.remove(i); - } - } - } - } - }), - ); - - let icon = app_info.icon().unwrap_or( - Icon::for_string("image-missing").expect("Failed to set default icon"), - ); - drag_controller.connect_drag_begin( - glib::clone!(@weak icon, => move |_self, _drag| { - // set drag source icon if possible... - // gio Icon is not easily converted to a Paintable, but this seems to be the correct method - _drag.set_selected_action(gdk4::DragAction::MOVE); - if let Some(default_display) = &Display::default() { - if let Some(icon_theme) = IconTheme::for_display(default_display) { - if let Some(paintable_icon) = icon_theme.lookup_by_gicon( - &icon, - 64, - 1, - gtk4::TextDirection::None, - gtk4::IconLookupFlags::empty(), - ) { - _self.set_icon(Some(&paintable_icon), 32, 32); - } - } - } - }), - ); - } } } else { println!("initializing dock item failed..."); diff --git a/examples/dock/dock_object/mod.rs b/examples/dock/dock_object/mod.rs index f2da9d71..a9f7fa00 100644 --- a/examples/dock/dock_object/mod.rs +++ b/examples/dock/dock_object/mod.rs @@ -5,6 +5,7 @@ use gdk4::glib::Object; use gio::DesktopAppInfo; use gtk4::glib; use gtk4::prelude::AppInfoExt; +use std::path::Path; glib::wrapper! { pub struct DockObject(ObjectSubclass); @@ -17,12 +18,16 @@ impl DockObject { } pub fn from_app_info_path(path: &str) -> Option { - if let Some(appinfo) = gio::DesktopAppInfo::new(path) { - if appinfo.should_show() { - return Some( - Object::new(&[("appinfo", &Some(appinfo)), ("saved", &true)]) - .expect("Failed to create `DockObject`."), - ); + if let Some(path) = Path::new(path).file_name() { + if let Some(path) = path.to_str() { + if let Some(appinfo) = gio::DesktopAppInfo::new(path) { + if appinfo.should_show() { + return Some( + Object::new(&[("appinfo", &Some(appinfo)), ("saved", &true)]) + .expect("Failed to create `DockObject`."), + ); + } + } } } None diff --git a/examples/dock/window/imp.rs b/examples/dock/window/imp.rs index c7fd6a72..bfdacdd7 100644 --- a/examples/dock/window/imp.rs +++ b/examples/dock/window/imp.rs @@ -34,6 +34,7 @@ pub struct Window { pub saved_drag_source: Rc>, pub active_drag_source: OnceCell, pub drag_end_signal: Rc>>, + pub drag_cancel_signal: Rc>>, pub window_drop_controller: OnceCell, } diff --git a/examples/dock/window/mod.rs b/examples/dock/window/mod.rs index 6dcf19f9..24be5c6d 100644 --- a/examples/dock/window/mod.rs +++ b/examples/dock/window/mod.rs @@ -78,36 +78,6 @@ impl Window { .selected(gtk4::INVALID_LIST_POSITION) .model(&saved_app_model) .build(); - xdg::BaseDirectories::new() - .expect("could not access XDG Base directory") - .get_data_dirs() - .iter_mut() - .for_each(|xdg_data_path| { - let defaults = ["Firefox Web Browser", "Files", "Terminal", "Pop!_Shop"]; - xdg_data_path.push("applications"); - // dbg!(&xdg_data_path); - if let Ok(dir_iter) = std::fs::read_dir(xdg_data_path) { - dir_iter.for_each(|dir_entry| { - if let Ok(dir_entry) = dir_entry { - if let Some(path) = dir_entry.path().file_name() { - if let Some(path) = path.to_str() { - if let Some(app_info) = gio::DesktopAppInfo::new(path) { - if app_info.should_show() - && defaults.contains(&app_info.name().as_str()) - { - saved_app_model.append(&DockObject::new(app_info)); - } else { - // println!("Ignoring {}", path); - } - } else { - // println!("error loading {}", path); - } - } - } - } - }) - } - }); imp.saved_app_model .set(saved_app_model) @@ -236,7 +206,7 @@ impl Window { // dbg!(monitor_width); // dbg!(monitor_height); // dbg!(width); - dbg!(height); + // dbg!(height); let w_conf = xproto::ConfigureWindowAux::default() .x((monitor_x + monitor_width / 2 - width / 2).clamp(0, monitor_x + monitor_width - 1)) .y((monitor_y + monitor_height - height).clamp(0, monitor_y + monitor_height - 1)); @@ -375,7 +345,6 @@ impl Window { // dbg!("rejecting drop"); _self.reject(); } - Self::store_saved_apps(&saved_app_model); true }), ); @@ -445,8 +414,9 @@ impl Window { .build(); let drag_end = &imp.drag_end_signal; + let drag_cancel = &imp.drag_end_signal; saved_app_list_view.add_controller(&saved_drag_source); - saved_drag_source.connect_prepare(glib::clone!(@weak saved_app_model, @weak saved_app_list_view, @weak drag_end => @default-return None, move |self_, x, _y| { + saved_drag_source.connect_prepare(glib::clone!(@weak saved_app_model, @weak saved_app_list_view, @weak drag_end, @weak drag_cancel => @default-return None, move |self_, x, _y| { // set drag source icon if possible... // gio Icon is not easily converted to a Paintable, but this seems to be the correct method let max_x = saved_app_list_view.allocated_width(); @@ -464,7 +434,18 @@ impl Window { ))) { glib::signal_handler_disconnect(self_, old_handle); } - + if let Some(old_handle) = drag_cancel.replace(Some(self_.connect_drag_cancel( + glib::clone!(@weak saved_app_model => @default-return false, move |_self, _drag, cancel_reason| { + if cancel_reason != gdk4::DragCancelReason::UserCancelled { + saved_app_model.remove(index); + true + } else { + false + } + }), + ))) { + glib::signal_handler_disconnect(self_, old_handle); + } if let Ok(dock_object) = item.downcast::() { if let Ok(Some(app_info)) = dock_object.property("appinfo").expect("property appinfo missing from DockObject").get::>() { let icon = app_info @@ -513,7 +494,7 @@ impl Window { }); active_app_list_view.add_controller(&active_drag_source); - active_drag_source.connect_prepare(glib::clone!(@weak active_app_model, @weak active_app_list_view, @weak drag_end => @default-return None, move |self_, x, _y| { + active_drag_source.connect_prepare(glib::clone!(@weak active_app_model, @weak active_app_list_view, @weak drag_end, @weak drag_cancel => @default-return None, move |self_, x, _y| { let max_x = active_app_list_view.allocated_width(); // dbg!(max_x); // dbg!(max_y); @@ -528,6 +509,19 @@ impl Window { ))) { glib::signal_handler_disconnect(self_, old_handle); } + if let Some(old_handle) = drag_cancel.replace(Some(self_.connect_drag_cancel( + glib::clone!(@weak active_app_model => @default-return false, move |_self, _drag, cancel_reason| { + if cancel_reason != gdk4::DragCancelReason::UserCancelled { + active_app_model.remove(index); + true + } else { + false + } + }), + ))) { + glib::signal_handler_disconnect(self_, old_handle); + } + if let Ok(dock_object) = item.downcast::() { if let Ok(Some(app_info)) = dock_object.property("appinfo").expect("property appinfo missing from DockObject").get::>() { @@ -584,8 +578,7 @@ impl Window { .downcast::() .expect("The list item type needs to be `DockItem`"); - let i = list_item.position(); - dock_item.set_app_info(&application_object, i, &saved_app_model); + dock_item.set_app_info(&application_object); })); // Set the factory of the list view imp.saved_app_list_view @@ -612,8 +605,7 @@ impl Window { .downcast::() .expect("The list item type needs to be `DockItem`"); - let i = list_item.position(); - dock_item.set_app_info(&application_object, i, &active_app_model); + dock_item.set_app_info(&application_object); })); // Set the factory of the list view imp.active_app_list_view.set_factory(Some(&active_factory)); @@ -621,31 +613,60 @@ impl Window { fn restore_saved_apps(&self) { if let Ok(file) = File::open(data_path()) { - if let Ok(data) = serde_json::from_reader::<_, Vec>(file) { - dbg!(&data); - let dock_objects: Vec = data + if let Ok(saved_data) = serde_json::from_reader::<_, Vec>(file) { + // dbg!(&saved_data); + let dock_objects: Vec = saved_data .into_iter() .filter_map(|d| { DockObject::from_app_info_path(&d) .map(|dockobject| dockobject.upcast::()) }) .collect(); + // dbg!(&dock_objects); let saved_app_model = self.saved_app_model(); saved_app_model.splice(saved_app_model.n_items(), 0, &dock_objects); - } else { - println!("Error loading saved apps!"); - // let file = File::create(data_path()).expect("Could not create json file."); - // serde_json::to_writer_pretty(file, &Vec::<&str>::new()) - // .expect("Could not write data to json file"); + return; } } + println!("Error loading saved apps!"); + let saved_app_model = &self.saved_app_model(); + xdg::BaseDirectories::new() + .expect("could not access XDG Base directory") + .get_data_dirs() + .iter_mut() + .for_each(|xdg_data_path| { + let defaults = ["Firefox Web Browser", "Files", "Terminal", "Pop!_Shop"]; + xdg_data_path.push("applications"); + // dbg!(&xdg_data_path); + if let Ok(dir_iter) = std::fs::read_dir(xdg_data_path) { + dir_iter.for_each(|dir_entry| { + if let Ok(dir_entry) = dir_entry { + if let Some(path) = dir_entry.path().file_name() { + if let Some(path) = path.to_str() { + if let Some(app_info) = gio::DesktopAppInfo::new(path) { + if app_info.should_show() + && defaults.contains(&app_info.name().as_str()) + { + saved_app_model.append(&DockObject::new(app_info)); + } else { + // println!("Ignoring {}", path); + } + } else { + // println!("error loading {}", path); + } + } + } + } + }) + } + }); } fn store_saved_apps(saved_app_model: &gio::ListStore) { // Store todo data in vector let mut backup_data = Vec::new(); - let mut position = 3; - while let Some(item) = saved_app_model.item(position) { + let mut i = 0; + while let Some(item) = saved_app_model.item(i) { // Get `AppGroup` from `glib::Object` let dock_object = item .downcast_ref::() @@ -660,9 +681,9 @@ impl Window { backup_data.push(f); } } - position += 1; + i += 1; } - dbg!(&backup_data); + // dbg!(&backup_data); // Save state in file let file = File::create(data_path()).expect("Could not create json file."); serde_json::to_writer_pretty(file, &backup_data)