wip: corner radius v2

This commit is contained in:
Ashley Wulber 2026-04-16 23:02:39 -04:00
parent b814f54f67
commit 3ca50dd7f6
4 changed files with 115 additions and 166 deletions

View file

@ -126,7 +126,7 @@ ashpd = { version = "0.12.3", default-features = false, optional = true }
async-fs = { version = "2.2", optional = true } async-fs = { version = "2.2", optional = true }
async-std = { version = "1.13", optional = true } async-std = { version = "1.13", optional = true }
auto_enums = "0.8.8" auto_enums = "0.8.8"
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "160b086", optional = true } cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "a7d2d7a", optional = true }
jiff = "0.2" jiff = "0.2"
cosmic-config = { path = "cosmic-config" } cosmic-config = { path = "cosmic-config" }
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", optional = true } cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", optional = true }

2
iced

@ -1 +1 @@
Subproject commit 13b8d3eab67df7f40d3d9e932a9412f85ff8413c Subproject commit 4f6d52fce72749bb4421afe8d108f561c0bf77d2

View file

@ -6,6 +6,7 @@ use std::collections::{HashMap, HashSet};
use std::sync::Arc; use std::sync::Arc;
use super::{Action, Application, ApplicationExt, Subscription}; use super::{Action, Application, ApplicationExt, Subscription};
use crate::core::AppType;
use crate::theme::{THEME, Theme, ThemeType}; use crate::theme::{THEME, Theme, ThemeType};
use crate::{Core, Element, keyboard_nav}; use crate::{Core, Element, keyboard_nav};
#[cfg(all(feature = "wayland", target_os = "linux"))] #[cfg(all(feature = "wayland", target_os = "linux"))]
@ -673,34 +674,13 @@ impl<T: Application> Cosmic<T> {
state.intersects(WindowState::MAXIMIZED | WindowState::FULLSCREEN); state.intersects(WindowState::MAXIMIZED | WindowState::FULLSCREEN);
} }
if self.app.core().sync_window_border_radii_to_theme() { if self.app.core().sync_window_border_radii_to_theme() {
use iced_runtime::platform_specific::wayland::CornerRadius;
use iced_winit::platform_specific::commands::corner_radius::corner_radius; use iced_winit::platform_specific::commands::corner_radius::corner_radius;
let theme = THEME.lock().unwrap(); let theme = THEME.lock().unwrap();
let t = theme.cosmic();
let radii = t.radius_s().map(|x| if x < 4.0 { x } else { x + 4.0 });
let cur_rad = CornerRadius {
top_left: radii[0].round() as u32,
top_right: radii[1].round() as u32,
bottom_right: radii[2].round() as u32,
bottom_left: radii[3].round() as u32,
};
let rounded = !self.app.core().window.sharp_corners; let rounded = !self.app.core().window.sharp_corners;
return Task::batch([corner_radius(
id, let cur_rad = self.app.core().app_type.corners(&theme, rounded);
if rounded { return Task::batch([corner_radius(id, Some(cur_rad)).discard()]);
Some(cur_rad)
} else {
let rad_0 = t.radius_0();
Some(CornerRadius {
top_left: rad_0[0].round() as u32,
top_right: rad_0[1].round() as u32,
bottom_right: rad_0[2].round() as u32,
bottom_left: rad_0[3].round() as u32,
})
},
)
.discard()]);
} }
} }
@ -864,79 +844,26 @@ impl<T: Application> Cosmic<T> {
let t = cosmic_theme.cosmic(); let t = cosmic_theme.cosmic();
let radii = t.radius_s().map(|x| if x < 4.0 { x } else { x + 4.0 });
let cur_rad = CornerRadius {
top_left: radii[0].round() as u32,
top_right: radii[1].round() as u32,
bottom_right: radii[2].round() as u32,
bottom_left: radii[3].round() as u32,
};
let rounded = !self.app.core().window.sharp_corners; let rounded = !self.app.core().window.sharp_corners;
let cur_rad = self.app.core().app_type.corners(&cosmic_theme, rounded);
// Update radius for the main window // Update radius for the main window
let main_window_id = self let main_window_id = self
.app .app
.core() .core()
.main_window_id() .main_window_id()
.unwrap_or(window::Id::RESERVED); .unwrap_or(window::Id::RESERVED);
let mut cmds = vec![ let mut cmds =
corner_radius( vec![corner_radius(main_window_id, Some(cur_rad)).discard()];
main_window_id,
if rounded {
Some(cur_rad)
} else {
let rad_0 = t.radius_0();
Some(CornerRadius {
top_left: rad_0[0].round() as u32,
top_right: rad_0[1].round() as u32,
bottom_right: rad_0[2].round() as u32,
bottom_left: rad_0[3].round() as u32,
})
},
)
.discard(),
];
// Update radius for each tracked view with the window surface type // Update radius for each tracked view with the window surface type
for (id, (_, surface_type, _)) in self.surface_views.iter() { for (id, (_, surface_type, _)) in self.surface_views.iter() {
if let SurfaceIdWrapper::Window(_) = surface_type { let cur_rad = corners(*surface_type, rounded, &cosmic_theme);
cmds.push( cmds.push(corner_radius(*id, Some(cur_rad)).discard());
corner_radius(
*id,
if rounded {
Some(cur_rad)
} else {
let rad_0 = t.radius_0();
Some(CornerRadius {
top_left: rad_0[0].round() as u32,
top_right: rad_0[1].round() as u32,
bottom_right: rad_0[2].round() as u32,
bottom_left: rad_0[3].round() as u32,
})
},
)
.discard(),
);
}
} }
// Update radius for all tracked windows // Update radius for all tracked windows
for id in &self.tracked_windows { for id in &self.tracked_windows {
cmds.push( cmds.push(corner_radius(*id, Some(cur_rad)).discard());
corner_radius(
*id,
if rounded {
Some(cur_rad)
} else {
let rad_0 = t.radius_0();
Some(CornerRadius {
top_left: rad_0[0].round() as u32,
top_right: rad_0[1].round() as u32,
bottom_right: rad_0[2].round() as u32,
bottom_left: rad_0[3].round() as u32,
})
},
)
.discard(),
);
} }
return Task::batch(cmds); return Task::batch(cmds);
@ -1016,19 +943,13 @@ impl<T: Application> Cosmic<T> {
cosmic_theme.transparent = new_blur; cosmic_theme.transparent = new_blur;
#[cfg(all(feature = "wayland", target_os = "linux"))] #[cfg(all(feature = "wayland", target_os = "linux"))]
if self.app.core().sync_window_border_radii_to_theme() { if self.app.core().sync_window_border_radii_to_theme() {
use iced_runtime::platform_specific::wayland::CornerRadius;
use iced_winit::platform_specific::commands::corner_radius::corner_radius; use iced_winit::platform_specific::commands::corner_radius::corner_radius;
let t = cosmic_theme.cosmic(); let t = cosmic_theme.cosmic();
let radii = t.radius_s().map(|x| if x < 4.0 { x } else { x + 4.0 });
let cur_rad = CornerRadius {
top_left: radii[0].round() as u32,
top_right: radii[1].round() as u32,
bottom_right: radii[2].round() as u32,
bottom_left: radii[3].round() as u32,
};
let rounded = !self.app.core().window.sharp_corners; let rounded = !self.app.core().window.sharp_corners;
let cur_rad =
self.app.core().app_type.corners(&cosmic_theme, rounded);
// Update radius for the main window // Update radius for the main window
let main_window_id = self let main_window_id = self
@ -1036,64 +957,16 @@ impl<T: Application> Cosmic<T> {
.core() .core()
.main_window_id() .main_window_id()
.unwrap_or(window::Id::RESERVED); .unwrap_or(window::Id::RESERVED);
let mut cmds = vec![ let mut cmds =
corner_radius( vec![corner_radius(main_window_id, Some(cur_rad)).discard()];
main_window_id,
if rounded {
Some(cur_rad)
} else {
let rad_0 = t.radius_0();
Some(CornerRadius {
top_left: rad_0[0].round() as u32,
top_right: rad_0[1].round() as u32,
bottom_right: rad_0[2].round() as u32,
bottom_left: rad_0[3].round() as u32,
})
},
)
.discard(),
];
// Update radius for each tracked view with the window surface type // Update radius for each tracked view with the window surface type
for (id, (_, surface_type, _)) in self.surface_views.iter() { for (id, (_, surface_type, _)) in self.surface_views.iter() {
if let SurfaceIdWrapper::Window(_) = surface_type { let cur_rad = corners(*surface_type, rounded, &cosmic_theme);
cmds.push( cmds.push(corner_radius(*id, Some(cur_rad)).discard());
corner_radius(
*id,
if rounded {
Some(cur_rad)
} else {
let rad_0 = t.radius_0();
Some(CornerRadius {
top_left: rad_0[0].round() as u32,
top_right: rad_0[1].round() as u32,
bottom_right: rad_0[2].round() as u32,
bottom_left: rad_0[3].round() as u32,
})
},
)
.discard(),
);
}
} }
// Update radius for all tracked windows // Update radius for all tracked windows
for id in &self.tracked_windows { for id in &self.tracked_windows {
cmds.push( cmds.push(corner_radius(*id, Some(cur_rad)).discard());
corner_radius(
*id,
if rounded {
Some(cur_rad)
} else {
let rad_0 = t.radius_0();
Some(CornerRadius {
top_left: rad_0[0].round() as u32,
top_right: rad_0[1].round() as u32,
bottom_right: rad_0[2].round() as u32,
bottom_left: rad_0[3].round() as u32,
})
},
)
.discard(),
);
} }
let core = self.app.core(); let core = self.app.core();
@ -1387,32 +1260,33 @@ impl<T: Application> Cosmic<T> {
iced::window::disable_blur iced::window::disable_blur
}; };
let mut cmds = Vec::with_capacity(1 + self.tracked_windows.len()); let mut cmds = Vec::with_capacity(1 + self.tracked_windows.len());
cmds.push(blur(id)); if !self.tracked_windows.contains(&id) {
for id in &self.tracked_windows { cmds.push(blur(id));
cmds.push(blur(*id));
} }
Task::batch(cmds) Task::batch(cmds)
} else { } else {
Task::none() Task::none()
}; };
let corner_task = if let Some(s) = self.surface_views.get(&id) {
corner_radius(id, Some(corners(s.1, rounded, &theme))).discard()
} else if id
== self
.app
.core()
.main_window_id()
.unwrap_or(window::Id::RESERVED)
|| self.tracked_windows.contains(&id)
{
corner_radius(id, Some(self.app.core().app_type.corners(&theme, rounded)))
.discard()
} else {
Task::none()
};
let t = theme.cosmic(); let t = theme.cosmic();
return Task::batch([ return Task::batch([
blur_cmd, blur_cmd,
corner_radius( corner_task,
id,
if rounded {
Some(cur_rad)
} else {
let rad_0 = t.radius_0();
Some(CornerRadius {
top_left: rad_0[0].round() as u32,
top_right: rad_0[1].round() as u32,
bottom_right: rad_0[2].round() as u32,
bottom_left: rad_0[3].round() as u32,
})
},
)
.discard(),
iced_runtime::window::run_with_handle(id, init_windowing_system), iced_runtime::window::run_with_handle(id, init_windowing_system),
]); ]);
} }
@ -1537,3 +1411,39 @@ impl<App: Application> Cosmic<App> {
.discard() .discard()
} }
} }
#[cfg(all(feature = "wayland", target_os = "linux"))]
fn corners(
surface_type: SurfaceIdWrapper,
rounded: bool,
theme: &Theme,
) -> iced_runtime::platform_specific::wayland::CornerRadius {
let theme = theme.cosmic();
if let SurfaceIdWrapper::Popup(_) = surface_type {
let radius_m = theme.radius_m();
iced_runtime::platform_specific::wayland::CornerRadius {
top_left: radius_m[0].round() as u32,
top_right: radius_m[1].round() as u32,
bottom_right: radius_m[2].round() as u32,
bottom_left: radius_m[3].round() as u32,
}
} else if let SurfaceIdWrapper::Window(_) = surface_type
&& rounded
{
let radius_0 = theme.radius_0();
iced_runtime::platform_specific::wayland::CornerRadius {
top_left: radius_0[0].round() as u32,
top_right: radius_0[1].round() as u32,
bottom_right: radius_0[2].round() as u32,
bottom_left: radius_0[3].round() as u32,
}
} else {
let radius_s = theme.radius_s().map(|x| if x < 4.0 { x } else { x + 4.0 });
iced_runtime::platform_specific::wayland::CornerRadius {
top_left: radius_s[0].round() as u32,
top_right: radius_s[1].round() as u32,
bottom_right: radius_s[2].round() as u32,
bottom_left: radius_s[3].round() as u32,
}
}
}

View file

@ -117,6 +117,45 @@ pub enum AppType {
Applet, Applet,
} }
impl AppType {
/// Calculate suggested corners for each app type main window
#[cfg(all(feature = "wayland", target_os = "linux"))]
pub fn corners(
&self,
theme: &Theme,
rounded: bool,
) -> iced_runtime::platform_specific::wayland::CornerRadius {
let theme = theme.cosmic();
if let Self::Applet = self {
let radius_l = theme.radius_l();
iced_runtime::platform_specific::wayland::CornerRadius {
top_left: radius_l[0].round() as u32,
top_right: radius_l[1].round() as u32,
bottom_right: radius_l[2].round() as u32,
bottom_left: radius_l[3].round() as u32,
}
} else if let Self::Window = self
&& rounded
{
let radius_0 = theme.radius_0();
iced_runtime::platform_specific::wayland::CornerRadius {
top_left: radius_0[0].round() as u32,
top_right: radius_0[1].round() as u32,
bottom_right: radius_0[2].round() as u32,
bottom_left: radius_0[3].round() as u32,
}
} else {
let radius_s = theme.radius_s().map(|x| if x < 4.0 { x } else { x + 4.0 });
iced_runtime::platform_specific::wayland::CornerRadius {
top_left: radius_s[0].round() as u32,
top_right: radius_s[1].round() as u32,
bottom_right: radius_s[2].round() as u32,
bottom_left: radius_s[3].round() as u32,
}
}
}
}
impl Default for Core { impl Default for Core {
fn default() -> Self { fn default() -> Self {
Self { Self {