chore: updates after iced-rebase
This commit is contained in:
parent
bd0d180482
commit
71d9d6d5bb
41 changed files with 1786 additions and 2396 deletions
2736
Cargo.lock
generated
2736
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
16
Cargo.toml
16
Cargo.toml
|
|
@ -30,8 +30,6 @@ cosmic-applets-config = { path = "cosmic-applets-config" }
|
||||||
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [
|
||||||
"client",
|
"client",
|
||||||
], rev = "d0e95be" }
|
], rev = "d0e95be" }
|
||||||
cosmic-time = { git = "https://github.com/pop-os/cosmic-time", default-features = false }
|
|
||||||
# cosmic-time = { path = "../cosmic-time", default-features = false ] }
|
|
||||||
|
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
|
|
@ -59,24 +57,26 @@ tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
|
||||||
tracing-log = "0.2.0"
|
tracing-log = "0.2.0"
|
||||||
tokio = { version = "1.49.0", features = ["full"] }
|
tokio = { version = "1.49.0", features = ["full"] }
|
||||||
|
# cosmic-config = { path = "../libcosmic/cosmic-config" }
|
||||||
cosmic-config = { git = "https://github.com/pop-os/libcosmic" }
|
cosmic-config = { git = "https://github.com/pop-os/libcosmic" }
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
# opt-level = 3
|
||||||
panic = "abort"
|
# panic = "abort"
|
||||||
lto = "thin"
|
# lto = "thin"
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
[workspace.metadata.cargo-machete]
|
[workspace.metadata.cargo-machete]
|
||||||
ignored = ["libcosmic"]
|
ignored = ["libcosmic"]
|
||||||
|
|
||||||
# [patch."https://github.com/pop-os/libcosmic"]
|
# [patch."https://github.com/pop-os/libcosmic"]
|
||||||
# cosmic-config = { git = "https://github.com/pop-os/libcosmic//", branch = "" }
|
|
||||||
# libcosmic = { git = "https://github.com/pop-os/libcosmic//", branch = "" }
|
|
||||||
# iced_futures = { git = "https://github.com/pop-os/libcosmic//", branch = "" }
|
|
||||||
# cosmic-config = { path = "../libcosmic/cosmic-config" }
|
# cosmic-config = { path = "../libcosmic/cosmic-config" }
|
||||||
# libcosmic = { path = "../libcosmic" }
|
# libcosmic = { path = "../libcosmic" }
|
||||||
# iced_futures = { path = "../libcosmic/iced/futures" }
|
# iced_futures = { path = "../libcosmic/iced/futures" }
|
||||||
|
# cosmic-config = { git = "https://github.com/pop-os/libcosmic//" }
|
||||||
|
# libcosmic = { git = "https://github.com/pop-os/libcosmic//" }
|
||||||
|
# iced_futures = { git = "https://github.com/pop-os/libcosmic//" }
|
||||||
|
|
||||||
# [patch."https://github.com/pop-os/winit.git"]
|
# [patch."https://github.com/pop-os/winit.git"]
|
||||||
# winit = { git = "https://github.com/rust-windowing/winit.git", rev = "241b7a80bba96c91fa3901729cd5dec66abb9be4" }
|
# winit = { git = "https://github.com/rust-windowing/winit.git", rev = "241b7a80bba96c91fa3901729cd5dec66abb9be4" }
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ use cctk::{
|
||||||
workspace::v1::client::ext_workspace_handle_v1::ExtWorkspaceHandleV1,
|
workspace::v1::client::ext_workspace_handle_v1::ExtWorkspaceHandleV1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use cosmic::desktop::fde::{self, DesktopEntry, get_languages_from_env, unicase::Ascii};
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
Apply, Element, Task, app,
|
Apply, Element, Task, app,
|
||||||
applet::{
|
applet::{
|
||||||
|
|
@ -34,20 +33,27 @@ use cosmic::{
|
||||||
clipboard::mime::{AllowedMimeTypes, AsMimeTypes},
|
clipboard::mime::{AllowedMimeTypes, AsMimeTypes},
|
||||||
event::listen_with,
|
event::listen_with,
|
||||||
platform_specific::shell::commands::popup::{destroy_popup, get_popup},
|
platform_specific::shell::commands::popup::{destroy_popup, get_popup},
|
||||||
widget::{Column, Row, column, mouse_area, row, stack, vertical_rule, vertical_space},
|
widget::{
|
||||||
|
Column, Row, column, mouse_area, row, rule::vertical as vertical_rule,
|
||||||
|
space::horizontal as horizontal_space, space::vertical as vertical_space, stack,
|
||||||
|
},
|
||||||
window,
|
window,
|
||||||
},
|
},
|
||||||
iced_runtime::{core::event, dnd::peek_dnd},
|
iced_runtime::{core::event, dnd::peek_dnd},
|
||||||
surface,
|
surface,
|
||||||
theme::{self, Button, Container},
|
theme::{self, Button, Container},
|
||||||
widget::{
|
widget::{
|
||||||
DndDestination, Image, button, container, divider, dnd_source, horizontal_space,
|
DndDestination, Image, button, container, divider, dnd_source,
|
||||||
icon::{self, from_name},
|
icon::{self, from_name},
|
||||||
image::Handle,
|
image::Handle,
|
||||||
rectangle_tracker::{RectangleTracker, RectangleUpdate, rectangle_tracker_subscription},
|
rectangle_tracker::{RectangleTracker, RectangleUpdate, rectangle_tracker_subscription},
|
||||||
svg, text,
|
svg, text,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use cosmic::{
|
||||||
|
desktop::fde::{self, DesktopEntry, get_languages_from_env, unicase::Ascii},
|
||||||
|
widget::DndSource,
|
||||||
|
};
|
||||||
use cosmic_app_list_config::{APP_ID, AppListConfig};
|
use cosmic_app_list_config::{APP_ID, AppListConfig};
|
||||||
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
|
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
|
||||||
use futures::future::pending;
|
use futures::future::pending;
|
||||||
|
|
@ -295,7 +301,7 @@ impl DockItem {
|
||||||
|
|
||||||
let path = desktop_info.path.clone();
|
let path = desktop_info.path.clone();
|
||||||
let icon_button = if dnd_source_enabled && interaction_enabled {
|
let icon_button = if dnd_source_enabled && interaction_enabled {
|
||||||
dnd_source(icon_button)
|
DndSource::with_id(icon_button, cosmic::widget::Id::new("asdfasdfadfs"))
|
||||||
.window(window_id)
|
.window(window_id)
|
||||||
.drag_icon(move |_| {
|
.drag_icon(move |_| {
|
||||||
(
|
(
|
||||||
|
|
@ -2410,7 +2416,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use cctk::{
|
||||||
};
|
};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
iced::{self, Subscription, stream},
|
iced::{self, Subscription, stream},
|
||||||
iced_core::image::Bytes,
|
iced_core::Bytes,
|
||||||
};
|
};
|
||||||
use image::EncodableLayout;
|
use image::EncodableLayout;
|
||||||
|
|
||||||
|
|
@ -31,16 +31,15 @@ pub static WAYLAND_RX: LazyLock<Mutex<Option<UnboundedReceiver<WaylandUpdate>>>>
|
||||||
LazyLock::new(|| Mutex::new(None));
|
LazyLock::new(|| Mutex::new(None));
|
||||||
|
|
||||||
pub fn wayland_subscription() -> iced::Subscription<WaylandUpdate> {
|
pub fn wayland_subscription() -> iced::Subscription<WaylandUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(std::any::TypeId::of::<WaylandUpdate>(), |_| {
|
||||||
std::any::TypeId::of::<WaylandUpdate>(),
|
|
||||||
stream::channel(50, move |mut output| async move {
|
stream::channel(50, move |mut output| async move {
|
||||||
let mut state = State::Waiting;
|
let mut state = State::Waiting;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
state = start_listening(state, &mut output).await;
|
state = start_listening(state, &mut output).await;
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum State {
|
pub enum State {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ edition = "2024"
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
cctk.workspace = true
|
cctk.workspace = true
|
||||||
cosmic-protocols.workspace = true
|
cosmic-protocols.workspace = true
|
||||||
cosmic-time.workspace = true
|
|
||||||
i18n-embed-fl.workspace = true
|
i18n-embed-fl.workspace = true
|
||||||
i18n-embed.workspace = true
|
i18n-embed.workspace = true
|
||||||
libcosmic.workspace = true
|
libcosmic.workspace = true
|
||||||
|
|
@ -19,6 +18,8 @@ tracing.workspace = true
|
||||||
|
|
||||||
[dependencies.cosmic-settings-a11y-manager-subscription]
|
[dependencies.cosmic-settings-a11y-manager-subscription]
|
||||||
git = "https://github.com/pop-os/cosmic-settings"
|
git = "https://github.com/pop-os/cosmic-settings"
|
||||||
|
# path = "../../cosmic-settings/subscriptions/a11y-manager"
|
||||||
|
|
||||||
[dependencies.cosmic-settings-accessibility-subscription]
|
[dependencies.cosmic-settings-accessibility-subscription]
|
||||||
git = "https://github.com/pop-os/cosmic-settings"
|
git = "https://github.com/pop-os/cosmic-settings"
|
||||||
|
# path = "../../cosmic-settings/subscriptions/accessibility"
|
||||||
|
|
|
||||||
|
|
@ -22,23 +22,16 @@ use cosmic::{
|
||||||
},
|
},
|
||||||
surface,
|
surface,
|
||||||
theme::{self, CosmicTheme},
|
theme::{self, CosmicTheme},
|
||||||
widget::{Column, divider, text},
|
widget::{Column, divider, text, toggler},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cosmic_settings_a11y_manager_subscription::{
|
use cosmic_settings_a11y_manager_subscription::{
|
||||||
self as cosmic_a11y_manager, AccessibilityEvent, AccessibilityRequest, ColorFilter,
|
self as cosmic_a11y_manager, AccessibilityEvent, AccessibilityRequest, ColorFilter,
|
||||||
};
|
};
|
||||||
use cosmic_settings_accessibility_subscription::{self as accessibility};
|
use cosmic_settings_accessibility_subscription::{self as accessibility};
|
||||||
use cosmic_time::{Instant, Timeline, anim, chain, id};
|
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
static READER_TOGGLE: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
static FILTER_TOGGLE: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
static HC_TOGGLE: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
static MAGNIFIER_TOGGLE: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
static INVERT_COLORS_TOGGLE: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
|
|
||||||
pub fn run() -> cosmic::iced::Result {
|
pub fn run() -> cosmic::iced::Result {
|
||||||
cosmic::applet::run::<CosmicA11yApplet>(())
|
cosmic::applet::run::<CosmicA11yApplet>(())
|
||||||
}
|
}
|
||||||
|
|
@ -54,7 +47,6 @@ struct CosmicA11yApplet {
|
||||||
dbus_sender: Option<UnboundedSender<accessibility::Request>>,
|
dbus_sender: Option<UnboundedSender<accessibility::Request>>,
|
||||||
wayland_sender: Option<calloop::channel::Sender<AccessibilityRequest>>,
|
wayland_sender: Option<calloop::channel::Sender<AccessibilityRequest>>,
|
||||||
wayland_protocol_version: Option<u32>,
|
wayland_protocol_version: Option<u32>,
|
||||||
timeline: Timeline,
|
|
||||||
token_tx: Option<channel::Sender<TokenRequest>>,
|
token_tx: Option<channel::Sender<TokenRequest>>,
|
||||||
screen_filter_active: bool,
|
screen_filter_active: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -63,12 +55,11 @@ struct CosmicA11yApplet {
|
||||||
enum Message {
|
enum Message {
|
||||||
TogglePopup,
|
TogglePopup,
|
||||||
CloseRequested(window::Id),
|
CloseRequested(window::Id),
|
||||||
HighContrastEnabled(chain::Toggler, bool),
|
HighContrastEnabled(bool),
|
||||||
ScreenReaderEnabled(chain::Toggler, bool),
|
ScreenReaderEnabled(bool),
|
||||||
MagnifierEnabled(chain::Toggler, bool),
|
MagnifierEnabled(bool),
|
||||||
InvertedColorsEnabled(chain::Toggler, bool),
|
InvertedColorsEnabled(bool),
|
||||||
FilterColorsEnabled(chain::Toggler, bool),
|
FilterColorsEnabled(bool),
|
||||||
Frame(Instant),
|
|
||||||
Token(TokenUpdate),
|
Token(TokenUpdate),
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
DBusUpdate(accessibility::Response),
|
DBusUpdate(accessibility::Response),
|
||||||
|
|
@ -104,28 +95,24 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Message) -> app::Task<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> app::Task<Self::Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::Frame(now) => self.timeline.now(now),
|
Message::ScreenReaderEnabled(enabled) => {
|
||||||
Message::ScreenReaderEnabled(chain, enabled) => {
|
|
||||||
if let Some(tx) = &self.dbus_sender {
|
if let Some(tx) = &self.dbus_sender {
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.reader_enabled = enabled;
|
self.reader_enabled = enabled;
|
||||||
let _ = tx.send(accessibility::Request::ScreenReader(enabled));
|
let _ = tx.send(accessibility::Request::ScreenReader(enabled));
|
||||||
} else {
|
} else {
|
||||||
self.reader_enabled = false;
|
self.reader_enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::MagnifierEnabled(chain, enabled) => {
|
Message::MagnifierEnabled(enabled) => {
|
||||||
if let Some(tx) = &self.wayland_sender {
|
if let Some(tx) = &self.wayland_sender {
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.magnifier_enabled = enabled;
|
self.magnifier_enabled = enabled;
|
||||||
let _ = tx.send(AccessibilityRequest::Magnifier(enabled));
|
let _ = tx.send(AccessibilityRequest::Magnifier(enabled));
|
||||||
} else {
|
} else {
|
||||||
self.magnifier_enabled = false;
|
self.magnifier_enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::InvertedColorsEnabled(chain, enabled) => {
|
Message::InvertedColorsEnabled(enabled) => {
|
||||||
if let Some(tx) = &self.wayland_sender {
|
if let Some(tx) = &self.wayland_sender {
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.inverted_colors_enabled = enabled;
|
self.inverted_colors_enabled = enabled;
|
||||||
let _ = tx.send(AccessibilityRequest::ScreenFilter {
|
let _ = tx.send(AccessibilityRequest::ScreenFilter {
|
||||||
inverted: enabled,
|
inverted: enabled,
|
||||||
|
|
@ -135,9 +122,8 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
self.inverted_colors_enabled = false;
|
self.inverted_colors_enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::FilterColorsEnabled(chain, enabled) => {
|
Message::FilterColorsEnabled(enabled) => {
|
||||||
if let Some(sender) = self.wayland_sender.as_ref() {
|
if let Some(sender) = self.wayland_sender.as_ref() {
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.screen_filter_active = enabled;
|
self.screen_filter_active = enabled;
|
||||||
let _ = sender.send(AccessibilityRequest::ScreenFilter {
|
let _ = sender.send(AccessibilityRequest::ScreenFilter {
|
||||||
inverted: self.inverted_colors_enabled,
|
inverted: self.inverted_colors_enabled,
|
||||||
|
|
@ -149,8 +135,6 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
return destroy_popup(p);
|
return destroy_popup(p);
|
||||||
} else {
|
} else {
|
||||||
self.timeline = Timeline::new();
|
|
||||||
|
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
self.popup.replace(new_id);
|
self.popup.replace(new_id);
|
||||||
|
|
||||||
|
|
@ -170,13 +154,13 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
self.popup = None;
|
self.popup = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::HighContrastEnabled(chain, enabled) => {
|
Message::HighContrastEnabled(enabled) => {
|
||||||
if self.core.system_theme().cosmic().is_high_contrast == enabled
|
if self.core.system_theme().cosmic().is_high_contrast == enabled
|
||||||
|| self.high_contrast.is_some_and(|hc| hc == enabled)
|
|| self.high_contrast.is_some_and(|hc| hc == enabled)
|
||||||
{
|
{
|
||||||
return Task::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.high_contrast = Some(enabled);
|
self.high_contrast = Some(enabled);
|
||||||
|
|
||||||
_ = std::thread::spawn(move || {
|
_ = std::thread::spawn(move || {
|
||||||
|
|
@ -319,62 +303,44 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
||||||
let reader_toggle = padded_control(
|
let reader_toggle = padded_control(
|
||||||
anim!(
|
toggler(self.reader_enabled)
|
||||||
READER_TOGGLE,
|
.on_toggle(Message::ScreenReaderEnabled)
|
||||||
&self.timeline,
|
|
||||||
fl!("screen-reader"),
|
|
||||||
self.reader_enabled,
|
|
||||||
Message::ScreenReaderEnabled,
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill)
|
||||||
|
.label(fl!("screen-reader")),
|
||||||
);
|
);
|
||||||
let magnifier_toggle = padded_control(
|
let magnifier_toggle = padded_control(
|
||||||
anim!(
|
toggler(self.magnifier_enabled)
|
||||||
MAGNIFIER_TOGGLE,
|
.on_toggle(Message::MagnifierEnabled)
|
||||||
&self.timeline,
|
|
||||||
fl!("magnifier"),
|
|
||||||
self.magnifier_enabled,
|
|
||||||
Message::MagnifierEnabled,
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill)
|
||||||
|
.label(fl!("magnifier")),
|
||||||
);
|
);
|
||||||
let invert_colors_toggle = padded_control(
|
let invert_colors_toggle = padded_control(
|
||||||
anim!(
|
toggler(self.inverted_colors_enabled)
|
||||||
INVERT_COLORS_TOGGLE,
|
.on_toggle(Message::InvertedColorsEnabled)
|
||||||
&self.timeline,
|
|
||||||
fl!("invert-colors"),
|
|
||||||
self.inverted_colors_enabled,
|
|
||||||
Message::InvertedColorsEnabled,
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill)
|
||||||
|
.label(fl!("invert-colors")),
|
||||||
);
|
);
|
||||||
|
|
||||||
let hc_colors_toggle = padded_control(
|
let hc_colors_toggle = padded_control(
|
||||||
anim!(
|
toggler(
|
||||||
HC_TOGGLE,
|
|
||||||
&self.timeline,
|
|
||||||
fl!("high-contrast"),
|
|
||||||
self.high_contrast
|
self.high_contrast
|
||||||
.unwrap_or(self.core.system_theme().cosmic().is_high_contrast),
|
.unwrap_or(self.core.system_theme().cosmic().is_high_contrast),
|
||||||
Message::HighContrastEnabled,
|
|
||||||
)
|
)
|
||||||
|
.on_toggle(Message::HighContrastEnabled)
|
||||||
|
.label(fl!("high-contrast"))
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
);
|
);
|
||||||
|
|
||||||
let filter_colors_toggle = padded_control(
|
let filter_colors_toggle = padded_control(
|
||||||
anim!(
|
toggler(self.screen_filter_active)
|
||||||
FILTER_TOGGLE,
|
.on_toggle(Message::FilterColorsEnabled)
|
||||||
&self.timeline,
|
.label(fl!("filter-colors"))
|
||||||
fl!("filter-colors"),
|
.width(Length::Fill)
|
||||||
self.screen_filter_active,
|
.text_size(14),
|
||||||
Message::FilterColorsEnabled,
|
|
||||||
)
|
|
||||||
.text_size(14)
|
|
||||||
.width(Length::Fill),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let content_list = Column::with_capacity(5)
|
let content_list = Column::with_capacity(5)
|
||||||
|
|
@ -406,9 +372,6 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
Subscription::batch([
|
Subscription::batch([
|
||||||
accessibility::subscription().map(Message::DBusUpdate),
|
accessibility::subscription().map(Message::DBusUpdate),
|
||||||
backend::wayland::a11y_subscription().map(Message::WaylandUpdate),
|
backend::wayland::a11y_subscription().map(Message::WaylandUpdate),
|
||||||
self.timeline
|
|
||||||
.as_subscription()
|
|
||||||
.map(|(_, now)| Message::Frame(now)),
|
|
||||||
activation_token_subscription(0).map(Message::Token),
|
activation_token_subscription(0).map(Message::Token),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
@ -417,7 +380,7 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
Some(Message::CloseRequested(id))
|
Some(Message::CloseRequested(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,15 @@ pub enum WaylandUpdate {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a11y_subscription() -> iced::Subscription<WaylandUpdate> {
|
pub fn a11y_subscription() -> iced::Subscription<WaylandUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(std::any::TypeId::of::<WaylandUpdate>(), |_| {
|
||||||
std::any::TypeId::of::<WaylandUpdate>(),
|
|
||||||
stream::channel(50, move |mut output| async move {
|
stream::channel(50, move |mut output| async move {
|
||||||
let mut state = State::Waiting;
|
let mut state = State::Waiting;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
state = start_listening(state, &mut output).await;
|
state = start_listening(state, &mut output).await;
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_listening(
|
async fn start_listening(
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ edition = "2024"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmic-time.workspace = true
|
|
||||||
i18n-embed-fl.workspace = true
|
i18n-embed-fl.workspace = true
|
||||||
i18n-embed.workspace = true
|
i18n-embed.workspace = true
|
||||||
libcosmic.workspace = true
|
libcosmic.workspace = true
|
||||||
|
|
@ -23,3 +22,4 @@ zbus.workspace = true
|
||||||
|
|
||||||
[dependencies.cosmic-settings-sound-subscription]
|
[dependencies.cosmic-settings-sound-subscription]
|
||||||
git = "https://github.com/pop-os/cosmic-settings"
|
git = "https://github.com/pop-os/cosmic-settings"
|
||||||
|
# path = "../../cosmic-settings/subscriptions/sound"
|
||||||
|
|
|
||||||
|
|
@ -24,20 +24,16 @@ use cosmic::{
|
||||||
window,
|
window,
|
||||||
},
|
},
|
||||||
surface, theme,
|
surface, theme,
|
||||||
widget::{Row, button, container, divider, horizontal_space, icon, text},
|
widget::{Row, button, container, divider, icon, space, text, toggler},
|
||||||
};
|
};
|
||||||
use cosmic_settings_sound_subscription as css;
|
use cosmic_settings_sound_subscription as css;
|
||||||
use cosmic_time::{Instant, Timeline, anim, chain, id};
|
|
||||||
use iced::platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup};
|
use iced::platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup};
|
||||||
use mpris_subscription::{MprisRequest, MprisUpdate};
|
use mpris_subscription::{MprisRequest, MprisUpdate};
|
||||||
use mpris2_zbus::player::PlaybackStatus;
|
use mpris2_zbus::player::PlaybackStatus;
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod mpris_subscription;
|
mod mpris_subscription;
|
||||||
|
|
||||||
static SHOW_MEDIA_CONTROLS: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
|
|
||||||
const GO_BACK: &str = "media-skip-backward-symbolic";
|
const GO_BACK: &str = "media-skip-backward-symbolic";
|
||||||
const GO_NEXT: &str = "media-skip-forward-symbolic";
|
const GO_NEXT: &str = "media-skip-forward-symbolic";
|
||||||
const PAUSE: &str = "media-playback-pause-symbolic";
|
const PAUSE: &str = "media-playback-pause-symbolic";
|
||||||
|
|
@ -66,8 +62,6 @@ pub struct Audio {
|
||||||
sink_breakpoints: &'static [u32],
|
sink_breakpoints: &'static [u32],
|
||||||
/// Breakpoitns for the source volume slider.
|
/// Breakpoitns for the source volume slider.
|
||||||
source_breakpoints: &'static [u32],
|
source_breakpoints: &'static [u32],
|
||||||
/// Track animations used by the revealers.
|
|
||||||
timeline: Timeline,
|
|
||||||
/// Config file specific to this applet.
|
/// Config file specific to this applet.
|
||||||
config: AudioAppletConfig,
|
config: AudioAppletConfig,
|
||||||
/// mpris player status
|
/// mpris player status
|
||||||
|
|
@ -129,8 +123,7 @@ pub enum Message {
|
||||||
InputToggle,
|
InputToggle,
|
||||||
TogglePopup,
|
TogglePopup,
|
||||||
CloseRequested(window::Id),
|
CloseRequested(window::Id),
|
||||||
ToggleMediaControlsInTopPanel(chain::Toggler, bool),
|
ToggleMediaControlsInTopPanel(bool),
|
||||||
Frame(Instant),
|
|
||||||
ConfigChanged(AudioAppletConfig),
|
ConfigChanged(AudioAppletConfig),
|
||||||
Mpris(mpris_subscription::MprisUpdate),
|
Mpris(mpris_subscription::MprisUpdate),
|
||||||
MprisRequest(MprisRequest),
|
MprisRequest(MprisRequest),
|
||||||
|
|
@ -272,13 +265,12 @@ impl cosmic::Application for Audio {
|
||||||
&mut self.core
|
&mut self.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> app::Task<Message> {
|
fn update(&mut self, message: Message) -> app::Task<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::Frame(now) => self.timeline.now(now),
|
|
||||||
Message::Ignore => {}
|
Message::Ignore => {}
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
|
|
@ -286,7 +278,6 @@ impl cosmic::Application for Audio {
|
||||||
} else {
|
} else {
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
self.popup.replace(new_id);
|
self.popup.replace(new_id);
|
||||||
self.timeline = Timeline::new();
|
|
||||||
|
|
||||||
(self.max_sink_volume, self.sink_breakpoints) = if amplification_sink() {
|
(self.max_sink_volume, self.sink_breakpoints) = if amplification_sink() {
|
||||||
(150, &[100][..])
|
(150, &[100][..])
|
||||||
|
|
@ -365,8 +356,7 @@ impl cosmic::Application for Audio {
|
||||||
.map(|message| Message::Subscription(message).into());
|
.map(|message| Message::Subscription(message).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::ToggleMediaControlsInTopPanel(chain, enabled) => {
|
Message::ToggleMediaControlsInTopPanel(enabled) => {
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.config.show_media_controls_in_top_panel = enabled;
|
self.config.show_media_controls_in_top_panel = enabled;
|
||||||
if let Ok(helper) =
|
if let Ok(helper) =
|
||||||
cosmic::cosmic_config::Config::new(Self::APP_ID, AudioAppletConfig::VERSION)
|
cosmic::cosmic_config::Config::new(Self::APP_ID, AudioAppletConfig::VERSION)
|
||||||
|
|
@ -478,9 +468,6 @@ impl cosmic::Application for Audio {
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
Subscription::batch([
|
Subscription::batch([
|
||||||
self.timeline
|
|
||||||
.as_subscription()
|
|
||||||
.map(|(_, now)| Message::Frame(now)),
|
|
||||||
self.core.watch_config(Self::APP_ID).map(|u| {
|
self.core.watch_config(Self::APP_ID).map(|u| {
|
||||||
for err in u.errors {
|
for err in u.errors {
|
||||||
tracing::error!(?err, "Error watching config");
|
tracing::error!(?err, "Error watching config");
|
||||||
|
|
@ -532,6 +519,7 @@ impl cosmic::Application for Audio {
|
||||||
applet_column::Column::with_children(playback_buttons)
|
applet_column::Column::with_children(playback_buttons)
|
||||||
.push(btn)
|
.push(btn)
|
||||||
.align_x(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
|
.height(Length::Shrink)
|
||||||
// TODO configurable variable from the panel?
|
// TODO configurable variable from the panel?
|
||||||
.spacing(
|
.spacing(
|
||||||
-(self.core.applet.suggested_padding(true).0 as f32)
|
-(self.core.applet.suggested_padding(true).0 as f32)
|
||||||
|
|
@ -542,6 +530,7 @@ impl cosmic::Application for Audio {
|
||||||
applet_row::Row::with_children(playback_buttons)
|
applet_row::Row::with_children(playback_buttons)
|
||||||
.push(btn)
|
.push(btn)
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
|
.width(Length::Shrink)
|
||||||
// TODO configurable variable from the panel?
|
// TODO configurable variable from the panel?
|
||||||
.spacing(
|
.spacing(
|
||||||
-(self.core.applet.suggested_padding(true).0 as f32)
|
-(self.core.applet.suggested_padding(true).0 as f32)
|
||||||
|
|
@ -696,7 +685,7 @@ impl cosmic::Application for Audio {
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut control_elements = Vec::with_capacity(4);
|
let mut control_elements = Vec::with_capacity(4);
|
||||||
control_elements.push(horizontal_space().width(Length::Fill).into());
|
control_elements.push(space::horizontal().width(Length::Fill).into());
|
||||||
if let Some(go_prev) = self.go_previous(32) {
|
if let Some(go_prev) = self.go_previous(32) {
|
||||||
control_elements.push(go_prev);
|
control_elements.push(go_prev);
|
||||||
}
|
}
|
||||||
|
|
@ -745,14 +734,9 @@ impl cosmic::Application for Audio {
|
||||||
audio_content,
|
audio_content,
|
||||||
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
||||||
padded_control(
|
padded_control(
|
||||||
anim!(
|
toggler(self.config.show_media_controls_in_top_panel)
|
||||||
// toggler
|
.on_toggle(Message::ToggleMediaControlsInTopPanel)
|
||||||
SHOW_MEDIA_CONTROLS,
|
.label(fl!("show-media-controls"))
|
||||||
&self.timeline,
|
|
||||||
Some(fl!("show-media-controls")),
|
|
||||||
self.config.show_media_controls_in_top_panel,
|
|
||||||
Message::ToggleMediaControlsInTopPanel,
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -156,50 +156,51 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
limits: &layout::Limits,
|
limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
self.content
|
self.content
|
||||||
.as_widget()
|
.as_widget_mut()
|
||||||
.layout(&mut tree.children[0], renderer, limits)
|
.layout(&mut tree.children[0], renderer, limits)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
operation: &mut dyn Operation<()>,
|
operation: &mut dyn Operation<()>,
|
||||||
) {
|
) {
|
||||||
self.content
|
self.content
|
||||||
.as_widget()
|
.as_widget_mut()
|
||||||
.operate(&mut tree.children[0], layout, renderer, operation);
|
.operate(&mut tree.children[0], layout, renderer, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
event: Event,
|
event: &Event,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: &mut dyn Clipboard,
|
clipboard: &mut dyn Clipboard,
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) -> event::Status {
|
) {
|
||||||
if let event::Status::Captured = self.content.as_widget_mut().on_event(
|
self.content.as_widget_mut().update(
|
||||||
&mut tree.children[0],
|
&mut tree.children[0],
|
||||||
event.clone(),
|
&event,
|
||||||
layout,
|
layout,
|
||||||
cursor,
|
cursor,
|
||||||
renderer,
|
renderer,
|
||||||
clipboard,
|
clipboard,
|
||||||
shell,
|
shell,
|
||||||
viewport,
|
viewport,
|
||||||
) {
|
);
|
||||||
return event::Status::Captured;
|
if shell.is_event_captured() {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(
|
update(
|
||||||
|
|
@ -209,7 +210,7 @@ where
|
||||||
cursor,
|
cursor,
|
||||||
shell,
|
shell,
|
||||||
tree.state.downcast_mut::<State>(),
|
tree.state.downcast_mut::<State>(),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_interaction(
|
fn mouse_interaction(
|
||||||
|
|
@ -249,17 +250,24 @@ where
|
||||||
viewport,
|
viewport,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overlay<'b>(
|
fn overlay<'b>(
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
tree: &'b mut Tree,
|
tree: &'b mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'b>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
|
viewport: &Rectangle,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
||||||
self.content
|
self.content.as_widget_mut().overlay(
|
||||||
.as_widget_mut()
|
&mut tree.children[0],
|
||||||
.overlay(&mut tree.children[0], layout, renderer, translation)
|
layout,
|
||||||
|
renderer,
|
||||||
|
viewport,
|
||||||
|
translation,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drag_destinations(
|
fn drag_destinations(
|
||||||
&self,
|
&self,
|
||||||
state: &Tree,
|
state: &Tree,
|
||||||
|
|
@ -298,7 +306,7 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
) -> event::Status {
|
) {
|
||||||
if !cursor.is_over(layout.bounds()) {
|
if !cursor.is_over(layout.bounds()) {
|
||||||
if !state.is_out_of_bounds {
|
if !state.is_out_of_bounds {
|
||||||
if widget
|
if widget
|
||||||
|
|
@ -312,12 +320,13 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
if let Some(message) = widget.on_mouse_exit.as_ref() {
|
if let Some(message) = widget.on_mouse_exit.as_ref() {
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
}
|
}
|
||||||
return event::Status::Captured;
|
shell.capture_event();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return event::Status::Ignored;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message) = widget.on_press.as_ref() {
|
if let Some(message) = widget.on_press.as_ref() {
|
||||||
|
|
@ -326,8 +335,8 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
{
|
{
|
||||||
state.drag_initiated = cursor.position();
|
state.drag_initiated = cursor.position();
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
|
shell.capture_event();
|
||||||
return event::Status::Captured;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,32 +346,32 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
{
|
{
|
||||||
state.drag_initiated = None;
|
state.drag_initiated = None;
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
|
shell.capture_event();
|
||||||
return event::Status::Captured;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message) = widget.on_right_press.as_ref() {
|
if let Some(message) = widget.on_right_press.as_ref() {
|
||||||
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) = event {
|
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) = event {
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
|
shell.capture_event();
|
||||||
return event::Status::Captured;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message) = widget.on_right_release.as_ref() {
|
if let Some(message) = widget.on_right_release.as_ref() {
|
||||||
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Right)) = event {
|
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Right)) = event {
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
|
shell.capture_event();
|
||||||
return event::Status::Captured;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message) = widget.on_middle_press.as_ref() {
|
if let Some(message) = widget.on_middle_press.as_ref() {
|
||||||
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Middle)) = event {
|
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Middle)) = event {
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
|
shell.capture_event();
|
||||||
return event::Status::Captured;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -370,7 +379,8 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Middle)) = event {
|
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Middle)) = event {
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
|
|
||||||
return event::Status::Captured;
|
shell.capture_event();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(message) = widget
|
if let Some(message) = widget
|
||||||
|
|
@ -384,7 +394,8 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
if widget.on_mouse_enter.is_some() {
|
if widget.on_mouse_enter.is_some() {
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
}
|
}
|
||||||
return event::Status::Captured;
|
shell.capture_event();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -400,8 +411,8 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
if position.distance(drag_source) > 1.0 {
|
if position.distance(drag_source) > 1.0 {
|
||||||
state.drag_initiated = None;
|
state.drag_initiated = None;
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
|
shell.capture_event();
|
||||||
return event::Status::Captured;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -409,9 +420,8 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
if let Some(message) = widget.on_mouse_wheel.as_ref() {
|
if let Some(message) = widget.on_mouse_wheel.as_ref() {
|
||||||
if let Event::Mouse(mouse::Event::WheelScrolled { delta }) = event {
|
if let Event::Mouse(mouse::Event::WheelScrolled { delta }) = event {
|
||||||
shell.publish((message)(*delta));
|
shell.publish((message)(*delta));
|
||||||
return event::Status::Captured;
|
shell.capture_event();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event::Status::Ignored
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,14 +83,13 @@ impl PlayerStatus {
|
||||||
pub fn mpris_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
pub fn mpris_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
id: I,
|
id: I,
|
||||||
) -> iced::Subscription<MprisUpdate> {
|
) -> iced::Subscription<MprisUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(id, |_| {
|
||||||
id,
|
|
||||||
stream::channel(50, move |mut output| async move {
|
stream::channel(50, move |mut output| async move {
|
||||||
run(&mut output).await;
|
run(&mut output).await;
|
||||||
let _ = output.send(MprisUpdate::Finished).await;
|
let _ = output.send(MprisUpdate::Finished).await;
|
||||||
futures::future::pending().await
|
futures::future::pending().await
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ license = "GPL-3.0-only"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
cosmic-time.workspace = true
|
|
||||||
cosmic-config.workspace = true
|
cosmic-config.workspace = true
|
||||||
cosmic-applets-config.workspace = true
|
cosmic-applets-config.workspace = true
|
||||||
drm = "0.14.1"
|
drm = "0.14.1"
|
||||||
|
|
@ -26,6 +25,8 @@ serde.workspace = true
|
||||||
|
|
||||||
[dependencies.cosmic-settings-upower-subscription]
|
[dependencies.cosmic-settings-upower-subscription]
|
||||||
git = "https://github.com/pop-os/cosmic-settings"
|
git = "https://github.com/pop-os/cosmic-settings"
|
||||||
|
# path = "../../cosmic-settings/subscriptions/upower"
|
||||||
|
|
||||||
[dependencies.cosmic-settings-daemon-subscription]
|
[dependencies.cosmic-settings-daemon-subscription]
|
||||||
git = "https://github.com/pop-os/cosmic-settings"
|
git = "https://github.com/pop-os/cosmic-settings"
|
||||||
|
# path = "../../cosmic-settings/subscriptions/settings-daemon"
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ use cosmic::{
|
||||||
iced_core::{Alignment, Background, Border, Color, Shadow},
|
iced_core::{Alignment, Background, Border, Color, Shadow},
|
||||||
surface,
|
surface,
|
||||||
theme::{self, Button},
|
theme::{self, Button},
|
||||||
widget::{button, divider, horizontal_space, icon, scrollable, slider, text, vertical_space},
|
widget::{button, divider, icon, scrollable, slider, space, text, toggler},
|
||||||
};
|
};
|
||||||
use cosmic_applets_config::battery::BatteryAppletConfig;
|
use cosmic_applets_config::battery::BatteryAppletConfig;
|
||||||
use cosmic_config::{Config, CosmicConfigEntry};
|
use cosmic_config::{Config, CosmicConfigEntry};
|
||||||
|
|
@ -39,8 +39,6 @@ use cosmic_settings_upower_subscription::{
|
||||||
kbdbacklight::{KeyboardBacklightRequest, KeyboardBacklightUpdate, kbd_backlight_subscription},
|
kbdbacklight::{KeyboardBacklightRequest, KeyboardBacklightUpdate, kbd_backlight_subscription},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cosmic_time::{Instant, Timeline, anim, chain, id};
|
|
||||||
|
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::{path::PathBuf, sync::LazyLock, time::Duration};
|
use std::{path::PathBuf, sync::LazyLock, time::Duration};
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
@ -65,8 +63,6 @@ pub fn run() -> cosmic::iced::Result {
|
||||||
cosmic::applet::run::<CosmicBatteryApplet>(())
|
cosmic::applet::run::<CosmicBatteryApplet>(())
|
||||||
}
|
}
|
||||||
|
|
||||||
static MAX_CHARGE: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
struct GPUData {
|
struct GPUData {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
@ -95,7 +91,6 @@ struct CosmicBatteryApplet {
|
||||||
kbd_sender: Option<UnboundedSender<KeyboardBacklightRequest>>,
|
kbd_sender: Option<UnboundedSender<KeyboardBacklightRequest>>,
|
||||||
power_profile: Power,
|
power_profile: Power,
|
||||||
power_profile_sender: Option<UnboundedSender<PowerProfileRequest>>,
|
power_profile_sender: Option<UnboundedSender<PowerProfileRequest>>,
|
||||||
timeline: Timeline,
|
|
||||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||||
zbus_connection: Option<zbus::Connection>,
|
zbus_connection: Option<zbus::Connection>,
|
||||||
dragging_screen_brightness: bool,
|
dragging_screen_brightness: bool,
|
||||||
|
|
@ -186,7 +181,7 @@ enum Message {
|
||||||
SetScreenBrightnessDebounced,
|
SetScreenBrightnessDebounced,
|
||||||
ReleaseScreenBrightness,
|
ReleaseScreenBrightness,
|
||||||
InitChargingLimit(Option<bool>),
|
InitChargingLimit(Option<bool>),
|
||||||
SetChargingLimit(chain::Toggler, bool),
|
SetChargingLimit(bool),
|
||||||
KeyboardBacklight(KeyboardBacklightUpdate),
|
KeyboardBacklight(KeyboardBacklightUpdate),
|
||||||
UpowerDevice(DeviceDbusEvent),
|
UpowerDevice(DeviceDbusEvent),
|
||||||
GpuInit(UnboundedSender<()>),
|
GpuInit(UnboundedSender<()>),
|
||||||
|
|
@ -197,7 +192,6 @@ enum Message {
|
||||||
InitProfile(UnboundedSender<PowerProfileRequest>, Power),
|
InitProfile(UnboundedSender<PowerProfileRequest>, Power),
|
||||||
Profile(Power),
|
Profile(Power),
|
||||||
SelectProfile(Power),
|
SelectProfile(Power),
|
||||||
Frame(Instant),
|
|
||||||
ConfigChanged(BatteryAppletConfig),
|
ConfigChanged(BatteryAppletConfig),
|
||||||
Token(TokenUpdate),
|
Token(TokenUpdate),
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
|
|
@ -248,7 +242,6 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Message) -> app::Task<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> app::Task<Self::Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::Frame(now) => self.timeline.now(now),
|
|
||||||
Message::SetKbdBrightness(brightness) => {
|
Message::SetKbdBrightness(brightness) => {
|
||||||
self.kbd_brightness = Some(brightness);
|
self.kbd_brightness = Some(brightness);
|
||||||
|
|
||||||
|
|
@ -330,8 +323,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
self.set_charging_limit(enable);
|
self.set_charging_limit(enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SetChargingLimit(chain, enable) => {
|
Message::SetChargingLimit(enable) => {
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.set_charging_limit(enable);
|
self.set_charging_limit(enable);
|
||||||
|
|
||||||
if enable {
|
if enable {
|
||||||
|
|
@ -357,7 +349,6 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
if let Some(tx) = &self.kbd_sender {
|
if let Some(tx) = &self.kbd_sender {
|
||||||
let _ = tx.send(KeyboardBacklightRequest::Get);
|
let _ = tx.send(KeyboardBacklightRequest::Get);
|
||||||
}
|
}
|
||||||
self.timeline = Timeline::new();
|
|
||||||
|
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
self.popup.replace(new_id);
|
self.popup.replace(new_id);
|
||||||
|
|
@ -582,7 +573,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
let content = if self.gpus.is_empty() {
|
let content = if self.gpus.is_empty() {
|
||||||
btn
|
btn
|
||||||
} else {
|
} else {
|
||||||
let dot = container(vertical_space().height(Length::Fixed(0.0)))
|
let dot = container(space::vertical().height(Length::Fixed(0.0)))
|
||||||
.padding(2.0)
|
.padding(2.0)
|
||||||
.class(cosmic::style::Container::Custom(Box::new(|theme| {
|
.class(cosmic::style::Container::Custom(Box::new(|theme| {
|
||||||
container::Style {
|
container::Style {
|
||||||
|
|
@ -595,6 +586,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
},
|
},
|
||||||
shadow: Shadow::default(),
|
shadow: Shadow::default(),
|
||||||
icon_color: Some(Color::TRANSPARENT),
|
icon_color: Some(Color::TRANSPARENT),
|
||||||
|
snap: true,
|
||||||
}
|
}
|
||||||
})));
|
})));
|
||||||
let (dot_align_x, dot_align_y) = match self.core.applet.anchor {
|
let (dot_align_x, dot_align_y) = match self.core.applet.anchor {
|
||||||
|
|
@ -638,7 +630,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut content = vec![
|
let mut content: Vec<Element<'_, Message>> = vec![
|
||||||
padded_control(
|
padded_control(
|
||||||
row![
|
row![
|
||||||
icon::from_name(&*self.icon_name).size(24).symbolic(true),
|
icon::from_name(&*self.icon_name).size(24).symbolic(true),
|
||||||
|
|
@ -665,7 +657,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
.symbolic(true),
|
.symbolic(true),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
container(horizontal_space().width(1.0))
|
container(space::horizontal().width(1.0))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
.align_y(Alignment::Center),
|
.align_y(Alignment::Center),
|
||||||
|
|
@ -686,7 +678,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
.symbolic(true),
|
.symbolic(true),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
container(horizontal_space().width(1.0))
|
container(space::horizontal().width(1.0))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
.align_y(Alignment::Center),
|
.align_y(Alignment::Center),
|
||||||
|
|
@ -707,7 +699,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
.symbolic(true),
|
.symbolic(true),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
container(horizontal_space().width(1.0))
|
container(space::horizontal().width(1.0))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
.align_y(Alignment::Center),
|
.align_y(Alignment::Center),
|
||||||
|
|
@ -722,14 +714,9 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
if let Some(charging_limit) = self.charging_limit {
|
if let Some(charging_limit) = self.charging_limit {
|
||||||
content.push(
|
content.push(
|
||||||
padded_control(
|
padded_control(
|
||||||
anim!(
|
toggler(charging_limit)
|
||||||
//toggler
|
.on_toggle(Message::SetChargingLimit)
|
||||||
MAX_CHARGE,
|
.label(fl!("max-charge"))
|
||||||
&self.timeline,
|
|
||||||
fl!("max-charge"),
|
|
||||||
charging_limit,
|
|
||||||
Message::SetChargingLimit,
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
)
|
)
|
||||||
|
|
@ -819,7 +806,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.align_x(Alignment::Start),
|
.align_x(Alignment::Start),
|
||||||
container(
|
container(
|
||||||
vertical_space()
|
space::vertical()
|
||||||
.width(Length::Fixed(0.0))
|
.width(Length::Fixed(0.0))
|
||||||
.height(Length::Fixed(0.0))
|
.height(Length::Fixed(0.0))
|
||||||
)
|
)
|
||||||
|
|
@ -837,6 +824,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
},
|
},
|
||||||
shadow: Shadow::default(),
|
shadow: Shadow::default(),
|
||||||
icon_color: Some(Color::TRANSPARENT),
|
icon_color: Some(Color::TRANSPARENT),
|
||||||
|
snap: true,
|
||||||
}
|
}
|
||||||
},))),
|
},))),
|
||||||
]
|
]
|
||||||
|
|
@ -902,7 +890,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
if let Some(icon) = &app.icon {
|
if let Some(icon) = &app.icon {
|
||||||
container(icon::from_name(&**icon).size(12).symbolic(true))
|
container(icon::from_name(&**icon).size(12).symbolic(true))
|
||||||
} else {
|
} else {
|
||||||
container(horizontal_space().width(12.0))
|
container(space::horizontal().width(12.0))
|
||||||
},
|
},
|
||||||
column![text::body(&app.name), text::caption(&app.secondary)]
|
column![text::body(&app.name), text::caption(&app.secondary)]
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
|
|
@ -952,9 +940,6 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
GpuUpdate::On(path, name, list) => Message::GpuOn(path, name, list),
|
GpuUpdate::On(path, name, list) => Message::GpuOn(path, name, list),
|
||||||
GpuUpdate::Off(path) => Message::GpuOff(path),
|
GpuUpdate::Off(path) => Message::GpuOff(path),
|
||||||
}),
|
}),
|
||||||
self.timeline
|
|
||||||
.as_subscription()
|
|
||||||
.map(|(_, now)| Message::Frame(now)),
|
|
||||||
activation_token_subscription(0).map(Message::Token),
|
activation_token_subscription(0).map(Message::Token),
|
||||||
self.core.watch_config(Self::APP_ID).map(|u| {
|
self.core.watch_config(Self::APP_ID).map(|u| {
|
||||||
for err in u.errors {
|
for err in u.errors {
|
||||||
|
|
@ -973,7 +958,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
Some(Message::CloseRequested(id))
|
Some(Message::CloseRequested(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,16 +98,15 @@ pub async fn set_power_profile(daemon: Backend<'_>, power: Power) -> Result<()>
|
||||||
pub fn power_profile_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
pub fn power_profile_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
id: I,
|
id: I,
|
||||||
) -> iced::Subscription<PowerProfileUpdate> {
|
) -> iced::Subscription<PowerProfileUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(id, |_| {
|
||||||
id,
|
|
||||||
stream::channel(50, move |mut output| async move {
|
stream::channel(50, move |mut output| async move {
|
||||||
let mut state = State::Ready;
|
let mut state = State::Ready;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
state = start_listening(state, &mut output).await;
|
state = start_listening(state, &mut output).await;
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -418,16 +418,15 @@ fn all_gpus<S: AsRef<str>>(seat: S) -> io::Result<Vec<Gpu>> {
|
||||||
pub fn dgpu_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
pub fn dgpu_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
id: I,
|
id: I,
|
||||||
) -> iced::Subscription<GpuUpdate> {
|
) -> iced::Subscription<GpuUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(id, |_| {
|
||||||
id,
|
|
||||||
stream::channel(50, move |mut output| async move {
|
stream::channel(50, move |mut output| async move {
|
||||||
let mut state = State::Ready;
|
let mut state = State::Ready;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
state = start_listening(state, &mut output).await;
|
state = start_listening(state, &mut output).await;
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ license = "GPL-3.0-only"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
bluer = { version = "0.17", features = ["bluetoothd", "id"] }
|
bluer = { version = "0.17", features = ["bluetoothd", "id"] }
|
||||||
cosmic-time.workspace = true
|
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
i18n-embed-fl.workspace = true
|
i18n-embed-fl.workspace = true
|
||||||
i18n-embed.workspace = true
|
i18n-embed.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use cosmic::{
|
||||||
applet::token::subscription::{TokenRequest, TokenUpdate, activation_token_subscription},
|
applet::token::subscription::{TokenRequest, TokenUpdate, activation_token_subscription},
|
||||||
cctk::sctk::reexports::calloop,
|
cctk::sctk::reexports::calloop,
|
||||||
surface,
|
surface,
|
||||||
|
widget::toggler,
|
||||||
};
|
};
|
||||||
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
|
|
@ -22,7 +23,6 @@ use cosmic::{
|
||||||
theme,
|
theme,
|
||||||
widget::{button, divider, icon, scrollable, text},
|
widget::{button, divider, icon, scrollable, text},
|
||||||
};
|
};
|
||||||
use cosmic_time::{Instant, Timeline, anim, chain, id};
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use std::{collections::HashMap, sync::LazyLock, time::Duration};
|
use std::{collections::HashMap, sync::LazyLock, time::Duration};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
|
|
@ -32,8 +32,6 @@ use crate::{
|
||||||
config, fl,
|
config, fl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static BLUETOOTH_ENABLED: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run() -> cosmic::iced::Result {
|
pub fn run() -> cosmic::iced::Result {
|
||||||
cosmic::applet::run::<CosmicBluetoothApplet>(())
|
cosmic::applet::run::<CosmicBluetoothApplet>(())
|
||||||
|
|
@ -50,7 +48,6 @@ struct CosmicBluetoothApplet {
|
||||||
show_visible_devices: bool,
|
show_visible_devices: bool,
|
||||||
request_confirmation: Option<(BluerDevice, String, Sender<bool>)>,
|
request_confirmation: Option<(BluerDevice, String, Sender<bool>)>,
|
||||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||||
timeline: Timeline,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CosmicBluetoothApplet {
|
impl CosmicBluetoothApplet {
|
||||||
|
|
@ -77,8 +74,7 @@ enum Message {
|
||||||
Confirm,
|
Confirm,
|
||||||
Token(TokenUpdate),
|
Token(TokenUpdate),
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
Frame(Instant),
|
ToggleBluetooth(bool),
|
||||||
ToggleBluetooth(chain::Toggler, bool),
|
|
||||||
Surface(surface::Action),
|
Surface(surface::Action),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,7 +123,6 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
// TODO request update of state maybe
|
// TODO request update of state maybe
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
self.popup.replace(new_id);
|
self.popup.replace(new_id);
|
||||||
self.timeline = Timeline::new();
|
|
||||||
|
|
||||||
let popup_settings = self.core.applet.get_popup_settings(
|
let popup_settings = self.core.applet.get_popup_settings(
|
||||||
self.core.main_window_id().unwrap(),
|
self.core.main_window_id().unwrap(),
|
||||||
|
|
@ -157,15 +152,6 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
if let Some(err_msg) = err_msg {
|
if let Some(err_msg) = err_msg {
|
||||||
eprintln!("bluetooth request error: {err_msg}");
|
eprintln!("bluetooth request error: {err_msg}");
|
||||||
}
|
}
|
||||||
if self.bluer_state.bluetooth_enabled != state.bluetooth_enabled {
|
|
||||||
self.timeline
|
|
||||||
.set_chain(if state.bluetooth_enabled {
|
|
||||||
chain::Toggler::on(BLUETOOTH_ENABLED.clone(), 1.0)
|
|
||||||
} else {
|
|
||||||
chain::Toggler::off(BLUETOOTH_ENABLED.clone(), 1.0)
|
|
||||||
})
|
|
||||||
.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.bluer_state = state;
|
self.bluer_state = state;
|
||||||
}
|
}
|
||||||
|
|
@ -300,12 +286,10 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
tokio::spawn(cosmic::process::spawn(cmd));
|
tokio::spawn(cosmic::process::spawn(cmd));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Message::Frame(instant) => self.timeline.now(instant),
|
Message::ToggleBluetooth(enabled) => {
|
||||||
Message::ToggleBluetooth(chain, enabled) => {
|
|
||||||
if self.bluer_state.bluetooth_enabled == enabled {
|
if self.bluer_state.bluetooth_enabled == enabled {
|
||||||
return Task::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.bluer_state.bluetooth_enabled = enabled;
|
self.bluer_state.bluetooth_enabled = enabled;
|
||||||
if let Some(tx) = self.bluer_sender.clone() {
|
if let Some(tx) = self.bluer_sender.clone() {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|
@ -416,16 +400,11 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut content = column![column![padded_control(
|
let mut content = column![column![padded_control(
|
||||||
anim!(
|
toggler(self.bluer_state.bluetooth_enabled)
|
||||||
//toggler
|
.label(fl!("bluetooth"))
|
||||||
BLUETOOTH_ENABLED,
|
.on_toggle(Message::ToggleBluetooth)
|
||||||
&self.timeline,
|
|
||||||
fl!("bluetooth"),
|
|
||||||
self.bluer_state.bluetooth_enabled,
|
|
||||||
Message::ToggleBluetooth,
|
|
||||||
)
|
|
||||||
.text_size(14)
|
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
.text_size(14)
|
||||||
),],]
|
),],]
|
||||||
.align_x(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
.padding([8, 0]);
|
.padding([8, 0]);
|
||||||
|
|
@ -549,13 +528,10 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
Subscription::batch([
|
Subscription::batch([
|
||||||
activation_token_subscription(0).map(Message::Token),
|
activation_token_subscription(0).map(Message::Token),
|
||||||
bluetooth_subscription(0).map(Message::BluetoothEvent),
|
bluetooth_subscription(0).map(Message::BluetoothEvent),
|
||||||
self.timeline
|
|
||||||
.as_subscription()
|
|
||||||
.map(|(_, now)| Message::Frame(now)),
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use rustc_hash::FxHashMap;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
mem,
|
|
||||||
sync::{
|
sync::{
|
||||||
Arc, LazyLock,
|
Arc, LazyLock,
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
|
|
@ -90,9 +89,10 @@ fn rfkill_path_var() -> std::ffi::OsString {
|
||||||
pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
id: I,
|
id: I,
|
||||||
) -> iced::Subscription<BluerEvent> {
|
) -> iced::Subscription<BluerEvent> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(id, |_| {
|
||||||
id,
|
stream::channel(
|
||||||
stream::channel(50, move |mut output| async move {
|
50,
|
||||||
|
move |mut output: futures::channel::mpsc::Sender<BluerEvent>| async move {
|
||||||
let mut retry_count = 0u32;
|
let mut retry_count = 0u32;
|
||||||
|
|
||||||
// Initialize connection.
|
// Initialize connection.
|
||||||
|
|
@ -115,7 +115,9 @@ pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
// reconnect to paired and trusted devices
|
// reconnect to paired and trusted devices
|
||||||
if state.bluetooth_enabled {
|
if state.bluetooth_enabled {
|
||||||
for d in &state.devices {
|
for d in &state.devices {
|
||||||
if d.paired_and_trusted() && !matches!(d.status, BluerDeviceStatus::Connected) {
|
if d.paired_and_trusted()
|
||||||
|
&& !matches!(d.status, BluerDeviceStatus::Connected)
|
||||||
|
{
|
||||||
_ = session_state
|
_ = session_state
|
||||||
.req_tx
|
.req_tx
|
||||||
.send(BluerRequest::ConnectDevice(d.address))
|
.send(BluerRequest::ConnectDevice(d.address))
|
||||||
|
|
@ -182,8 +184,9 @@ pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
|
|
||||||
_ = output.send(BluerEvent::Finished).await;
|
_ = output.send(BluerEvent::Finished).await;
|
||||||
futures::future::pending().await
|
futures::future::pending().await
|
||||||
}),
|
},
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ edition = "2024"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# cosmic-time.workspace = true
|
|
||||||
cosmic-comp-config = { git = "https://github.com/pop-os/cosmic-comp.git", rev = "5eb5af4" }
|
cosmic-comp-config = { git = "https://github.com/pop-os/cosmic-comp.git", rev = "5eb5af4" }
|
||||||
i18n-embed-fl.workspace = true
|
i18n-embed-fl.workspace = true
|
||||||
i18n-embed.workspace = true
|
i18n-embed.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ use cosmic::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
surface, theme,
|
surface, theme,
|
||||||
widget::{
|
widget::{
|
||||||
self, autosize, horizontal_space,
|
self, autosize,
|
||||||
rectangle_tracker::{RectangleTracker, RectangleUpdate, rectangle_tracker_subscription},
|
rectangle_tracker::{RectangleTracker, RectangleUpdate, rectangle_tracker_subscription},
|
||||||
vertical_space,
|
space,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use cosmic_comp_config::CosmicCompConfig;
|
use cosmic_comp_config::CosmicCompConfig;
|
||||||
|
|
@ -291,7 +291,7 @@ impl cosmic::Application for Window {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<Appearance> {
|
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ impl cosmic::Application for Minimize {
|
||||||
&mut self.core
|
&mut self.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use cosmic::{
|
||||||
wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||||
},
|
},
|
||||||
iced::{self, Subscription},
|
iced::{self, Subscription},
|
||||||
iced_core::image::Bytes,
|
iced_core::Bytes,
|
||||||
iced_futures::{futures, stream},
|
iced_futures::{futures, stream},
|
||||||
};
|
};
|
||||||
use futures::SinkExt;
|
use futures::SinkExt;
|
||||||
|
|
@ -22,9 +22,10 @@ use std::fmt::Debug;
|
||||||
use crate::wayland_handler::wayland_handler;
|
use crate::wayland_handler::wayland_handler;
|
||||||
|
|
||||||
pub fn wayland_subscription() -> iced::Subscription<WaylandUpdate> {
|
pub fn wayland_subscription() -> iced::Subscription<WaylandUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(std::any::TypeId::of::<WaylandUpdate>(), |_| {
|
||||||
std::any::TypeId::of::<WaylandUpdate>(),
|
stream::channel(
|
||||||
stream::channel(1, move |mut output| async move {
|
1,
|
||||||
|
move |mut output: futures::channel::mpsc::Sender<WaylandUpdate>| async move {
|
||||||
let (calloop_tx, calloop_rx) = calloop::channel::channel();
|
let (calloop_tx, calloop_rx) = calloop::channel::channel();
|
||||||
let runtime = tokio::runtime::Handle::current();
|
let runtime = tokio::runtime::Handle::current();
|
||||||
|
|
||||||
|
|
@ -38,8 +39,9 @@ pub fn wayland_subscription() -> iced::Subscription<WaylandUpdate> {
|
||||||
});
|
});
|
||||||
|
|
||||||
futures::future::pending().await
|
futures::future::pending().await
|
||||||
}),
|
},
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,9 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg>
|
||||||
fn overlay<'b>(
|
fn overlay<'b>(
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
state: &'b mut Tree,
|
state: &'b mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'b>,
|
||||||
renderer: &cosmic::Renderer,
|
renderer: &cosmic::Renderer,
|
||||||
|
viewport: &cosmic::iced_core::Rectangle,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
) -> Option<cosmic::iced_core::overlay::Element<'b, Msg, cosmic::Theme, cosmic::Renderer>> {
|
) -> Option<cosmic::iced_core::overlay::Element<'b, Msg, cosmic::Theme, cosmic::Renderer>> {
|
||||||
let children = [&mut self.image_button, &mut self.icon]
|
let children = [&mut self.image_button, &mut self.icon]
|
||||||
|
|
@ -104,7 +105,7 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg>
|
||||||
.filter_map(|((child, state), layout)| {
|
.filter_map(|((child, state), layout)| {
|
||||||
child
|
child
|
||||||
.as_widget_mut()
|
.as_widget_mut()
|
||||||
.overlay(state, layout, renderer, translation)
|
.overlay(state, layout, renderer, viewport, translation)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|
@ -116,7 +117,7 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut cosmic::iced_core::widget::Tree,
|
tree: &mut cosmic::iced_core::widget::Tree,
|
||||||
renderer: &cosmic::Renderer,
|
renderer: &cosmic::Renderer,
|
||||||
limits: &cosmic::iced_core::layout::Limits,
|
limits: &cosmic::iced_core::layout::Limits,
|
||||||
|
|
@ -125,7 +126,7 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg>
|
||||||
let button = &mut children[0];
|
let button = &mut children[0];
|
||||||
let button_node = self
|
let button_node = self
|
||||||
.image_button
|
.image_button
|
||||||
.as_widget()
|
.as_widget_mut()
|
||||||
.layout(button, renderer, limits);
|
.layout(button, renderer, limits);
|
||||||
let img_node = &button_node.children()[0].children()[0];
|
let img_node = &button_node.children()[0].children()[0];
|
||||||
|
|
||||||
|
|
@ -135,7 +136,7 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg>
|
||||||
let icon = &mut children[1];
|
let icon = &mut children[1];
|
||||||
let icon_node = self
|
let icon_node = self
|
||||||
.icon
|
.icon
|
||||||
.as_widget()
|
.as_widget_mut()
|
||||||
.layout(
|
.layout(
|
||||||
icon,
|
icon,
|
||||||
renderer,
|
renderer,
|
||||||
|
|
@ -185,14 +186,14 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut cosmic::iced_core::widget::Tree,
|
tree: &mut cosmic::iced_core::widget::Tree,
|
||||||
layout: cosmic::iced_core::Layout<'_>,
|
layout: cosmic::iced_core::Layout<'_>,
|
||||||
renderer: &cosmic::Renderer,
|
renderer: &cosmic::Renderer,
|
||||||
operation: &mut dyn cosmic::widget::Operation<()>,
|
operation: &mut dyn cosmic::widget::Operation<()>,
|
||||||
) {
|
) {
|
||||||
let layout = layout.children().collect::<Vec<_>>();
|
let layout = layout.children().collect::<Vec<_>>();
|
||||||
let children = [&self.image_button, &self.icon];
|
let children = [&mut self.image_button, &mut self.icon];
|
||||||
for (i, (layout, child)) in layout
|
for (i, (layout, child)) in layout
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(children.into_iter())
|
.zip(children.into_iter())
|
||||||
|
|
@ -200,26 +201,27 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg>
|
||||||
.rev()
|
.rev()
|
||||||
{
|
{
|
||||||
let tree = &mut tree.children[i];
|
let tree = &mut tree.children[i];
|
||||||
child.as_widget().operate(tree, layout, renderer, operation);
|
child
|
||||||
|
.as_widget_mut()
|
||||||
|
.operate(tree, layout, renderer, operation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut cosmic::iced_core::widget::Tree,
|
state: &mut cosmic::iced_core::widget::Tree,
|
||||||
event: cosmic::iced_core::Event,
|
event: &cosmic::iced_core::Event,
|
||||||
layout: cosmic::iced_core::Layout<'_>,
|
layout: cosmic::iced_core::Layout<'_>,
|
||||||
cursor: cosmic::iced_core::mouse::Cursor,
|
cursor: cosmic::iced_core::mouse::Cursor,
|
||||||
renderer: &cosmic::Renderer,
|
renderer: &cosmic::Renderer,
|
||||||
clipboard: &mut dyn cosmic::iced_core::Clipboard,
|
clipboard: &mut dyn cosmic::iced_core::Clipboard,
|
||||||
shell: &mut cosmic::iced_core::Shell<'_, Msg>,
|
shell: &mut cosmic::iced_core::Shell<'_, Msg>,
|
||||||
viewport: &cosmic::iced_core::Rectangle,
|
viewport: &cosmic::iced_core::Rectangle,
|
||||||
) -> cosmic::iced_core::event::Status {
|
) {
|
||||||
let children = [&mut self.image_button, &mut self.icon];
|
let children = [&mut self.image_button, &mut self.icon];
|
||||||
|
|
||||||
let layout = layout.children().collect::<Vec<_>>();
|
let layout = layout.children().collect::<Vec<_>>();
|
||||||
// draw children in order
|
// draw children in order
|
||||||
let mut status = cosmic::iced_core::event::Status::Ignored;
|
|
||||||
for (i, (layout, child)) in layout
|
for (i, (layout, child)) in layout
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(children.into_iter())
|
.zip(children.into_iter())
|
||||||
|
|
@ -228,21 +230,13 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg>
|
||||||
{
|
{
|
||||||
let tree = &mut state.children[i];
|
let tree = &mut state.children[i];
|
||||||
|
|
||||||
status = child.as_widget_mut().on_event(
|
child.as_widget_mut().update(
|
||||||
tree,
|
tree, event, layout, cursor, renderer, clipboard, shell, viewport,
|
||||||
event.clone(),
|
|
||||||
layout,
|
|
||||||
cursor,
|
|
||||||
renderer,
|
|
||||||
clipboard,
|
|
||||||
shell,
|
|
||||||
viewport,
|
|
||||||
);
|
);
|
||||||
if matches!(status, cosmic::iced_core::event::Status::Captured) {
|
if shell.is_event_captured() {
|
||||||
return status;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_interaction(
|
fn mouse_interaction(
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ license = "GPL-3.0-or-later"
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
async-fn-stream = "0.3"
|
async-fn-stream = "0.3"
|
||||||
cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings" }
|
cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings" }
|
||||||
cosmic-time.workspace = true
|
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
futures-util.workspace = true
|
futures-util.workspace = true
|
||||||
i18n-embed-fl.workspace = true
|
i18n-embed-fl.workspace = true
|
||||||
|
|
@ -35,7 +34,8 @@ uuid = { version = "1.21.0", features = ["v4"] }
|
||||||
|
|
||||||
[dependencies.cosmic-settings-network-manager-subscription]
|
[dependencies.cosmic-settings-network-manager-subscription]
|
||||||
git = "https://github.com/pop-os/cosmic-settings/"
|
git = "https://github.com/pop-os/cosmic-settings/"
|
||||||
|
# path = "../../cosmic-settings/subscriptions/network-manager"
|
||||||
|
|
||||||
[dependencies.cosmic-settings-airplane-mode-subscription]
|
[dependencies.cosmic-settings-airplane-mode-subscription]
|
||||||
git = "https://github.com/pop-os/cosmic-settings/"
|
git = "https://github.com/pop-os/cosmic-settings/"
|
||||||
|
# path = "../../cosmic-settings/subscriptions/airplane-mode"
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,13 @@ use cosmic::{
|
||||||
widget::{
|
widget::{
|
||||||
Column, Id, Row, button, container, divider,
|
Column, Id, Row, button, container, divider,
|
||||||
icon::{self, from_name},
|
icon::{self, from_name},
|
||||||
scrollable, secure_input, text, text_input,
|
scrollable, secure_input, text, text_input, toggler,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use cosmic_dbus_networkmanager::interface::{
|
use cosmic_dbus_networkmanager::interface::{
|
||||||
access_point,
|
access_point,
|
||||||
enums::{ActiveConnectionState, DeviceState, NmConnectivityState, NmState},
|
enums::{ActiveConnectionState, DeviceState, NmConnectivityState, NmState},
|
||||||
};
|
};
|
||||||
use cosmic_time::{Instant, Timeline, anim, chain, id};
|
|
||||||
|
|
||||||
use futures::{StreamExt, channel::mpsc::TrySendError};
|
use futures::{StreamExt, channel::mpsc::TrySendError};
|
||||||
use zbus::{Connection, zvariant::ObjectPath};
|
use zbus::{Connection, zvariant::ObjectPath};
|
||||||
|
|
@ -96,9 +95,6 @@ impl From<NewConnectionState> for AccessPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WIFI: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
static AIRPLANE_MODE: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
|
|
||||||
pub static SECURE_INPUT_WIFI: LazyLock<Id> = LazyLock::new(Id::unique);
|
pub static SECURE_INPUT_WIFI: LazyLock<Id> = LazyLock::new(Id::unique);
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
|
|
@ -170,7 +166,6 @@ struct CosmicNetworkApplet {
|
||||||
show_available_vpns: bool,
|
show_available_vpns: bool,
|
||||||
new_connection: Option<NewConnectionState>,
|
new_connection: Option<NewConnectionState>,
|
||||||
conn: Option<Connection>,
|
conn: Option<Connection>,
|
||||||
timeline: Timeline,
|
|
||||||
toggle_wifi_ctr: u128,
|
toggle_wifi_ctr: u128,
|
||||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||||
failed_known_ssids: FxHashSet<Arc<str>>,
|
failed_known_ssids: FxHashSet<Arc<str>>,
|
||||||
|
|
@ -363,31 +358,15 @@ impl CosmicNetworkApplet {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_togglers(&mut self, state: &NetworkManagerState) {
|
fn update_togglers(&mut self, state: &NetworkManagerState) {
|
||||||
let timeline = &mut self.timeline;
|
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
if self.nm_state.nm_state.wifi_enabled != state.wifi_enabled {
|
if self.nm_state.nm_state.wifi_enabled != state.wifi_enabled {
|
||||||
self.nm_state.nm_state.wifi_enabled = state.wifi_enabled;
|
self.nm_state.nm_state.wifi_enabled = state.wifi_enabled;
|
||||||
changed = true;
|
changed = true;
|
||||||
let chain = if state.wifi_enabled {
|
|
||||||
chain::Toggler::on(WIFI.clone(), 1.)
|
|
||||||
} else {
|
|
||||||
chain::Toggler::off(WIFI.clone(), 1.)
|
|
||||||
};
|
|
||||||
timeline.set_chain(chain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.nm_state.nm_state.airplane_mode != state.airplane_mode {
|
if self.nm_state.nm_state.airplane_mode != state.airplane_mode {
|
||||||
self.nm_state.nm_state.airplane_mode = state.airplane_mode;
|
self.nm_state.nm_state.airplane_mode = state.airplane_mode;
|
||||||
changed = true;
|
changed = true;
|
||||||
let chain = if state.airplane_mode {
|
|
||||||
chain::Toggler::on(AIRPLANE_MODE.clone(), 1.)
|
|
||||||
} else {
|
|
||||||
chain::Toggler::off(AIRPLANE_MODE.clone(), 1.)
|
|
||||||
};
|
|
||||||
timeline.set_chain(chain);
|
|
||||||
}
|
|
||||||
if changed {
|
|
||||||
timeline.start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn view_window_return<'a>(&self, mut content: Column<'a, Message>) -> Element<'a, Message> {
|
fn view_window_return<'a>(&self, mut content: Column<'a, Message>) -> Element<'a, Message> {
|
||||||
|
|
@ -463,7 +442,6 @@ pub(crate) enum Message {
|
||||||
ToggleVisibleNetworks,
|
ToggleVisibleNetworks,
|
||||||
SelectWirelessAccessPoint(AccessPoint),
|
SelectWirelessAccessPoint(AccessPoint),
|
||||||
CancelNewConnection,
|
CancelNewConnection,
|
||||||
Frame(Instant),
|
|
||||||
Token(TokenUpdate),
|
Token(TokenUpdate),
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
ResetFailedKnownSsid(String, HwAddress),
|
ResetFailedKnownSsid(String, HwAddress),
|
||||||
|
|
@ -789,7 +767,6 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> app::Task<Message> {
|
fn update(&mut self, message: Message) -> app::Task<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::Frame(now) => self.timeline.now(now),
|
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
self.show_visible_networks = false;
|
self.show_visible_networks = false;
|
||||||
|
|
@ -817,7 +794,6 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
// TODO request update of state maybe
|
// TODO request update of state maybe
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
self.popup.replace(new_id);
|
self.popup.replace(new_id);
|
||||||
self.timeline = Timeline::new();
|
|
||||||
|
|
||||||
let popup_settings = self.core.applet.get_popup_settings(
|
let popup_settings = self.core.applet.get_popup_settings(
|
||||||
self.core.main_window_id().unwrap(),
|
self.core.main_window_id().unwrap(),
|
||||||
|
|
@ -1604,14 +1580,9 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
column![
|
column![
|
||||||
vpn_ethernet_col,
|
vpn_ethernet_col,
|
||||||
padded_control(
|
padded_control(
|
||||||
anim!(
|
toggler(self.nm_state.nm_state.airplane_mode,)
|
||||||
//toggler
|
.label(fl!("airplane-mode"))
|
||||||
AIRPLANE_MODE,
|
.on_toggle(Message::ToggleAirplaneMode)
|
||||||
&self.timeline,
|
|
||||||
fl!("airplane-mode"),
|
|
||||||
self.nm_state.nm_state.airplane_mode,
|
|
||||||
|_chain, enable| { Message::ToggleAirplaneMode(enable) },
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
),
|
),
|
||||||
|
|
@ -1621,14 +1592,9 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
.align_x(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
),
|
),
|
||||||
padded_control(
|
padded_control(
|
||||||
anim!(
|
toggler(self.nm_state.nm_state.wifi_enabled,)
|
||||||
//toggler
|
.label(fl!("wifi"))
|
||||||
WIFI,
|
.on_toggle(Message::WiFiEnable)
|
||||||
&self.timeline,
|
|
||||||
fl!("wifi"),
|
|
||||||
self.nm_state.nm_state.wifi_enabled,
|
|
||||||
|_chain, enable| { Message::WiFiEnable(enable) },
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
),
|
),
|
||||||
|
|
@ -1993,16 +1959,10 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
let timeline = self
|
activation_token_subscription(0).map(Message::Token)
|
||||||
.timeline
|
|
||||||
.as_subscription()
|
|
||||||
.map(|(_, now)| Message::Frame(now));
|
|
||||||
let token_sub = activation_token_subscription(0).map(Message::Token);
|
|
||||||
|
|
||||||
Subscription::batch([timeline, token_sub])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ license = "GPL-3.0-only"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
cosmic-time.workspace = true
|
|
||||||
libcosmic.workspace = true
|
libcosmic.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
cosmic-notifications-util = { git = "https://github.com/pop-os/cosmic-notifications" }
|
cosmic-notifications-util = { git = "https://github.com/pop-os/cosmic-notifications" }
|
||||||
|
|
|
||||||
|
|
@ -16,18 +16,17 @@ use cosmic::{
|
||||||
Alignment, Length, Subscription,
|
Alignment, Length, Subscription,
|
||||||
advanced::text::{Ellipsize, EllipsizeHeightLimit},
|
advanced::text::{Ellipsize, EllipsizeHeightLimit},
|
||||||
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
||||||
widget::{column, row},
|
widget::{self, column, row},
|
||||||
window,
|
window,
|
||||||
},
|
},
|
||||||
surface, theme,
|
surface, theme,
|
||||||
widget::{Column, button, container, divider, icon, scrollable, text},
|
widget::{Column, button, cards, container, divider, icon, scrollable, space, text, toggler},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cosmic::iced_futures::futures::executor::block_on;
|
use cosmic::iced_futures::futures::executor::block_on;
|
||||||
|
|
||||||
use cosmic_notifications_config::NotificationsConfig;
|
use cosmic_notifications_config::NotificationsConfig;
|
||||||
use cosmic_notifications_util::{ActionId, Image, Notification};
|
use cosmic_notifications_util::{ActionId, Image, Notification};
|
||||||
use cosmic_time::{Instant, Timeline, anim, chain, id};
|
|
||||||
use std::{borrow::Cow, collections::HashMap, path::PathBuf, sync::LazyLock};
|
use std::{borrow::Cow, collections::HashMap, path::PathBuf, sync::LazyLock};
|
||||||
use subscriptions::notifications::{self, NotificationsAppletProxy};
|
use subscriptions::notifications::{self, NotificationsAppletProxy};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
|
|
@ -38,8 +37,6 @@ pub fn run() -> cosmic::iced::Result {
|
||||||
cosmic::applet::run::<Notifications>(())
|
cosmic::applet::run::<Notifications>(())
|
||||||
}
|
}
|
||||||
|
|
||||||
static DO_NOT_DISTURB: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
|
||||||
|
|
||||||
struct Notifications {
|
struct Notifications {
|
||||||
core: cosmic::app::Core,
|
core: cosmic::app::Core,
|
||||||
config: NotificationsConfig,
|
config: NotificationsConfig,
|
||||||
|
|
@ -47,27 +44,14 @@ struct Notifications {
|
||||||
icon_name: String,
|
icon_name: String,
|
||||||
popup: Option<window::Id>,
|
popup: Option<window::Id>,
|
||||||
// notifications: Vec<Notification>,
|
// notifications: Vec<Notification>,
|
||||||
timeline: Timeline,
|
|
||||||
dbus_sender: Option<Sender<subscriptions::dbus::Input>>,
|
dbus_sender: Option<Sender<subscriptions::dbus::Input>>,
|
||||||
cards: Vec<(id::Cards, Vec<Notification>, bool, String, String, String)>,
|
cards: Vec<(widget::Id, Vec<Notification>, bool, String, String, String)>,
|
||||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||||
proxy: NotificationsAppletProxy<'static>,
|
proxy: NotificationsAppletProxy<'static>,
|
||||||
notifications_tx: Option<Sender<notifications::Input>>,
|
notifications_tx: Option<Sender<notifications::Input>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Notifications {
|
impl Notifications {
|
||||||
fn update_cards(&mut self, id: id::Cards) {
|
|
||||||
if let Some((id, _, card_value, ..)) = self.cards.iter().find(|c| c.0 == id) {
|
|
||||||
let chain = if *card_value {
|
|
||||||
chain::Cards::on(id.clone(), 1.)
|
|
||||||
} else {
|
|
||||||
chain::Cards::off(id.clone(), 1.)
|
|
||||||
};
|
|
||||||
self.timeline.set_chain(chain);
|
|
||||||
self.timeline.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_icon(&mut self) {
|
fn update_icon(&mut self) {
|
||||||
self.icon_name = if self.config.do_not_disturb {
|
self.icon_name = if self.config.do_not_disturb {
|
||||||
"cosmic-applet-notification-disabled-symbolic"
|
"cosmic-applet-notification-disabled-symbolic"
|
||||||
|
|
@ -84,8 +68,7 @@ impl Notifications {
|
||||||
enum Message {
|
enum Message {
|
||||||
TogglePopup,
|
TogglePopup,
|
||||||
CloseRequested(window::Id),
|
CloseRequested(window::Id),
|
||||||
DoNotDisturb(chain::Toggler, bool),
|
DoNotDisturb(bool),
|
||||||
Frame(Instant),
|
|
||||||
NotificationEvent(notifications::Output),
|
NotificationEvent(notifications::Output),
|
||||||
Config(NotificationsConfig),
|
Config(NotificationsConfig),
|
||||||
DbusEvent(subscriptions::dbus::Output),
|
DbusEvent(subscriptions::dbus::Output),
|
||||||
|
|
@ -128,7 +111,6 @@ impl cosmic::Application for Notifications {
|
||||||
config,
|
config,
|
||||||
icon_name: String::default(),
|
icon_name: String::default(),
|
||||||
popup: None,
|
popup: None,
|
||||||
timeline: Timeline::default(),
|
|
||||||
dbus_sender: Option::default(),
|
dbus_sender: Option::default(),
|
||||||
cards: Vec::new(),
|
cards: Vec::new(),
|
||||||
token_tx: Option::default(),
|
token_tx: Option::default(),
|
||||||
|
|
@ -148,7 +130,7 @@ impl cosmic::Application for Notifications {
|
||||||
&mut self.core
|
&mut self.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,9 +144,6 @@ impl cosmic::Application for Notifications {
|
||||||
}
|
}
|
||||||
Message::Config(res.config)
|
Message::Config(res.config)
|
||||||
}),
|
}),
|
||||||
self.timeline
|
|
||||||
.as_subscription()
|
|
||||||
.map(|(_, now)| Message::Frame(now)),
|
|
||||||
subscriptions::dbus::proxy().map(Message::DbusEvent),
|
subscriptions::dbus::proxy().map(Message::DbusEvent),
|
||||||
subscriptions::notifications::notifications(self.proxy.clone())
|
subscriptions::notifications::notifications(self.proxy.clone())
|
||||||
.map(Message::NotificationEvent),
|
.map(Message::NotificationEvent),
|
||||||
|
|
@ -174,16 +153,12 @@ impl cosmic::Application for Notifications {
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Message) -> app::Task<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> app::Task<Self::Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::Frame(now) => {
|
|
||||||
self.timeline.now(now);
|
|
||||||
}
|
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
return destroy_popup(p);
|
return destroy_popup(p);
|
||||||
} else {
|
} else {
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
self.popup.replace(new_id);
|
self.popup.replace(new_id);
|
||||||
self.timeline = Timeline::new();
|
|
||||||
|
|
||||||
let popup_settings = self.core.applet.get_popup_settings(
|
let popup_settings = self.core.applet.get_popup_settings(
|
||||||
self.core.main_window_id().unwrap(),
|
self.core.main_window_id().unwrap(),
|
||||||
|
|
@ -196,8 +171,7 @@ impl cosmic::Application for Notifications {
|
||||||
return get_popup(popup_settings);
|
return get_popup(popup_settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::DoNotDisturb(chain, b) => {
|
Message::DoNotDisturb(b) => {
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.config.do_not_disturb = b;
|
self.config.do_not_disturb = b;
|
||||||
if let Some(helper) = &self.config_helper {
|
if let Some(helper) = &self.config_helper {
|
||||||
if let Err(err) = self.config.write_entry(helper) {
|
if let Err(err) = self.config.write_entry(helper) {
|
||||||
|
|
@ -223,7 +197,7 @@ impl cosmic::Application for Notifications {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.cards.push((
|
self.cards.push((
|
||||||
id::Cards::new(n.app_name.clone()),
|
widget::Id::new(n.app_name.clone()),
|
||||||
vec![n],
|
vec![n],
|
||||||
false,
|
false,
|
||||||
fl!("show-more", HashMap::from([("more", "1")])),
|
fl!("show-more", HashMap::from([("more", "1")])),
|
||||||
|
|
@ -315,7 +289,6 @@ impl cosmic::Application for Notifications {
|
||||||
} else {
|
} else {
|
||||||
return Task::none();
|
return Task::none();
|
||||||
};
|
};
|
||||||
self.update_cards(id);
|
|
||||||
}
|
}
|
||||||
Message::CloseRequested(id) => {
|
Message::CloseRequested(id) => {
|
||||||
if Some(id) == self.popup {
|
if Some(id) == self.popup {
|
||||||
|
|
@ -412,15 +385,11 @@ impl cosmic::Application for Notifications {
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
||||||
let do_not_disturb = padded_control(row![
|
let do_not_disturb = padded_control(row![
|
||||||
anim!(
|
toggler(self.config.do_not_disturb)
|
||||||
DO_NOT_DISTURB,
|
.on_toggle(Message::DoNotDisturb)
|
||||||
&self.timeline,
|
|
||||||
fl!("do-not-disturb"),
|
|
||||||
self.config.do_not_disturb,
|
|
||||||
Message::DoNotDisturb
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
.label(fl!("do-not-disturb"))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let notifications = if self.cards.is_empty() {
|
let notifications = if self.cards.is_empty() {
|
||||||
|
|
@ -522,13 +491,12 @@ impl cosmic::Application for Notifications {
|
||||||
Some(cosmic::widget::icon::from_name(n.app_icon.as_str()).handle())
|
Some(cosmic::widget::icon::from_name(n.app_icon.as_str()).handle())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let card_list = anim!(
|
let card_list = cards(
|
||||||
//cards
|
//cards
|
||||||
c.0.clone(),
|
c.0.clone(),
|
||||||
&self.timeline,
|
|
||||||
notif_elems,
|
notif_elems,
|
||||||
Message::ClearAll(Some(name.clone())),
|
Message::ClearAll(Some(name.clone())),
|
||||||
Some(move |_, e| Message::CardsToggled(name.clone(), e)),
|
Some(move |e| Message::CardsToggled(name.clone(), e)),
|
||||||
Some(move |id| Message::ActivateNotification(ids[id])),
|
Some(move |id| Message::ActivateNotification(ids[id])),
|
||||||
&c.3,
|
&c.3,
|
||||||
&c.4,
|
&c.4,
|
||||||
|
|
@ -536,6 +504,7 @@ impl cosmic::Application for Notifications {
|
||||||
show_more_icon,
|
show_more_icon,
|
||||||
c.2,
|
c.2,
|
||||||
);
|
);
|
||||||
|
// let card_list = space::horizontal().width(Length::Fixed(10.));
|
||||||
notifs.push(card_list.into());
|
notifs.push(card_list.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,10 @@ pub enum Output {
|
||||||
pub fn proxy() -> Subscription<Output> {
|
pub fn proxy() -> Subscription<Output> {
|
||||||
struct SomeWorker;
|
struct SomeWorker;
|
||||||
|
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(std::any::TypeId::of::<SomeWorker>(), |_| {
|
||||||
std::any::TypeId::of::<SomeWorker>(),
|
stream::channel(
|
||||||
stream::channel(50, |mut output| async move {
|
50,
|
||||||
|
|mut output: futures::channel::mpsc::Sender<Output>| async move {
|
||||||
let mut state = State::Ready;
|
let mut state = State::Ready;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -100,6 +101,7 @@ pub fn proxy() -> Subscription<Output> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ use cosmic_notifications_util::Notification;
|
||||||
use futures_util::{SinkExt, StreamExt};
|
use futures_util::{SinkExt, StreamExt};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
hash::Hash,
|
||||||
os::unix::io::{FromRawFd, RawFd},
|
os::unix::io::{FromRawFd, RawFd},
|
||||||
pin::pin,
|
pin::pin,
|
||||||
};
|
};
|
||||||
|
|
@ -37,11 +38,18 @@ pub enum Output {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<Output> {
|
pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<Output> {
|
||||||
struct SomeWorker;
|
struct Wrapper(NotificationsAppletProxy<'static>);
|
||||||
|
|
||||||
Subscription::run_with_id(
|
impl Hash for Wrapper {
|
||||||
std::any::TypeId::of::<SomeWorker>(),
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
stream::channel(50, |mut output| async move {
|
std::any::TypeId::of::<NotificationsAppletProxy<'static>>().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Subscription::run_with(Wrapper(proxy), |Wrapper(proxy)| {
|
||||||
|
let proxy = proxy.clone();
|
||||||
|
stream::channel(
|
||||||
|
50,
|
||||||
|
move |mut output: futures::channel::mpsc::Sender<Output>| async move {
|
||||||
let mut state = State::WaitingForNotificationEvent;
|
let mut state = State::WaitingForNotificationEvent;
|
||||||
let (sender, mut receiver) = mpsc::channel(10);
|
let (sender, mut receiver) = mpsc::channel(10);
|
||||||
_ = output.send(Output::Ready(sender)).await;
|
_ = output.send(Output::Ready(sender)).await;
|
||||||
|
|
@ -118,8 +126,9 @@ pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<O
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proxy(
|
#[proxy(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use cosmic::{
|
||||||
window,
|
window,
|
||||||
},
|
},
|
||||||
surface, theme,
|
surface, theme,
|
||||||
widget::{Space, button, divider, icon, text},
|
widget::{Space, button, divider, icon, space, text},
|
||||||
};
|
};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
|
@ -227,7 +227,7 @@ impl cosmic::Application for Power {
|
||||||
row![
|
row![
|
||||||
text_icon("system-lock-screen-symbolic", 24),
|
text_icon("system-lock-screen-symbolic", 24),
|
||||||
text::body(fl!("lock-screen")),
|
text::body(fl!("lock-screen")),
|
||||||
Space::with_width(Length::Fill),
|
space::horizontal().width(Length::Fill),
|
||||||
text::body(fl!("lock-screen-shortcut")),
|
text::body(fl!("lock-screen-shortcut")),
|
||||||
]
|
]
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
|
|
@ -238,7 +238,7 @@ impl cosmic::Application for Power {
|
||||||
row![
|
row![
|
||||||
text_icon("system-log-out-symbolic", 24),
|
text_icon("system-log-out-symbolic", 24),
|
||||||
text::body(fl!("log-out")),
|
text::body(fl!("log-out")),
|
||||||
Space::with_width(Length::Fill),
|
space::horizontal().width(Length::Fill),
|
||||||
text::body(fl!("log-out-shortcut")),
|
text::body(fl!("log-out-shortcut")),
|
||||||
]
|
]
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
|
|
@ -285,7 +285,7 @@ impl cosmic::Application for Power {
|
||||||
activation_token_subscription(0).map(Message::Token)
|
activation_token_subscription(0).map(Message::Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,15 @@
|
||||||
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
Element, Task, app,
|
Element, Task, app,
|
||||||
applet::cosmic_panel_config::PanelAnchor,
|
applet::{
|
||||||
applet::token::subscription::{TokenRequest, TokenUpdate, activation_token_subscription},
|
cosmic_panel_config::PanelAnchor,
|
||||||
|
token::subscription::{TokenRequest, TokenUpdate, activation_token_subscription},
|
||||||
|
},
|
||||||
cctk::sctk::reexports::calloop,
|
cctk::sctk::reexports::calloop,
|
||||||
iced::{
|
iced::{
|
||||||
self, Length, Subscription,
|
self, Length, Subscription,
|
||||||
platform_specific::shell::commands::popup::{destroy_popup, get_popup},
|
platform_specific::shell::commands::popup::{destroy_popup, get_popup},
|
||||||
|
theme::Style,
|
||||||
window,
|
window,
|
||||||
},
|
},
|
||||||
surface,
|
surface,
|
||||||
|
|
@ -146,7 +149,7 @@ impl cosmic::Application for App {
|
||||||
&mut self.core
|
&mut self.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ fn layout_view(layout: &Layout, expanded: Option<i32>) -> cosmic::Element<'_, Ms
|
||||||
if !i.visible() {
|
if !i.visible() {
|
||||||
None
|
None
|
||||||
} else if i.type_() == Some("separator") {
|
} else if i.type_() == Some("separator") {
|
||||||
Some(iced::widget::horizontal_rule(2).into())
|
Some(iced::widget::rule::horizontal(2).into())
|
||||||
} else if let Some(label) = i.label() {
|
} else if let Some(label) = i.label() {
|
||||||
// Strip _ when not doubled
|
// Strip _ when not doubled
|
||||||
// TODO: interpret as "access key"? And label with underline.
|
// TODO: interpret as "access key"? And label with underline.
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
use cosmic::iced::{self, Subscription};
|
use cosmic::iced::{self, Subscription};
|
||||||
use futures::{FutureExt, StreamExt};
|
use futures::{FutureExt, StreamExt};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::path::PathBuf;
|
|
||||||
use zbus::zvariant::{self, OwnedValue};
|
use zbus::zvariant::{self, OwnedValue};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -76,22 +77,40 @@ impl StatusNotifierItem {
|
||||||
let Some(menu_proxy) = self.menu_proxy.clone() else {
|
let Some(menu_proxy) = self.menu_proxy.clone() else {
|
||||||
return Subscription::none();
|
return Subscription::none();
|
||||||
};
|
};
|
||||||
Subscription::run_with_id(
|
struct Wrapper {
|
||||||
format!("status-notifier-item-layout-{}", &self.name),
|
menu_proxy: DBusMenuProxy<'static>,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
impl Hash for Wrapper {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.name.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Subscription::run_with(
|
||||||
|
Wrapper {
|
||||||
|
menu_proxy,
|
||||||
|
name: format!("status-notifier-item-layout-{}", &self.name),
|
||||||
|
},
|
||||||
|
|Wrapper { menu_proxy, .. }| {
|
||||||
|
let menu_proxy = menu_proxy.clone();
|
||||||
async move {
|
async move {
|
||||||
let initial = futures::stream::once(get_layout(menu_proxy.clone()));
|
let initial = futures::stream::once(get_layout(menu_proxy.clone()));
|
||||||
|
|
||||||
let layout_updated = menu_proxy.receive_layout_updated().await.unwrap();
|
let layout_updated = menu_proxy.receive_layout_updated().await.unwrap();
|
||||||
let props_updated = menu_proxy.receive_items_properties_updated().await.unwrap();
|
let props_updated =
|
||||||
|
menu_proxy.receive_items_properties_updated().await.unwrap();
|
||||||
|
|
||||||
// Merge both streams - any update triggers a layout refetch
|
// Merge both streams - any update triggers a layout refetch
|
||||||
let updates =
|
let updates = futures::stream_select!(
|
||||||
futures::stream_select!(layout_updated.map(|_| ()), props_updated.map(|_| ()))
|
layout_updated.map(|_| ()),
|
||||||
|
props_updated.map(|_| ())
|
||||||
|
)
|
||||||
.then(move |()| get_layout(menu_proxy.clone()));
|
.then(move |()| get_layout(menu_proxy.clone()));
|
||||||
|
|
||||||
initial.chain(updates)
|
initial.chain(updates)
|
||||||
}
|
}
|
||||||
.flatten_stream(),
|
.flatten_stream()
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,15 +127,30 @@ impl StatusNotifierItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_proxy = self.item_proxy.clone();
|
let item_proxy = self.item_proxy.clone();
|
||||||
Subscription::run_with_id(
|
struct Wrapper {
|
||||||
format!("status-notifier-item-icon-{}", &self.name),
|
item_proxy: StatusNotifierItemProxy<'static>,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
impl Hash for Wrapper {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.name.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Subscription::run_with(
|
||||||
|
Wrapper {
|
||||||
|
item_proxy,
|
||||||
|
name: format!("status-notifier-item-icon-{}", &self.name),
|
||||||
|
},
|
||||||
|
|Wrapper { item_proxy, .. }| {
|
||||||
|
let item_proxy = item_proxy.clone();
|
||||||
async move {
|
async move {
|
||||||
let new_icon_stream = item_proxy.receive_new_icon().await.unwrap();
|
let new_icon_stream = item_proxy.receive_new_icon().await.unwrap();
|
||||||
futures::stream::once(async {})
|
futures::stream::once(async {})
|
||||||
.chain(new_icon_stream.map(|_| ()))
|
.chain(new_icon_stream.map(|_| ()))
|
||||||
.then(move |()| icon_events(item_proxy.clone()))
|
.then(move |()| icon_events(item_proxy.clone()))
|
||||||
}
|
}
|
||||||
.flatten_stream(),
|
.flatten_stream()
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
// TODO: Both this and server proxy could emit same events, have way to generate stream from either?
|
// TODO: Both this and server proxy could emit same events, have way to generate stream from either?
|
||||||
|
|
||||||
|
use std::any::TypeId;
|
||||||
|
|
||||||
use cosmic::iced::{self, Subscription};
|
use cosmic::iced::{self, Subscription};
|
||||||
use futures::{StreamExt, stream};
|
use futures::{StreamExt, stream};
|
||||||
|
|
||||||
|
|
@ -26,8 +28,8 @@ enum State {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscription() -> iced::Subscription<Event> {
|
pub fn subscription() -> iced::Subscription<Event> {
|
||||||
Subscription::run_with_id(
|
pub struct MyID;
|
||||||
"status-notifier-watcher",
|
Subscription::run_with(TypeId::of::<MyID>(), |_| {
|
||||||
stream::unfold(State::NotConnected, |state| async move {
|
stream::unfold(State::NotConnected, |state| async move {
|
||||||
match state {
|
match state {
|
||||||
State::NotConnected => match connect().await {
|
State::NotConnected => match connect().await {
|
||||||
|
|
@ -42,8 +44,8 @@ pub fn subscription() -> iced::Subscription<Event> {
|
||||||
.map(|event| (event, State::Connected(stream))),
|
.map(|event| (event, State::Connected(stream))),
|
||||||
State::Failed => None,
|
State::Failed => None,
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn connect() -> zbus::Result<(zbus::Connection, client::EventStream)> {
|
async fn connect() -> zbus::Result<(zbus::Connection, client::EventStream)> {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ anyhow.workspace = true
|
||||||
cctk.workspace = true
|
cctk.workspace = true
|
||||||
cosmic-comp-config = { git = "https://github.com/pop-os/cosmic-comp.git", rev = "5eb5af4" }
|
cosmic-comp-config = { git = "https://github.com/pop-os/cosmic-comp.git", rev = "5eb5af4" }
|
||||||
cosmic-protocols.workspace = true
|
cosmic-protocols.workspace = true
|
||||||
cosmic-time.workspace = true
|
|
||||||
i18n-embed-fl.workspace = true
|
i18n-embed-fl.workspace = true
|
||||||
i18n-embed.workspace = true
|
i18n-embed.workspace = true
|
||||||
rust-embed.workspace = true
|
rust-embed.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,15 @@ pub enum WorkspacesUpdate {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn workspaces() -> iced::Subscription<WorkspacesUpdate> {
|
pub fn workspaces() -> iced::Subscription<WorkspacesUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(std::any::TypeId::of::<WorkspacesUpdate>(), |_| {
|
||||||
std::any::TypeId::of::<WorkspacesUpdate>(),
|
|
||||||
stream::channel(50, move |mut output| async move {
|
stream::channel(50, move |mut output| async move {
|
||||||
let mut state = State::Waiting;
|
let mut state = State::Waiting;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
state = start_listening(state, &mut output).await;
|
state = start_listening(state, &mut output).await;
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_listening(
|
async fn start_listening(
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
use cctk::sctk::reexports::calloop::channel::SyncSender;
|
use cctk::sctk::reexports::calloop::channel::SyncSender;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
Element, Task, app,
|
Element, Task,
|
||||||
app::Core,
|
app::{self, Core},
|
||||||
applet::{menu_button, padded_control},
|
applet::{menu_button, padded_control},
|
||||||
cosmic_config::{Config, ConfigSet, CosmicConfigEntry},
|
cosmic_config::{Config, ConfigSet, CosmicConfigEntry},
|
||||||
cosmic_theme::Spacing,
|
cosmic_theme::Spacing,
|
||||||
|
|
@ -21,12 +21,11 @@ use cosmic::{
|
||||||
widget::{
|
widget::{
|
||||||
container, divider,
|
container, divider,
|
||||||
segmented_button::{self, Entity, SingleSelectModel},
|
segmented_button::{self, Entity, SingleSelectModel},
|
||||||
segmented_control, text,
|
segmented_control, text, toggler,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use cosmic_comp_config::{CosmicCompConfig, TileBehavior};
|
use cosmic_comp_config::{CosmicCompConfig, TileBehavior};
|
||||||
use cosmic_protocols::workspace::v2::client::zcosmic_workspace_handle_v2::TilingState;
|
use cosmic_protocols::workspace::v2::client::zcosmic_workspace_handle_v2::TilingState;
|
||||||
use cosmic_time::{Timeline, anim, chain, id};
|
|
||||||
use std::{thread, time::Instant};
|
use std::{thread, time::Instant};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
|
|
@ -37,7 +36,6 @@ const OFF: &str = "com.system76.CosmicAppletTiling.Off";
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
core: Core,
|
core: Core,
|
||||||
popup: Option<Id>,
|
popup: Option<Id>,
|
||||||
timeline: Timeline,
|
|
||||||
config: CosmicCompConfig,
|
config: CosmicCompConfig,
|
||||||
config_helper: Config,
|
config_helper: Config,
|
||||||
new_workspace_behavior_model: segmented_button::SingleSelectModel,
|
new_workspace_behavior_model: segmented_button::SingleSelectModel,
|
||||||
|
|
@ -45,17 +43,14 @@ pub struct Window {
|
||||||
/// may not match the config value if behavior is per-workspace
|
/// may not match the config value if behavior is per-workspace
|
||||||
autotiled: bool,
|
autotiled: bool,
|
||||||
workspace_tx: Option<SyncSender<AppRequest>>,
|
workspace_tx: Option<SyncSender<AppRequest>>,
|
||||||
tile_windows: id::Toggler,
|
|
||||||
active_hint: id::Toggler,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
TogglePopup,
|
TogglePopup,
|
||||||
PopupClosed(Id),
|
PopupClosed(Id),
|
||||||
Frame(Instant),
|
ToggleTileWindows(bool),
|
||||||
ToggleTileWindows(chain::Toggler, bool),
|
ToggleActiveHint(bool),
|
||||||
ToggleActiveHint(chain::Toggler, bool),
|
|
||||||
MyConfigUpdate(Box<CosmicCompConfig>),
|
MyConfigUpdate(Box<CosmicCompConfig>),
|
||||||
WorkspaceUpdate(WorkspacesUpdate),
|
WorkspaceUpdate(WorkspacesUpdate),
|
||||||
NewWorkspace(Entity),
|
NewWorkspace(Entity),
|
||||||
|
|
@ -110,15 +105,12 @@ impl cosmic::Application for Window {
|
||||||
let window = Self {
|
let window = Self {
|
||||||
core,
|
core,
|
||||||
popup: None,
|
popup: None,
|
||||||
timeline: Timeline::default(),
|
|
||||||
autotiled: config.autotile,
|
autotiled: config.autotile,
|
||||||
config,
|
config,
|
||||||
config_helper,
|
config_helper,
|
||||||
new_workspace_behavior_model,
|
new_workspace_behavior_model,
|
||||||
new_workspace_entity,
|
new_workspace_entity,
|
||||||
workspace_tx: None,
|
workspace_tx: None,
|
||||||
tile_windows: id::Toggler::unique(),
|
|
||||||
active_hint: id::Toggler::unique(),
|
|
||||||
};
|
};
|
||||||
(window, Task::none())
|
(window, Task::none())
|
||||||
}
|
}
|
||||||
|
|
@ -128,12 +120,7 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Self::Message> {
|
fn subscription(&self) -> Subscription<Self::Message> {
|
||||||
let timeline = self
|
|
||||||
.timeline
|
|
||||||
.as_subscription()
|
|
||||||
.map(|(_, now)| Message::Frame(now));
|
|
||||||
Subscription::batch([
|
Subscription::batch([
|
||||||
timeline,
|
|
||||||
self.core
|
self.core
|
||||||
.watch_config::<CosmicCompConfig>("com.system76.CosmicComp")
|
.watch_config::<CosmicCompConfig>("com.system76.CosmicComp")
|
||||||
.map(|u| Message::MyConfigUpdate(Box::new(u.config))),
|
.map(|u| Message::MyConfigUpdate(Box::new(u.config))),
|
||||||
|
|
@ -146,15 +133,7 @@ impl cosmic::Application for Window {
|
||||||
Message::WorkspaceUpdate(msg) => match msg {
|
Message::WorkspaceUpdate(msg) => match msg {
|
||||||
WorkspacesUpdate::State(state) => {
|
WorkspacesUpdate::State(state) => {
|
||||||
self.autotiled = matches!(state, TilingState::TilingEnabled);
|
self.autotiled = matches!(state, TilingState::TilingEnabled);
|
||||||
if self.popup.is_some() {
|
if self.popup.is_some() {}
|
||||||
self.timeline
|
|
||||||
.set_chain(if self.autotiled {
|
|
||||||
cosmic_time::chain::Toggler::on(self.tile_windows.clone(), 1.0)
|
|
||||||
} else {
|
|
||||||
cosmic_time::chain::Toggler::off(self.tile_windows.clone(), 1.0)
|
|
||||||
})
|
|
||||||
.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
WorkspacesUpdate::Started(tx) => {
|
WorkspacesUpdate::Started(tx) => {
|
||||||
self.workspace_tx = Some(tx);
|
self.workspace_tx = Some(tx);
|
||||||
|
|
@ -167,9 +146,6 @@ impl cosmic::Application for Window {
|
||||||
return if let Some(p) = self.popup.take() {
|
return if let Some(p) = self.popup.take() {
|
||||||
destroy_popup(p)
|
destroy_popup(p)
|
||||||
} else {
|
} else {
|
||||||
self.timeline = Timeline::default();
|
|
||||||
self.tile_windows = id::Toggler::unique();
|
|
||||||
self.active_hint = id::Toggler::unique();
|
|
||||||
let new_id = Id::unique();
|
let new_id = Id::unique();
|
||||||
self.popup = Some(new_id);
|
self.popup = Some(new_id);
|
||||||
let popup_settings = self.core.applet.get_popup_settings(
|
let popup_settings = self.core.applet.get_popup_settings(
|
||||||
|
|
@ -188,9 +164,7 @@ impl cosmic::Application for Window {
|
||||||
self.popup = None;
|
self.popup = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Frame(now) => self.timeline.now(now),
|
Message::ToggleTileWindows(toggled) => {
|
||||||
Message::ToggleTileWindows(chain, toggled) => {
|
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.autotiled = toggled;
|
self.autotiled = toggled;
|
||||||
|
|
||||||
// set via protocol
|
// set via protocol
|
||||||
|
|
@ -206,8 +180,7 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ToggleActiveHint(chain, toggled) => {
|
Message::ToggleActiveHint(toggled) => {
|
||||||
self.timeline.set_chain(chain).start();
|
|
||||||
self.config.active_hint = toggled;
|
self.config.active_hint = toggled;
|
||||||
|
|
||||||
let helper = self.config_helper.clone();
|
let helper = self.config_helper.clone();
|
||||||
|
|
@ -223,16 +196,6 @@ impl cosmic::Application for Window {
|
||||||
.activate_position(if c.autotile { 0 } else { 1 });
|
.activate_position(if c.autotile { 0 } else { 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.active_hint != self.config.active_hint && self.popup.is_some() {
|
|
||||||
self.timeline
|
|
||||||
.set_chain(if c.active_hint {
|
|
||||||
cosmic_time::chain::Toggler::on(self.active_hint.clone(), 1.0)
|
|
||||||
} else {
|
|
||||||
cosmic_time::chain::Toggler::off(self.active_hint.clone(), 1.0)
|
|
||||||
})
|
|
||||||
.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.config = *c;
|
self.config = *c;
|
||||||
}
|
}
|
||||||
Message::NewWorkspace(e) => {
|
Message::NewWorkspace(e) => {
|
||||||
|
|
@ -295,17 +258,12 @@ impl cosmic::Application for Window {
|
||||||
.on_activate(Message::NewWorkspace);
|
.on_activate(Message::NewWorkspace);
|
||||||
let content_list = column![
|
let content_list = column![
|
||||||
padded_control(container(
|
padded_control(container(
|
||||||
anim!(
|
toggler(self.autotiled)
|
||||||
self.tile_windows,
|
.on_toggle(Message::ToggleTileWindows)
|
||||||
&self.timeline,
|
|
||||||
fl!("tile-current"),
|
|
||||||
self.autotiled,
|
|
||||||
|chain, enable| { Message::ToggleTileWindows(chain, enable) },
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill)
|
||||||
))
|
.label(fl!("tile-current"))
|
||||||
.width(Length::Fill),
|
)),
|
||||||
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
||||||
padded_control(
|
padded_control(
|
||||||
column![
|
column![
|
||||||
|
|
@ -334,13 +292,9 @@ impl cosmic::Application for Window {
|
||||||
)),
|
)),
|
||||||
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
||||||
padded_control(
|
padded_control(
|
||||||
anim!(
|
toggler(self.config.active_hint)
|
||||||
self.active_hint,
|
.on_toggle(Message::ToggleActiveHint)
|
||||||
&self.timeline,
|
.label(fl!("active-hint"))
|
||||||
fl!("active-hint"),
|
|
||||||
self.config.active_hint,
|
|
||||||
|chain, enable| { Message::ToggleActiveHint(chain, enable) },
|
|
||||||
)
|
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
),
|
),
|
||||||
|
|
@ -353,7 +307,7 @@ impl cosmic::Application for Window {
|
||||||
self.core.applet.popup_container(content_list).into()
|
self.core.applet.popup_container(content_list).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,15 @@ use cosmic::{
|
||||||
Alignment, Length, Rectangle, Subscription,
|
Alignment, Length, Rectangle, Subscription,
|
||||||
futures::{SinkExt, StreamExt, channel::mpsc},
|
futures::{SinkExt, StreamExt, channel::mpsc},
|
||||||
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
||||||
widget::{column, row, vertical_space},
|
widget::{column, row, rule},
|
||||||
window,
|
window,
|
||||||
},
|
},
|
||||||
iced_futures::stream,
|
iced_futures::stream,
|
||||||
iced_widget::{Column, horizontal_rule},
|
iced_widget::Column,
|
||||||
surface, theme,
|
surface, theme,
|
||||||
widget::{
|
widget::{
|
||||||
Button, Grid, Id, Space, autosize, button, container, divider, grid, horizontal_space,
|
Button, Grid, Id, autosize, button, container, divider, grid, icon, rectangle_tracker::*,
|
||||||
icon, rectangle_tracker::*, text,
|
space, text,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use jiff::{
|
use jiff::{
|
||||||
|
|
@ -28,6 +28,7 @@ use jiff::{
|
||||||
tz::TimeZone,
|
tz::TimeZone,
|
||||||
};
|
};
|
||||||
use logind_zbus::manager::ManagerProxy;
|
use logind_zbus::manager::ManagerProxy;
|
||||||
|
use std::hash::Hash;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
use timedate_zbus::TimeDateProxy;
|
use timedate_zbus::TimeDateProxy;
|
||||||
use tokio::{sync::watch, time};
|
use tokio::{sync::watch, time};
|
||||||
|
|
@ -215,7 +216,7 @@ impl Window {
|
||||||
elements.push(self.core.applet.text(p.to_owned()).into());
|
elements.push(self.core.applet.text(p.to_owned()).into());
|
||||||
}
|
}
|
||||||
elements.push(
|
elements.push(
|
||||||
horizontal_rule(2)
|
rule::horizontal(2)
|
||||||
.width(self.core.applet.suggested_size(true).0)
|
.width(self.core.applet.suggested_size(true).0)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
@ -245,7 +246,7 @@ impl Window {
|
||||||
Element::from(
|
Element::from(
|
||||||
column!(
|
column!(
|
||||||
date_time_col,
|
date_time_col,
|
||||||
horizontal_space().width(Length::Fixed(
|
space::horizontal().width(Length::Fixed(
|
||||||
(self.core.applet.suggested_size(true).0
|
(self.core.applet.suggested_size(true).0
|
||||||
+ 2 * self.core.applet.suggested_padding(true).1)
|
+ 2 * self.core.applet.suggested_padding(true).1)
|
||||||
as f32
|
as f32
|
||||||
|
|
@ -302,7 +303,7 @@ impl Window {
|
||||||
Element::from(
|
Element::from(
|
||||||
row!(
|
row!(
|
||||||
self.core.applet.text(formatted_date),
|
self.core.applet.text(formatted_date),
|
||||||
container(vertical_space().height(Length::Fixed(
|
container(space::vertical().height(Length::Fixed(
|
||||||
(self.core.applet.suggested_size(true).1
|
(self.core.applet.suggested_size(true).1
|
||||||
+ 2 * self.core.applet.suggested_padding(true).1)
|
+ 2 * self.core.applet.suggested_padding(true).1)
|
||||||
as f32
|
as f32
|
||||||
|
|
@ -355,15 +356,29 @@ impl cosmic::Application for Window {
|
||||||
&mut self.core
|
&mut self.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
fn time_subscription(mut show_seconds: watch::Receiver<bool>) -> Subscription<Message> {
|
fn time_subscription(mut show_seconds: watch::Receiver<bool>) -> Subscription<Message> {
|
||||||
Subscription::run_with_id(
|
struct Wrapper {
|
||||||
"time-sub",
|
inner: watch::Receiver<bool>,
|
||||||
stream::channel(1, |mut output| async move {
|
id: &'static str,
|
||||||
|
}
|
||||||
|
impl Hash for Wrapper {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.id.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Subscription::run_with(
|
||||||
|
Wrapper {
|
||||||
|
inner: show_seconds,
|
||||||
|
id: "time-sub",
|
||||||
|
},
|
||||||
|
|Wrapper { inner, id }| {
|
||||||
|
let mut show_seconds = inner.clone();
|
||||||
|
stream::channel(1, move |mut output: mpsc::Sender<Message>| async move {
|
||||||
// Mark this receiver's state as changed so that it always receives an initial
|
// Mark this receiver's state as changed so that it always receives an initial
|
||||||
// update during the loop below
|
// update during the loop below
|
||||||
// This allows us to avoid duplicating code from the loop
|
// This allows us to avoid duplicating code from the loop
|
||||||
|
|
@ -406,13 +421,14 @@ impl cosmic::Application for Window {
|
||||||
let start = now + delta;
|
let start = now + delta;
|
||||||
let period = time::Duration::from_secs(period);
|
let period = time::Duration::from_secs(period);
|
||||||
timer = time::interval_at(start, period);
|
timer = time::interval_at(start, period);
|
||||||
}
|
|
||||||
|
|
||||||
timer.set_missed_tick_behavior(time::MissedTickBehavior::Skip);
|
timer.set_missed_tick_behavior(time::MissedTickBehavior::Skip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,8 +454,7 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timezone_subscription() -> Subscription<Message> {
|
fn timezone_subscription() -> Subscription<Message> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with("timezone-sub", |_| {
|
||||||
"timezone-sub",
|
|
||||||
stream::channel(1, |mut output| async move {
|
stream::channel(1, |mut output| async move {
|
||||||
'retry: loop {
|
'retry: loop {
|
||||||
match timezone_update(&mut output).await {
|
match timezone_update(&mut output).await {
|
||||||
|
|
@ -455,8 +470,8 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future::pending().await
|
std::future::pending().await
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the time when waking from sleep
|
// Update the time when waking from sleep
|
||||||
|
|
@ -474,14 +489,13 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wake_from_sleep_subscription() -> Subscription<Message> {
|
fn wake_from_sleep_subscription() -> Subscription<Message> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with("wake-from-suspend-sub", |_| {
|
||||||
"wake-from-suspend-sub",
|
|
||||||
stream::channel(1, |mut output| async move {
|
stream::channel(1, |mut output| async move {
|
||||||
if let Err(err) = wake_from_sleep(&mut output).await {
|
if let Err(err) = wake_from_sleep(&mut output).await {
|
||||||
tracing::error!(?err, "Failed to subscribe to wake-from-sleep signal");
|
tracing::error!(?err, "Failed to subscribe to wake-from-sleep signal");
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let show_seconds_rx = self.show_seconds_tx.subscribe();
|
let show_seconds_rx = self.show_seconds_tx.subscribe();
|
||||||
|
|
@ -728,7 +742,7 @@ impl cosmic::Application for Window {
|
||||||
let content_list = column![
|
let content_list = column![
|
||||||
row![
|
row![
|
||||||
column![date, day_of_week],
|
column![date, day_of_week],
|
||||||
Space::with_width(Length::Fill),
|
space::horizontal().width(Length::Fill),
|
||||||
month_controls,
|
month_controls,
|
||||||
]
|
]
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use cosmic::{
|
||||||
iced_core::{Background, Border},
|
iced_core::{Background, Border},
|
||||||
scroll::DiscreteScrollState,
|
scroll::DiscreteScrollState,
|
||||||
surface,
|
surface,
|
||||||
widget::{Id, autosize, container, horizontal_space, vertical_space},
|
widget::{Id, autosize, container, space},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -196,10 +196,10 @@ impl cosmic::Application for IcedWorkspacesApplet {
|
||||||
(suggested_window_size.0.get() as f32, suggested_total as f32)
|
(suggested_window_size.0.get() as f32, suggested_total as f32)
|
||||||
};
|
};
|
||||||
|
|
||||||
let content = row!(content, vertical_space().height(Length::Fixed(height)))
|
let content = row!(content, space::vertical().height(Length::Fixed(height)))
|
||||||
.align_y(Alignment::Center);
|
.align_y(Alignment::Center);
|
||||||
|
|
||||||
let content = column!(content, horizontal_space().width(Length::Fixed(width)))
|
let content = column!(content, space::horizontal().width(Length::Fixed(width)))
|
||||||
.align_x(Alignment::Center);
|
.align_x(Alignment::Center);
|
||||||
|
|
||||||
let btn = button(
|
let btn = button(
|
||||||
|
|
@ -323,7 +323,7 @@ impl cosmic::Application for IcedWorkspacesApplet {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,15 @@ pub enum WorkspacesUpdate {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn workspaces() -> iced::Subscription<WorkspacesUpdate> {
|
pub fn workspaces() -> iced::Subscription<WorkspacesUpdate> {
|
||||||
Subscription::run_with_id(
|
Subscription::run_with(std::any::TypeId::of::<WorkspacesUpdate>(), |_| {
|
||||||
std::any::TypeId::of::<WorkspacesUpdate>(),
|
|
||||||
stream::channel(50, move |mut output| async move {
|
stream::channel(50, move |mut output| async move {
|
||||||
let mut state = State::Waiting;
|
let mut state = State::Waiting;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
state = start_listening(state, &mut output).await;
|
state = start_listening(state, &mut output).await;
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_listening(
|
async fn start_listening(
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
use config::{CosmicPanelButtonConfig, IndividualConfig, Override};
|
use config::{CosmicPanelButtonConfig, IndividualConfig, Override};
|
||||||
use cosmic::desktop::fde::{self, DesktopEntry, get_languages_from_env};
|
use cosmic::desktop::fde::{self, DesktopEntry, get_languages_from_env};
|
||||||
|
use cosmic::widget::space;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
Task, app,
|
Task, app,
|
||||||
applet::{
|
applet::{
|
||||||
|
|
@ -12,7 +13,7 @@ use cosmic::{
|
||||||
iced::{self, Length},
|
iced::{self, Length},
|
||||||
iced_widget::row,
|
iced_widget::row,
|
||||||
surface,
|
surface,
|
||||||
widget::{Id, autosize, vertical_space},
|
widget::{Id, autosize},
|
||||||
};
|
};
|
||||||
use cosmic_config::{Config, CosmicConfigEntry};
|
use cosmic_config::{Config, CosmicConfigEntry};
|
||||||
use std::{env, fs, process::Command, sync::LazyLock};
|
use std::{env, fs, process::Command, sync::LazyLock};
|
||||||
|
|
@ -115,7 +116,7 @@ impl cosmic::Application for Button {
|
||||||
&mut self.core
|
&mut self.core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
fn style(&self) -> Option<iced::theme::Style> {
|
||||||
Some(cosmic::applet::style())
|
Some(cosmic::applet::style())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,7 +180,7 @@ impl cosmic::Application for Button {
|
||||||
} else {
|
} else {
|
||||||
let content = row!(
|
let content = row!(
|
||||||
self.core.applet.text(&self.desktop.name),
|
self.core.applet.text(&self.desktop.name),
|
||||||
vertical_space().height(Length::Fixed(
|
space::vertical().height(Length::Fixed(
|
||||||
(self.core.applet.suggested_size(true).1
|
(self.core.applet.suggested_size(true).1
|
||||||
+ 2 * self.core.applet.suggested_padding(true).1)
|
+ 2 * self.core.applet.suggested_padding(true).1)
|
||||||
as f32
|
as f32
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue