reorder dock items & move item if it is dropped on dock but already exists
This commit is contained in:
parent
9f5af5e573
commit
e9c5bf9254
3 changed files with 66 additions and 33 deletions
|
|
@ -8,7 +8,6 @@ cascade = "1"
|
||||||
gdk4 = "0.3.1"
|
gdk4 = "0.3.1"
|
||||||
gdk4-x11 = "0.3.0"
|
gdk4-x11 = "0.3.0"
|
||||||
gio = "0.14.8"
|
gio = "0.14.8"
|
||||||
gtk4 = "0.3.1"
|
|
||||||
x11 = { version = "2", features = ["xlib"] }
|
x11 = { version = "2", features = ["xlib"] }
|
||||||
|
|
||||||
# examples/launcher
|
# examples/launcher
|
||||||
|
|
@ -24,3 +23,8 @@ once_cell = "1.8.0"
|
||||||
xdg = "2.4.0"
|
xdg = "2.4.0"
|
||||||
serde = "1.0.130"
|
serde = "1.0.130"
|
||||||
x11rb = "0.9.0"
|
x11rb = "0.9.0"
|
||||||
|
|
||||||
|
[dependencies.gtk4]
|
||||||
|
package = "gtk4"
|
||||||
|
version = "0.3.1"
|
||||||
|
features = ["v4_4"]
|
||||||
|
|
@ -28,7 +28,7 @@ impl DockItem {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let dc = DragSource::builder()
|
let dc = DragSource::builder()
|
||||||
.name("dock drag source")
|
.name("dock drag source")
|
||||||
.actions(gdk4::DragAction::MOVE)
|
.actions(gdk4::DragAction::COPY)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let self_: DockItem = glib::Object::new(&[]).expect("Failed to create DockItem");
|
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()));
|
self_.image.set_tooltip_text(Some(&app_info.name()));
|
||||||
|
|
||||||
if let Some(drag_controller) = self_.drag_controller.get() {
|
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() {
|
if let Some(file) = app_info.filename() {
|
||||||
let file = File::for_path(file);
|
let provider = ContentProvider::for_value(&file.to_string_lossy().to_value());
|
||||||
let provider = ContentProvider::for_value(&file.to_value());
|
|
||||||
drag_controller.set_content(Some(&provider));
|
drag_controller.set_content(Some(&provider));
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
drag_controller.connect_drag_end(move |_self, _drag, delete_data| {
|
drag_controller.connect_drag_end(move |_self, _drag, delete_data| {
|
||||||
dbg!("removing", delete_data);
|
dbg!("removing", delete_data);
|
||||||
});
|
});
|
||||||
|
|
@ -94,7 +90,8 @@ impl DockItem {
|
||||||
.icon()
|
.icon()
|
||||||
.unwrap_or(Icon::for_string("image-missing").expect("Failed to set default 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_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...
|
// set drag source icon if possible...
|
||||||
// gio Icon is not easily converted to a Paintable, but this seems to be the correct method
|
// gio Icon is not easily converted to a Paintable, but this seems to be the correct method
|
||||||
if let Some(default_display) = &Display::default() {
|
if let Some(default_display) = &Display::default() {
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,19 @@ mod imp;
|
||||||
// use crate::ApplicationObject;
|
// use crate::ApplicationObject;
|
||||||
use crate::dock_item::DockItem;
|
use crate::dock_item::DockItem;
|
||||||
use crate::X11_CONN;
|
use crate::X11_CONN;
|
||||||
|
use gdk4::ContentProvider;
|
||||||
use gdk4::Rectangle;
|
use gdk4::Rectangle;
|
||||||
use gdk4::Surface;
|
use gdk4::Surface;
|
||||||
use gdk4_x11::X11Surface;
|
use gdk4_x11::X11Surface;
|
||||||
use gio::Cancellable;
|
use gio::Cancellable;
|
||||||
use gio::DesktopAppInfo;
|
use gio::DesktopAppInfo;
|
||||||
|
use glib::Type;
|
||||||
use gtk4 as gtk;
|
use gtk4 as gtk;
|
||||||
|
use gtk4::prelude::ListModelExt;
|
||||||
use gtk4::DropTarget;
|
use gtk4::DropTarget;
|
||||||
use gtk4::DropTargetAsync;
|
use gtk4::DropTargetAsync;
|
||||||
use gtk4::EventControllerMotion;
|
use gtk4::EventControllerMotion;
|
||||||
|
use gtk4::ListStore;
|
||||||
use gtk4::TreeIter;
|
use gtk4::TreeIter;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use x11rb::connection::Connection;
|
use x11rb::connection::Connection;
|
||||||
|
|
@ -225,31 +229,52 @@ impl Window {
|
||||||
// });
|
// });
|
||||||
|
|
||||||
let saved_app_list_view = saved_app_list_view.get();
|
let saved_app_list_view = saved_app_list_view.get();
|
||||||
|
|
||||||
drop_controller.connect_drop(
|
drop_controller.connect_drop(
|
||||||
glib::clone!(@weak saved_app_model, @weak saved_app_list_view => @default-return true, move |_self, drop_value, x, y| {
|
glib::clone!(@weak saved_app_model, @weak saved_app_list_view => @default-return true, move |_self, drop_value, x, y| {
|
||||||
dbg!(x);
|
if let Ok(Some(path_str)) = drop_value.get::<Option<String>>() {
|
||||||
dbg!(y);
|
dbg!(&path_str);
|
||||||
let max_y = saved_app_list_view.allocated_height();
|
let desktop_path = &Path::new(&path_str);
|
||||||
let max_x = saved_app_list_view.allocated_width();
|
if let Some(pathbase) = desktop_path.file_name() {
|
||||||
dbg!(max_x);
|
if let Some(app_info) = gio::DesktopAppInfo::new(&pathbase.to_string_lossy()) {
|
||||||
dbg!(max_y);
|
let mut i: u32 = 0;
|
||||||
let n_buckets = saved_app_model.n_items() * 2;
|
let mut index_of_existing_app: Option<u32> = None;
|
||||||
|
while let Some(item) = saved_app_model.item(i) {
|
||||||
let drop_bucket = (x * n_buckets as f64 / (max_x as f64 + 0.1)) as u32;
|
if let Ok(cur_app_info) = item.downcast::<gio::DesktopAppInfo>() {
|
||||||
let index = if drop_bucket == 0 {
|
dbg!(cur_app_info.filename());
|
||||||
0
|
if cur_app_info.filename() == Some(Path::new(&path_str).to_path_buf()) {
|
||||||
} else if drop_bucket == n_buckets - 1 {
|
index_of_existing_app = Some(i);
|
||||||
saved_app_model.n_items()
|
}
|
||||||
} else {
|
}
|
||||||
(drop_bucket + 1) / 2
|
i += 1;
|
||||||
};
|
}
|
||||||
dbg!(index);
|
|
||||||
dbg!("dropped it!");
|
|
||||||
if let Ok(Some(path)) = drop_value.get::<Option<String>>() {
|
|
||||||
dbg!(&path);
|
|
||||||
if let Some(path) = &Path::new(&path).file_name() {
|
|
||||||
if let Some(app_info) = gio::DesktopAppInfo::new(&path.to_string_lossy()) {
|
|
||||||
dbg!(app_info.name());
|
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);
|
saved_app_model.insert(index, &app_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -289,12 +314,19 @@ impl Window {
|
||||||
fn setup_drop_target(&self) {
|
fn setup_drop_target(&self) {
|
||||||
let imp = imp::Window::from_instance(self);
|
let imp = imp::Window::from_instance(self);
|
||||||
let drop_target_widget = &imp.saved_app_list_view;
|
let drop_target_widget = &imp.saved_app_list_view;
|
||||||
let mut drop_actions = gdk4::DragAction::COPY;
|
let drop_actions = gdk4::DragAction::COPY;
|
||||||
drop_actions.toggle(gdk4::DragAction::MOVE);
|
// 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()
|
let drop_target_controller = DropTarget::builder()
|
||||||
.preload(true)
|
.preload(true)
|
||||||
.actions(drop_actions)
|
.actions(drop_actions)
|
||||||
.formats(&gdk4::ContentFormats::for_type(glib::types::Type::STRING))
|
.formats(&drop_format)
|
||||||
.build();
|
.build();
|
||||||
drop_target_widget.add_controller(&drop_target_controller);
|
drop_target_widget.add_controller(&drop_target_controller);
|
||||||
imp.drop_controller
|
imp.drop_controller
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue