From e9c5bf92541c672864de1afab540dc138012fdca Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 16 Dec 2021 17:14:44 -0500 Subject: [PATCH] reorder dock items & move item if it is dropped on dock but already exists --- Cargo.toml | 6 ++- examples/dock/dock_item/mod.rs | 11 ++--- examples/dock/window/mod.rs | 82 +++++++++++++++++++++++----------- 3 files changed, 66 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 01ca6ea..15a9b33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ cascade = "1" gdk4 = "0.3.1" gdk4-x11 = "0.3.0" gio = "0.14.8" -gtk4 = "0.3.1" x11 = { version = "2", features = ["xlib"] } # examples/launcher @@ -24,3 +23,8 @@ once_cell = "1.8.0" xdg = "2.4.0" serde = "1.0.130" x11rb = "0.9.0" + +[dependencies.gtk4] +package = "gtk4" +version = "0.3.1" +features = ["v4_4"] \ No newline at end of file diff --git a/examples/dock/dock_item/mod.rs b/examples/dock/dock_item/mod.rs index a3e7e85..21a347a 100644 --- a/examples/dock/dock_item/mod.rs +++ b/examples/dock/dock_item/mod.rs @@ -28,7 +28,7 @@ impl DockItem { pub fn new() -> Self { let dc = DragSource::builder() .name("dock drag source") - .actions(gdk4::DragAction::MOVE) + .actions(gdk4::DragAction::COPY) .build(); let self_: DockItem = glib::Object::new(&[]).expect("Failed to create DockItem"); @@ -60,14 +60,10 @@ impl DockItem { self_.image.set_tooltip_text(Some(&app_info.name())); if let Some(drag_controller) = self_.drag_controller.get() { - // if let Some(file) = app_info.filename() { - // let file = File::for_path(file); if let Some(file) = app_info.filename() { - let file = File::for_path(file); - let provider = ContentProvider::for_value(&file.to_value()); + let provider = ContentProvider::for_value(&file.to_string_lossy().to_value()); drag_controller.set_content(Some(&provider)); } - // } drag_controller.connect_drag_end(move |_self, _drag, delete_data| { dbg!("removing", delete_data); }); @@ -94,7 +90,8 @@ impl DockItem { .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| { - drag.set_selected_action(gdk4::DragAction::MOVE); + // drag.set_selected_action(gdk4::DragAction::MOVE); + // override formats // set drag source icon if possible... // gio Icon is not easily converted to a Paintable, but this seems to be the correct method if let Some(default_display) = &Display::default() { diff --git a/examples/dock/window/mod.rs b/examples/dock/window/mod.rs index 663b3f5..2ea0585 100644 --- a/examples/dock/window/mod.rs +++ b/examples/dock/window/mod.rs @@ -2,15 +2,19 @@ mod imp; // use crate::ApplicationObject; use crate::dock_item::DockItem; use crate::X11_CONN; +use gdk4::ContentProvider; use gdk4::Rectangle; use gdk4::Surface; use gdk4_x11::X11Surface; use gio::Cancellable; use gio::DesktopAppInfo; +use glib::Type; use gtk4 as gtk; +use gtk4::prelude::ListModelExt; use gtk4::DropTarget; use gtk4::DropTargetAsync; use gtk4::EventControllerMotion; +use gtk4::ListStore; use gtk4::TreeIter; use std::path::Path; use x11rb::connection::Connection; @@ -225,31 +229,52 @@ impl Window { // }); let saved_app_list_view = saved_app_list_view.get(); + drop_controller.connect_drop( glib::clone!(@weak saved_app_model, @weak saved_app_list_view => @default-return true, move |_self, drop_value, x, y| { - dbg!(x); - dbg!(y); - let max_y = saved_app_list_view.allocated_height(); - let max_x = saved_app_list_view.allocated_width(); - dbg!(max_x); - dbg!(max_y); - let n_buckets = saved_app_model.n_items() * 2; - - let drop_bucket = (x * n_buckets as f64 / (max_x as f64 + 0.1)) as u32; - let index = if drop_bucket == 0 { - 0 - } else if drop_bucket == n_buckets - 1 { - saved_app_model.n_items() - } else { - (drop_bucket + 1) / 2 - }; - dbg!(index); - dbg!("dropped it!"); - if let Ok(Some(path)) = drop_value.get::>() { - dbg!(&path); - if let Some(path) = &Path::new(&path).file_name() { - if let Some(app_info) = gio::DesktopAppInfo::new(&path.to_string_lossy()) { + if let Ok(Some(path_str)) = drop_value.get::>() { + dbg!(&path_str); + let desktop_path = &Path::new(&path_str); + if let Some(pathbase) = desktop_path.file_name() { + if let Some(app_info) = gio::DesktopAppInfo::new(&pathbase.to_string_lossy()) { + let mut i: u32 = 0; + let mut index_of_existing_app: Option = None; + while let Some(item) = saved_app_model.item(i) { + if let Ok(cur_app_info) = item.downcast::() { + dbg!(cur_app_info.filename()); + if cur_app_info.filename() == Some(Path::new(&path_str).to_path_buf()) { + index_of_existing_app = Some(i); + } + } + i += 1; + } dbg!(app_info.name()); + dbg!(index_of_existing_app); + if let Some(index_of_existing_app) = index_of_existing_app { + // remove existing entry + saved_app_model.remove(index_of_existing_app); + } + + //calculate insertion location + dbg!(x); + dbg!(y); + let max_y = saved_app_list_view.allocated_height(); + let max_x = saved_app_list_view.allocated_width(); + dbg!(max_x); + dbg!(max_y); + let n_buckets = saved_app_model.n_items() * 2; + + let drop_bucket = (x * n_buckets as f64 / (max_x as f64 + 0.1)) as u32; + let index = if drop_bucket == 0 { + 0 + } else if drop_bucket == n_buckets - 1 { + saved_app_model.n_items() + } else { + (drop_bucket + 1) / 2 + }; + dbg!(index); + dbg!("dropped it!"); + dbg!(drop_value.type_()); saved_app_model.insert(index, &app_info); } } @@ -289,12 +314,19 @@ impl Window { fn setup_drop_target(&self) { let imp = imp::Window::from_instance(self); let drop_target_widget = &imp.saved_app_list_view; - let mut drop_actions = gdk4::DragAction::COPY; - drop_actions.toggle(gdk4::DragAction::MOVE); + let drop_actions = gdk4::DragAction::COPY; + // drop_actions.toggle(gdk4::DragAction::MOVE); + let drop_format = gdk4::ContentFormats::for_type(Type::STRING); + let provider = + ContentProvider::for_value(&DesktopAppInfo::new("firefox.desktop").to_value()); + let desktop_type = provider.formats().types()[0]; + // causes error for some reason... + // let desktop_type = Type::from_name("GDesktopAppInfo").expect("Invalid GType"); + drop_format.union(&gdk4::ContentFormats::for_type(desktop_type)); let drop_target_controller = DropTarget::builder() .preload(true) .actions(drop_actions) - .formats(&gdk4::ContentFormats::for_type(glib::types::Type::STRING)) + .formats(&drop_format) .build(); drop_target_widget.add_controller(&drop_target_controller); imp.drop_controller