diff --git a/Cargo.lock b/Cargo.lock index ae76fa8..84c9cb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1211,18 +1211,19 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=c8d3a1c#c8d3a1c3d40d16235f4720969a54ed570ec7a976" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=d218c76#d218c76b58c7a3b20dd5e7943f93fc306a1b81b8" dependencies = [ "cosmic-protocols", "libc", "smithay-client-toolkit", "wayland-client", + "wayland-protocols", ] [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1241,7 +1242,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "quote", "syn 1.0.109", @@ -1311,7 +1312,7 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=c8d3a1c#c8d3a1c3d40d16235f4720969a54ed570ec7a976" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=d218c76#d218c76b58c7a3b20dd5e7943f93fc306a1b81b8" dependencies = [ "bitflags 2.6.0", "wayland-backend", @@ -1348,7 +1349,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "almost", "cosmic-config", @@ -2766,7 +2767,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "dnd", "iced_accessibility", @@ -2784,7 +2785,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "accesskit", "accesskit_winit", @@ -2793,10 +2794,11 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "bitflags 2.6.0", "bytes", + "cosmic-client-toolkit", "dnd", "glam", "log", @@ -2807,7 +2809,6 @@ dependencies = [ "raw-window-handle", "rustc-hash 2.1.0", "serde", - "smithay-client-toolkit", "smol_str", "thiserror 1.0.69", "web-time", @@ -2817,7 +2818,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "futures", "iced_core", @@ -2843,7 +2844,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "bitflags 2.6.0", "bytemuck", @@ -2865,7 +2866,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2877,14 +2878,14 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "bytes", + "cosmic-client-toolkit", "dnd", "iced_core", "iced_futures", "raw-window-handle", - "smithay-client-toolkit", "thiserror 1.0.69", "window_clipboard", ] @@ -2892,7 +2893,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "bytemuck", "cosmic-text", @@ -2908,11 +2909,12 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "as-raw-xcb-connection", "bitflags 2.6.0", "bytemuck", + "cosmic-client-toolkit", "futures", "glam", "guillotiere", @@ -2925,7 +2927,6 @@ dependencies = [ "resvg", "rustc-hash 2.1.0", "rustix 0.38.41", - "smithay-client-toolkit", "thiserror 1.0.69", "tiny-xlib", "wayland-backend", @@ -2939,8 +2940,9 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ + "cosmic-client-toolkit", "dnd", "iced_renderer", "iced_runtime", @@ -2948,7 +2950,6 @@ dependencies = [ "once_cell", "ouroboros", "rustc-hash 2.1.0", - "smithay-client-toolkit", "thiserror 1.0.69", "unicode-segmentation", "window_clipboard", @@ -2957,8 +2958,9 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ + "cosmic-client-toolkit", "dnd", "iced_futures", "iced_graphics", @@ -2966,7 +2968,6 @@ dependencies = [ "log", "raw-window-handle", "rustc-hash 2.1.0", - "smithay-client-toolkit", "thiserror 1.0.69", "tracing", "wasm-bindgen-futures", @@ -3542,7 +3543,7 @@ checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#de0c1921f71a2cbd26a653fa2bbf7e5f948a36fc" +source = "git+https://github.com/pop-os/libcosmic.git#b524ccb0a46b1ca585db09638c33e39e79829716" dependencies = [ "apply", "ashpd 0.9.2", diff --git a/src/app.rs b/src/app.rs index e034188..b24012f 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,7 +3,7 @@ #[cfg(feature = "wayland")] use cosmic::iced::{ - event::wayland::{Event as WaylandEvent, OutputEvent}, + event::wayland::{Event as WaylandEvent, OutputEvent, OverlapNotifyEvent}, platform_specific::runtime::wayland::layer_surface::{ IcedMargin, IcedOutput, SctkLayerSurfaceSettings, }, @@ -12,6 +12,8 @@ use cosmic::iced::{ }, Limits, }; +#[cfg(feature = "wayland")] +use cosmic::iced_winit::commands::overlap_notify::overlap_notify; use cosmic::{ app::{self, context_drawer, message, Core, Task}, cosmic_config, cosmic_theme, executor, @@ -22,15 +24,17 @@ use cosmic::{ keyboard::{Event as KeyEvent, Key, Modifiers}, stream, window::{self, Event as WindowEvent, Id as WindowId}, - Alignment, Event, Length, Size, Subscription, + Alignment, Background, Border, Event, Length, Point, Rectangle, Size, Subscription, }, iced_runtime::clipboard, style, theme, widget::{ self, dnd_destination::DragId, + horizontal_space, menu::{action::MenuAction, key_bind::KeyBind}, segmented_button::{self, Entity}, + vertical_space, }, Application, ApplicationExt, Element, }; @@ -303,6 +307,8 @@ pub enum Message { OpenWithBrowse, OpenWithDialog(Option), OpenWithSelection(usize), + #[cfg(all(feature = "desktop", feature = "wayland"))] + Overlap(OverlapNotifyEvent, window::Id), Paste(Option), PasteContents(PathBuf, ClipboardPaste), PendingCancel(u64), @@ -321,6 +327,7 @@ pub enum Message { SearchClear, SearchInput(String), SystemThemeModeChange(cosmic_theme::ThemeMode), + Size(Size), TabActivate(Entity), TabNext, TabPrev, @@ -500,18 +507,21 @@ pub struct App { dialog_pages: VecDeque, dialog_text_input: widget::Id, key_binds: HashMap, + margin: HashMap, modifiers: Modifiers, mounter_items: HashMap, network_drive_connecting: Option<(MounterKey, String)>, network_drive_input: String, #[cfg(feature = "notify")] notification_opt: Option>>, + overlap: HashMap, pending_operation_id: u64, pending_operations: BTreeMap, progress_operations: BTreeSet, complete_operations: BTreeMap, failed_operations: BTreeMap, search_id: widget::Id, + size: Option, #[cfg(feature = "wayland")] surface_ids: HashMap, #[cfg(feature = "wayland")] @@ -637,6 +647,57 @@ impl App { } } + fn handle_overlap(&mut self) { + let Some((bl, br, tl, tr)) = self.size.as_ref().map(|s| { + ( + Rectangle::new( + Point::new(0., s.height / 2.), + Size::new(s.width / 2., s.height / 2.), + ), + Rectangle::new( + Point::new(s.width / 2., s.height / 2.), + Size::new(s.width / 2., s.height / 2.), + ), + Rectangle::new(Point::new(0., 0.), Size::new(s.width / 2., s.height / 2.)), + Rectangle::new( + Point::new(s.width / 2., 0.), + Size::new(s.width / 2., s.height / 2.), + ), + ) + }) else { + return; + }; + + let mut overlaps: HashMap<_, _> = self + .windows + .keys() + .into_iter() + .map(|k| (*k, (0, 0, 0, 0))) + .collect(); + for (w_id, overlap) in self.overlap.values() { + let tl = tl.intersects(overlap); + let tr = tr.intersects(overlap); + let bl = bl.intersects(overlap); + let br = br.intersects(overlap); + let Some((top, left, bottom, right)) = overlaps.get_mut(&w_id) else { + continue; + }; + if tl && tr { + *top += overlap.height as i32; + } + if tl && bl { + *left += overlap.width as i32; + } + if bl && br { + *bottom += overlap.height as i32; + } + if tr && br { + *right += overlap.width as i32; + } + } + self.margin = overlaps; + } + fn open_tab_entity( &mut self, location: Location, @@ -1450,18 +1511,21 @@ impl Application for App { dialog_pages: VecDeque::new(), dialog_text_input: widget::Id::unique(), key_binds, + margin: HashMap::new(), modifiers: Modifiers::empty(), mounter_items: HashMap::new(), network_drive_connecting: None, network_drive_input: String::new(), #[cfg(feature = "notify")] notification_opt: None, + overlap: HashMap::new(), pending_operation_id: 0, pending_operations: BTreeMap::new(), progress_operations: BTreeSet::new(), complete_operations: BTreeMap::new(), failed_operations: BTreeMap::new(), search_id: widget::Id::unique(), + size: None, #[cfg(feature = "wayland")] surface_ids: HashMap::new(), #[cfg(feature = "wayland")] @@ -3278,6 +3342,8 @@ impl Application for App { exclusive_zone: 0, size_limits: Limits::NONE.min_width(1.0).min_height(1.0), }), + #[cfg(feature = "wayland")] + overlap_notify(surface_id, true), ]); } OutputEvent::Removed => { @@ -3303,6 +3369,30 @@ impl Application for App { return Task::perform(async move { cosmic }, |cosmic| message::cosmic(cosmic)); } Message::None => {} + #[cfg(all(feature = "desktop", feature = "wayland"))] + Message::Overlap(overlap_notify_event, w_id) => match overlap_notify_event { + OverlapNotifyEvent::OverlapLayerAdd { + identifier, + namespace, + logical_rect, + exclusive, + .. + } => { + if exclusive > 0 || namespace == "Dock" || namespace == "Panel" { + self.overlap.insert(identifier, (w_id, logical_rect)); + self.handle_overlap(); + } + } + OverlapNotifyEvent::OverlapLayerRemove { identifier } => { + self.overlap.remove(&identifier); + self.handle_overlap(); + } + _ => {} + }, + Message::Size(size) => { + self.size = Some(size); + self.handle_overlap(); + } } Task::none() @@ -3720,8 +3810,11 @@ impl Application for App { widget::row::with_children(vec![ widget::icon(app.icon.clone()).size(32).into(), if app.is_default { - widget::text::body(fl!("default-app", name = app.name.as_str())) - .into() + widget::text::body(fl!( + "default-app", + name = Some(app.name.as_str()) + )) + .into() } else { widget::text::body(app.name.to_string()).into() }, @@ -4165,8 +4258,26 @@ impl Application for App { // The toaster is added on top of an empty element to ensure that it does not override context menus tab_column = tab_column.push(widget::toaster(&self.toasts, widget::horizontal_space())); - - return tab_column.into(); + return if let Some(margin) = self.margin.get(&id) { + if margin.0 != 0 || margin.2 != 0 { + tab_column = widget::column::with_children(vec![ + vertical_space().height(margin.0 as f32).into(), + tab_column.into(), + vertical_space().height(margin.2 as f32).into(), + ]) + } + if margin.1 != 0 || margin.3 != 0 { + Element::from(widget::row::with_children(vec![ + horizontal_space().width(margin.1 as f32).into(), + tab_column.into(), + horizontal_space().width(margin.3 as f32).into(), + ])) + } else { + tab_column.into() + } + } else { + tab_column.into() + }; } Some(WindowKind::DesktopViewOptions) => self.desktop_view_options(), Some(WindowKind::Preview(entity_opt, kind)) => self.preview(entity_opt, kind, false), @@ -4193,7 +4304,7 @@ impl Application for App { struct TrashWatcherSubscription; let mut subscriptions = vec![ - event::listen_with(|event, status, _window_id| match event { + event::listen_with(|event, status, window_id| match event { Event::Keyboard(KeyEvent::KeyPressed { key, modifiers, .. }) => match status { event::Status::Ignored => Some(Message::Key(modifiers, key)), event::Status::Captured => None, @@ -4202,12 +4313,20 @@ impl Application for App { Some(Message::Modifiers(modifiers)) } Event::Window(WindowEvent::CloseRequested) => Some(Message::WindowClose), + Event::Window(WindowEvent::Opened { position: _, size }) => { + Some(Message::Size(size)) + } + Event::Window(WindowEvent::Resized(s)) => Some(Message::Size(s)), #[cfg(feature = "wayland")] Event::PlatformSpecific(event::PlatformSpecific::Wayland(wayland_event)) => { match wayland_event { WaylandEvent::Output(output_event, output) => { Some(Message::OutputEvent(output_event, output)) } + #[cfg(feature = "desktop")] + WaylandEvent::OverlapNotify(event) => { + Some(Message::Overlap(event, window_id)) + } _ => None, } }