Update for toplevel-info cctk changes
Requires pop-os/cosmic-protocols#49. The duplication between applets, and cosmic-workspace/xdg-desktop-portal-cosmic, should be moved to shared abstractions. But that can be done after moving to `ext-image-copy-capture`. `ToplevelInfo` now contains both ext and cosmic handles, so the tuples of handles and info are needed. Use just the info.
This commit is contained in:
parent
69fd2b62df
commit
e9848a2d4f
9 changed files with 218 additions and 178 deletions
|
|
@ -11,8 +11,8 @@ use cosmic::{
|
|||
app,
|
||||
applet::cosmic_panel_config::PanelAnchor,
|
||||
cctk::{
|
||||
cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
||||
sctk::reexports::calloop, toplevel_info::ToplevelInfo,
|
||||
wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||
},
|
||||
desktop::DesktopEntryData,
|
||||
iced::{
|
||||
|
|
@ -45,12 +45,7 @@ pub fn run() -> cosmic::iced::Result {
|
|||
#[derive(Default)]
|
||||
struct Minimize {
|
||||
core: cosmic::app::Core,
|
||||
apps: Vec<(
|
||||
ZcosmicToplevelHandleV1,
|
||||
ToplevelInfo,
|
||||
DesktopEntryData,
|
||||
Option<WaylandImage>,
|
||||
)>,
|
||||
apps: Vec<(ToplevelInfo, DesktopEntryData, Option<WaylandImage>)>,
|
||||
tx: Option<calloop::channel::Sender<WaylandRequest>>,
|
||||
overflow_popup: Option<window::Id>,
|
||||
}
|
||||
|
|
@ -83,7 +78,7 @@ impl Minimize {
|
|||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
Wayland(WaylandUpdate),
|
||||
Activate(ZcosmicToplevelHandleV1),
|
||||
Activate(ExtForeignToplevelHandleV1),
|
||||
Closed(window::Id),
|
||||
OpenOverflowPopup,
|
||||
CloseOverflowPopup,
|
||||
|
|
@ -127,7 +122,7 @@ impl cosmic::Application for Minimize {
|
|||
panic!("Wayland Subscription ended...")
|
||||
}
|
||||
WaylandUpdate::Toplevel(t) => match t {
|
||||
ToplevelUpdate::Add(handle, info) | ToplevelUpdate::Update(handle, info) => {
|
||||
ToplevelUpdate::Add(info) | ToplevelUpdate::Update(info) => {
|
||||
let data = |id| {
|
||||
cosmic::desktop::load_applications_for_app_ids(
|
||||
None,
|
||||
|
|
@ -137,24 +132,32 @@ impl cosmic::Application for Minimize {
|
|||
)
|
||||
.remove(0)
|
||||
};
|
||||
if let Some(pos) = self.apps.iter_mut().position(|a| a.0 == handle) {
|
||||
if self.apps[pos].1.app_id != info.app_id {
|
||||
self.apps[pos].2 = data(&info.app_id)
|
||||
if let Some(pos) = self
|
||||
.apps
|
||||
.iter_mut()
|
||||
.position(|a| a.0.foreign_toplevel == info.foreign_toplevel)
|
||||
{
|
||||
if self.apps[pos].0.app_id != info.app_id {
|
||||
self.apps[pos].1 = data(&info.app_id)
|
||||
}
|
||||
self.apps[pos].1 = info;
|
||||
self.apps[pos].0 = info;
|
||||
} else {
|
||||
let data = data(&info.app_id);
|
||||
self.apps.push((handle, info, data, None));
|
||||
self.apps.push((info, data, None));
|
||||
}
|
||||
}
|
||||
ToplevelUpdate::Remove(handle) => {
|
||||
self.apps.retain(|a| a.0 != handle);
|
||||
self.apps.retain(|a| a.0.foreign_toplevel != handle);
|
||||
self.apps.shrink_to_fit();
|
||||
}
|
||||
},
|
||||
WaylandUpdate::Image(handle, img) => {
|
||||
if let Some(pos) = self.apps.iter().position(|a| a.0 == handle) {
|
||||
self.apps[pos].3 = Some(img);
|
||||
if let Some(pos) = self
|
||||
.apps
|
||||
.iter()
|
||||
.position(|a| a.0.foreign_toplevel == handle)
|
||||
{
|
||||
self.apps[pos].2 = Some(img);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -230,31 +233,29 @@ impl cosmic::Application for Minimize {
|
|||
let padding = self.core.applet.suggested_padding(false);
|
||||
let theme = self.core.system_theme().cosmic();
|
||||
let space_xxs = theme.space_xxs();
|
||||
let icon_buttons = self.apps[..max_icon_count]
|
||||
.iter()
|
||||
.map(|(handle, _, data, img)| {
|
||||
tooltip(
|
||||
Element::from(crate::window_image::WindowImage::new(
|
||||
img.clone(),
|
||||
&data.icon,
|
||||
width as f32,
|
||||
Message::Activate(handle.clone()),
|
||||
padding,
|
||||
)),
|
||||
text(data.name.clone()).shaping(text::Shaping::Advanced),
|
||||
// tooltip::Position::FollowCursor,
|
||||
// FIXME tooltip fails to appear when created as indicated in design
|
||||
// maybe it should be a subsurface
|
||||
match self.core.applet.anchor {
|
||||
PanelAnchor::Left => tooltip::Position::Right,
|
||||
PanelAnchor::Right => tooltip::Position::Left,
|
||||
PanelAnchor::Top => tooltip::Position::Bottom,
|
||||
PanelAnchor::Bottom => tooltip::Position::Top,
|
||||
},
|
||||
)
|
||||
.snap_within_viewport(false)
|
||||
.into()
|
||||
});
|
||||
let icon_buttons = self.apps[..max_icon_count].iter().map(|(info, data, img)| {
|
||||
tooltip(
|
||||
Element::from(crate::window_image::WindowImage::new(
|
||||
img.clone(),
|
||||
&data.icon,
|
||||
width as f32,
|
||||
Message::Activate(info.foreign_toplevel.clone()),
|
||||
padding,
|
||||
)),
|
||||
text(data.name.clone()).shaping(text::Shaping::Advanced),
|
||||
// tooltip::Position::FollowCursor,
|
||||
// FIXME tooltip fails to appear when created as indicated in design
|
||||
// maybe it should be a subsurface
|
||||
match self.core.applet.anchor {
|
||||
PanelAnchor::Left => tooltip::Position::Right,
|
||||
PanelAnchor::Right => tooltip::Position::Left,
|
||||
PanelAnchor::Top => tooltip::Position::Bottom,
|
||||
PanelAnchor::Bottom => tooltip::Position::Top,
|
||||
},
|
||||
)
|
||||
.snap_within_viewport(false)
|
||||
.into()
|
||||
});
|
||||
let overflow_btn = if max_icon_count < self.apps.len() {
|
||||
let icon = match self.core.applet.anchor {
|
||||
PanelAnchor::Bottom => "go-up-symbolic",
|
||||
|
|
@ -335,31 +336,29 @@ impl cosmic::Application for Minimize {
|
|||
let padding = self.core.applet.suggested_padding(false);
|
||||
let theme = self.core.system_theme().cosmic();
|
||||
let space_xxs = theme.space_xxs();
|
||||
let icon_buttons = self.apps[max_icon_count..]
|
||||
.iter()
|
||||
.map(|(handle, _, data, img)| {
|
||||
tooltip(
|
||||
Element::from(crate::window_image::WindowImage::new(
|
||||
img.clone(),
|
||||
&data.icon,
|
||||
width as f32,
|
||||
Message::Activate(handle.clone()),
|
||||
padding,
|
||||
)),
|
||||
text(data.name.clone()).shaping(text::Shaping::Advanced),
|
||||
// tooltip::Position::FollowCursor,
|
||||
// FIXME tooltip fails to appear when created as indicated in design
|
||||
// maybe it should be a subsurface
|
||||
match self.core.applet.anchor {
|
||||
PanelAnchor::Left => tooltip::Position::Right,
|
||||
PanelAnchor::Right => tooltip::Position::Left,
|
||||
PanelAnchor::Top => tooltip::Position::Bottom,
|
||||
PanelAnchor::Bottom => tooltip::Position::Top,
|
||||
},
|
||||
)
|
||||
.snap_within_viewport(false)
|
||||
.into()
|
||||
});
|
||||
let icon_buttons = self.apps[max_icon_count..].iter().map(|(info, data, img)| {
|
||||
tooltip(
|
||||
Element::from(crate::window_image::WindowImage::new(
|
||||
img.clone(),
|
||||
&data.icon,
|
||||
width as f32,
|
||||
Message::Activate(info.foreign_toplevel.clone()),
|
||||
padding,
|
||||
)),
|
||||
text(data.name.clone()).shaping(text::Shaping::Advanced),
|
||||
// tooltip::Position::FollowCursor,
|
||||
// FIXME tooltip fails to appear when created as indicated in design
|
||||
// maybe it should be a subsurface
|
||||
match self.core.applet.anchor {
|
||||
PanelAnchor::Left => tooltip::Position::Right,
|
||||
PanelAnchor::Right => tooltip::Position::Left,
|
||||
PanelAnchor::Top => tooltip::Position::Bottom,
|
||||
PanelAnchor::Bottom => tooltip::Position::Top,
|
||||
},
|
||||
)
|
||||
.snap_within_viewport(false)
|
||||
.into()
|
||||
});
|
||||
|
||||
// TODO optional dividers on ends if detects app list neighbor
|
||||
// not sure the best way to tell if there is an adjacent app-list
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ use cosmic::{
|
|||
},
|
||||
Dispatch,
|
||||
},
|
||||
wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||
},
|
||||
iced_futures::futures,
|
||||
};
|
||||
|
|
@ -291,7 +292,17 @@ impl ToplevelManagerHandler for AppData {
|
|||
}
|
||||
}
|
||||
impl AppData {
|
||||
fn send_image(&self, handle: ZcosmicToplevelHandleV1) {
|
||||
fn cosmic_toplevel(
|
||||
&self,
|
||||
handle: &ExtForeignToplevelHandleV1,
|
||||
) -> Option<ZcosmicToplevelHandleV1> {
|
||||
self.toplevel_info_state
|
||||
.info(&handle)?
|
||||
.cosmic_toplevel
|
||||
.clone()
|
||||
}
|
||||
|
||||
fn send_image(&self, handle: ExtForeignToplevelHandleV1) {
|
||||
let mut tx = self.tx.clone();
|
||||
let capure_data = CaptureData {
|
||||
qh: self.queue_handle.clone(),
|
||||
|
|
@ -299,6 +310,9 @@ impl AppData {
|
|||
wl_shm: self.shm_state.wl_shm().clone(),
|
||||
capturer: self.screencopy_state.capturer().clone(),
|
||||
};
|
||||
let Some(cosmic_toplevel) = self.cosmic_toplevel(&handle) else {
|
||||
return;
|
||||
};
|
||||
std::thread::spawn(move || {
|
||||
use std::ffi::CStr;
|
||||
let name =
|
||||
|
|
@ -309,7 +323,7 @@ impl AppData {
|
|||
};
|
||||
|
||||
// XXX is this going to use to much memory?
|
||||
let img = capure_data.capture_source_shm_fd(false, handle.clone(), fd, None);
|
||||
let img = capure_data.capture_source_shm_fd(false, cosmic_toplevel, fd, None);
|
||||
if let Some(img) = img {
|
||||
let Ok(mut img) = img.image() else {
|
||||
tracing::error!("Failed to get RgbaImage");
|
||||
|
|
@ -353,7 +367,7 @@ impl ToplevelInfoHandler for AppData {
|
|||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
||||
toplevel: &ExtForeignToplevelHandleV1,
|
||||
) {
|
||||
if let Some(info) = self.toplevel_info_state.info(toplevel) {
|
||||
if info
|
||||
|
|
@ -362,9 +376,10 @@ impl ToplevelInfoHandler for AppData {
|
|||
{
|
||||
// spawn thread for sending the image
|
||||
self.send_image(toplevel.clone());
|
||||
let _ = futures::executor::block_on(self.tx.send(WaylandUpdate::Toplevel(
|
||||
ToplevelUpdate::Add(toplevel.clone(), info.clone()),
|
||||
)));
|
||||
let _ = futures::executor::block_on(
|
||||
self.tx
|
||||
.send(WaylandUpdate::Toplevel(ToplevelUpdate::Add(info.clone()))),
|
||||
);
|
||||
} else {
|
||||
let _ = futures::executor::block_on(self.tx.send(WaylandUpdate::Toplevel(
|
||||
ToplevelUpdate::Remove(toplevel.clone()),
|
||||
|
|
@ -377,7 +392,7 @@ impl ToplevelInfoHandler for AppData {
|
|||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
||||
toplevel: &ExtForeignToplevelHandleV1,
|
||||
) {
|
||||
if let Some(info) = self.toplevel_info_state.info(toplevel) {
|
||||
if info
|
||||
|
|
@ -386,7 +401,7 @@ impl ToplevelInfoHandler for AppData {
|
|||
{
|
||||
self.send_image(toplevel.clone());
|
||||
let _ = futures::executor::block_on(self.tx.send(WaylandUpdate::Toplevel(
|
||||
ToplevelUpdate::Update(toplevel.clone(), info.clone()),
|
||||
ToplevelUpdate::Update(info.clone()),
|
||||
)));
|
||||
} else {
|
||||
let _ = futures::executor::block_on(self.tx.send(WaylandUpdate::Toplevel(
|
||||
|
|
@ -400,7 +415,7 @@ impl ToplevelInfoHandler for AppData {
|
|||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
||||
toplevel: &ExtForeignToplevelHandleV1,
|
||||
) {
|
||||
let _ = futures::executor::block_on(self.tx.send(WaylandUpdate::Toplevel(
|
||||
ToplevelUpdate::Remove(toplevel.clone()),
|
||||
|
|
@ -442,7 +457,9 @@ pub(crate) fn wayland_handler(
|
|||
ToplevelRequest::Activate(handle) => {
|
||||
if let Some(seat) = state.seat_state.seats().next() {
|
||||
let manager = &state.toplevel_manager_state.manager;
|
||||
manager.activate(&handle, &seat);
|
||||
if let Some(cosmic_toplevel) = state.cosmic_toplevel(&handle) {
|
||||
manager.activate(&cosmic_toplevel, &seat);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@
|
|||
//! Source: `Interface '/org/freedesktop/UPower/KbdBacklight' from service 'org.freedesktop.UPower' on system bus`.
|
||||
use cctk::{sctk::reexports::calloop, toplevel_info::ToplevelInfo};
|
||||
use cosmic::{
|
||||
cctk::{self, cosmic_protocols},
|
||||
cctk::{
|
||||
self,
|
||||
wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||
},
|
||||
iced::{self, Subscription},
|
||||
iced_core::image::Bytes,
|
||||
iced_futures::{futures, stream},
|
||||
};
|
||||
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1;
|
||||
use futures::SinkExt;
|
||||
use image::EncodableLayout;
|
||||
use std::fmt::Debug;
|
||||
|
|
@ -45,7 +47,7 @@ pub enum WaylandUpdate {
|
|||
Init(calloop::channel::Sender<WaylandRequest>),
|
||||
Finished,
|
||||
Toplevel(ToplevelUpdate),
|
||||
Image(ZcosmicToplevelHandleV1, WaylandImage),
|
||||
Image(ExtForeignToplevelHandleV1, WaylandImage),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -73,9 +75,9 @@ impl AsRef<[u8]> for WaylandImage {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ToplevelUpdate {
|
||||
Add(ZcosmicToplevelHandleV1, ToplevelInfo),
|
||||
Update(ZcosmicToplevelHandleV1, ToplevelInfo),
|
||||
Remove(ZcosmicToplevelHandleV1),
|
||||
Add(ToplevelInfo),
|
||||
Update(ToplevelInfo),
|
||||
Remove(ExtForeignToplevelHandleV1),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -85,5 +87,5 @@ pub enum WaylandRequest {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ToplevelRequest {
|
||||
Activate(ZcosmicToplevelHandleV1),
|
||||
Activate(ExtForeignToplevelHandleV1),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue