wip: use desktop file stem for app id

This commit is contained in:
Ashley Wulber 2022-07-19 23:39:19 -04:00
parent 223c7855cf
commit adc02df64f
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
12 changed files with 209 additions and 146 deletions

4
Cargo.lock generated
View file

@ -2141,7 +2141,7 @@ checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]] [[package]]
name = "relm4" name = "relm4"
version = "0.5.0-beta.1" version = "0.5.0-beta.1"
source = "git+https://github.com/Relm4/Relm4.git?branch=next#746d244004e23764294b23519f6f8be1002c1ceb" source = "git+https://github.com/relm4/relm4?branch=next#746d244004e23764294b23519f6f8be1002c1ceb"
dependencies = [ dependencies = [
"async-broadcast", "async-broadcast",
"async-oneshot", "async-oneshot",
@ -2158,7 +2158,7 @@ dependencies = [
[[package]] [[package]]
name = "relm4-macros" name = "relm4-macros"
version = "0.5.0-beta.1" version = "0.5.0-beta.1"
source = "git+https://github.com/Relm4/Relm4.git?branch=next#746d244004e23764294b23519f6f8be1002c1ceb" source = "git+https://github.com/relm4/relm4?branch=next#746d244004e23764294b23519f6f8be1002c1ceb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -6,11 +6,11 @@ use crate::dock_list::DockList;
use crate::dock_list::DockListType; use crate::dock_list::DockListType;
use crate::utils::AppListEvent; use crate::utils::AppListEvent;
use cascade::cascade; use cascade::cascade;
use cosmic_panel_config::{PanelAnchor, CosmicPanelConfig}; use cosmic_panel_config::{CosmicPanelConfig, PanelAnchor};
use gtk4::Separator;
use gtk4::prelude::*; use gtk4::prelude::*;
use gtk4::subclass::prelude::*; use gtk4::subclass::prelude::*;
use gtk4::Orientation; use gtk4::Orientation;
use gtk4::Separator;
use gtk4::{gio, glib}; use gtk4::{gio, glib};
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
@ -70,7 +70,6 @@ impl AppsContainer {
self_.setup_callbacks(); self_.setup_callbacks();
self_.set_position(config.anchor); self_.set_position(config.anchor);
Self::setup_callbacks(&self_); Self::setup_callbacks(&self_);
self_ self_

View file

@ -1,9 +1,9 @@
use std::fmt::Debug; use crate::ID;
use std::fs::File;
use anyhow::anyhow; use anyhow::anyhow;
use serde::Deserialize; use serde::Deserialize;
use std::fmt::Debug;
use std::fs::File;
use xdg::BaseDirectories; use xdg::BaseDirectories;
use crate::ID;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub enum TopLevelFilter { pub enum TopLevelFilter {
@ -19,13 +19,18 @@ pub struct AppListConfig {
impl AppListConfig { impl AppListConfig {
/// load config with the provided name /// load config with the provided name
pub fn load() -> anyhow::Result<AppListConfig> { pub fn load() -> anyhow::Result<AppListConfig> {
let file= match BaseDirectories::new().ok().and_then(|dirs| dirs.find_config_file(format!("{ID}/config.ron"))).and_then(|p| File::open(p).ok()) { let file = match BaseDirectories::new()
.ok()
.and_then(|dirs| dirs.find_config_file(format!("{ID}/config.ron")))
.and_then(|p| File::open(p).ok())
{
Some(path) => path, Some(path) => path,
_ => { _ => {
anyhow::bail!("Failed to load config"); anyhow::bail!("Failed to load config");
} }
}; };
ron::de::from_reader::<_, AppListConfig>(file).map_err(|err| anyhow!("Failed to parse config file: {}", err)) ron::de::from_reader::<_, AppListConfig>(file)
.map_err(|err| anyhow!("Failed to parse config file: {}", err))
} }
} }

View file

@ -2,8 +2,8 @@
use crate::dock_object::DockObject; use crate::dock_object::DockObject;
use crate::dock_popover::DockPopover; use crate::dock_popover::DockPopover;
use crate::utils::BoxedWindowList;
use crate::utils::AppListEvent; use crate::utils::AppListEvent;
use crate::utils::BoxedWindowList;
use cascade::cascade; use cascade::cascade;
use cosmic_panel_config::PanelAnchor; use cosmic_panel_config::PanelAnchor;
use gtk4::glib; use gtk4::glib;

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MPL-2.0-only // SPDX-License-Identifier: MPL-2.0-only
use cosmic_panel_config::{PanelAnchor, CosmicPanelConfig}; use cosmic_panel_config::{CosmicPanelConfig, PanelAnchor};
use glib::SignalHandlerId; use glib::SignalHandlerId;
use gtk4::subclass::prelude::*; use gtk4::subclass::prelude::*;
use gtk4::{gio, glib}; use gtk4::{gio, glib};
@ -25,7 +25,7 @@ pub struct DockList {
pub popover_menu_index: Rc<Cell<Option<u32>>>, pub popover_menu_index: Rc<Cell<Option<u32>>>,
pub position: Rc<Cell<PanelAnchor>>, pub position: Rc<Cell<PanelAnchor>>,
pub tx: OnceCell<mpsc::Sender<AppListEvent>>, pub tx: OnceCell<mpsc::Sender<AppListEvent>>,
pub config: OnceCell<CosmicPanelConfig> pub config: OnceCell<CosmicPanelConfig>,
} }
#[glib::object_subclass] #[glib::object_subclass]

View file

@ -1,12 +1,13 @@
// SPDX-License-Identifier: MPL-2.0-only // SPDX-License-Identifier: MPL-2.0-only
use crate::{TX, WAYLAND_TX};
use crate::dock_item::DockItem; use crate::dock_item::DockItem;
use crate::dock_object::DockObject; use crate::dock_object::DockObject;
use crate::utils::data_path; use crate::utils::data_path;
use crate::utils::{BoxedWindowList, AppListEvent}; use crate::utils::{AppListEvent, BoxedWindowList};
use crate::wayland::{Toplevel, ToplevelEvent}; use crate::wayland::{Toplevel, ToplevelEvent};
use crate::{TX, WAYLAND_TX};
use cascade::cascade; use cascade::cascade;
use cosmic_panel_config::{CosmicPanelConfig, PanelAnchor};
use gio::DesktopAppInfo; use gio::DesktopAppInfo;
use gio::Icon; use gio::Icon;
use glib::Object; use glib::Object;
@ -27,7 +28,6 @@ use gtk4::SignalListItemFactory;
use gtk4::{DragSource, GestureClick}; use gtk4::{DragSource, GestureClick};
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
use cosmic_panel_config::{CosmicPanelConfig, PanelAnchor};
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
mod imp; mod imp;

View file

@ -95,7 +95,10 @@ impl DockObject {
if let Some(path) = path.to_str() { if let Some(path) = path.to_str() {
if let Some(app_info) = gio::DesktopAppInfo::new(path) { if let Some(app_info) = gio::DesktopAppInfo::new(path) {
if app_info.should_show() if app_info.should_show()
&& Some(&first.app_id) == app_info.id().map(|s| s.to_string()).as_ref() && Some(&first.app_id)
== app_info.filename().and_then(|p| p
.file_stem()
.and_then(|s| s.to_str().map(|s| s.to_string()))).as_ref()
{ {
return Some(app_info); return Some(app_info);
} }
@ -109,7 +112,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`.")
} }

View file

@ -9,11 +9,11 @@ use gtk4::{prelude::*, Label};
use gtk4::{Box, Button, Image, ListBox, Orientation}; use gtk4::{Box, Button, Image, ListBox, Orientation};
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use crate::dock_object::DockObject;
use crate::utils::AppListEvent;
use crate::utils::BoxedWindowList;
use crate::wayland::ToplevelEvent; use crate::wayland::ToplevelEvent;
use crate::{TX, WAYLAND_TX}; use crate::{TX, WAYLAND_TX};
use crate::dock_object::DockObject;
use crate::utils::BoxedWindowList;
use crate::utils::AppListEvent;
mod imp; mod imp;

View file

@ -8,15 +8,16 @@ use gio::{ApplicationFlags, DesktopAppInfo};
use gtk4::gdk::Display; use gtk4::gdk::Display;
use gtk4::{glib, prelude::*, CssProvider, StyleContext}; use gtk4::{glib, prelude::*, CssProvider, StyleContext};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use wayland::{ToplevelEvent, Toplevel};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::Duration; use std::time::Duration;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use utils::{block_on, BoxedWindowList, AppListEvent, DEST, PATH}; use utils::{block_on, AppListEvent, BoxedWindowList, DEST, PATH};
use wayland::{Toplevel, ToplevelEvent};
mod apps_container; mod apps_container;
mod apps_window; mod apps_window;
mod config;
mod dock_item; mod dock_item;
mod dock_list; mod dock_list;
mod dock_object; mod dock_object;
@ -25,7 +26,6 @@ mod localize;
mod utils; mod utils;
mod wayland; mod wayland;
mod wayland_source; mod wayland_source;
mod config;
const ID: &str = "com.system76.CosmicAppList"; const ID: &str = "com.system76.CosmicAppList";
static TX: OnceCell<glib::Sender<AppListEvent>> = OnceCell::new(); static TX: OnceCell<glib::Sender<AppListEvent>> = OnceCell::new();
@ -152,7 +152,9 @@ fn main() {
if let Some((i, _s)) = stack_active if let Some((i, _s)) = stack_active
.iter() .iter()
.enumerate() .enumerate()
.find(|(_i, s)| Some(&s.0[0].app_id) == cur_app_info.id().map(|s| s.to_string()).as_ref()) .find(|(_i, s)| Some(&s.0[0].app_id) == cur_app_info.filename().and_then(|p| p
.file_stem()
.and_then(|s| s.to_str().map(|s| s.to_string()))).as_ref())
{ {
// println!( // println!(
// "found active saved app {} at {}", // "found active saved app {} at {}",
@ -163,7 +165,9 @@ fn main() {
saved_app_model.items_changed(saved_i, 0, 0); saved_app_model.items_changed(saved_i, 0, 0);
} else if cached_results } else if cached_results
.iter() .iter()
.any(|s| Some(&s.app_id) == cur_app_info.id().map(|s| s.to_string()).as_ref()) .any(|s| Some(&s.app_id) == cur_app_info.filename().and_then(|p| p
.file_stem()
.and_then(|s| s.to_str().map(|s| s.to_string()))).as_ref())
{ {
dock_obj.set_property( dock_obj.set_property(
"active", "active",
@ -238,7 +242,9 @@ fn main() {
if let Some((i, _s)) = stack_active if let Some((i, _s)) = stack_active
.iter() .iter()
.enumerate() .enumerate()
.find(|(_i, s)| Some(&s.0[0].app_id) == cur_app_info.id().map(|s| s.to_string()).as_ref()) .find(|(_i, s)| Some(&s.0[0].app_id) == cur_app_info.filename().and_then(|p| p
.file_stem()
.and_then(|s| s.to_str().map(|s| s.to_string()))).as_ref())
{ {
// println!("found active saved app {} at {}", s.0[0].name, i); // println!("found active saved app {} at {}", s.0[0].name, i);
let active = stack_active.remove(i); let active = stack_active.remove(i);
@ -246,7 +252,9 @@ fn main() {
saved_app_model.items_changed(saved_i, 0, 0); saved_app_model.items_changed(saved_i, 0, 0);
} else if cached_results } else if cached_results
.iter() .iter()
.any(|s| Some(&s.app_id) == cur_app_info.id().map(|s| s.to_string()).as_ref()) .any(|s| Some(&s.app_id) == cur_app_info.filename().and_then(|p| p
.file_stem()
.and_then(|s| s.to_str().map(|s| s.to_string()))).as_ref())
{ {
dock_obj.set_property( dock_obj.set_property(
"active", "active",

View file

@ -1,10 +1,22 @@
use crate::{ use crate::config::AppListConfig;
wayland_source::WaylandSource, config::TopLevelFilter, TX, utils::AppListEvent, use crate::{config::TopLevelFilter, utils::AppListEvent, wayland_source::WaylandSource, TX};
}; use calloop::channel::*;
use cosmic_panel_config::CosmicPanelConfig; use cosmic_panel_config::CosmicPanelConfig;
use std::{ use cosmic_protocols::{
env, os::unix::net::UnixStream, path::PathBuf,time::Duration, toplevel_info::v1::client::{
zcosmic_toplevel_handle_v1::{self, ZcosmicToplevelHandleV1},
zcosmic_toplevel_info_v1::{self, ZcosmicToplevelInfoV1},
},
toplevel_management::v1::client::zcosmic_toplevel_manager_v1::{
self, ZcosmicToplevelManagerV1,
},
workspace::v1::client::{
zcosmic_workspace_group_handle_v1::{self, ZcosmicWorkspaceGroupHandleV1},
zcosmic_workspace_handle_v1::{self, ZcosmicWorkspaceHandleV1},
zcosmic_workspace_manager_v1::{self, ZcosmicWorkspaceManagerV1},
},
}; };
use std::{env, os::unix::net::UnixStream, path::PathBuf, time::Duration};
use wayland_client::{ use wayland_client::{
event_created_child, event_created_child,
protocol::{ protocol::{
@ -13,14 +25,7 @@ use wayland_client::{
}, },
ConnectError, Proxy, ConnectError, Proxy,
}; };
use cosmic_protocols::{workspace::v1::client::{
zcosmic_workspace_manager_v1::{self, ZcosmicWorkspaceManagerV1},
zcosmic_workspace_group_handle_v1::{self, ZcosmicWorkspaceGroupHandleV1},
zcosmic_workspace_handle_v1::{self, ZcosmicWorkspaceHandleV1},
}, toplevel_info::v1::client::{zcosmic_toplevel_info_v1::{ZcosmicToplevelInfoV1, self}, zcosmic_toplevel_handle_v1::{ZcosmicToplevelHandleV1, self}}, toplevel_management::v1::client::zcosmic_toplevel_manager_v1::{self, ZcosmicToplevelManagerV1}};
use wayland_client::{Connection, Dispatch, QueueHandle}; use wayland_client::{Connection, Dispatch, QueueHandle};
use calloop::channel::*;
use crate::config::AppListConfig;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ToplevelEvent { pub enum ToplevelEvent {
@ -47,8 +52,9 @@ pub fn spawn_toplevels() -> SyncSender<ToplevelEvent> {
{ {
std::thread::spawn(move || { std::thread::spawn(move || {
let output = match config.filter_top_levels { let output = match config.filter_top_levels {
Some(TopLevelFilter::ConfiguredOutput) => CosmicPanelConfig::load_from_env() Some(TopLevelFilter::ConfiguredOutput) => {
.ok().map(|c| c.output), CosmicPanelConfig::load_from_env().ok().map(|c| c.output)
}
_ => None, _ => None,
}; };
let mut event_loop = calloop::EventLoop::<State>::try_new().unwrap(); let mut event_loop = calloop::EventLoop::<State>::try_new().unwrap();
@ -73,14 +79,14 @@ pub fn spawn_toplevels() -> SyncSender<ToplevelEvent> {
configured_output: output, configured_output: output,
expected_output: None, expected_output: None,
running: true, running: true,
toplevels: vec![] toplevels: vec![],
}; };
let loop_handle = event_loop.handle(); let loop_handle = event_loop.handle();
loop_handle loop_handle
.insert_source(workspaces_rx, |e, _, state| match e { .insert_source(workspaces_rx, |e, _, state| match e {
Event::Msg(ToplevelEvent::Activate(_t)) => { Event::Msg(ToplevelEvent::Activate(_t)) => {
todo!() todo!()
} }
Event::Msg(ToplevelEvent::Close(_t)) => { Event::Msg(ToplevelEvent::Close(_t)) => {
todo!() todo!()
} }
@ -136,12 +142,17 @@ impl State {
.iter() .iter()
.filter_map(|g| { .filter_map(|g| {
if g.output == self.expected_output { if g.output == self.expected_output {
Some(g.workspaces.iter().map(|w| (w.name.clone(), match &w.states { Some(g.workspaces.iter().map(|w| {
x if x.contains(&zcosmic_workspace_handle_v1::State::Active) => 0, (
x if x.contains(&zcosmic_workspace_handle_v1::State::Urgent) => 1, w.name.clone(),
x if x.contains(&zcosmic_workspace_handle_v1::State::Hidden) => 2, match &w.states {
_ => 3, x if x.contains(&zcosmic_workspace_handle_v1::State::Active) => 0,
}))) x if x.contains(&zcosmic_workspace_handle_v1::State::Urgent) => 1,
x if x.contains(&zcosmic_workspace_handle_v1::State::Hidden) => 2,
_ => 3,
},
)
}))
} else { } else {
None None
} }
@ -193,34 +204,19 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State {
match &interface[..] { match &interface[..] {
"zcosmic_toplevel_info_v1" => { "zcosmic_toplevel_info_v1" => {
let ti = registry let ti = registry
.bind::<ZcosmicToplevelInfoV1, _, _>( .bind::<ZcosmicToplevelInfoV1, _, _>(name, 1, qh, ())
name,
1,
qh,
(),
)
.unwrap(); .unwrap();
state.toplevel_info = Some(ti); state.toplevel_info = Some(ti);
} }
"zcosmic_toplevel_manager_v1" => { "zcosmic_toplevel_manager_v1" => {
let tm = registry let tm = registry
.bind::<ZcosmicToplevelManagerV1, _, _>( .bind::<ZcosmicToplevelManagerV1, _, _>(name, 1, qh, ())
name,
1,
qh,
(),
)
.unwrap(); .unwrap();
state.toplevel_manager = Some(tm); state.toplevel_manager = Some(tm);
} }
"zcosmic_workspace_manager_v1" => { "zcosmic_workspace_manager_v1" => {
let workspace_manager = registry let workspace_manager = registry
.bind::<ZcosmicWorkspaceManagerV1, _, _>( .bind::<ZcosmicWorkspaceManagerV1, _, _>(name, 1, qh, ())
name,
1,
qh,
(),
)
.unwrap(); .unwrap();
state.workspace_manager = Some(workspace_manager); state.workspace_manager = Some(workspace_manager);
} }
@ -245,12 +241,19 @@ impl Dispatch<ZcosmicToplevelInfoV1, ()> for State {
dbg!(&event); dbg!(&event);
match event { match event {
zcosmic_toplevel_info_v1::Event::Toplevel { toplevel } => { zcosmic_toplevel_info_v1::Event::Toplevel { toplevel } => {
state.toplevels.push(Toplevel { name: "".into(), app_id: "".into(), toplevel_handle: toplevel, states: vec![], output: None, workspace: None }); state.toplevels.push(Toplevel {
}, name: "".into(),
app_id: "".into(),
toplevel_handle: toplevel,
states: vec![],
output: None,
workspace: None,
});
}
zcosmic_toplevel_info_v1::Event::Finished => { zcosmic_toplevel_info_v1::Event::Finished => {
todo!() todo!()
}, }
_ => {}, _ => {}
} }
} }
@ -259,7 +262,6 @@ impl Dispatch<ZcosmicToplevelInfoV1, ()> for State {
]); ]);
} }
impl Dispatch<ZcosmicToplevelManagerV1, ()> for State { impl Dispatch<ZcosmicToplevelManagerV1, ()> for State {
fn event( fn event(
_: &mut Self, _: &mut Self,
@ -272,8 +274,8 @@ impl Dispatch<ZcosmicToplevelManagerV1, ()> for State {
match event { match event {
zcosmic_toplevel_manager_v1::Event::Capabilities { .. } => { zcosmic_toplevel_manager_v1::Event::Capabilities { .. } => {
// TODO capabilities affect what is shown to user in applet // TODO capabilities affect what is shown to user in applet
}, }
_ => {}, _ => {}
} }
} }
} }
@ -292,27 +294,33 @@ impl Dispatch<ZcosmicToplevelHandleV1, ()> for State {
if let Some(i) = state.toplevels.iter().position(|t| &t.toplevel_handle == p) { if let Some(i) = state.toplevels.iter().position(|t| &t.toplevel_handle == p) {
state.toplevels.remove(i); state.toplevels.remove(i);
} }
}, }
zcosmic_toplevel_handle_v1::Event::Done => { zcosmic_toplevel_handle_v1::Event::Done => {
let to_send = match state.config.filter_top_levels { let to_send = match state.config.filter_top_levels {
Some(TopLevelFilter::ActiveWorkspace) => { Some(TopLevelFilter::ActiveWorkspace) => state.toplevels.iter_mut().find(|t| {
state.toplevels.iter_mut().find(|t| { if &t.toplevel_handle == p {
if &t.toplevel_handle == p { state
state
.workspace_groups .workspace_groups
.iter() .iter()
.find(|g| { .find(|g| {
g.workspaces g.workspaces
.iter() .iter()
.find(|w| w.states.contains(&zcosmic_workspace_handle_v1::State::Active) && Some(&w.workspace_handle) == t.workspace.as_ref()).is_some() .find(|w| {
}).is_some() w.states.contains(
} else { &zcosmic_workspace_handle_v1::State::Active,
false ) && Some(&w.workspace_handle) == t.workspace.as_ref()
} })
}) .is_some()
}, })
Some(TopLevelFilter::ConfiguredOutput) => .is_some()
state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p && state.expected_output == t.output), } else {
false
}
}),
Some(TopLevelFilter::ConfiguredOutput) => state
.toplevels
.iter_mut()
.find(|t| &t.toplevel_handle == p && state.expected_output == t.output),
_ => state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p), _ => state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p),
}; };
@ -321,49 +329,63 @@ impl Dispatch<ZcosmicToplevelHandleV1, ()> for State {
let _ = tx.send(AppListEvent::Add(toplevel)); let _ = tx.send(AppListEvent::Add(toplevel));
} }
}
},
zcosmic_toplevel_handle_v1::Event::Title { title } => { zcosmic_toplevel_handle_v1::Event::Title { title } => {
if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) { if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) {
i.name = title; i.name = title;
} }
}, }
zcosmic_toplevel_handle_v1::Event::AppId { app_id } => { zcosmic_toplevel_handle_v1::Event::AppId { app_id } => {
if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) { if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) {
i.app_id = app_id; i.app_id = app_id;
} }
}, }
zcosmic_toplevel_handle_v1::Event::OutputEnter { output } => { zcosmic_toplevel_handle_v1::Event::OutputEnter { output } => {
if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) { if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) {
i.output.replace(output); i.output.replace(output);
} }
}, }
zcosmic_toplevel_handle_v1::Event::OutputLeave { output } => { zcosmic_toplevel_handle_v1::Event::OutputLeave { output } => {
if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p && t.output.as_ref() == Some(&output)) { if let Some(i) = state
.toplevels
.iter_mut()
.find(|t| &t.toplevel_handle == p && t.output.as_ref() == Some(&output))
{
i.output.take(); i.output.take();
} }
}, }
zcosmic_toplevel_handle_v1::Event::WorkspaceEnter { workspace } => { zcosmic_toplevel_handle_v1::Event::WorkspaceEnter { workspace } => {
if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) { if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) {
i.workspace.replace(workspace); i.workspace.replace(workspace);
} }
}, }
zcosmic_toplevel_handle_v1::Event::WorkspaceLeave { workspace } => { zcosmic_toplevel_handle_v1::Event::WorkspaceLeave { workspace } => {
if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p && t.workspace.as_ref() == Some(&workspace)) { if let Some(i) = state
.toplevels
.iter_mut()
.find(|t| &t.toplevel_handle == p && t.workspace.as_ref() == Some(&workspace))
{
i.workspace.take(); i.workspace.take();
} }
}, }
zcosmic_toplevel_handle_v1::Event::State { state: t_state } => { zcosmic_toplevel_handle_v1::Event::State { state: t_state } => {
if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) { if let Some(i) = state.toplevels.iter_mut().find(|t| &t.toplevel_handle == p) {
i.states = t_state.chunks(4).map(|chunk| zcosmic_toplevel_handle_v1::State::try_from(u32::from_ne_bytes(chunk.try_into().unwrap())).unwrap()).collect(); i.states = t_state
.chunks(4)
.map(|chunk| {
zcosmic_toplevel_handle_v1::State::try_from(u32::from_ne_bytes(
chunk.try_into().unwrap(),
))
.unwrap()
})
.collect();
} }
}, }
_ => todo!(), _ => todo!(),
} }
} }
} }
impl Dispatch<ZcosmicWorkspaceManagerV1, ()> for State { impl Dispatch<ZcosmicWorkspaceManagerV1, ()> for State {
fn event( fn event(
state: &mut Self, state: &mut Self,
@ -384,7 +406,9 @@ impl Dispatch<ZcosmicWorkspaceManagerV1, ()> for State {
zcosmic_workspace_manager_v1::Event::Done => { zcosmic_workspace_manager_v1::Event::Done => {
for group in &mut state.workspace_groups { for group in &mut state.workspace_groups {
group.workspaces.sort_by(|w1, w2| { group.workspaces.sort_by(|w1, w2| {
w1.coordinates.iter().zip(w2.coordinates.iter()) w1.coordinates
.iter()
.zip(w2.coordinates.iter())
.skip_while(|(coord1, coord2)| coord1 == coord2) .skip_while(|(coord1, coord2)| coord1 == coord2)
.next() .next()
.map(|(coord1, coord2)| coord1.cmp(coord2)) .map(|(coord1, coord2)| coord1.cmp(coord2))
@ -488,19 +512,31 @@ impl Dispatch<ZcosmicWorkspaceHandleV1, ()> for State {
.find(|w| &w.workspace_handle == workspace) .find(|w| &w.workspace_handle == workspace)
}) { }) {
// wayland is host byte order // wayland is host byte order
w.coordinates = coordinates.chunks(4).map(|chunk| u32::from_ne_bytes(chunk.try_into().unwrap())).collect(); w.coordinates = coordinates
.chunks(4)
.map(|chunk| u32::from_ne_bytes(chunk.try_into().unwrap()))
.collect();
} }
} }
zcosmic_workspace_handle_v1::Event::State { state: workspace_state } => { zcosmic_workspace_handle_v1::Event::State {
state: workspace_state,
} => {
if let Some(w) = state.workspace_groups.iter_mut().find_map(|g| { if let Some(w) = state.workspace_groups.iter_mut().find_map(|g| {
g.workspaces g.workspaces
.iter_mut() .iter_mut()
.find(|w| &w.workspace_handle == workspace) .find(|w| &w.workspace_handle == workspace)
}) { }) {
// wayland is host byte order // wayland is host byte order
w.states = workspace_state.chunks(4).map(|chunk| zcosmic_workspace_handle_v1::State::try_from(u32::from_ne_bytes(chunk.try_into().unwrap())).unwrap()).collect(); w.states = workspace_state
.chunks(4)
.map(|chunk| {
zcosmic_workspace_handle_v1::State::try_from(u32::from_ne_bytes(
chunk.try_into().unwrap(),
))
.unwrap()
})
.collect();
// TODO if workspace active status changes while configured to only show active workspace, clear the list // TODO if workspace active status changes while configured to only show active workspace, clear the list
} }
} }
zcosmic_workspace_handle_v1::Event::Remove => { zcosmic_workspace_handle_v1::Event::Remove => {

View file

@ -51,8 +51,6 @@ fn main() {
gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION,
); );
let current_graphics = RT let current_graphics = RT
.block_on(get_current_graphics()) .block_on(get_current_graphics())
.expect("failed to connect to system76-power"); .expect("failed to connect to system76-power");

View file

@ -2,7 +2,13 @@ use crate::{
utils::{Activate, WorkspaceEvent}, utils::{Activate, WorkspaceEvent},
wayland_source::WaylandSource, wayland_source::WaylandSource,
}; };
use calloop::channel::*;
use cosmic_panel_config::CosmicPanelConfig; use cosmic_panel_config::CosmicPanelConfig;
use cosmic_protocols::workspace::v1::client::{
zcosmic_workspace_group_handle_v1::{self, ZcosmicWorkspaceGroupHandleV1},
zcosmic_workspace_handle_v1::{self, ZcosmicWorkspaceHandleV1},
zcosmic_workspace_manager_v1::{self, ZcosmicWorkspaceManagerV1},
};
use gtk4::glib; use gtk4::glib;
use std::{ use std::{
collections::HashMap, env, hash::Hash, mem, os::unix::net::UnixStream, path::PathBuf, collections::HashMap, env, hash::Hash, mem, os::unix::net::UnixStream, path::PathBuf,
@ -18,13 +24,7 @@ use wayland_client::{
}, },
ConnectError, Proxy, ConnectError, Proxy,
}; };
use cosmic_protocols::workspace::v1::client::{
zcosmic_workspace_manager_v1::{self, ZcosmicWorkspaceManagerV1},
zcosmic_workspace_group_handle_v1::{self, ZcosmicWorkspaceGroupHandleV1},
zcosmic_workspace_handle_v1::{self, ZcosmicWorkspaceHandleV1},
};
use wayland_client::{Connection, Dispatch, QueueHandle}; use wayland_client::{Connection, Dispatch, QueueHandle};
use calloop::channel::*;
pub fn spawn_workspaces(tx: glib::Sender<State>) -> SyncSender<WorkspaceEvent> { pub fn spawn_workspaces(tx: glib::Sender<State>) -> SyncSender<WorkspaceEvent> {
let (workspaces_tx, workspaces_rx) = calloop::channel::sync_channel(100); let (workspaces_tx, workspaces_rx) = calloop::channel::sync_channel(100);
@ -80,19 +80,18 @@ pub fn spawn_workspaces(tx: glib::Sender<State>) -> SyncSender<WorkspaceEvent> {
} }
} }
Event::Msg(WorkspaceEvent::Scroll(v)) => { Event::Msg(WorkspaceEvent::Scroll(v)) => {
if let Some((w_g, w_i)) = state if let Some((w_g, w_i)) = state.workspace_groups.iter().find_map(|g| {
.workspace_groups if g.output != state.expected_output {
.iter() return None;
.find_map(|g| { }
if g.output != state.expected_output { g.workspaces
return None; .iter()
} .position(|w| {
g.workspaces w.states
.iter() .contains(&zcosmic_workspace_handle_v1::State::Active)
.position(|w| w.states.contains(&zcosmic_workspace_handle_v1::State::Active)) })
.map(|w_i| (g, w_i)) .map(|w_i| (g, w_i))
}) }) {
{
let max_w = w_g.workspaces.len().wrapping_sub(1); let max_w = w_g.workspaces.len().wrapping_sub(1);
let d_i = if v > 0.0 { let d_i = if v > 0.0 {
if w_i == max_w { if w_i == max_w {
@ -154,12 +153,17 @@ impl State {
.iter() .iter()
.filter_map(|g| { .filter_map(|g| {
if g.output == self.expected_output { if g.output == self.expected_output {
Some(g.workspaces.iter().map(|w| (w.name.clone(), match &w.states { Some(g.workspaces.iter().map(|w| {
x if x.contains(&zcosmic_workspace_handle_v1::State::Active) => 0, (
x if x.contains(&zcosmic_workspace_handle_v1::State::Urgent) => 1, w.name.clone(),
x if x.contains(&zcosmic_workspace_handle_v1::State::Hidden) => 2, match &w.states {
_ => 3, x if x.contains(&zcosmic_workspace_handle_v1::State::Active) => 0,
}))) x if x.contains(&zcosmic_workspace_handle_v1::State::Urgent) => 1,
x if x.contains(&zcosmic_workspace_handle_v1::State::Hidden) => 2,
_ => 3,
},
)
}))
} else { } else {
None None
} }
@ -201,12 +205,7 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State {
match &interface[..] { match &interface[..] {
"zcosmic_workspace_manager_v1" => { "zcosmic_workspace_manager_v1" => {
let workspace_manager = registry let workspace_manager = registry
.bind::<ZcosmicWorkspaceManagerV1, _, _>( .bind::<ZcosmicWorkspaceManagerV1, _, _>(name, 1, qh, ())
name,
1,
qh,
(),
)
.unwrap(); .unwrap();
state.workspace_manager = Some(workspace_manager); state.workspace_manager = Some(workspace_manager);
} }
@ -239,7 +238,9 @@ impl Dispatch<ZcosmicWorkspaceManagerV1, ()> for State {
zcosmic_workspace_manager_v1::Event::Done => { zcosmic_workspace_manager_v1::Event::Done => {
for group in &mut state.workspace_groups { for group in &mut state.workspace_groups {
group.workspaces.sort_by(|w1, w2| { group.workspaces.sort_by(|w1, w2| {
w1.coordinates.iter().zip(w2.coordinates.iter()) w1.coordinates
.iter()
.zip(w2.coordinates.iter())
.skip_while(|(coord1, coord2)| coord1 == coord2) .skip_while(|(coord1, coord2)| coord1 == coord2)
.next() .next()
.map(|(coord1, coord2)| coord1.cmp(coord2)) .map(|(coord1, coord2)| coord1.cmp(coord2))
@ -344,17 +345,30 @@ impl Dispatch<ZcosmicWorkspaceHandleV1, ()> for State {
.find(|w| &w.workspace_handle == workspace) .find(|w| &w.workspace_handle == workspace)
}) { }) {
// wayland is host byte order // wayland is host byte order
w.coordinates = coordinates.chunks(4).map(|chunk| u32::from_ne_bytes(chunk.try_into().unwrap())).collect(); w.coordinates = coordinates
.chunks(4)
.map(|chunk| u32::from_ne_bytes(chunk.try_into().unwrap()))
.collect();
} }
} }
zcosmic_workspace_handle_v1::Event::State { state: workspace_state } => { zcosmic_workspace_handle_v1::Event::State {
state: workspace_state,
} => {
if let Some(w) = state.workspace_groups.iter_mut().find_map(|g| { if let Some(w) = state.workspace_groups.iter_mut().find_map(|g| {
g.workspaces g.workspaces
.iter_mut() .iter_mut()
.find(|w| &w.workspace_handle == workspace) .find(|w| &w.workspace_handle == workspace)
}) { }) {
// wayland is host byte order // wayland is host byte order
w.states = workspace_state.chunks(4).map(|chunk| zcosmic_workspace_handle_v1::State::try_from(u32::from_ne_bytes(chunk.try_into().unwrap())).unwrap()).collect(); w.states = workspace_state
.chunks(4)
.map(|chunk| {
zcosmic_workspace_handle_v1::State::try_from(u32::from_ne_bytes(
chunk.try_into().unwrap(),
))
.unwrap()
})
.collect();
} }
} }
zcosmic_workspace_handle_v1::Event::Remove => { zcosmic_workspace_handle_v1::Event::Remove => {