Skip to content

Commit 0541d90

Browse files
wiiznokeswash2
authored andcommitted
feat: reliable alt tab switching !!
1 parent 49c5ef2 commit 0541d90

File tree

2 files changed

+56
-68
lines changed

2 files changed

+56
-68
lines changed

plugins/src/cosmic_toplevel/mod.rs

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use cctk::{cosmic_protocols, sctk::reexports::calloop, toplevel_info::ToplevelIn
66
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1;
77
use fde::DesktopEntry;
88
use freedesktop_desktop_entry as fde;
9+
use toplevel_handler::TopLevelsUpdate;
910
use tracing::{debug, error, info, warn};
1011

1112
use crate::desktop_entries::utils::{get_description, is_session_cosmic};
@@ -21,10 +22,9 @@ use pop_launcher::{
2122
};
2223
use std::borrow::Cow;
2324
use std::iter;
24-
use std::collections::VecDeque;
2525
use tokio::io::{AsyncWrite, AsyncWriteExt};
2626

27-
use self::toplevel_handler::{toplevel_handler, ToplevelAction, ToplevelEvent};
27+
use self::toplevel_handler::{toplevel_handler, ToplevelAction};
2828

2929
pub async fn main() {
3030
let mut tx = async_stdout();
@@ -66,40 +66,33 @@ pub async fn main() {
6666
}
6767
};
6868
}
69-
Either::Right((Some(event), second_to_next_request)) => {
69+
Either::Right((Some(updates), second_to_next_request)) => {
7070
next_event = toplevel_rx.next();
7171
next_request = second_to_next_request;
7272

73-
match event {
74-
ToplevelEvent::Add(handle, info) => {
75-
debug!("add {}", &info.app_id);
76-
app.toplevels.retain(|t| t.0 != handle);
77-
app.toplevels.push_front((handle, info));
78-
}
79-
ToplevelEvent::Remove(handle) => {
80-
if let Some(pos) = app.toplevels.iter().position(|t| t.0 == handle) {
81-
app.toplevels.remove(pos);
82-
// ignore requests for this id until after the next search
83-
app.ids_to_ignore.push(handle.id().protocol_id());
84-
} else {
85-
warn!("ToplevelEvent::Remove, no toplevel found");
73+
for (handle, info) in updates {
74+
match info {
75+
Some(info) => {
76+
if let Some(pos) = app.toplevels.iter().position(|t| t.0 == handle) {
77+
if info.state.contains(&State::Activated) {
78+
app.toplevels.remove(pos);
79+
app.toplevels.push((handle, Box::new(info)));
80+
} else {
81+
app.toplevels[pos].1 = Box::new(info);
82+
}
83+
} else {
84+
app.toplevels.push((handle, Box::new(info)));
85+
}
8686
}
87-
}
88-
ToplevelEvent::Update(handle, info) => {
89-
debug!("Update {}", &info.app_id);
90-
debug!("Update {:?}", &info.state);
91-
92-
if let Some(pos) = app.toplevels.iter().position(|t| t.0 == handle) {
93-
if info.state.contains(&State::Activated) {
94-
debug!("Update {:?}: push front", &info.app_id);
87+
// no info means remove
88+
None => {
89+
if let Some(pos) = app.toplevels.iter().position(|t| t.0 == handle) {
9590
app.toplevels.remove(pos);
96-
app.toplevels.push_front((handle, info));
91+
// ignore requests for this id until after the next search
92+
app.ids_to_ignore.push(handle.id().protocol_id());
9793
} else {
98-
app.toplevels[pos].1 = info;
94+
warn!("no toplevel to remove");
9995
}
100-
} else {
101-
warn!("ToplevelEvent::Update, no toplevel found");
102-
app.toplevels.push_front((handle, info));
10396
}
10497
}
10598
}
@@ -113,14 +106,13 @@ struct App<W> {
113106
locales: Vec<String>,
114107
desktop_entries: Vec<DesktopEntry<'static>>,
115108
ids_to_ignore: Vec<u32>,
116-
// XXX: use LinkedList, and Box the tuple because it will be re ordered a lot?
117-
toplevels: VecDeque<(ZcosmicToplevelHandleV1, ToplevelInfo)>,
109+
toplevels: Vec<(ZcosmicToplevelHandleV1, Box<ToplevelInfo>)>,
118110
calloop_tx: calloop::channel::Sender<ToplevelAction>,
119111
tx: W,
120112
}
121113

122114
impl<W: AsyncWrite + Unpin> App<W> {
123-
fn new(tx: W) -> (Self, mpsc::UnboundedReceiver<ToplevelEvent>) {
115+
fn new(tx: W) -> (Self, mpsc::UnboundedReceiver<TopLevelsUpdate>) {
124116
let (toplevels_tx, toplevel_rx) = mpsc::unbounded();
125117
let (calloop_tx, calloop_rx) = calloop::channel::channel();
126118
let _handle = std::thread::spawn(move || toplevel_handler(toplevels_tx, calloop_rx));
@@ -138,7 +130,7 @@ impl<W: AsyncWrite + Unpin> App<W> {
138130
locales,
139131
desktop_entries,
140132
ids_to_ignore: Vec::new(),
141-
toplevels: VecDeque::new(),
133+
toplevels: Vec::new(),
142134
calloop_tx,
143135
tx,
144136
},
@@ -181,7 +173,7 @@ impl<W: AsyncWrite + Unpin> App<W> {
181173
async fn search(&mut self, query: &str) {
182174
let query = query.to_ascii_lowercase();
183175

184-
for (handle, info) in &self.toplevels {
176+
for (handle, info) in self.toplevels.iter().rev() {
185177
let entry = if query.is_empty() {
186178
fde::matching::get_best_match(
187179
&[&info.app_id, &info.title],

plugins/src/cosmic_toplevel/toplevel_handler.rs

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use std::collections::HashSet;
2+
13
use cctk::{
24
cosmic_protocols,
35
toplevel_info::{ToplevelInfo, ToplevelInfoHandler, ToplevelInfoState},
46
toplevel_management::{ToplevelManagerHandler, ToplevelManagerState},
5-
wayland_client::{self, protocol::wl_output::WlOutput, WEnum},
7+
wayland_client::{self, WEnum},
68
};
79
use sctk::{
810
self,
@@ -15,10 +17,10 @@ use sctk::{
1517
use cosmic_protocols::{
1618
toplevel_info::v1::client::zcosmic_toplevel_handle_v1::{self, ZcosmicToplevelHandleV1},
1719
toplevel_management::v1::client::zcosmic_toplevel_manager_v1,
18-
workspace::v1::server::zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
1920
};
2021
use futures::channel::mpsc::UnboundedSender;
2122
use sctk::registry::{ProvidesRegistryState, RegistryState};
23+
use tracing::warn;
2224
use wayland_client::{globals::registry_queue_init, Connection, QueueHandle};
2325

2426
#[derive(Debug, Clone)]
@@ -27,31 +29,19 @@ pub enum ToplevelAction {
2729
Close(ZcosmicToplevelHandleV1),
2830
}
2931

30-
#[derive(Debug, Clone)]
31-
pub enum ToplevelEvent {
32-
Add(ZcosmicToplevelHandleV1, ToplevelInfo),
33-
Remove(ZcosmicToplevelHandleV1),
34-
Update(ZcosmicToplevelHandleV1, ToplevelInfo),
35-
}
36-
37-
#[allow(dead_code)]
38-
#[derive(Debug, Clone)]
39-
pub struct Toplevel {
40-
pub name: String,
41-
pub app_id: String,
42-
pub toplevel_handle: ZcosmicToplevelHandleV1,
43-
pub states: Vec<zcosmic_toplevel_handle_v1::State>,
44-
pub output: Option<WlOutput>,
45-
pub workspace: Option<ZcosmicWorkspaceHandleV1>,
46-
}
32+
pub type TopLevelsUpdate = Vec<(
33+
zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
34+
Option<ToplevelInfo>,
35+
)>;
4736

4837
struct AppData {
4938
exit: bool,
50-
tx: UnboundedSender<ToplevelEvent>,
39+
tx: UnboundedSender<TopLevelsUpdate>,
5140
registry_state: RegistryState,
5241
toplevel_info_state: ToplevelInfoState,
5342
toplevel_manager_state: ToplevelManagerState,
5443
seat_state: SeatState,
44+
pending_update: HashSet<zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1>,
5545
}
5646

5747
impl ProvidesRegistryState for AppData {
@@ -115,11 +105,7 @@ impl ToplevelInfoHandler for AppData {
115105
_qh: &QueueHandle<Self>,
116106
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
117107
) {
118-
if let Some(info) = self.toplevel_info_state.info(toplevel) {
119-
let _ = self
120-
.tx
121-
.unbounded_send(ToplevelEvent::Add(toplevel.clone(), info.clone()));
122-
}
108+
self.pending_update.insert(toplevel.clone());
123109
}
124110

125111
fn update_toplevel(
@@ -128,11 +114,7 @@ impl ToplevelInfoHandler for AppData {
128114
_qh: &QueueHandle<Self>,
129115
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
130116
) {
131-
if let Some(info) = self.toplevel_info_state.info(toplevel) {
132-
let _ = self
133-
.tx
134-
.unbounded_send(ToplevelEvent::Update(toplevel.clone(), info.clone()));
135-
}
117+
self.pending_update.insert(toplevel.clone());
136118
}
137119

138120
fn toplevel_closed(
@@ -141,14 +123,27 @@ impl ToplevelInfoHandler for AppData {
141123
_qh: &QueueHandle<Self>,
142124
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
143125
) {
144-
let _ = self
145-
.tx
146-
.unbounded_send(ToplevelEvent::Remove(toplevel.clone()));
126+
self.pending_update.insert(toplevel.clone());
127+
}
128+
129+
fn info_done(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>) {
130+
let mut res = Vec::with_capacity(self.pending_update.len());
131+
132+
for toplevel_handle in self.pending_update.drain() {
133+
res.push((
134+
toplevel_handle.clone(),
135+
self.toplevel_info_state.info(&toplevel_handle).cloned(),
136+
));
137+
}
138+
139+
if let Err(err) = self.tx.unbounded_send(res) {
140+
warn!("{err}");
141+
}
147142
}
148143
}
149144

150145
pub(crate) fn toplevel_handler(
151-
tx: UnboundedSender<ToplevelEvent>,
146+
tx: UnboundedSender<TopLevelsUpdate>,
152147
rx: calloop::channel::Channel<ToplevelAction>,
153148
) -> anyhow::Result<()> {
154149
let conn = Connection::connect_to_env()?;
@@ -188,6 +183,7 @@ pub(crate) fn toplevel_handler(
188183
toplevel_info_state: ToplevelInfoState::new(&registry_state, &qh),
189184
toplevel_manager_state: ToplevelManagerState::new(&registry_state, &qh),
190185
registry_state,
186+
pending_update: HashSet::new(),
191187
};
192188

193189
loop {

0 commit comments

Comments
 (0)