show active apps
This commit is contained in:
parent
ad6f147546
commit
03300c788a
9 changed files with 113 additions and 339 deletions
|
|
@ -1,213 +0,0 @@
|
||||||
use glib::{FromVariant, ParamFlags, ParamSpec, ToVariant, Value, Variant, VariantTy};
|
|
||||||
use gtk4::glib;
|
|
||||||
use gtk4::prelude::*;
|
|
||||||
use gtk4::subclass::prelude::*;
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use super::ApplicationData;
|
|
||||||
|
|
||||||
// Object holding the state
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ApplicationObject {
|
|
||||||
data: Rc<RefCell<ApplicationData>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// The central trait for subclassing a GObject
|
|
||||||
#[glib::object_subclass]
|
|
||||||
impl ObjectSubclass for ApplicationObject {
|
|
||||||
const NAME: &'static str = "ApplicationObject";
|
|
||||||
type Type = super::ApplicationObject;
|
|
||||||
type ParentType = glib::Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trait shared by all GObjects
|
|
||||||
impl ObjectImpl for ApplicationObject {
|
|
||||||
fn properties() -> &'static [ParamSpec] {
|
|
||||||
static PROPERTIES: Lazy<Vec<ParamSpec>> = Lazy::new(|| {
|
|
||||||
vec![
|
|
||||||
ParamSpec::new_uint(
|
|
||||||
// Name
|
|
||||||
"id",
|
|
||||||
// Nickname
|
|
||||||
"id",
|
|
||||||
// Short description
|
|
||||||
"ID of application in launcher search result",
|
|
||||||
0,
|
|
||||||
u32::MAX,
|
|
||||||
// Default value
|
|
||||||
0,
|
|
||||||
// The property can be read and written to
|
|
||||||
ParamFlags::READWRITE,
|
|
||||||
),
|
|
||||||
ParamSpec::new_string(
|
|
||||||
// Name
|
|
||||||
"name",
|
|
||||||
// Nickname
|
|
||||||
"name",
|
|
||||||
// Short description
|
|
||||||
"Name of application in launcher search result",
|
|
||||||
// Default value
|
|
||||||
Some(""),
|
|
||||||
// The property can be read and written to
|
|
||||||
ParamFlags::READWRITE,
|
|
||||||
),
|
|
||||||
ParamSpec::new_string(
|
|
||||||
// Name
|
|
||||||
"description",
|
|
||||||
// Nickname
|
|
||||||
"description",
|
|
||||||
// Short description
|
|
||||||
"Description of application in launcher search result",
|
|
||||||
// Default value
|
|
||||||
Some(""),
|
|
||||||
// The property can be read and written to
|
|
||||||
ParamFlags::READWRITE,
|
|
||||||
),
|
|
||||||
ParamSpec::new_variant(
|
|
||||||
// Name
|
|
||||||
"icon",
|
|
||||||
// Nickname
|
|
||||||
"icon",
|
|
||||||
// Short description
|
|
||||||
"Icon of application in launcher search result",
|
|
||||||
VariantTy::new("(is)").expect("Oops invalid string for VariantTy tuple."),
|
|
||||||
// Default value
|
|
||||||
None,
|
|
||||||
// The property can be read and written to
|
|
||||||
ParamFlags::READWRITE,
|
|
||||||
),
|
|
||||||
ParamSpec::new_variant(
|
|
||||||
// Name
|
|
||||||
"categoryicon",
|
|
||||||
// Nickname
|
|
||||||
"categoryicon",
|
|
||||||
// Short description
|
|
||||||
"Category icon of application in launcher search result",
|
|
||||||
VariantTy::new("(is)").expect("Oops invalid string for VariantTy tuple."),
|
|
||||||
// Default value
|
|
||||||
None,
|
|
||||||
// The property can be read and written to
|
|
||||||
ParamFlags::READWRITE,
|
|
||||||
),
|
|
||||||
ParamSpec::new_variant(
|
|
||||||
// Name
|
|
||||||
"window",
|
|
||||||
// Nickname
|
|
||||||
"window",
|
|
||||||
// Short description
|
|
||||||
"Window of application in launcher search result",
|
|
||||||
// type (tuple of two uint32)
|
|
||||||
VariantTy::new("(uu)").expect("Oops invalid string for VariantTy tuple."),
|
|
||||||
// Default value
|
|
||||||
None,
|
|
||||||
// The property can be read and written to
|
|
||||||
ParamFlags::READWRITE,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
});
|
|
||||||
PROPERTIES.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_property(&self, _obj: &Self::Type, _id: usize, value: &Value, pspec: &ParamSpec) {
|
|
||||||
match pspec.name() {
|
|
||||||
"id" => {
|
|
||||||
let id = value.get().expect("The value needs to be of type `u32`.");
|
|
||||||
self.data.borrow_mut().0.id = id;
|
|
||||||
}
|
|
||||||
"name" => {
|
|
||||||
let name = value
|
|
||||||
.get()
|
|
||||||
.expect("The value needs to be of type `String`.");
|
|
||||||
self.data.borrow_mut().0.name = name;
|
|
||||||
}
|
|
||||||
"description" => {
|
|
||||||
let description = value
|
|
||||||
.get()
|
|
||||||
.expect("The description needs to be of type `String`");
|
|
||||||
self.data.borrow_mut().0.description = description;
|
|
||||||
}
|
|
||||||
"icon" => {
|
|
||||||
let icon = <(i32, String)>::from_variant(
|
|
||||||
&value
|
|
||||||
.get::<Variant>()
|
|
||||||
.expect("The icon needs to be a Variant"),
|
|
||||||
)
|
|
||||||
.expect("The icon variant needs to be an (i32, String)");
|
|
||||||
self.data.borrow_mut().0.icon = match icon {
|
|
||||||
(i_type, name) if i_type == pop_launcher::IconSource::Name as i32 => {
|
|
||||||
Some(pop_launcher::IconSource::Name(name.into()))
|
|
||||||
}
|
|
||||||
(i_type, name) if i_type == pop_launcher::IconSource::Mime as i32 => {
|
|
||||||
Some(pop_launcher::IconSource::Mime(name.into()))
|
|
||||||
}
|
|
||||||
(i_type, name) => {
|
|
||||||
println!("Failed to set icon. {} {}", i_type, name);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
"categoryicon" => {
|
|
||||||
let icon = <(i32, String)>::from_variant(
|
|
||||||
&value
|
|
||||||
.get::<Variant>()
|
|
||||||
.expect("The icon needs to be a Variant"),
|
|
||||||
)
|
|
||||||
.expect("The icon variant needs to be an Option<(i32, String)>");
|
|
||||||
self.data.borrow_mut().0.category_icon = match icon {
|
|
||||||
(i_type, name) if i_type == pop_launcher::IconSource::Name as i32 => {
|
|
||||||
Some(pop_launcher::IconSource::Name(name.into()))
|
|
||||||
}
|
|
||||||
(i_type, name) if i_type == pop_launcher::IconSource::Mime as i32 => {
|
|
||||||
Some(pop_launcher::IconSource::Mime(name.into()))
|
|
||||||
}
|
|
||||||
(i_type, name) => {
|
|
||||||
println!("Failed to set icon. {} {}", i_type, name);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
"window" => {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn property(&self, _obj: &Self::Type, _id: usize, pspec: &ParamSpec) -> Value {
|
|
||||||
match pspec.name() {
|
|
||||||
"id" => self.data.borrow().0.id.to_value(),
|
|
||||||
"name" => self.data.borrow().0.name.to_value(),
|
|
||||||
"description" => self.data.borrow().0.description.to_value(),
|
|
||||||
"icon" => match &self.data.borrow().0.icon {
|
|
||||||
Some(pop_launcher::IconSource::Name(icon_name)) => {
|
|
||||||
(pop_launcher::IconSource::Name as i32, icon_name.to_string())
|
|
||||||
.to_variant()
|
|
||||||
.to_value()
|
|
||||||
}
|
|
||||||
Some(pop_launcher::IconSource::Mime(icon_name)) => {
|
|
||||||
(pop_launcher::IconSource::Mime as i32, icon_name.to_string())
|
|
||||||
.to_variant()
|
|
||||||
.to_value()
|
|
||||||
}
|
|
||||||
_ => None::<Variant>.to_value(),
|
|
||||||
},
|
|
||||||
"categoryicon" => match &self.data.borrow().0.category_icon {
|
|
||||||
Some(pop_launcher::IconSource::Name(icon_name)) => {
|
|
||||||
(pop_launcher::IconSource::Name as i32, icon_name.to_string())
|
|
||||||
.to_variant()
|
|
||||||
.to_value()
|
|
||||||
}
|
|
||||||
Some(pop_launcher::IconSource::Mime(icon_name)) => {
|
|
||||||
(pop_launcher::IconSource::Mime as i32, icon_name.to_string())
|
|
||||||
.to_variant()
|
|
||||||
.to_value()
|
|
||||||
}
|
|
||||||
_ => None::<Variant>.to_value(),
|
|
||||||
},
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
mod imp;
|
|
||||||
|
|
||||||
use gdk4::glib::Object;
|
|
||||||
use glib::ObjectExt;
|
|
||||||
use glib::ToVariant;
|
|
||||||
use gtk4::glib;
|
|
||||||
|
|
||||||
glib::wrapper! {
|
|
||||||
pub struct ApplicationObject(ObjectSubclass<imp::ApplicationObject>);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ApplicationObject {
|
|
||||||
pub fn new(application_search_result: &pop_launcher::SearchResult) -> Self {
|
|
||||||
let self_: Self = Object::new(&[
|
|
||||||
("id", &application_search_result.id),
|
|
||||||
("name", &application_search_result.name),
|
|
||||||
("description", &application_search_result.description),
|
|
||||||
])
|
|
||||||
.expect("Failed to create `ApplicationObject`.");
|
|
||||||
if let Some(icon) = &application_search_result.icon {
|
|
||||||
if let Err(e) = self_.set_property(
|
|
||||||
"icon",
|
|
||||||
match icon {
|
|
||||||
pop_launcher::IconSource::Name(name) => {
|
|
||||||
(pop_launcher::IconSource::Name as i32, name.to_string()).to_variant()
|
|
||||||
}
|
|
||||||
pop_launcher::IconSource::Mime(name) => {
|
|
||||||
(pop_launcher::IconSource::Mime as i32, name.to_string()).to_variant()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
println!("failed to set icon property");
|
|
||||||
dbg!(e);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if let Some(icon) = &application_search_result.category_icon {
|
|
||||||
if let Err(e) = self_.set_property(
|
|
||||||
"categoryicon",
|
|
||||||
match icon {
|
|
||||||
pop_launcher::IconSource::Name(name) => {
|
|
||||||
(pop_launcher::IconSource::Name as i32, name.to_string()).to_variant()
|
|
||||||
}
|
|
||||||
pop_launcher::IconSource::Mime(name) => {
|
|
||||||
(pop_launcher::IconSource::Mime as i32, name.to_string()).to_variant()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
println!("failed to set category icon property");
|
|
||||||
dbg!(e);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
self_
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Object holding the state
|
|
||||||
pub struct ApplicationData(pop_launcher::SearchResult);
|
|
||||||
|
|
||||||
impl Default for ApplicationData {
|
|
||||||
fn default() -> Self {
|
|
||||||
let default_application = pop_launcher::SearchResult {
|
|
||||||
id: 0,
|
|
||||||
name: String::default(),
|
|
||||||
description: String::default(),
|
|
||||||
icon: None,
|
|
||||||
category_icon: None,
|
|
||||||
window: None,
|
|
||||||
};
|
|
||||||
Self(default_application)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -53,10 +53,15 @@ impl DockItem {
|
||||||
pub fn set_app_info(&self, app_info: &DockObject, i: u32, saved_app_model: &ListStore) {
|
pub fn set_app_info(&self, app_info: &DockObject, i: u32, saved_app_model: &ListStore) {
|
||||||
if let Ok(app_info_value) = app_info.property("appinfo") {
|
if let Ok(app_info_value) = app_info.property("appinfo") {
|
||||||
if let Ok(Some(app_info)) = app_info_value.get::<Option<DesktopAppInfo>>() {
|
if let Ok(Some(app_info)) = app_info_value.get::<Option<DesktopAppInfo>>() {
|
||||||
dbg!("setting app info");
|
println!("setting app info {}", &app_info.name());
|
||||||
let self_ = imp::DockItem::from_instance(self);
|
let self_ = imp::DockItem::from_instance(self);
|
||||||
self_.image.set_tooltip_text(Some(&app_info.name()));
|
self_.image.set_tooltip_text(Some(&app_info.name()));
|
||||||
|
|
||||||
|
let icon = app_info.icon().unwrap_or(
|
||||||
|
Icon::for_string("image-missing").expect("Failed to set default icon"),
|
||||||
|
);
|
||||||
|
|
||||||
|
self_.image.set_from_gicon(&icon);
|
||||||
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() {
|
if let Some(file) = app_info.filename() {
|
||||||
let provider =
|
let provider =
|
||||||
|
|
@ -108,39 +113,9 @@ impl DockItem {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon = app_info.icon().unwrap_or(
|
|
||||||
Icon::for_string("image-missing").expect("Failed to set default icon"),
|
|
||||||
);
|
|
||||||
|
|
||||||
self_.image.set_from_gicon(&icon);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
println!("initializing dock item failed...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn set_app_info(&self, app_obj: ApplicationObject) {
|
|
||||||
// let self_ = imp::DockItem::from_instance(self);
|
|
||||||
|
|
||||||
// if let Ok(name) = app_obj.property("name") {
|
|
||||||
// self_.image.set_tooltip_text(Some(
|
|
||||||
// &name
|
|
||||||
// .get::<String>()
|
|
||||||
// .expect("Property name needs to be a String."),
|
|
||||||
// ));
|
|
||||||
// }
|
|
||||||
// if let Ok(icon) = app_obj.property("icon") {
|
|
||||||
// if let Ok(icon) = icon.get::<Variant>() {
|
|
||||||
// let icon = match <(i32, String)>::from_variant(&icon) {
|
|
||||||
// Some((i_type, name)) if i_type == pop_launcher::IconSource::Name as i32 => {
|
|
||||||
// Some(pop_launcher::IconSource::Name(name.into()))
|
|
||||||
// }
|
|
||||||
// Some((i_type, name)) if i_type == pop_launcher::IconSource::Mime as i32 => {
|
|
||||||
// Some(pop_launcher::IconSource::Mime(name.into()))
|
|
||||||
// }
|
|
||||||
// _ => None,
|
|
||||||
// };
|
|
||||||
// icon_source(&self_.image, &icon);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use gtk4::glib;
|
||||||
use gtk4::prelude::*;
|
use gtk4::prelude::*;
|
||||||
use gtk4::subclass::prelude::*;
|
use gtk4::subclass::prelude::*;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
use std::cell::Cell;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
// Object holding the state
|
// Object holding the state
|
||||||
|
|
@ -12,6 +13,7 @@ use std::cell::RefCell;
|
||||||
pub struct DockObject {
|
pub struct DockObject {
|
||||||
appinfo: RefCell<Option<DesktopAppInfo>>,
|
appinfo: RefCell<Option<DesktopAppInfo>>,
|
||||||
active: RefCell<BoxedSearchResults>,
|
active: RefCell<BoxedSearchResults>,
|
||||||
|
saved: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The central trait for subclassing a GObject
|
// The central trait for subclassing a GObject
|
||||||
|
|
@ -49,6 +51,13 @@ impl ObjectImpl for DockObject {
|
||||||
// The property can be read and written to
|
// The property can be read and written to
|
||||||
ParamFlags::READWRITE,
|
ParamFlags::READWRITE,
|
||||||
),
|
),
|
||||||
|
ParamSpec::new_boolean(
|
||||||
|
"saved",
|
||||||
|
"saved",
|
||||||
|
"Indicates whether app is saved to the dock",
|
||||||
|
false,
|
||||||
|
ParamFlags::READWRITE,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
PROPERTIES.as_ref()
|
PROPERTIES.as_ref()
|
||||||
|
|
@ -66,6 +75,10 @@ impl ObjectImpl for DockObject {
|
||||||
let active = value.get().expect("Value needs to be BoxedSearchResults");
|
let active = value.get().expect("Value needs to be BoxedSearchResults");
|
||||||
self.active.replace(active);
|
self.active.replace(active);
|
||||||
}
|
}
|
||||||
|
"saved" => {
|
||||||
|
self.saved
|
||||||
|
.replace(value.get().expect("Value needs to be a boolean"));
|
||||||
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,6 +86,8 @@ impl ObjectImpl for DockObject {
|
||||||
fn property(&self, _obj: &Self::Type, _id: usize, pspec: &ParamSpec) -> Value {
|
fn property(&self, _obj: &Self::Type, _id: usize, pspec: &ParamSpec) -> Value {
|
||||||
match pspec.name() {
|
match pspec.name() {
|
||||||
"appinfo" => self.appinfo.borrow().to_value(),
|
"appinfo" => self.appinfo.borrow().to_value(),
|
||||||
|
"active" => self.active.borrow().to_value(),
|
||||||
|
"saved" => self.saved.get().to_value(),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ glib::wrapper! {
|
||||||
|
|
||||||
impl DockObject {
|
impl DockObject {
|
||||||
pub fn new(appinfo: DesktopAppInfo) -> Self {
|
pub fn new(appinfo: DesktopAppInfo) -> Self {
|
||||||
Object::new(&[("appinfo", &Some(appinfo))]).expect("Failed to create `DockObject`.")
|
Object::new(&[("appinfo", &Some(appinfo)), ("saved", &true)])
|
||||||
|
.expect("Failed to create `DockObject`.")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_search_results(results: BoxedSearchResults) -> Self {
|
pub fn from_search_results(results: BoxedSearchResults) -> Self {
|
||||||
|
|
@ -23,7 +24,6 @@ impl DockObject {
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(|xdg_data_path| {
|
.filter_map(|xdg_data_path| {
|
||||||
xdg_data_path.push("applications");
|
xdg_data_path.push("applications");
|
||||||
dbg!(&xdg_data_path);
|
|
||||||
std::fs::read_dir(xdg_data_path).ok()
|
std::fs::read_dir(xdg_data_path).ok()
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
|
|
@ -35,7 +35,7 @@ impl DockObject {
|
||||||
if app_info.should_show()
|
if app_info.should_show()
|
||||||
&& first.description.as_str() == app_info.name().as_str()
|
&& first.description.as_str() == app_info.name().as_str()
|
||||||
{
|
{
|
||||||
return Some(DockObject::new(app_info));
|
return Some(app_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -47,6 +47,7 @@ impl DockObject {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
dbg!(&appinfo);
|
||||||
Object::new(&[("appinfo", &appinfo), ("active", &results)])
|
Object::new(&[("appinfo", &appinfo), ("active", &results)])
|
||||||
.expect("Failed to create `DockObject`.")
|
.expect("Failed to create `DockObject`.")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
mod application_object;
|
|
||||||
mod dock_item;
|
mod dock_item;
|
||||||
mod dock_object;
|
mod dock_object;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
|
use crate::utils::BoxedSearchResults;
|
||||||
use async_io::Timer;
|
use async_io::Timer;
|
||||||
use gdk4::Display;
|
use gdk4::Display;
|
||||||
use gio::DesktopAppInfo;
|
use gio::DesktopAppInfo;
|
||||||
|
|
@ -18,9 +18,11 @@ use once_cell::sync::OnceCell;
|
||||||
use pop_launcher_service::IpcClient;
|
use pop_launcher_service::IpcClient;
|
||||||
use postage::mpsc::Sender;
|
use postage::mpsc::Sender;
|
||||||
use postage::prelude::*;
|
use postage::prelude::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use x11rb::rust_connection::RustConnection;
|
use x11rb::rust_connection::RustConnection;
|
||||||
|
|
||||||
|
use self::dock_object::DockObject;
|
||||||
use self::window::Window;
|
use self::window::Window;
|
||||||
|
|
||||||
const NUM_LAUNCHER_ITEMS: u8 = 10;
|
const NUM_LAUNCHER_ITEMS: u8 = 10;
|
||||||
|
|
@ -48,10 +50,10 @@ fn spawn_launcher(tx: Sender<Event>) -> IpcClient {
|
||||||
|
|
||||||
let mut sender = tx.clone();
|
let mut sender = tx.clone();
|
||||||
glib::MainContext::default().spawn_local(async move {
|
glib::MainContext::default().spawn_local(async move {
|
||||||
loop {
|
// loop {
|
||||||
Timer::after(Duration::from_secs(1)).await;
|
let _ = sender.send(Event::Search(String::new())).await;
|
||||||
let _ = sender.send(Event::Search(String::new())).await;
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
}
|
// }
|
||||||
});
|
});
|
||||||
|
|
||||||
launcher
|
launcher
|
||||||
|
|
@ -120,8 +122,23 @@ fn main() {
|
||||||
let _ = launcher.send(pop_launcher::Request::Activate(index)).await;
|
let _ = launcher.send(pop_launcher::Request::Activate(index)).await;
|
||||||
}
|
}
|
||||||
Event::Response(event) => {
|
Event::Response(event) => {
|
||||||
if let pop_launcher::Response::Update(_results) = event {
|
if let pop_launcher::Response::Update(results) = event {
|
||||||
println!("updating active apps")
|
println!("updating active apps");
|
||||||
|
let model = window.active_app_model();
|
||||||
|
let model_len = model.n_items();
|
||||||
|
let stack_active = results.iter().fold(HashMap::new(), |mut acc: HashMap<String, BoxedSearchResults>, elem| {
|
||||||
|
if let Some(v) = acc.get_mut(&elem.description) {
|
||||||
|
v.0.push(elem.clone());
|
||||||
|
} else {
|
||||||
|
acc.insert(elem.description.clone(), BoxedSearchResults(vec![elem.clone()]));
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
let new_results: Vec<glib::Object> = stack_active
|
||||||
|
.into_values()
|
||||||
|
.map(|v| DockObject::from_search_results(v).upcast())
|
||||||
|
.collect();
|
||||||
|
model.splice(0, model_len, &new_results[..]);
|
||||||
}
|
}
|
||||||
else if let pop_launcher::Response::DesktopEntry {
|
else if let pop_launcher::Response::DesktopEntry {
|
||||||
path,
|
path,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ pub struct Window {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub saved_app_list_view: TemplateChild<ListView>,
|
pub saved_app_list_view: TemplateChild<ListView>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub unsaved_open_app_list_view: TemplateChild<ListView>,
|
pub active_app_list_view: TemplateChild<ListView>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub revealer: TemplateChild<Revealer>,
|
pub revealer: TemplateChild<Revealer>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
|
|
@ -26,7 +26,7 @@ pub struct Window {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub cursor_leave_handle: TemplateChild<Box>,
|
pub cursor_leave_handle: TemplateChild<Box>,
|
||||||
pub saved_app_model: OnceCell<gio::ListStore>,
|
pub saved_app_model: OnceCell<gio::ListStore>,
|
||||||
pub unsaved_open_app_model: OnceCell<gio::ListStore>,
|
pub active_app_model: OnceCell<gio::ListStore>,
|
||||||
pub enter_event_controller: OnceCell<EventControllerMotion>,
|
pub enter_event_controller: OnceCell<EventControllerMotion>,
|
||||||
pub leave_event_controller: OnceCell<EventControllerMotion>,
|
pub leave_event_controller: OnceCell<EventControllerMotion>,
|
||||||
pub drop_controller: OnceCell<DropTarget>,
|
pub drop_controller: OnceCell<DropTarget>,
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,21 @@ impl Window {
|
||||||
.expect("Could not get saved_app_model")
|
.expect("Could not get saved_app_model")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn active_app_model(&self) -> &gio::ListStore {
|
||||||
|
// Get state
|
||||||
|
let imp = imp::Window::from_instance(self);
|
||||||
|
imp.active_app_model
|
||||||
|
.get()
|
||||||
|
.expect("Could not get active_app_model")
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_model(&self) {
|
fn setup_model(&self) {
|
||||||
// Get state and set model
|
// Get state and set model
|
||||||
|
|
||||||
let imp = imp::Window::from_instance(self);
|
let imp = imp::Window::from_instance(self);
|
||||||
let saved_app_model = gio::ListStore::new(DockObject::static_type());
|
let saved_app_model = gio::ListStore::new(DockObject::static_type());
|
||||||
|
|
||||||
let selection_model = gtk::SingleSelection::builder()
|
let saved_selection_model = gtk::SingleSelection::builder()
|
||||||
.autoselect(false)
|
.autoselect(false)
|
||||||
.can_unselect(true)
|
.can_unselect(true)
|
||||||
.selected(gtk4::INVALID_LIST_POSITION)
|
.selected(gtk4::INVALID_LIST_POSITION)
|
||||||
|
|
@ -93,7 +101,23 @@ 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.set_model(Some(&selection_model));
|
imp.saved_app_list_view
|
||||||
|
.set_model(Some(&saved_selection_model));
|
||||||
|
|
||||||
|
let active_app_model = gio::ListStore::new(DockObject::static_type());
|
||||||
|
let active_selection_model = gtk::SingleSelection::builder()
|
||||||
|
.autoselect(false)
|
||||||
|
.can_unselect(true)
|
||||||
|
.selected(gtk4::INVALID_LIST_POSITION)
|
||||||
|
.model(&active_app_model)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
imp.active_app_model
|
||||||
|
.set(active_app_model)
|
||||||
|
.expect("Could not set model");
|
||||||
|
// Wrap model with selection and pass it to the list view
|
||||||
|
imp.active_app_list_view
|
||||||
|
.set_model(Some(&active_selection_model));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_callbacks(&self) {
|
fn setup_callbacks(&self) {
|
||||||
|
|
@ -346,8 +370,8 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_factory(&self) {
|
fn setup_factory(&self) {
|
||||||
let factory = SignalListItemFactory::new();
|
let saved_app_factory = SignalListItemFactory::new();
|
||||||
factory.connect_setup(move |_, list_item| {
|
saved_app_factory.connect_setup(move |_, list_item| {
|
||||||
let dock_item = DockItem::new();
|
let dock_item = DockItem::new();
|
||||||
list_item.set_child(Some(&dock_item));
|
list_item.set_child(Some(&dock_item));
|
||||||
});
|
});
|
||||||
|
|
@ -356,7 +380,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.");
|
||||||
factory.connect_bind(glib::clone!(@weak saved_app_model => move |_, list_item| {
|
saved_app_factory.connect_bind(glib::clone!(@weak saved_app_model => move |_, list_item| {
|
||||||
let application_object = list_item
|
let application_object = list_item
|
||||||
.item()
|
.item()
|
||||||
.expect("The item has to exist.")
|
.expect("The item has to exist.")
|
||||||
|
|
@ -372,6 +396,35 @@ impl Window {
|
||||||
dock_item.set_app_info(&application_object, i, &saved_app_model);
|
dock_item.set_app_info(&application_object, i, &saved_app_model);
|
||||||
}));
|
}));
|
||||||
// Set the factory of the list view
|
// Set the factory of the list view
|
||||||
imp.saved_app_list_view.set_factory(Some(&factory));
|
imp.saved_app_list_view
|
||||||
|
.set_factory(Some(&saved_app_factory));
|
||||||
|
|
||||||
|
let active_app_model = imp
|
||||||
|
.active_app_model
|
||||||
|
.get()
|
||||||
|
.expect("Failed to get saved app model.");
|
||||||
|
let active_factory = SignalListItemFactory::new();
|
||||||
|
active_factory.connect_setup(move |_, list_item| {
|
||||||
|
let dock_item = DockItem::new();
|
||||||
|
list_item.set_child(Some(&dock_item));
|
||||||
|
});
|
||||||
|
active_factory.connect_bind(glib::clone!(@weak active_app_model => move |_, list_item| {
|
||||||
|
let application_object = list_item
|
||||||
|
.item()
|
||||||
|
.expect("The item has to exist.")
|
||||||
|
.downcast::<DockObject>()
|
||||||
|
.expect("The item has to be a `DockObject`");
|
||||||
|
let dock_item = list_item
|
||||||
|
.child()
|
||||||
|
.expect("The list item child needs to exist.")
|
||||||
|
.downcast::<DockItem>()
|
||||||
|
.expect("The list item type needs to be `DockItem`");
|
||||||
|
|
||||||
|
let i = list_item.position();
|
||||||
|
println!("setting position {} of active app list.", i);
|
||||||
|
dock_item.set_app_info(&application_object, i, &active_app_model);
|
||||||
|
}));
|
||||||
|
// Set the factory of the list view
|
||||||
|
imp.active_app_list_view.set_factory(Some(&active_factory));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkListView" id="saved_app_list_view">
|
<object class="GtkListView" id="saved_app_list_view">
|
||||||
<property name="orientation">horizontal</property>
|
<property name="orientation">horizontal</property>
|
||||||
<property name="hexpand">true</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
|
@ -44,9 +43,8 @@
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkListView" id="unsaved_open_app_list_view">
|
<object class="GtkListView" id="active_app_list_view">
|
||||||
<property name="orientation">horizontal</property>
|
<property name="orientation">horizontal</property>
|
||||||
<property name="hexpand">true</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue