2022-12-30 14:07:39 -08:00
|
|
|
use cctk::{
|
2022-12-30 15:21:05 -08:00
|
|
|
cosmic_protocols::{
|
|
|
|
|
toplevel_info::v1::client::zcosmic_toplevel_handle_v1,
|
2023-01-04 15:17:57 -08:00
|
|
|
toplevel_management::v1::client::zcosmic_toplevel_manager_v1,
|
2023-01-04 14:41:44 -08:00
|
|
|
workspace::v1::client::{zcosmic_workspace_handle_v1, zcosmic_workspace_manager_v1},
|
2022-12-30 15:21:05 -08:00
|
|
|
},
|
2022-12-30 14:07:39 -08:00
|
|
|
sctk::shell::layer::{Anchor, KeyboardInteractivity, Layer},
|
2022-12-30 15:21:05 -08:00
|
|
|
toplevel_info::ToplevelInfo,
|
2023-01-04 15:41:19 -08:00
|
|
|
wayland_client::{
|
|
|
|
|
protocol::{wl_output, wl_seat},
|
|
|
|
|
Connection, QueueHandle, WEnum,
|
|
|
|
|
},
|
2022-12-30 14:07:39 -08:00
|
|
|
};
|
2023-01-17 12:36:05 -08:00
|
|
|
use cosmic::{
|
|
|
|
|
iced::{
|
|
|
|
|
self,
|
|
|
|
|
event::wayland::{Event as WaylandEvent, OutputEvent},
|
|
|
|
|
keyboard::KeyCode,
|
|
|
|
|
widget, Application, Command, Element, Subscription,
|
|
|
|
|
},
|
|
|
|
|
iced_native::{
|
|
|
|
|
command::platform_specific::wayland::layer_surface::{
|
|
|
|
|
IcedOutput, SctkLayerSurfaceSettings,
|
|
|
|
|
},
|
|
|
|
|
window::Id as SurfaceId,
|
|
|
|
|
},
|
2022-12-30 14:07:39 -08:00
|
|
|
};
|
|
|
|
|
use iced_sctk::{
|
|
|
|
|
application::SurfaceIdWrapper,
|
|
|
|
|
commands::layer_surface::{destroy_layer_surface, get_layer_surface},
|
2023-01-04 14:41:44 -08:00
|
|
|
settings::InitialSurface,
|
2022-12-30 14:07:39 -08:00
|
|
|
};
|
2023-01-04 14:41:44 -08:00
|
|
|
use std::{collections::HashMap, mem, process};
|
2022-12-30 14:07:39 -08:00
|
|
|
|
2023-01-19 16:29:20 -08:00
|
|
|
mod toggle_dbus;
|
2022-12-30 14:07:39 -08:00
|
|
|
mod wayland;
|
|
|
|
|
|
2022-12-30 15:21:05 -08:00
|
|
|
#[derive(Clone, Debug)]
|
2022-12-30 14:07:39 -08:00
|
|
|
enum Msg {
|
|
|
|
|
WaylandEvent(WaylandEvent),
|
|
|
|
|
Wayland(wayland::Event),
|
|
|
|
|
Close,
|
|
|
|
|
Closed(SurfaceIdWrapper),
|
2022-12-30 15:21:05 -08:00
|
|
|
ActivateWorkspace(zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1),
|
2023-01-18 10:58:22 -08:00
|
|
|
CloseWorkspace(zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1),
|
2023-01-04 15:17:57 -08:00
|
|
|
ActivateToplevel(zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1),
|
2023-01-18 10:58:22 -08:00
|
|
|
CloseToplevel(zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1),
|
2023-01-19 16:29:20 -08:00
|
|
|
DBus(toggle_dbus::Event),
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct Workspace {
|
|
|
|
|
name: String,
|
|
|
|
|
img: Option<iced::widget::image::Handle>,
|
|
|
|
|
handle: zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
|
2022-12-30 14:29:42 -08:00
|
|
|
output_name: Option<String>,
|
2023-01-05 18:30:50 -08:00
|
|
|
is_active: bool,
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
2022-12-30 15:21:05 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct Toplevel {
|
|
|
|
|
handle: zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
|
|
|
|
info: ToplevelInfo,
|
|
|
|
|
img: Option<iced::widget::image::Handle>,
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 16:29:20 -08:00
|
|
|
#[derive(Clone)]
|
|
|
|
|
struct Output {
|
|
|
|
|
// Output, on the `iced_sctk` Wayland connection
|
|
|
|
|
handle: wl_output::WlOutput,
|
|
|
|
|
name: Option<String>,
|
|
|
|
|
width: i32,
|
|
|
|
|
height: i32,
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-30 14:07:39 -08:00
|
|
|
struct LayerSurface {
|
2023-01-19 16:29:20 -08:00
|
|
|
// Output, on the `iced_sctk` Wayland connection
|
2022-12-30 14:07:39 -08:00
|
|
|
output: wl_output::WlOutput,
|
2022-12-30 14:29:42 -08:00
|
|
|
output_name: Option<String>,
|
2022-12-30 15:35:36 -08:00
|
|
|
// for transitions, would need windows in more than one workspace? But don't capture all of
|
|
|
|
|
// them all the time every frame.
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
|
struct App {
|
|
|
|
|
max_surface_id: usize,
|
|
|
|
|
layer_surfaces: HashMap<SurfaceId, LayerSurface>,
|
2023-01-19 16:29:20 -08:00
|
|
|
outputs: Vec<Output>,
|
2022-12-30 14:07:39 -08:00
|
|
|
workspaces: Vec<Workspace>,
|
2022-12-30 15:21:05 -08:00
|
|
|
toplevels: Vec<Toplevel>,
|
2023-01-04 15:17:57 -08:00
|
|
|
conn: Option<Connection>,
|
|
|
|
|
workspace_manager: Option<zcosmic_workspace_manager_v1::ZcosmicWorkspaceManagerV1>,
|
|
|
|
|
toplevel_manager: Option<zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1>,
|
2023-01-04 15:41:19 -08:00
|
|
|
seats: Vec<wl_seat::WlSeat>,
|
2023-01-19 16:29:20 -08:00
|
|
|
visible: bool,
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl App {
|
|
|
|
|
fn next_surface_id(&mut self) -> SurfaceId {
|
|
|
|
|
self.max_surface_id += 1;
|
|
|
|
|
SurfaceId::new(self.max_surface_id)
|
|
|
|
|
}
|
2023-01-03 12:30:04 -08:00
|
|
|
|
2023-01-05 18:30:50 -08:00
|
|
|
fn workspace_for_handle(
|
|
|
|
|
&self,
|
|
|
|
|
handle: &zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
|
|
|
|
|
) -> Option<&Workspace> {
|
|
|
|
|
self.workspaces.iter().find(|i| &i.handle == handle)
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 12:30:04 -08:00
|
|
|
fn workspace_for_handle_mut(
|
|
|
|
|
&mut self,
|
|
|
|
|
handle: &zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
|
|
|
|
|
) -> Option<&mut Workspace> {
|
|
|
|
|
self.workspaces.iter_mut().find(|i| &i.handle == handle)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn toplevel_for_handle_mut(
|
|
|
|
|
&mut self,
|
|
|
|
|
handle: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
|
|
|
|
|
) -> Option<&mut Toplevel> {
|
|
|
|
|
self.toplevels.iter_mut().find(|i| &i.handle == handle)
|
|
|
|
|
}
|
2023-01-19 16:29:20 -08:00
|
|
|
|
|
|
|
|
fn create_surface(
|
|
|
|
|
&mut self,
|
|
|
|
|
output: wl_output::WlOutput,
|
|
|
|
|
output_name: Option<String>,
|
|
|
|
|
width: i32,
|
|
|
|
|
height: i32,
|
|
|
|
|
) -> Command<Msg> {
|
|
|
|
|
let id = self.next_surface_id();
|
|
|
|
|
self.layer_surfaces.insert(
|
|
|
|
|
id.clone(),
|
|
|
|
|
LayerSurface {
|
|
|
|
|
output: output.clone(),
|
|
|
|
|
output_name,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
get_layer_surface(SctkLayerSurfaceSettings {
|
|
|
|
|
id,
|
|
|
|
|
keyboard_interactivity: KeyboardInteractivity::Exclusive,
|
|
|
|
|
namespace: "workspaces".into(),
|
|
|
|
|
layer: Layer::Overlay,
|
|
|
|
|
size: Some((Some(width as _), Some(height as _))),
|
|
|
|
|
output: IcedOutput::Output(output),
|
|
|
|
|
..Default::default()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn destroy_surface(&mut self, output: &wl_output::WlOutput) -> Command<Msg> {
|
|
|
|
|
if let Some((id, _)) = self
|
|
|
|
|
.layer_surfaces
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|(_id, surface)| &surface.output == output)
|
|
|
|
|
{
|
|
|
|
|
let id = *id;
|
|
|
|
|
self.layer_surfaces.remove(&id).unwrap();
|
|
|
|
|
destroy_layer_surface(id)
|
|
|
|
|
} else {
|
|
|
|
|
Command::none()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn toggle(&mut self) -> Command<Msg> {
|
|
|
|
|
if self.visible {
|
|
|
|
|
self.hide()
|
|
|
|
|
} else {
|
|
|
|
|
self.show()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn show(&mut self) -> Command<Msg> {
|
|
|
|
|
if !self.visible {
|
|
|
|
|
self.visible = true;
|
|
|
|
|
let outputs = self.outputs.clone();
|
|
|
|
|
Command::batch(
|
|
|
|
|
outputs
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|output| {
|
|
|
|
|
self.create_surface(output.handle, output.name, output.width, output.height)
|
|
|
|
|
})
|
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
Command::none()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close all shell surfaces
|
|
|
|
|
fn hide(&mut self) -> Command<Msg> {
|
|
|
|
|
self.visible = false;
|
|
|
|
|
Command::batch(
|
|
|
|
|
mem::take(&mut self.layer_surfaces)
|
|
|
|
|
.into_keys()
|
|
|
|
|
.map(destroy_layer_surface)
|
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
|
)
|
|
|
|
|
}
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Application for App {
|
|
|
|
|
type Message = Msg;
|
|
|
|
|
type Theme = cosmic::Theme;
|
|
|
|
|
type Executor = iced::executor::Default;
|
|
|
|
|
type Flags = ();
|
|
|
|
|
|
|
|
|
|
fn new(_flags: ()) -> (Self, Command<Msg>) {
|
|
|
|
|
//(Self::default(), destroy_layer_surface(SurfaceId::new(0)))
|
|
|
|
|
(Self::default(), Command::none())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn title(&self) -> String {
|
|
|
|
|
String::from("cosmic-workspaces")
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 12:30:04 -08:00
|
|
|
// TODO transparent style?
|
|
|
|
|
// TODO: show panel and dock? Drag?
|
|
|
|
|
|
2022-12-30 14:07:39 -08:00
|
|
|
fn update(&mut self, message: Msg) -> Command<Msg> {
|
|
|
|
|
match message {
|
|
|
|
|
Msg::WaylandEvent(evt) => match evt {
|
|
|
|
|
WaylandEvent::Output(evt, output) => match evt {
|
|
|
|
|
OutputEvent::Created(Some(info)) => {
|
|
|
|
|
if let Some((width, height)) = info.logical_size {
|
2023-01-19 16:29:20 -08:00
|
|
|
self.outputs.push(Output {
|
|
|
|
|
handle: output.clone(),
|
|
|
|
|
name: info.name.clone(),
|
|
|
|
|
width,
|
|
|
|
|
height,
|
2022-12-30 14:07:39 -08:00
|
|
|
});
|
2023-01-19 16:29:20 -08:00
|
|
|
if self.visible {
|
|
|
|
|
return self.create_surface(
|
|
|
|
|
output.clone(),
|
|
|
|
|
info.name,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
2023-01-20 14:02:52 -08:00
|
|
|
OutputEvent::Created(None) => {} // XXX?
|
|
|
|
|
OutputEvent::InfoUpdate(info) => {
|
|
|
|
|
if let Some(output) = self.outputs.iter_mut().find(|x| &x.handle == &output)
|
|
|
|
|
{
|
|
|
|
|
if let Some((width, height)) = info.logical_size {
|
|
|
|
|
output.width = width;
|
|
|
|
|
output.height = height;
|
|
|
|
|
}
|
|
|
|
|
output.name = info.name;
|
|
|
|
|
// XXX re-create surface?
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-30 14:07:39 -08:00
|
|
|
OutputEvent::Removed => {
|
2023-01-19 16:29:20 -08:00
|
|
|
if let Some(idx) = self.outputs.iter().position(|x| &x.handle == &output) {
|
|
|
|
|
self.outputs.remove(idx);
|
|
|
|
|
}
|
|
|
|
|
if self.visible {
|
|
|
|
|
return self.destroy_surface(&output);
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
_ => {}
|
|
|
|
|
},
|
|
|
|
|
Msg::Wayland(evt) => {
|
|
|
|
|
match evt {
|
2023-01-04 15:17:57 -08:00
|
|
|
wayland::Event::Connection(conn) => {
|
|
|
|
|
self.conn = Some(conn);
|
|
|
|
|
}
|
|
|
|
|
wayland::Event::ToplevelManager(manager) => {
|
|
|
|
|
self.toplevel_manager = Some(manager);
|
|
|
|
|
}
|
|
|
|
|
wayland::Event::WorkspaceManager(manager) => {
|
|
|
|
|
self.workspace_manager = Some(manager);
|
2023-01-04 14:41:44 -08:00
|
|
|
}
|
2022-12-30 14:07:39 -08:00
|
|
|
wayland::Event::Workspaces(workspaces) => {
|
2023-01-04 14:41:44 -08:00
|
|
|
let old_workspaces = mem::take(&mut self.workspaces);
|
2022-12-30 14:07:39 -08:00
|
|
|
self.workspaces = Vec::new();
|
2022-12-30 14:29:42 -08:00
|
|
|
for (output_name, workspace) in workspaces {
|
2023-01-04 14:41:44 -08:00
|
|
|
let is_active = workspace.state.contains(&WEnum::Value(
|
|
|
|
|
zcosmic_workspace_handle_v1::State::Active,
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
// XXX efficiency
|
|
|
|
|
let img = old_workspaces
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|i| &i.handle == &workspace.handle)
|
|
|
|
|
.and_then(|i| i.img.clone());
|
|
|
|
|
|
2022-12-30 14:07:39 -08:00
|
|
|
self.workspaces.push(Workspace {
|
|
|
|
|
name: workspace.name,
|
|
|
|
|
handle: workspace.handle,
|
2022-12-30 14:29:42 -08:00
|
|
|
output_name,
|
2023-01-04 14:41:44 -08:00
|
|
|
img,
|
2023-01-05 18:30:50 -08:00
|
|
|
is_active,
|
2022-12-30 14:07:39 -08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-30 15:21:05 -08:00
|
|
|
wayland::Event::NewToplevel(handle, info) => {
|
2023-01-03 12:30:04 -08:00
|
|
|
println!("New toplevel: {:?}", info);
|
2022-12-30 15:21:05 -08:00
|
|
|
self.toplevels.push(Toplevel {
|
|
|
|
|
handle,
|
|
|
|
|
info,
|
|
|
|
|
img: None,
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-01-18 11:01:47 -08:00
|
|
|
wayland::Event::CloseToplevel(handle) => {
|
|
|
|
|
if let Some(idx) = self.toplevels.iter().position(|x| x.handle == handle) {
|
|
|
|
|
self.toplevels.remove(idx);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-03 12:30:04 -08:00
|
|
|
wayland::Event::WorkspaceCapture(handle, image) => {
|
|
|
|
|
if let Some(workspace) = self.workspace_for_handle_mut(&handle) {
|
|
|
|
|
workspace.img = Some(image.clone());
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
2023-01-03 12:30:04 -08:00
|
|
|
wayland::Event::ToplevelCapture(handle, image) => {
|
|
|
|
|
if let Some(toplevel) = self.toplevel_for_handle_mut(&handle) {
|
|
|
|
|
println!("Got toplevel image!");
|
|
|
|
|
toplevel.img = Some(image.clone());
|
2022-12-30 15:21:05 -08:00
|
|
|
}
|
|
|
|
|
}
|
2023-01-04 15:41:19 -08:00
|
|
|
wayland::Event::Seats(seats) => {
|
|
|
|
|
self.seats = seats;
|
|
|
|
|
}
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Msg::Close => {
|
2023-01-19 16:29:20 -08:00
|
|
|
self.hide();
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
Msg::Closed(_) => {}
|
2022-12-30 15:35:36 -08:00
|
|
|
Msg::ActivateWorkspace(workspace_handle) => {
|
2023-01-04 15:17:57 -08:00
|
|
|
let workspace_manager = self.workspace_manager.as_ref().unwrap();
|
2023-01-04 14:41:44 -08:00
|
|
|
workspace_handle.activate();
|
|
|
|
|
workspace_manager.commit();
|
2023-01-04 15:17:57 -08:00
|
|
|
self.conn.as_ref().unwrap().flush();
|
|
|
|
|
}
|
|
|
|
|
Msg::ActivateToplevel(toplevel_handle) => {
|
|
|
|
|
if let Some(toplevel_manager) = self.toplevel_manager.as_ref() {
|
2023-01-04 15:41:19 -08:00
|
|
|
if !self.seats.is_empty() {
|
|
|
|
|
for seat in &self.seats {
|
2023-01-05 18:24:35 -08:00
|
|
|
toplevel_manager.activate(&toplevel_handle, &seat);
|
2023-01-04 15:41:19 -08:00
|
|
|
self.conn.as_ref().unwrap().flush();
|
|
|
|
|
}
|
2023-01-19 16:29:20 -08:00
|
|
|
self.hide();
|
2023-01-04 15:41:19 -08:00
|
|
|
}
|
2023-01-04 15:17:57 -08:00
|
|
|
}
|
2022-12-30 15:21:05 -08:00
|
|
|
}
|
2023-01-18 10:58:22 -08:00
|
|
|
Msg::CloseWorkspace(workspace_handle) => {}
|
|
|
|
|
Msg::CloseToplevel(toplevel_handle) => {
|
|
|
|
|
// TODO confirmation?
|
|
|
|
|
if let Some(toplevel_manager) = self.toplevel_manager.as_ref() {
|
|
|
|
|
toplevel_manager.close(&toplevel_handle);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-19 16:29:20 -08:00
|
|
|
Msg::DBus(toggle_dbus::Event::Toggle) => {
|
|
|
|
|
return self.toggle();
|
|
|
|
|
}
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Command::none()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn subscription(&self) -> Subscription<Msg> {
|
|
|
|
|
let events = iced::subscription::events_with(|evt, _| {
|
|
|
|
|
if let iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland(evt)) = evt
|
|
|
|
|
{
|
|
|
|
|
Some(Msg::WaylandEvent(evt))
|
|
|
|
|
} else if let iced::Event::Keyboard(iced::keyboard::Event::KeyReleased {
|
|
|
|
|
key_code: KeyCode::Escape,
|
|
|
|
|
modifiers: _,
|
|
|
|
|
}) = evt
|
|
|
|
|
{
|
|
|
|
|
Some(Msg::Close)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-01-19 16:29:20 -08:00
|
|
|
iced::Subscription::batch(vec![
|
|
|
|
|
events,
|
|
|
|
|
toggle_dbus::subscription().map(Msg::DBus),
|
|
|
|
|
wayland::subscription().map(Msg::Wayland),
|
|
|
|
|
])
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn view(&self, id: SurfaceIdWrapper) -> cosmic::Element<Msg> {
|
|
|
|
|
use iced::widget::*;
|
|
|
|
|
if let SurfaceIdWrapper::LayerSurface(id) = id {
|
|
|
|
|
if let Some(surface) = self.layer_surfaces.get(&id) {
|
|
|
|
|
return layer_surface(self, surface);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
text("workspaces").into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn close_requested(&self, id: SurfaceIdWrapper) -> Msg {
|
|
|
|
|
Msg::Closed(id)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn layer_surface<'a>(app: &'a App, surface: &'a LayerSurface) -> cosmic::Element<'a, Msg> {
|
2023-01-03 12:30:04 -08:00
|
|
|
widget::row![
|
2022-12-30 15:21:05 -08:00
|
|
|
workspaces_sidebar(
|
|
|
|
|
app.workspaces
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|i| &i.output_name == &surface.output_name),
|
|
|
|
|
),
|
2023-01-05 18:30:50 -08:00
|
|
|
toplevel_previews(app.toplevels.iter().filter(|i| {
|
|
|
|
|
if let Some(workspace) = &i.info.workspace {
|
2023-01-05 18:41:48 -08:00
|
|
|
app.workspace_for_handle(workspace).map_or(false, |x| {
|
|
|
|
|
x.is_active && x.output_name == surface.output_name
|
|
|
|
|
})
|
2023-01-05 18:30:50 -08:00
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
})),
|
2022-12-30 15:21:05 -08:00
|
|
|
]
|
|
|
|
|
.height(iced::Length::Fill)
|
|
|
|
|
.width(iced::Length::Fill)
|
|
|
|
|
.into()
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
2023-01-18 10:58:22 -08:00
|
|
|
fn close_button(on_press: Msg) -> cosmic::Element<'static, Msg> {
|
2023-01-06 19:21:49 -08:00
|
|
|
iced::widget::button(cosmic::widget::icon("window-close-symbolic", 16))
|
|
|
|
|
.style(cosmic::theme::Button::Destructive)
|
2023-01-18 10:58:22 -08:00
|
|
|
.on_press(on_press)
|
2023-01-06 19:21:49 -08:00
|
|
|
.into()
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-30 14:07:39 -08:00
|
|
|
fn workspace_sidebar_entry(workspace: &Workspace) -> cosmic::Element<Msg> {
|
2023-01-06 19:06:09 -08:00
|
|
|
// TODO style
|
|
|
|
|
let theme = if workspace.is_active {
|
|
|
|
|
cosmic::theme::Button::Primary
|
|
|
|
|
} else {
|
|
|
|
|
cosmic::theme::Button::Secondary
|
|
|
|
|
};
|
2022-12-30 15:21:05 -08:00
|
|
|
widget::column![
|
2023-01-18 10:58:22 -08:00
|
|
|
close_button(Msg::CloseWorkspace(workspace.handle.clone())),
|
2022-12-30 15:21:05 -08:00
|
|
|
widget::button(widget::Image::new(workspace.img.clone().unwrap_or_else(
|
|
|
|
|
|| widget::image::Handle::from_pixels(0, 0, vec![0, 0, 0, 255])
|
|
|
|
|
)))
|
2023-01-06 19:06:09 -08:00
|
|
|
.style(theme)
|
2022-12-30 15:21:05 -08:00
|
|
|
.on_press(Msg::ActivateWorkspace(workspace.handle.clone())),
|
|
|
|
|
widget::text(&workspace.name)
|
2022-12-30 14:07:39 -08:00
|
|
|
]
|
|
|
|
|
.into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn workspaces_sidebar<'a>(
|
|
|
|
|
workspaces: impl Iterator<Item = &'a Workspace>,
|
|
|
|
|
) -> cosmic::Element<'a, Msg> {
|
2023-01-03 12:38:02 -08:00
|
|
|
widget::column(workspaces.map(workspace_sidebar_entry).collect())
|
|
|
|
|
.width(iced::Length::Fill)
|
|
|
|
|
.height(iced::Length::Fill)
|
|
|
|
|
.into()
|
|
|
|
|
|
2022-12-30 14:07:39 -08:00
|
|
|
// New workspace
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-30 15:21:05 -08:00
|
|
|
fn toplevel_preview<'a>(toplevel: &'a Toplevel) -> cosmic::Element<'a, Msg> {
|
|
|
|
|
// capture of window
|
|
|
|
|
// - selectable
|
|
|
|
|
// name of window
|
2023-01-05 18:41:48 -08:00
|
|
|
widget::column![
|
2023-01-18 10:58:22 -08:00
|
|
|
close_button(Msg::CloseToplevel(toplevel.handle.clone())),
|
2023-01-05 18:41:48 -08:00
|
|
|
widget::button(widget::Image::new(toplevel.img.clone().unwrap_or_else(
|
|
|
|
|
|| widget::image::Handle::from_pixels(0, 0, vec![0, 0, 0, 255]),
|
|
|
|
|
)))
|
|
|
|
|
.on_press(Msg::ActivateToplevel(toplevel.handle.clone())),
|
|
|
|
|
widget::text(&toplevel.info.title)
|
|
|
|
|
]
|
2022-12-30 15:21:05 -08:00
|
|
|
.into()
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
2022-12-30 15:21:05 -08:00
|
|
|
fn toplevel_previews<'a>(
|
|
|
|
|
toplevels: impl Iterator<Item = &'a Toplevel>,
|
|
|
|
|
) -> cosmic::Element<'a, Msg> {
|
2023-01-03 12:38:02 -08:00
|
|
|
widget::row(toplevels.map(toplevel_preview).collect())
|
|
|
|
|
.width(iced::Length::FillPortion(4))
|
|
|
|
|
.height(iced::Length::Fill)
|
|
|
|
|
.into()
|
2022-12-30 14:07:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn main() -> iced::Result {
|
|
|
|
|
App::run(iced::Settings {
|
|
|
|
|
antialiasing: true,
|
|
|
|
|
exit_on_close_request: false,
|
|
|
|
|
initial_surface: InitialSurface::LayerSurface(SctkLayerSurfaceSettings {
|
|
|
|
|
keyboard_interactivity: KeyboardInteractivity::None,
|
|
|
|
|
namespace: "ignore".into(),
|
|
|
|
|
size: Some((Some(1), Some(1))),
|
|
|
|
|
layer: Layer::Background,
|
|
|
|
|
..Default::default()
|
|
|
|
|
}),
|
|
|
|
|
..iced::Settings::default()
|
|
|
|
|
})
|
|
|
|
|
}
|