2023-08-02 11:54:07 +02:00
|
|
|
// Copyright 2023 System76 <info@system76.com>
|
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2025-03-14 11:56:21 -04:00
|
|
|
use std::collections::HashMap;
|
2023-12-07 15:27:52 -05:00
|
|
|
|
2024-10-02 00:32:08 +02:00
|
|
|
use crate::widget::nav_bar;
|
2023-10-16 16:19:04 -04:00
|
|
|
use cosmic_config::CosmicConfigEntry;
|
|
|
|
|
use cosmic_theme::ThemeMode;
|
2025-03-21 03:17:59 +01:00
|
|
|
use iced::{Limits, Size, window};
|
2023-12-07 15:27:52 -05:00
|
|
|
use iced_core::window::Id;
|
2024-02-21 17:34:42 -05:00
|
|
|
use palette::Srgba;
|
2024-04-09 16:54:50 +02:00
|
|
|
use slotmap::Key;
|
2023-10-16 16:19:04 -04:00
|
|
|
|
2023-09-14 01:25:01 +02:00
|
|
|
use crate::Theme;
|
|
|
|
|
|
2023-08-02 11:54:07 +02:00
|
|
|
/// Status of the nav bar and its panels.
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct NavBar {
|
|
|
|
|
active: bool,
|
2024-04-09 16:54:50 +02:00
|
|
|
context_id: crate::widget::nav_bar::Id,
|
2023-08-02 11:54:07 +02:00
|
|
|
toggled: bool,
|
|
|
|
|
toggled_condensed: bool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// COSMIC-specific settings for windows.
|
|
|
|
|
#[allow(clippy::struct_excessive_bools)]
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct Window {
|
2023-10-12 13:23:59 +02:00
|
|
|
/// Label to display as header bar title.
|
2023-09-13 15:26:51 +02:00
|
|
|
pub header_title: String,
|
2023-08-08 18:09:57 -04:00
|
|
|
pub use_template: bool,
|
2023-12-21 11:53:19 -07:00
|
|
|
pub content_container: bool,
|
2024-09-20 11:25:52 -06:00
|
|
|
pub context_is_overlay: bool,
|
2023-08-02 11:54:07 +02:00
|
|
|
pub sharp_corners: bool,
|
2023-10-12 13:23:59 +02:00
|
|
|
pub show_context: bool,
|
2023-08-02 11:54:07 +02:00
|
|
|
pub show_headerbar: bool,
|
|
|
|
|
pub show_window_menu: bool,
|
2024-08-26 09:35:41 -06:00
|
|
|
pub show_close: bool,
|
2023-08-02 11:54:07 +02:00
|
|
|
pub show_maximize: bool,
|
|
|
|
|
pub show_minimize: bool,
|
2025-10-03 18:19:19 +02:00
|
|
|
pub is_maximized: bool,
|
2024-10-16 20:36:46 -04:00
|
|
|
height: f32,
|
|
|
|
|
width: f32,
|
2023-08-02 11:54:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// COSMIC-specific application settings
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct Core {
|
|
|
|
|
/// Enables debug features in cosmic/iced.
|
|
|
|
|
pub debug: bool,
|
|
|
|
|
|
2024-03-18 15:49:01 +01:00
|
|
|
/// Disables loading the icon theme from cosmic-config.
|
|
|
|
|
pub(super) icon_theme_override: bool,
|
|
|
|
|
|
2023-08-02 11:54:07 +02:00
|
|
|
/// Whether the window is too small for the nav bar + main content.
|
|
|
|
|
is_condensed: bool,
|
|
|
|
|
|
2024-03-01 13:53:15 -05:00
|
|
|
/// Enables built in keyboard navigation
|
|
|
|
|
pub(super) keyboard_nav: bool,
|
|
|
|
|
|
2023-08-02 11:54:07 +02:00
|
|
|
/// Current status of the nav bar panel.
|
|
|
|
|
nav_bar: NavBar,
|
|
|
|
|
|
|
|
|
|
/// Scaling factor used by the application
|
|
|
|
|
scale_factor: f32,
|
|
|
|
|
|
2024-03-11 15:21:48 -04:00
|
|
|
/// Window focus state
|
2025-07-16 13:48:08 -04:00
|
|
|
pub(super) focused_window: Vec<window::Id>,
|
2024-03-11 15:21:48 -04:00
|
|
|
|
2023-10-26 14:21:07 -04:00
|
|
|
pub(super) theme_sub_counter: u64,
|
2023-09-14 01:25:01 +02:00
|
|
|
/// Last known system theme
|
|
|
|
|
pub(super) system_theme: Theme,
|
|
|
|
|
|
2024-02-21 17:34:42 -05:00
|
|
|
/// Configured theme mode
|
2023-10-16 16:19:04 -04:00
|
|
|
pub(super) system_theme_mode: ThemeMode,
|
|
|
|
|
|
2024-02-21 17:34:42 -05:00
|
|
|
pub(super) portal_is_dark: Option<bool>,
|
|
|
|
|
|
|
|
|
|
pub(super) portal_accent: Option<Srgba>,
|
|
|
|
|
|
|
|
|
|
pub(super) portal_is_high_contrast: Option<bool>,
|
|
|
|
|
|
2023-12-07 15:27:52 -05:00
|
|
|
pub(super) title: HashMap<Id, String>,
|
2023-09-18 07:45:11 +02:00
|
|
|
|
2023-08-02 11:54:07 +02:00
|
|
|
pub window: Window,
|
2023-09-18 07:45:11 +02:00
|
|
|
|
2023-08-08 18:09:57 -04:00
|
|
|
#[cfg(feature = "applet")]
|
2023-09-18 07:45:11 +02:00
|
|
|
pub applet: crate::applet::Context,
|
2023-11-13 16:28:48 -05:00
|
|
|
|
2023-11-21 15:18:39 -05:00
|
|
|
#[cfg(feature = "single-instance")]
|
|
|
|
|
pub(crate) single_instance: bool,
|
2023-12-15 17:00:08 -05:00
|
|
|
|
2025-08-20 16:09:17 +02:00
|
|
|
#[cfg(all(feature = "dbus-config", target_os = "linux"))]
|
2023-12-15 17:00:08 -05:00
|
|
|
pub(crate) settings_daemon: Option<cosmic_settings_daemon::CosmicSettingsDaemonProxy<'static>>,
|
2024-10-16 20:36:46 -04:00
|
|
|
|
2024-10-21 17:32:16 -04:00
|
|
|
pub(crate) main_window: Option<window::Id>,
|
2024-10-16 20:36:46 -04:00
|
|
|
|
|
|
|
|
pub(crate) exit_on_main_window_closed: bool,
|
2025-03-14 11:56:21 -04:00
|
|
|
|
|
|
|
|
pub(crate) menu_bars: HashMap<crate::widget::Id, (Limits, Size)>,
|
2025-09-24 15:55:34 -04:00
|
|
|
|
2026-03-30 18:51:33 -04:00
|
|
|
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
2025-09-24 15:55:34 -04:00
|
|
|
pub(crate) sync_window_border_radii_to_theme: bool,
|
2023-08-02 11:54:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Core {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
debug: false,
|
2024-03-18 15:49:01 +01:00
|
|
|
icon_theme_override: false,
|
2023-08-02 11:54:07 +02:00
|
|
|
is_condensed: false,
|
2024-03-01 13:53:15 -05:00
|
|
|
keyboard_nav: true,
|
2023-08-02 11:54:07 +02:00
|
|
|
nav_bar: NavBar {
|
|
|
|
|
active: true,
|
2024-04-09 16:54:50 +02:00
|
|
|
context_id: crate::widget::nav_bar::Id::null(),
|
2023-08-02 11:54:07 +02:00
|
|
|
toggled: true,
|
2024-05-30 21:39:59 +02:00
|
|
|
toggled_condensed: false,
|
2023-08-02 11:54:07 +02:00
|
|
|
},
|
|
|
|
|
scale_factor: 1.0,
|
2023-12-07 15:27:52 -05:00
|
|
|
title: HashMap::new(),
|
2023-10-26 14:21:07 -04:00
|
|
|
theme_sub_counter: 0,
|
2023-09-14 01:25:01 +02:00
|
|
|
system_theme: crate::theme::active(),
|
2023-10-16 16:19:04 -04:00
|
|
|
system_theme_mode: ThemeMode::config()
|
|
|
|
|
.map(|c| {
|
|
|
|
|
ThemeMode::get_entry(&c).unwrap_or_else(|(errors, mode)| {
|
2025-02-19 16:57:24 +01:00
|
|
|
for why in errors.into_iter().filter(cosmic_config::Error::is_err) {
|
2024-03-05 16:05:33 +01:00
|
|
|
tracing::error!(?why, "ThemeMode config entry error");
|
|
|
|
|
}
|
|
|
|
|
mode
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_default(),
|
2023-08-02 11:54:07 +02:00
|
|
|
window: Window {
|
2023-09-13 15:26:51 +02:00
|
|
|
header_title: String::new(),
|
2023-08-08 18:09:57 -04:00
|
|
|
use_template: true,
|
2023-12-21 11:53:19 -07:00
|
|
|
content_container: true,
|
2024-09-20 11:25:52 -06:00
|
|
|
context_is_overlay: true,
|
2023-08-02 11:54:07 +02:00
|
|
|
sharp_corners: false,
|
2023-10-12 13:23:59 +02:00
|
|
|
show_context: false,
|
2023-08-02 11:54:07 +02:00
|
|
|
show_headerbar: true,
|
2024-08-26 09:35:41 -06:00
|
|
|
show_close: true,
|
2023-08-02 11:54:07 +02:00
|
|
|
show_maximize: true,
|
|
|
|
|
show_minimize: true,
|
|
|
|
|
show_window_menu: false,
|
2025-10-03 18:19:19 +02:00
|
|
|
is_maximized: false,
|
2024-10-16 20:36:46 -04:00
|
|
|
height: 0.,
|
|
|
|
|
width: 0.,
|
2023-08-02 11:54:07 +02:00
|
|
|
},
|
2025-07-16 13:48:08 -04:00
|
|
|
focused_window: Vec::new(),
|
2023-08-08 18:09:57 -04:00
|
|
|
#[cfg(feature = "applet")]
|
2023-09-18 07:45:11 +02:00
|
|
|
applet: crate::applet::Context::default(),
|
2023-11-21 15:18:39 -05:00
|
|
|
#[cfg(feature = "single-instance")]
|
2023-11-13 16:28:48 -05:00
|
|
|
single_instance: false,
|
2025-08-20 16:09:17 +02:00
|
|
|
#[cfg(all(feature = "dbus-config", target_os = "linux"))]
|
2023-12-15 17:00:08 -05:00
|
|
|
settings_daemon: None,
|
2024-02-21 17:34:42 -05:00
|
|
|
portal_is_dark: None,
|
|
|
|
|
portal_accent: None,
|
|
|
|
|
portal_is_high_contrast: None,
|
2024-10-21 17:32:16 -04:00
|
|
|
main_window: None,
|
2024-10-16 20:36:46 -04:00
|
|
|
exit_on_main_window_closed: true,
|
2025-03-14 11:56:21 -04:00
|
|
|
menu_bars: HashMap::new(),
|
2026-03-30 18:51:33 -04:00
|
|
|
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
2025-09-24 17:52:03 -04:00
|
|
|
sync_window_border_radii_to_theme: true,
|
2023-08-02 11:54:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Core {
|
|
|
|
|
/// Whether the window is too small for the nav bar + main content.
|
|
|
|
|
#[must_use]
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub const fn is_condensed(&self) -> bool {
|
2023-08-02 11:54:07 +02:00
|
|
|
self.is_condensed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The scaling factor used by the application.
|
|
|
|
|
#[must_use]
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub const fn scale_factor(&self) -> f32 {
|
2023-08-02 11:54:07 +02:00
|
|
|
self.scale_factor
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-01 13:53:15 -05:00
|
|
|
/// Enable or disable keyboard navigation
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub const fn set_keyboard_nav(&mut self, enabled: bool) {
|
2024-03-01 13:53:15 -05:00
|
|
|
self.keyboard_nav = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Enable or disable keyboard navigation
|
2025-03-21 03:17:59 +01:00
|
|
|
#[must_use]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub const fn keyboard_nav(&self) -> bool {
|
2024-03-01 13:53:15 -05:00
|
|
|
self.keyboard_nav
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-02 11:54:07 +02:00
|
|
|
/// Changes the scaling factor used by the application.
|
2025-03-21 03:17:59 +01:00
|
|
|
#[cold]
|
2023-08-02 11:54:07 +02:00
|
|
|
pub(crate) fn set_scale_factor(&mut self, factor: f32) {
|
|
|
|
|
self.scale_factor = factor;
|
|
|
|
|
self.is_condensed_update();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 13:36:23 +02:00
|
|
|
/// Set header bar title
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-10-12 13:36:23 +02:00
|
|
|
pub fn set_header_title(&mut self, title: String) {
|
|
|
|
|
self.window.header_title = title;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-08-02 11:54:07 +02:00
|
|
|
/// Whether to show or hide the main window's content.
|
|
|
|
|
pub(crate) fn show_content(&self) -> bool {
|
|
|
|
|
!self.is_condensed || !self.nav_bar.toggled_condensed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(clippy::cast_precision_loss)]
|
2025-03-21 03:17:59 +01:00
|
|
|
/// Call this whenever the scaling factor or window width has changed.
|
2023-08-02 11:54:07 +02:00
|
|
|
fn is_condensed_update(&mut self) {
|
2024-09-23 10:02:34 -06:00
|
|
|
// Nav bar (280px) + padding (8px) + content (360px)
|
|
|
|
|
let mut breakpoint = 280.0 + 8.0 + 360.0;
|
2024-09-20 11:25:52 -06:00
|
|
|
//TODO: the app may return None from the context_drawer function even if show_context is true
|
2024-09-23 10:02:34 -06:00
|
|
|
if self.window.show_context && !self.window.context_is_overlay {
|
|
|
|
|
// Context drawer min width (344px) + padding (8px)
|
|
|
|
|
breakpoint += 344.0 + 8.0;
|
2024-09-20 11:25:52 -06:00
|
|
|
};
|
2025-03-14 11:56:21 -04:00
|
|
|
self.is_condensed = (breakpoint * self.scale_factor) > self.window.width;
|
2023-08-02 11:54:07 +02:00
|
|
|
self.nav_bar_update();
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2024-09-20 11:25:52 -06:00
|
|
|
fn condensed_conflict(&self) -> bool {
|
|
|
|
|
// There is a conflict if the view is condensed and both the nav bar and context drawer are open on the same layer
|
|
|
|
|
self.is_condensed
|
|
|
|
|
&& self.nav_bar.toggled_condensed
|
|
|
|
|
&& self.window.show_context
|
|
|
|
|
&& !self.window.context_is_overlay
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2024-09-23 10:02:34 -06:00
|
|
|
pub(crate) fn context_width(&self, has_nav: bool) -> f32 {
|
2025-03-14 11:56:21 -04:00
|
|
|
let window_width = self.window.width / self.scale_factor;
|
2024-09-23 10:02:34 -06:00
|
|
|
|
|
|
|
|
// Content width (360px) + padding (8px)
|
|
|
|
|
let mut reserved_width = 360.0 + 8.0;
|
|
|
|
|
if has_nav {
|
|
|
|
|
// Navbar width (280px) + padding (8px)
|
|
|
|
|
reserved_width += 280.0 + 8.0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[allow(clippy::manual_clamp)]
|
2024-09-23 10:02:34 -06:00
|
|
|
// This logic is to ensure the context drawer does not take up too much of the content's space
|
|
|
|
|
// The minimum width is 344px and the maximum with is 480px
|
|
|
|
|
// We want to keep the content at least 360px until going down to the minimum width
|
|
|
|
|
(window_width - reserved_width).min(480.0).max(344.0)
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[cold]
|
2024-09-20 11:25:52 -06:00
|
|
|
pub fn set_show_context(&mut self, show: bool) {
|
|
|
|
|
self.window.show_context = show;
|
|
|
|
|
self.is_condensed_update();
|
|
|
|
|
// Ensure nav bar is closed if condensed view and context drawer is opened
|
|
|
|
|
if self.condensed_conflict() {
|
|
|
|
|
self.nav_bar.toggled_condensed = false;
|
|
|
|
|
self.is_condensed_update();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2025-03-14 11:56:21 -04:00
|
|
|
pub fn main_window_is(&self, id: iced::window::Id) -> bool {
|
|
|
|
|
self.main_window_id().is_some_and(|main_id| main_id == id)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-02 11:54:07 +02:00
|
|
|
/// Whether the nav panel is visible or not
|
|
|
|
|
#[must_use]
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub const fn nav_bar_active(&self) -> bool {
|
2023-08-02 11:54:07 +02:00
|
|
|
self.nav_bar.active
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-08-02 11:54:07 +02:00
|
|
|
pub fn nav_bar_toggle(&mut self) {
|
|
|
|
|
self.nav_bar.toggled = !self.nav_bar.toggled;
|
|
|
|
|
self.nav_bar_set_toggled_condensed(self.nav_bar.toggled);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-08-02 11:54:07 +02:00
|
|
|
pub fn nav_bar_toggle_condensed(&mut self) {
|
|
|
|
|
self.nav_bar_set_toggled_condensed(!self.nav_bar.toggled_condensed);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub(crate) const fn nav_bar_context(&self) -> nav_bar::Id {
|
2024-04-09 16:54:50 +02:00
|
|
|
self.nav_bar.context_id
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2024-04-09 16:54:50 +02:00
|
|
|
pub(crate) fn nav_bar_set_context(&mut self, id: nav_bar::Id) {
|
|
|
|
|
self.nav_bar.context_id = id;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2024-03-18 09:23:07 -06:00
|
|
|
pub fn nav_bar_set_toggled(&mut self, toggled: bool) {
|
|
|
|
|
self.nav_bar.toggled = toggled;
|
|
|
|
|
self.nav_bar_set_toggled_condensed(self.nav_bar.toggled);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[cold]
|
2023-08-02 11:54:07 +02:00
|
|
|
pub(crate) fn nav_bar_set_toggled_condensed(&mut self, toggled: bool) {
|
|
|
|
|
self.nav_bar.toggled_condensed = toggled;
|
|
|
|
|
self.nav_bar_update();
|
2024-09-20 11:25:52 -06:00
|
|
|
// Ensure context drawer is closed if condensed view and nav bar is opened
|
|
|
|
|
if self.condensed_conflict() {
|
|
|
|
|
self.window.show_context = false;
|
|
|
|
|
self.is_condensed_update();
|
|
|
|
|
// Sync nav bar state if the view is no longer condensed after closing the context drawer
|
|
|
|
|
if !self.is_condensed {
|
|
|
|
|
self.nav_bar.toggled = toggled;
|
|
|
|
|
self.nav_bar_update();
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-02 11:54:07 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-08-02 11:54:07 +02:00
|
|
|
pub(crate) fn nav_bar_update(&mut self) {
|
|
|
|
|
self.nav_bar.active = if self.is_condensed {
|
|
|
|
|
self.nav_bar.toggled_condensed
|
|
|
|
|
} else {
|
|
|
|
|
self.nav_bar.toggled
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-08-02 11:54:07 +02:00
|
|
|
/// Set the height of the main window.
|
2025-03-21 03:17:59 +01:00
|
|
|
pub(crate) const fn set_window_height(&mut self, new_height: f32) {
|
2023-08-02 11:54:07 +02:00
|
|
|
self.window.height = new_height;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-08-02 11:54:07 +02:00
|
|
|
/// Set the width of the main window.
|
2024-10-16 20:36:46 -04:00
|
|
|
pub(crate) fn set_window_width(&mut self, new_width: f32) {
|
2023-08-02 11:54:07 +02:00
|
|
|
self.window.width = new_width;
|
|
|
|
|
self.is_condensed_update();
|
|
|
|
|
}
|
2023-10-16 16:19:04 -04:00
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-10-16 16:19:04 -04:00
|
|
|
/// Get the current system theme
|
2025-03-21 03:17:59 +01:00
|
|
|
pub const fn system_theme(&self) -> &Theme {
|
2023-10-16 16:19:04 -04:00
|
|
|
&self.system_theme
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2023-10-16 16:19:04 -04:00
|
|
|
#[must_use]
|
|
|
|
|
/// Get the current system theme mode
|
2025-03-21 03:17:59 +01:00
|
|
|
pub const fn system_theme_mode(&self) -> ThemeMode {
|
2023-10-16 16:19:04 -04:00
|
|
|
self.system_theme_mode
|
|
|
|
|
}
|
2023-12-15 17:00:08 -05:00
|
|
|
|
2024-01-18 19:01:11 -05:00
|
|
|
pub fn watch_config<
|
|
|
|
|
T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone + PartialEq,
|
|
|
|
|
>(
|
2023-12-15 17:00:08 -05:00
|
|
|
&self,
|
|
|
|
|
config_id: &'static str,
|
2024-01-18 19:01:11 -05:00
|
|
|
) -> iced::Subscription<cosmic_config::Update<T>> {
|
2025-08-20 16:09:17 +02:00
|
|
|
#[cfg(all(feature = "dbus-config", target_os = "linux"))]
|
2025-10-11 13:36:35 +10:00
|
|
|
if let Some(settings_daemon) = self.settings_daemon.as_ref() {
|
|
|
|
|
return cosmic_config::dbus::watcher_subscription(
|
|
|
|
|
settings_daemon.clone(),
|
|
|
|
|
config_id,
|
|
|
|
|
false,
|
|
|
|
|
);
|
2023-12-28 18:25:12 -05:00
|
|
|
}
|
2024-01-18 19:01:11 -05:00
|
|
|
cosmic_config::config_subscription(
|
|
|
|
|
std::any::TypeId::of::<T>(),
|
|
|
|
|
std::borrow::Cow::Borrowed(config_id),
|
|
|
|
|
T::VERSION,
|
|
|
|
|
)
|
2023-12-28 18:25:12 -05:00
|
|
|
}
|
|
|
|
|
|
2024-01-18 19:01:11 -05:00
|
|
|
pub fn watch_state<
|
|
|
|
|
T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone + PartialEq,
|
|
|
|
|
>(
|
2023-12-28 18:25:12 -05:00
|
|
|
&self,
|
|
|
|
|
state_id: &'static str,
|
2024-01-18 19:01:11 -05:00
|
|
|
) -> iced::Subscription<cosmic_config::Update<T>> {
|
2025-08-20 16:09:17 +02:00
|
|
|
#[cfg(all(feature = "dbus-config", target_os = "linux"))]
|
2025-10-11 13:36:35 +10:00
|
|
|
if let Some(settings_daemon) = self.settings_daemon.as_ref() {
|
|
|
|
|
return cosmic_config::dbus::watcher_subscription(
|
|
|
|
|
settings_daemon.clone(),
|
|
|
|
|
state_id,
|
|
|
|
|
true,
|
|
|
|
|
);
|
2023-12-15 17:00:08 -05:00
|
|
|
}
|
2024-01-18 19:01:11 -05:00
|
|
|
cosmic_config::config_subscription(
|
|
|
|
|
std::any::TypeId::of::<T>(),
|
|
|
|
|
std::borrow::Cow::Borrowed(state_id),
|
|
|
|
|
T::VERSION,
|
|
|
|
|
)
|
2023-12-15 17:00:08 -05:00
|
|
|
}
|
2024-02-21 17:34:42 -05:00
|
|
|
|
2024-03-11 15:21:48 -04:00
|
|
|
/// Get the current focused window if it exists
|
|
|
|
|
#[must_use]
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2025-07-16 13:48:08 -04:00
|
|
|
pub fn focused_window(&self) -> Option<window::Id> {
|
|
|
|
|
self.focused_window.last().copied()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the current focus chain of windows
|
|
|
|
|
#[must_use]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn focus_chain(&self) -> &[window::Id] {
|
|
|
|
|
&self.focused_window
|
2024-03-11 15:21:48 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-21 17:34:42 -05:00
|
|
|
/// Whether the application should use a dark theme, according to the system
|
|
|
|
|
#[must_use]
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2024-02-21 17:34:42 -05:00
|
|
|
pub fn system_is_dark(&self) -> bool {
|
|
|
|
|
self.portal_is_dark
|
|
|
|
|
.unwrap_or(self.system_theme_mode.is_dark)
|
|
|
|
|
}
|
2024-10-16 20:36:46 -04:00
|
|
|
|
|
|
|
|
/// The [`Id`] of the main window
|
2024-10-21 18:25:25 -04:00
|
|
|
#[must_use]
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2024-10-16 20:36:46 -04:00
|
|
|
pub fn main_window_id(&self) -> Option<window::Id> {
|
2024-10-21 17:32:16 -04:00
|
|
|
self.main_window.filter(|id| iced::window::Id::NONE != *id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reset the tracked main window to a new value
|
2025-03-21 03:17:59 +01:00
|
|
|
#[inline]
|
2024-10-21 18:25:25 -04:00
|
|
|
pub fn set_main_window_id(&mut self, mut id: Option<window::Id>) -> Option<window::Id> {
|
|
|
|
|
std::mem::swap(&mut self.main_window, &mut id);
|
|
|
|
|
id
|
2024-10-16 20:36:46 -04:00
|
|
|
}
|
2025-03-14 11:56:21 -04:00
|
|
|
|
|
|
|
|
pub fn drag<M: Send + 'static>(&self, id: Option<window::Id>) -> crate::app::Task<M> {
|
|
|
|
|
let Some(id) = id.or(self.main_window) else {
|
|
|
|
|
return iced::Task::none();
|
|
|
|
|
};
|
|
|
|
|
crate::command::drag(id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn maximize<M: Send + 'static>(
|
|
|
|
|
&self,
|
|
|
|
|
id: Option<window::Id>,
|
|
|
|
|
maximized: bool,
|
|
|
|
|
) -> crate::app::Task<M> {
|
|
|
|
|
let Some(id) = id.or(self.main_window) else {
|
|
|
|
|
return iced::Task::none();
|
|
|
|
|
};
|
|
|
|
|
crate::command::maximize(id, maximized)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn minimize<M: Send + 'static>(&self, id: Option<window::Id>) -> crate::app::Task<M> {
|
|
|
|
|
let Some(id) = id.or(self.main_window) else {
|
|
|
|
|
return iced::Task::none();
|
|
|
|
|
};
|
|
|
|
|
crate::command::minimize(id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_title<M: Send + 'static>(
|
|
|
|
|
&self,
|
|
|
|
|
id: Option<window::Id>,
|
|
|
|
|
title: String,
|
|
|
|
|
) -> crate::app::Task<M> {
|
|
|
|
|
let Some(id) = id.or(self.main_window) else {
|
|
|
|
|
return iced::Task::none();
|
|
|
|
|
};
|
|
|
|
|
crate::command::set_title(id, title)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_windowed<M: Send + 'static>(&self, id: Option<window::Id>) -> crate::app::Task<M> {
|
|
|
|
|
let Some(id) = id.or(self.main_window) else {
|
|
|
|
|
return iced::Task::none();
|
|
|
|
|
};
|
|
|
|
|
crate::command::set_windowed(id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn toggle_maximize<M: Send + 'static>(
|
|
|
|
|
&self,
|
|
|
|
|
id: Option<window::Id>,
|
|
|
|
|
) -> crate::app::Task<M> {
|
|
|
|
|
let Some(id) = id.or(self.main_window) else {
|
|
|
|
|
return iced::Task::none();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
crate::command::toggle_maximize(id)
|
|
|
|
|
}
|
2025-09-24 15:55:34 -04:00
|
|
|
|
|
|
|
|
// TODO should we emit tasks setting the corner radius or unsetting it if this is changed?
|
2026-03-30 18:51:33 -04:00
|
|
|
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
2025-09-24 15:55:34 -04:00
|
|
|
pub fn set_sync_window_border_radii_to_theme(&mut self, sync: bool) {
|
|
|
|
|
self.sync_window_border_radii_to_theme = sync;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 18:51:33 -04:00
|
|
|
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
2025-09-24 15:55:34 -04:00
|
|
|
pub fn sync_window_border_radii_to_theme(&self) -> bool {
|
|
|
|
|
self.sync_window_border_radii_to_theme
|
|
|
|
|
}
|
2023-08-02 11:54:07 +02:00
|
|
|
}
|