Update for toplevel-info cctk changes
This commit is contained in:
parent
0e01b09ddd
commit
926abeb373
3 changed files with 73 additions and 51 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -571,7 +571,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-client-toolkit"
|
name = "cosmic-client-toolkit"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os//cosmic-protocols#d218c76b58c7a3b20dd5e7943f93fc306a1b81b8"
|
source = "git+https://github.com/pop-os//cosmic-protocols#178eb0b14a0e5c192f64f6dee6c40341a8e5ee51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmic-protocols",
|
"cosmic-protocols",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -583,7 +583,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-protocols"
|
name = "cosmic-protocols"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os//cosmic-protocols#d218c76b58c7a3b20dd5e7943f93fc306a1b81b8"
|
source = "git+https://github.com/pop-os//cosmic-protocols#178eb0b14a0e5c192f64f6dee6c40341a8e5ee51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
|
|
@ -1485,7 +1485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,10 @@ mod toplevel_handler;
|
||||||
|
|
||||||
use cctk::cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
|
use cctk::cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
|
||||||
use cctk::wayland_client::Proxy;
|
use cctk::wayland_client::Proxy;
|
||||||
use cctk::{cosmic_protocols, sctk::reexports::calloop, toplevel_info::ToplevelInfo};
|
use cctk::{sctk::reexports::calloop, toplevel_info::ToplevelInfo};
|
||||||
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1;
|
|
||||||
use fde::DesktopEntry;
|
use fde::DesktopEntry;
|
||||||
use freedesktop_desktop_entry as fde;
|
use freedesktop_desktop_entry as fde;
|
||||||
use toplevel_handler::TopLevelsUpdate;
|
use toplevel_handler::ToplevelUpdate;
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
use crate::desktop_entries::utils::{get_description, is_session_cosmic};
|
use crate::desktop_entries::utils::{get_description, is_session_cosmic};
|
||||||
|
|
@ -70,26 +69,33 @@ pub async fn main() {
|
||||||
next_event = toplevel_rx.next();
|
next_event = toplevel_rx.next();
|
||||||
next_request = second_to_next_request;
|
next_request = second_to_next_request;
|
||||||
|
|
||||||
for (handle, info) in updates {
|
for update in updates {
|
||||||
match info {
|
match update {
|
||||||
Some(info) => {
|
ToplevelUpdate::Info(info) => {
|
||||||
if let Some(pos) = app.toplevels.iter().position(|t| t.0 == handle) {
|
if let Some(pos) = app
|
||||||
|
.toplevels
|
||||||
|
.iter()
|
||||||
|
.position(|t| t.foreign_toplevel == info.foreign_toplevel)
|
||||||
|
{
|
||||||
if info.state.contains(&State::Activated) {
|
if info.state.contains(&State::Activated) {
|
||||||
app.toplevels.remove(pos);
|
app.toplevels.remove(pos);
|
||||||
app.toplevels.push((handle, Box::new(info)));
|
app.toplevels.push(Box::new(info));
|
||||||
} else {
|
} else {
|
||||||
app.toplevels[pos].1 = Box::new(info);
|
app.toplevels[pos] = Box::new(info);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
app.toplevels.push((handle, Box::new(info)));
|
app.toplevels.push(Box::new(info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// no info means remove
|
ToplevelUpdate::Remove(foreign_toplevel) => {
|
||||||
None => {
|
if let Some(pos) = app
|
||||||
if let Some(pos) = app.toplevels.iter().position(|t| t.0 == handle) {
|
.toplevels
|
||||||
|
.iter()
|
||||||
|
.position(|t| t.foreign_toplevel == foreign_toplevel)
|
||||||
|
{
|
||||||
app.toplevels.remove(pos);
|
app.toplevels.remove(pos);
|
||||||
// ignore requests for this id until after the next search
|
// ignore requests for this id until after the next search
|
||||||
app.ids_to_ignore.push(handle.id().protocol_id());
|
app.ids_to_ignore.push(foreign_toplevel.id().protocol_id());
|
||||||
} else {
|
} else {
|
||||||
warn!("no toplevel to remove");
|
warn!("no toplevel to remove");
|
||||||
}
|
}
|
||||||
|
|
@ -106,13 +112,13 @@ struct App<W> {
|
||||||
locales: Vec<String>,
|
locales: Vec<String>,
|
||||||
desktop_entries: Vec<DesktopEntry<'static>>,
|
desktop_entries: Vec<DesktopEntry<'static>>,
|
||||||
ids_to_ignore: Vec<u32>,
|
ids_to_ignore: Vec<u32>,
|
||||||
toplevels: Vec<(ZcosmicToplevelHandleV1, Box<ToplevelInfo>)>,
|
toplevels: Vec<Box<ToplevelInfo>>,
|
||||||
calloop_tx: calloop::channel::Sender<ToplevelAction>,
|
calloop_tx: calloop::channel::Sender<ToplevelAction>,
|
||||||
tx: W,
|
tx: W,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: AsyncWrite + Unpin> App<W> {
|
impl<W: AsyncWrite + Unpin> App<W> {
|
||||||
fn new(tx: W) -> (Self, mpsc::UnboundedReceiver<TopLevelsUpdate>) {
|
fn new(tx: W) -> (Self, mpsc::UnboundedReceiver<Vec<ToplevelUpdate>>) {
|
||||||
let (toplevels_tx, toplevel_rx) = mpsc::unbounded();
|
let (toplevels_tx, toplevel_rx) = mpsc::unbounded();
|
||||||
let (calloop_tx, calloop_rx) = calloop::channel::channel();
|
let (calloop_tx, calloop_rx) = calloop::channel::channel();
|
||||||
let _handle = std::thread::spawn(move || toplevel_handler(toplevels_tx, calloop_rx));
|
let _handle = std::thread::spawn(move || toplevel_handler(toplevels_tx, calloop_rx));
|
||||||
|
|
@ -144,8 +150,8 @@ impl<W: AsyncWrite + Unpin> App<W> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(handle) = self.toplevels.iter().find_map(|t| {
|
if let Some(handle) = self.toplevels.iter().find_map(|t| {
|
||||||
if t.0.id().protocol_id() == id {
|
if t.foreign_toplevel.id().protocol_id() == id {
|
||||||
Some(t.0.clone())
|
Some(t.foreign_toplevel.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -160,8 +166,8 @@ impl<W: AsyncWrite + Unpin> App<W> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(handle) = self.toplevels.iter().find_map(|t| {
|
if let Some(handle) = self.toplevels.iter().find_map(|t| {
|
||||||
if t.0.id().protocol_id() == id {
|
if t.foreign_toplevel.id().protocol_id() == id {
|
||||||
Some(t.0.clone())
|
Some(t.foreign_toplevel.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +179,7 @@ impl<W: AsyncWrite + Unpin> App<W> {
|
||||||
async fn search(&mut self, query: &str) {
|
async fn search(&mut self, query: &str) {
|
||||||
let query = query.to_ascii_lowercase();
|
let query = query.to_ascii_lowercase();
|
||||||
|
|
||||||
for (handle, info) in self.toplevels.iter().rev() {
|
for info in self.toplevels.iter().rev() {
|
||||||
let entry = if query.is_empty() {
|
let entry = if query.is_empty() {
|
||||||
fde::matching::get_best_match(
|
fde::matching::get_best_match(
|
||||||
&[&info.app_id, &info.title],
|
&[&info.app_id, &info.title],
|
||||||
|
|
@ -214,8 +220,8 @@ impl<W: AsyncWrite + Unpin> App<W> {
|
||||||
|
|
||||||
let response = PluginResponse::Append(PluginSearchResult {
|
let response = PluginResponse::Append(PluginSearchResult {
|
||||||
// XXX protocol id may be re-used later
|
// XXX protocol id may be re-used later
|
||||||
id: handle.id().protocol_id(),
|
id: info.foreign_toplevel.id().protocol_id(),
|
||||||
window: Some((0, handle.id().clone().protocol_id())),
|
window: Some((0, info.foreign_toplevel.id().protocol_id())),
|
||||||
description: info.title.clone(),
|
description: info.title.clone(),
|
||||||
name: get_description(de, &self.locales),
|
name: get_description(de, &self.locales),
|
||||||
icon: Some(IconSource::Name(icon_name)),
|
icon: Some(IconSource::Name(icon_name)),
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use cctk::{
|
||||||
toplevel_info::{ToplevelInfo, ToplevelInfoHandler, ToplevelInfoState},
|
toplevel_info::{ToplevelInfo, ToplevelInfoHandler, ToplevelInfoState},
|
||||||
toplevel_management::{ToplevelManagerHandler, ToplevelManagerState},
|
toplevel_management::{ToplevelManagerHandler, ToplevelManagerState},
|
||||||
wayland_client::{self, WEnum},
|
wayland_client::{self, WEnum},
|
||||||
|
wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||||
};
|
};
|
||||||
use sctk::{
|
use sctk::{
|
||||||
self,
|
self,
|
||||||
|
|
@ -15,7 +16,7 @@ use sctk::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use cosmic_protocols::{
|
use cosmic_protocols::{
|
||||||
toplevel_info::v1::client::zcosmic_toplevel_handle_v1::{self, ZcosmicToplevelHandleV1},
|
toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
||||||
toplevel_management::v1::client::zcosmic_toplevel_manager_v1,
|
toplevel_management::v1::client::zcosmic_toplevel_manager_v1,
|
||||||
};
|
};
|
||||||
use futures::channel::mpsc::UnboundedSender;
|
use futures::channel::mpsc::UnboundedSender;
|
||||||
|
|
@ -25,23 +26,35 @@ use wayland_client::{globals::registry_queue_init, Connection, QueueHandle};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ToplevelAction {
|
pub enum ToplevelAction {
|
||||||
Activate(ZcosmicToplevelHandleV1),
|
Activate(ExtForeignToplevelHandleV1),
|
||||||
Close(ZcosmicToplevelHandleV1),
|
Close(ExtForeignToplevelHandleV1),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TopLevelsUpdate = Vec<(
|
pub enum ToplevelUpdate {
|
||||||
zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
Info(ToplevelInfo),
|
||||||
Option<ToplevelInfo>,
|
Remove(ExtForeignToplevelHandleV1),
|
||||||
)>;
|
}
|
||||||
|
|
||||||
struct AppData {
|
struct AppData {
|
||||||
exit: bool,
|
exit: bool,
|
||||||
tx: UnboundedSender<TopLevelsUpdate>,
|
tx: UnboundedSender<Vec<ToplevelUpdate>>,
|
||||||
registry_state: RegistryState,
|
registry_state: RegistryState,
|
||||||
toplevel_info_state: ToplevelInfoState,
|
toplevel_info_state: ToplevelInfoState,
|
||||||
toplevel_manager_state: ToplevelManagerState,
|
toplevel_manager_state: ToplevelManagerState,
|
||||||
seat_state: SeatState,
|
seat_state: SeatState,
|
||||||
pending_update: HashSet<zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1>,
|
pending_update: HashSet<ExtForeignToplevelHandleV1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppData {
|
||||||
|
fn cosmic_toplevel_for_foreign(
|
||||||
|
&self,
|
||||||
|
foreign_toplevel: &ExtForeignToplevelHandleV1,
|
||||||
|
) -> Option<&ZcosmicToplevelHandleV1> {
|
||||||
|
self.toplevel_info_state
|
||||||
|
.info(foreign_toplevel)?
|
||||||
|
.cosmic_toplevel
|
||||||
|
.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProvidesRegistryState for AppData {
|
impl ProvidesRegistryState for AppData {
|
||||||
|
|
@ -103,7 +116,7 @@ impl ToplevelInfoHandler for AppData {
|
||||||
&mut self,
|
&mut self,
|
||||||
_conn: &Connection,
|
_conn: &Connection,
|
||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
toplevel: &ExtForeignToplevelHandleV1,
|
||||||
) {
|
) {
|
||||||
self.pending_update.insert(toplevel.clone());
|
self.pending_update.insert(toplevel.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +125,7 @@ impl ToplevelInfoHandler for AppData {
|
||||||
&mut self,
|
&mut self,
|
||||||
_conn: &Connection,
|
_conn: &Connection,
|
||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
toplevel: &ExtForeignToplevelHandleV1,
|
||||||
) {
|
) {
|
||||||
self.pending_update.insert(toplevel.clone());
|
self.pending_update.insert(toplevel.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -121,20 +134,20 @@ impl ToplevelInfoHandler for AppData {
|
||||||
&mut self,
|
&mut self,
|
||||||
_conn: &Connection,
|
_conn: &Connection,
|
||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
toplevel: &ExtForeignToplevelHandleV1,
|
||||||
) {
|
) {
|
||||||
self.pending_update.insert(toplevel.clone());
|
self.pending_update.insert(toplevel.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn info_done(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>) {
|
fn info_done(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>) {
|
||||||
let mut res = Vec::with_capacity(self.pending_update.len());
|
let res = self
|
||||||
|
.pending_update
|
||||||
for toplevel_handle in self.pending_update.drain() {
|
.drain()
|
||||||
res.push((
|
.map(|handle| match self.toplevel_info_state.info(&handle) {
|
||||||
toplevel_handle.clone(),
|
Some(info) => ToplevelUpdate::Info(info.clone()),
|
||||||
self.toplevel_info_state.info(&toplevel_handle).cloned(),
|
None => ToplevelUpdate::Remove(handle),
|
||||||
));
|
})
|
||||||
}
|
.collect();
|
||||||
|
|
||||||
if let Err(err) = self.tx.unbounded_send(res) {
|
if let Err(err) = self.tx.unbounded_send(res) {
|
||||||
warn!("{err}");
|
warn!("{err}");
|
||||||
|
|
@ -143,7 +156,7 @@ impl ToplevelInfoHandler for AppData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn toplevel_handler(
|
pub(crate) fn toplevel_handler(
|
||||||
tx: UnboundedSender<TopLevelsUpdate>,
|
tx: UnboundedSender<Vec<ToplevelUpdate>>,
|
||||||
rx: calloop::channel::Channel<ToplevelAction>,
|
rx: calloop::channel::Channel<ToplevelAction>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let conn = Connection::connect_to_env()?;
|
let conn = Connection::connect_to_env()?;
|
||||||
|
|
@ -159,15 +172,18 @@ pub(crate) fn toplevel_handler(
|
||||||
calloop::channel::Event::Msg(req) => match req {
|
calloop::channel::Event::Msg(req) => match req {
|
||||||
ToplevelAction::Activate(handle) => {
|
ToplevelAction::Activate(handle) => {
|
||||||
let manager = &state.toplevel_manager_state.manager;
|
let manager = &state.toplevel_manager_state.manager;
|
||||||
let state = &state.seat_state;
|
|
||||||
// TODO Ashley how to choose the seat in a multi-seat setup?
|
// TODO Ashley how to choose the seat in a multi-seat setup?
|
||||||
for s in state.seats() {
|
if let Some(cosmic_toplevel) = state.cosmic_toplevel_for_foreign(&handle) {
|
||||||
manager.activate(&handle, &s);
|
for s in state.seat_state.seats() {
|
||||||
|
manager.activate(cosmic_toplevel, &s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ToplevelAction::Close(handle) => {
|
ToplevelAction::Close(handle) => {
|
||||||
let manager = &state.toplevel_manager_state.manager;
|
let manager = &state.toplevel_manager_state.manager;
|
||||||
manager.close(&handle);
|
if let Some(cosmic_toplevel) = state.cosmic_toplevel_for_foreign(&handle) {
|
||||||
|
manager.close(cosmic_toplevel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
calloop::channel::Event::Closed => {
|
calloop::channel::Event::Closed => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue