refactor remove template for dock window

This commit is contained in:
Ashley Wulber 2021-12-30 19:01:59 -05:00
parent 71273ec430
commit 2b8e462c9d
3 changed files with 124 additions and 181 deletions

View file

@ -1,31 +1,24 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use glib::subclass::InitializingObject;
use glib::SignalHandlerId; use glib::SignalHandlerId;
use gtk4::prelude::*;
use gtk4::subclass::prelude::*; use gtk4::subclass::prelude::*;
use gtk4::DragSource; use gtk4::DragSource;
use gtk4::DropTarget; use gtk4::DropTarget;
use gtk4::EventControllerMotion; use gtk4::EventControllerMotion;
use gtk4::ListView;
use gtk4::Revealer; use gtk4::Revealer;
use gtk4::{gio, glib}; use gtk4::{gio, glib};
use gtk4::{Box, GestureClick}; use gtk4::{Box, GestureClick};
use gtk4::{CompositeTemplate, ListView};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
// Object holding the state // Object holding the state
#[derive(CompositeTemplate, Default)] #[derive(Default)]
#[template(file = "window.ui")]
pub struct Window { pub struct Window {
#[template_child] pub saved_app_list_view: OnceCell<ListView>,
pub saved_app_list_view: TemplateChild<ListView>, pub active_app_list_view: OnceCell<ListView>,
#[template_child] pub revealer: OnceCell<Revealer>,
pub active_app_list_view: TemplateChild<ListView>, pub cursor_handle: OnceCell<Box>,
#[template_child]
pub revealer: TemplateChild<Revealer>,
#[template_child]
pub cursor_handle: TemplateChild<Box>,
pub saved_app_model: OnceCell<gio::ListStore>, pub saved_app_model: OnceCell<gio::ListStore>,
pub active_app_model: OnceCell<gio::ListStore>, pub active_app_model: OnceCell<gio::ListStore>,
pub cursor_motion_controller: OnceCell<EventControllerMotion>, pub cursor_motion_controller: OnceCell<EventControllerMotion>,
@ -48,38 +41,10 @@ impl ObjectSubclass for Window {
const NAME: &'static str = "LauncherWindow"; const NAME: &'static str = "LauncherWindow";
type Type = super::Window; type Type = super::Window;
type ParentType = gtk4::ApplicationWindow; type ParentType = gtk4::ApplicationWindow;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
} }
// Trait shared by all GObjects // Trait shared by all GObjects
impl ObjectImpl for Window { impl ObjectImpl for Window {}
fn constructed(&self, obj: &Self::Type) {
// Call "constructed" on parent
self.parent_constructed(obj);
// Setup
obj.setup_model();
obj.setup_motion_controller();
obj.setup_click_controller();
obj.setup_drop_target();
obj.setup_drag_source();
obj.restore_saved_apps();
obj.setup_callbacks();
// obj.setup_window_callbacks();
// obj.setup_saved_list_callbacks();
// obj.setup_active_list_callbacks();
// obj.setup_drag_callbacks();
obj.setup_click_callbacks();
obj.setup_factory();
}
}
// Trait shared by all widgets // Trait shared by all widgets
impl WidgetImpl for Window {} impl WidgetImpl for Window {}

View file

@ -1,6 +1,4 @@
use std::fs::File; use cascade::cascade;
use std::path::Path;
use gdk4::ContentProvider; use gdk4::ContentProvider;
use gdk4::Display; use gdk4::Display;
use gdk4::ModifierType; use gdk4::ModifierType;
@ -9,15 +7,23 @@ use gdk4_x11::X11Display;
use gdk4_x11::X11Surface; use gdk4_x11::X11Surface;
use gio::DesktopAppInfo; use gio::DesktopAppInfo;
use gio::Icon; use gio::Icon;
use gtk4::ListView;
use gtk4::Revealer;
use gtk4::RevealerTransitionType;
use gtk4::Separator;
use std::fs::File;
use std::path::Path;
// use crate::application_row::ApplicationRow; // use crate::application_row::ApplicationRow;
use glib::Object; use glib::Object;
use glib::Type; use glib::Type;
use gtk4::prelude::ListModelExt; use gtk4::prelude::ListModelExt;
use gtk4::prelude::*; use gtk4::prelude::*;
use gtk4::subclass::prelude::*; use gtk4::subclass::prelude::*;
use gtk4::Box;
use gtk4::DropTarget; use gtk4::DropTarget;
use gtk4::EventControllerMotion; use gtk4::EventControllerMotion;
use gtk4::IconTheme; use gtk4::IconTheme;
use gtk4::Orientation;
use gtk4::{gio, glib}; use gtk4::{gio, glib};
use gtk4::{Application, SignalListItemFactory}; use gtk4::{Application, SignalListItemFactory};
use gtk4::{DragSource, GestureClick}; use gtk4::{DragSource, GestureClick};
@ -43,13 +49,99 @@ mod imp;
glib::wrapper! { glib::wrapper! {
pub struct Window(ObjectSubclass<imp::Window>) pub struct Window(ObjectSubclass<imp::Window>)
@extends gtk4::ApplicationWindow, gtk4::Window, gtk4::Widget, @extends gtk4::ApplicationWindow, gtk4::Window, gtk4::Widget,
@implements gio::ActionGroup, gio::ActionMap, gtk4::Accessible, gtk4::Buildable, @implements gio::ActionGroup, gio::ActionMap, gtk4::Accessible, gtk4::Buildable, gtk4::ConstraintTarget, gtk4::Native, gtk4::Root, gtk4::ShortcutManager;
gtk4::ConstraintTarget, gtk4::Native, gtk4::Root, gtk4::ShortcutManager;
} }
impl Window { impl Window {
pub fn new(app: &Application) -> Self { pub fn new(app: &Application) -> Self {
let self_: Self = Object::new(&[("application", app)]).expect("Failed to create `Window`."); let self_: Self = Object::new(&[("application", app)]).expect("Failed to create `Window`.");
let imp = imp::Window::from_instance(&self_);
cascade! {
&self_;
..set_height_request(80);
..set_width_request(128);
..set_title(Some("Cosmic Dock"));
..set_decorated(false);
..set_resizable(false);
};
let cursor_handle = Box::new(Orientation::Vertical, 0);
self_.set_child(Some(&cursor_handle));
let window_filler = cascade! {
Box::new(Orientation::Vertical, 0);
..set_height_request(0); // shrinks to nothing when revealer is shown
..set_vexpand(true); // expands to fill window when revealer is hidden, preventingb window from changing size so much...
};
cursor_handle.append(&window_filler);
let revealer = cascade! {
Revealer::new();
..set_reveal_child(true);
..set_transition_duration(300);
..set_transition_type(RevealerTransitionType::SlideUp);
};
cursor_handle.append(&revealer);
let dock_container = cascade! {
Box::new(Orientation::Vertical, 0);
..set_height_request(0);
};
revealer.set_child(Some(&dock_container));
let dock = cascade! {
Box::new(Orientation::Horizontal, 4);
..set_height_request(64);
..set_margin_start(4);
..set_margin_end(4);
};
dock_container.append(&dock);
let dock_bottom_gap = cascade! {
Box::new(Orientation::Horizontal, 0);
..set_height_request(4);
};
dock_container.append(&dock_bottom_gap);
let saved_app_list_view = cascade! {
ListView::builder().build();
..set_orientation(Orientation::Horizontal);
};
dock.append(&saved_app_list_view);
let separator = cascade! {
Separator::new(Orientation::Vertical);
..set_margin_top(4);
..set_margin_start(4);
..set_margin_bottom(4);
..set_margin_end(4);
};
dock.append(&separator);
let active_app_list_view = cascade! {
ListView::builder().build();
..set_orientation(Orientation::Horizontal);
};
dock.append(&active_app_list_view);
imp.cursor_handle.set(cursor_handle).unwrap();
imp.revealer.set(revealer).unwrap();
imp.saved_app_list_view.set(saved_app_list_view).unwrap();
imp.active_app_list_view.set(active_app_list_view).unwrap();
// Setup
self_.setup_model();
self_.setup_motion_controller();
self_.setup_click_controller();
self_.setup_drop_target();
self_.setup_drag_source();
self_.restore_saved_apps();
self_.setup_callbacks();
self_.setup_click_callbacks();
self_.setup_factory();
// obj.setup_window_callbacks();
// obj.setup_saved_list_callbacks();
// obj.setup_active_list_callbacks();
// obj.setup_drag_callbacks();
self_ self_
} }
@ -81,8 +173,8 @@ impl Window {
.set(saved_app_model) .set(saved_app_model)
.expect("Could not set model"); .expect("Could not set model");
// Wrap model with selection and pass it to the list view // Wrap model with selection and pass it to the list view
imp.saved_app_list_view let saved_app_list_view = imp.saved_app_list_view.get().unwrap();
.set_model(Some(&saved_selection_model)); saved_app_list_view.set_model(Some(&saved_selection_model));
let active_app_model = gio::ListStore::new(DockObject::static_type()); let active_app_model = gio::ListStore::new(DockObject::static_type());
let active_selection_model = gtk4::NoSelection::new(Some(&active_app_model)); let active_selection_model = gtk4::NoSelection::new(Some(&active_app_model));
@ -91,73 +183,24 @@ impl Window {
.set(active_app_model) .set(active_app_model)
.expect("Could not set model"); .expect("Could not set model");
// Wrap model with selection and pass it to the list view // Wrap model with selection and pass it to the list view
imp.active_app_list_view let active_app_list_view = imp.active_app_list_view.get().unwrap();
.set_model(Some(&active_selection_model)); active_app_list_view.set_model(Some(&active_selection_model));
} }
fn setup_callbacks(&self) { fn setup_callbacks(&self) {
// Get state // Get state
let imp = imp::Window::from_instance(self); let imp = imp::Window::from_instance(self);
let window = self.clone().upcast::<gtk4::Window>(); let window = self.clone().upcast::<gtk4::Window>();
let saved_app_list_view = &imp.saved_app_list_view; let saved_app_list_view = &imp.saved_app_list_view.get().unwrap();
let saved_app_model = &imp let saved_app_model = &imp
.saved_app_model .saved_app_model
.get() .get()
.expect("Failed to get saved app model"); .expect("Failed to get saved app model");
let saved_app_selection_model = saved_app_list_view
.model()
.expect("List view missing selection model")
.downcast::<gtk4::NoSelection>()
.expect("could not downcast listview model to single selection model");
let active_app_selection_model = imp
.active_app_list_view
.model()
.expect("List view missing selection model")
.downcast::<gtk4::NoSelection>()
.expect("could not downcast listview model to single selection model");
// let selected_handler = glib::clone!(@weak window => move |model: &gtk4::NoSelection| {
// let position = model.selected();
// println!("selected app {}", position);
// // Launch the application when an item of the list is activated
// if let Some(item) = model.item(position) {
// let dockobject = item.downcast::<DockObject>().expect("App model must only contain DockObject");
// if let Ok(active) = dockobject.property("active").expect("DockObject must have active property").get::<BoxedWindowList>() {
// if let Some(focused_item) = active.0.iter().next() {
// let entity = focused_item.entity.clone();
// glib::MainContext::default().spawn_local(async move {
// if let Some(tx) = TX.get() {
// let mut tx = tx.clone();
// let _ = tx.send(Event::Activate(entity)).await;
// }
// });
// }
// else if let Ok(Some(app_info)) = dockobject.property("appinfo").expect("DockObject must have appinfo property").get::<Option<DesktopAppInfo>>() {
// 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();
// }
// }
// }
// }
// model.set_selected(gtk4::INVALID_LIST_POSITION);
// });
// saved_app_selection_model.connect_selected_notify(selected_handler.clone());
//
// active_app_selection_model.connect_selected_notify(selected_handler);
let cursor_event_controller = &imp.cursor_motion_controller.get().unwrap(); let cursor_event_controller = &imp.cursor_motion_controller.get().unwrap();
let drop_controller = &imp.drop_controller.get().unwrap(); let drop_controller = &imp.drop_controller.get().unwrap();
let window_drop_controller = &imp.window_drop_controller.get().unwrap(); let window_drop_controller = &imp.window_drop_controller.get().unwrap();
let revealer = &imp.revealer.get(); let revealer = &imp.revealer.get().unwrap();
window.connect_show( window.connect_show(
glib::clone!(@weak revealer, @weak cursor_event_controller => move |_| { glib::clone!(@weak revealer, @weak cursor_event_controller => move |_| {
// dbg!(!cursor_event_controller.contains_pointer()); // dbg!(!cursor_event_controller.contains_pointer());
@ -276,7 +319,6 @@ impl Window {
println!("dropping into window"); println!("dropping into window");
false false
}); });
let saved_app_list_view = saved_app_list_view.get();
// drag end handler // drag end handler
// must be modified in case of reorder... // must be modified in case of reorder...
@ -368,7 +410,7 @@ impl Window {
fn setup_motion_controller(&self) { fn setup_motion_controller(&self) {
let imp = imp::Window::from_instance(self); let imp = imp::Window::from_instance(self);
let handle = &imp.cursor_handle.get(); let handle = &imp.cursor_handle.get().unwrap();
let ev = EventControllerMotion::builder() let ev = EventControllerMotion::builder()
.propagation_limit(gtk4::PropagationLimit::None) .propagation_limit(gtk4::PropagationLimit::None)
.propagation_phase(gtk4::PropagationPhase::Capture) .propagation_phase(gtk4::PropagationPhase::Capture)
@ -382,7 +424,7 @@ impl Window {
fn setup_click_controller(&self) { fn setup_click_controller(&self) {
let imp = imp::Window::from_instance(self); let imp = imp::Window::from_instance(self);
let saved_app_list_view = &imp.saved_app_list_view.get(); let saved_app_list_view = &imp.saved_app_list_view.get().unwrap();
let controller = GestureClick::builder() let controller = GestureClick::builder()
.button(0) .button(0)
.propagation_limit(gtk4::PropagationLimit::None) .propagation_limit(gtk4::PropagationLimit::None)
@ -395,7 +437,7 @@ impl Window {
.expect("Could not set event controller"); .expect("Could not set event controller");
let imp = imp::Window::from_instance(self); let imp = imp::Window::from_instance(self);
let active_app_list_view = &imp.active_app_list_view.get(); let active_app_list_view = &imp.active_app_list_view.get().unwrap();
let controller = GestureClick::builder() let controller = GestureClick::builder()
.button(0) .button(0)
.propagation_limit(gtk4::PropagationLimit::None) .propagation_limit(gtk4::PropagationLimit::None)
@ -419,7 +461,7 @@ impl Window {
.saved_app_model .saved_app_model
.get() .get()
.expect("Failed to get saved_app_model"); .expect("Failed to get saved_app_model");
let saved_app_list_view = imp.saved_app_list_view.get(); let saved_app_list_view = &imp.saved_app_list_view.get().unwrap();
saved_click_controller.connect_released(glib::clone!(@weak saved_app_model, @weak saved_app_list_view, @weak window => move |self_, _, x, _y| { saved_click_controller.connect_released(glib::clone!(@weak saved_app_model, @weak saved_app_list_view, @weak window => move |self_, _, x, _y| {
let max_x = saved_app_list_view.allocated_width(); let max_x = saved_app_list_view.allocated_width();
let n_buckets = saved_app_model.n_items(); let n_buckets = saved_app_model.n_items();
@ -477,7 +519,7 @@ 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.get().unwrap();
let mut drop_actions = gdk4::DragAction::COPY; let mut drop_actions = gdk4::DragAction::COPY;
drop_actions.insert(gdk4::DragAction::MOVE); drop_actions.insert(gdk4::DragAction::MOVE);
let drop_format = gdk4::ContentFormats::for_type(Type::STRING); let drop_format = gdk4::ContentFormats::for_type(Type::STRING);
@ -499,8 +541,8 @@ impl Window {
.actions(drop_actions) .actions(drop_actions)
.formats(&drop_format) .formats(&drop_format)
.build(); .build();
let enter_handle = &imp.cursor_handle.get();
let enter_handle = &imp.cursor_handle.get().unwrap();
enter_handle.add_controller(&window_drop_target_controller); enter_handle.add_controller(&window_drop_target_controller);
imp.window_drop_controller imp.window_drop_controller
.set(window_drop_target_controller) .set(window_drop_target_controller)
@ -509,7 +551,7 @@ impl Window {
fn setup_drag_source(&self) { fn setup_drag_source(&self) {
let imp = imp::Window::from_instance(self); let imp = imp::Window::from_instance(self);
let saved_app_list_view = &imp.saved_app_list_view.get(); let saved_app_list_view = &imp.saved_app_list_view.get().unwrap();
let saved_app_model = imp let saved_app_model = imp
.saved_app_model .saved_app_model
.get() .get()
@ -602,7 +644,7 @@ impl Window {
.set(saved_drag_source) .set(saved_drag_source)
.expect("Could not set saved drag source"); .expect("Could not set saved drag source");
let active_app_list_view = &imp.active_app_list_view.get(); let active_app_list_view = &imp.active_app_list_view.get().unwrap();
let active_app_model = imp let active_app_model = imp
.active_app_model .active_app_model
.get() .get()
@ -723,6 +765,8 @@ impl Window {
})); }));
// Set the factory of the list view // Set the factory of the list view
imp.saved_app_list_view imp.saved_app_list_view
.get()
.unwrap()
.set_factory(Some(&saved_app_factory)); .set_factory(Some(&saved_app_factory));
let active_app_model = imp let active_app_model = imp
@ -749,7 +793,10 @@ impl Window {
dock_item.set_app_info(&application_object); dock_item.set_app_info(&application_object);
})); }));
// Set the factory of the list view // Set the factory of the list view
imp.active_app_list_view.set_factory(Some(&active_factory)); imp.active_app_list_view
.get()
.unwrap()
.set_factory(Some(&active_factory));
} }
fn restore_saved_apps(&self) { fn restore_saved_apps(&self) {

View file

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="LauncherWindow" parent="GtkApplicationWindow">
<!-- drop controller seems to be buggy if window changes size -->
<property name="height-request">80</property>
<property name="width-request">128</property>
<property name="title">Gtk Pop Dock</property>
<property name="decorated">false</property>
<property name="resizable">false</property>
<child>
<object class="GtkBox" id="cursor_handle">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="height-request">0</property>
<property name="vexpand">true</property>
</object>
</child>
<child>
<object class="GtkRevealer" id="revealer">
<property name="reveal-child">true</property>
<property name="transition-duration">300</property>
<property name="transition-type">slide-up</property>
<child>
<object class="GtkBox">
<property name="height-request">0</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="height-request">64</property>
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<property name="spacing">4</property>
<property name="name">dock-container</property>
<child>
<object class="GtkListView" id="saved_app_list_view">
<property name="orientation">horizontal</property>
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">4</property>
<property name="margin-bottom">4</property>
<property name="orientation">vertical</property>
</object>
</child>
<child>
<object class="GtkListView" id="active_app_list_view">
<property name="orientation">horizontal</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="height-request">4</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>