feat: partial implementation of wallpaper settings
Will take some time to refactor the rest
This commit is contained in:
parent
14a4a23bc9
commit
a4eee2186c
14 changed files with 375 additions and 80 deletions
65
Cargo.lock
generated
65
Cargo.lock
generated
|
|
@ -715,12 +715,25 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmic-bg-config"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/cosmic-bg#c9fec966262a9a3572e662b4e98f647f4807ba33"
|
||||
dependencies = [
|
||||
"cosmic-config",
|
||||
"derive_setters",
|
||||
"image",
|
||||
"ron",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmic-config"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"atomicwrites",
|
||||
"calloop",
|
||||
"cosmic-config-derive",
|
||||
"dirs 5.0.1",
|
||||
"iced_futures",
|
||||
|
|
@ -732,7 +745,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cosmic-config-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
|
|
@ -741,7 +754,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cosmic-panel-config"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/cosmic-panel#adbe256782887cb0a15b9b421a477e70d1ca1b80"
|
||||
source = "git+https://github.com/pop-os/cosmic-panel?branch=settings_jammy#a71a4cba13184f22ba8874c910b20e99f60871c0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cosmic-config",
|
||||
|
|
@ -760,6 +773,7 @@ dependencies = [
|
|||
"async-channel",
|
||||
"color-eyre",
|
||||
"cosmic-panel-config",
|
||||
"cosmic-settings-desktop",
|
||||
"cosmic-settings-page",
|
||||
"cosmic-settings-system",
|
||||
"cosmic-settings-time",
|
||||
|
|
@ -779,6 +793,21 @@ dependencies = [
|
|||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmic-settings-desktop"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmic-bg-config",
|
||||
"cosmic-config",
|
||||
"dirs 5.0.1",
|
||||
"freedesktop-icons",
|
||||
"futures-lite",
|
||||
"image",
|
||||
"rayon",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmic-settings-page"
|
||||
version = "0.1.0"
|
||||
|
|
@ -836,7 +865,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cosmic-theme"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cosmic-config",
|
||||
|
|
@ -2015,7 +2044,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"iced_accessibility",
|
||||
"iced_core",
|
||||
|
|
@ -2031,7 +2060,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_accessibility"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_unix",
|
||||
|
|
@ -2040,7 +2069,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_core"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"iced_accessibility",
|
||||
|
|
@ -2055,7 +2084,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_futures"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"iced_core",
|
||||
|
|
@ -2068,7 +2097,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_graphics"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bytemuck",
|
||||
|
|
@ -2085,7 +2114,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_renderer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"iced_graphics",
|
||||
"iced_tiny_skia",
|
||||
|
|
@ -2097,7 +2126,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_runtime"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"iced_accessibility",
|
||||
"iced_core",
|
||||
|
|
@ -2109,7 +2138,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_sctk"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"enum-repr",
|
||||
"float-cmp",
|
||||
|
|
@ -2130,7 +2159,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_style"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"iced_core",
|
||||
"once_cell",
|
||||
|
|
@ -2140,7 +2169,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_tiny_skia"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"cosmic-text",
|
||||
|
|
@ -2158,7 +2187,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_wgpu"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bytemuck",
|
||||
|
|
@ -2180,7 +2209,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_widget"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"iced_renderer",
|
||||
"iced_runtime",
|
||||
|
|
@ -2195,7 +2224,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "iced_winit"
|
||||
version = "0.9.1"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"iced_graphics",
|
||||
"iced_runtime",
|
||||
|
|
@ -2487,7 +2516,7 @@ checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
|||
[[package]]
|
||||
name = "libcosmic"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/libcosmic?rev=f06a81c#f06a81ccf9fdeaef0033bfc07aa493ff8675f420"
|
||||
source = "git+https://github.com/pop-os/libcosmic#31f7e97d5bf4860be5afd406209eed733f736f04"
|
||||
dependencies = [
|
||||
"apply",
|
||||
"cosmic-config",
|
||||
|
|
|
|||
12
Cargo.toml
12
Cargo.toml
|
|
@ -2,12 +2,20 @@
|
|||
members = ["app", "page", "pages/*"]
|
||||
default-members = ["app"]
|
||||
|
||||
[workspace.dependencies.iced_core]
|
||||
git = "https://github.com/pop-os/libcosmic"
|
||||
|
||||
[workspace.dependencies.libcosmic]
|
||||
git = "https://github.com/pop-os/libcosmic"
|
||||
rev = "f06a81c"
|
||||
default-features = false
|
||||
features = ["debug", "wayland", "tokio"]
|
||||
|
||||
[workspace.dependencies.cosmic-config]
|
||||
git = "https://github.com/pop-os/libcosmic"
|
||||
rev = "f06a81c"
|
||||
|
||||
[workspace.dependencies.cosmic-bg-config]
|
||||
git = "https://github.com/pop-os/cosmic-bg"
|
||||
|
||||
[workspace.dependencies.cosmic-panel-config]
|
||||
git = "https://github.com/pop-os/cosmic-panel"
|
||||
branch = "settings_jammy"
|
||||
|
|
@ -9,6 +9,7 @@ rust-version = "1.65.0"
|
|||
apply = "0.3.0"
|
||||
async-channel = "1.8.0"
|
||||
color-eyre = "0.6.2"
|
||||
cosmic-settings-desktop = { path = "../pages/desktop" }
|
||||
cosmic-settings-page = { path = "../page" }
|
||||
cosmic-settings-system = { path = "../pages/system" }
|
||||
cosmic-settings-time = { path = "../pages/time" }
|
||||
|
|
@ -23,7 +24,8 @@ rust-embed = "6.6.1"
|
|||
slotmap = "1.0.6"
|
||||
tokio = "1.28.2"
|
||||
downcast-rs = "1.2.0"
|
||||
cosmic-panel-config = { git = "https://github.com/pop-os/cosmic-panel" }
|
||||
# TODO: migrate this dependency to the pages/desktop crate.
|
||||
cosmic-panel-config = { workspace = true }
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"]}
|
||||
|
||||
|
|
@ -33,6 +35,4 @@ features = ["fluent-system", "desktop-requester"]
|
|||
|
||||
[profile.release]
|
||||
opt-level = "s"
|
||||
overflow-checks = true
|
||||
lto = "thin"
|
||||
incremental = false
|
||||
|
|
|
|||
|
|
@ -235,19 +235,16 @@ impl Application for SettingsApp {
|
|||
Message::None | Message::Search(_) => {}
|
||||
Message::PageMessage(message) => match message {
|
||||
crate::pages::Message::About(message) => {
|
||||
if let Some(page) = self.pages.page_mut::<system::about::Page>() {
|
||||
page.update(message);
|
||||
}
|
||||
page::update!(self.pages, message, system::about::Page);
|
||||
}
|
||||
crate::pages::Message::DateAndTime(message) => {
|
||||
if let Some(page) = self.pages.page_mut::<time::date::Page>() {
|
||||
page.update(message);
|
||||
}
|
||||
page::update!(self.pages, message, time::date::Page);
|
||||
}
|
||||
crate::pages::Message::Desktop(message) => {
|
||||
if let Some(page) = self.pages.page_mut::<desktop::Page>() {
|
||||
page.update(message);
|
||||
}
|
||||
page::update!(self.pages, message, desktop::Page);
|
||||
}
|
||||
crate::pages::Message::DesktopWallpaper(message) => {
|
||||
page::update!(self.pages, message, desktop::wallpaper::Page);
|
||||
}
|
||||
crate::pages::Message::External { .. } => {
|
||||
todo!("external plugins not supported yet");
|
||||
|
|
@ -457,7 +454,10 @@ impl SettingsApp {
|
|||
);
|
||||
}
|
||||
|
||||
settings::view_column(column_widgets).into()
|
||||
settings::view_column(column_widgets)
|
||||
.max_width(683)
|
||||
.padding(0)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn search_changed(&mut self, phrase: String) {
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ pub fn main() -> color_eyre::Result<()> {
|
|||
let localizer = crate::localize::localizer();
|
||||
let requested_languages = DesktopLanguageRequester::requested_languages();
|
||||
|
||||
if let Err(error) = localizer.select(&requested_languages) {
|
||||
eprintln!("error while loading fluent localizations: {error}");
|
||||
if let Err(why) = localizer.select(&requested_languages) {
|
||||
tracing::error!(%why, "error while loading fluent localizations");
|
||||
}
|
||||
|
||||
cosmic::settings::set_default_icon_theme("Pop");
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ pub struct Page {
|
|||
pub show_applications_button: bool,
|
||||
pub show_minimize_button: bool,
|
||||
pub show_maximize_button: bool,
|
||||
pub slideshow: bool,
|
||||
pub same_background: bool,
|
||||
}
|
||||
|
||||
impl page::Page<crate::pages::Message> for Page {
|
||||
|
|
@ -39,10 +37,8 @@ impl page::AutoBind<crate::pages::Message> for Page {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Message {
|
||||
Slideshow(bool),
|
||||
SameBackground(bool),
|
||||
ShowWorkspacesButton(bool),
|
||||
ShowApplicationsButton(bool),
|
||||
ShowMinimizeButton(bool),
|
||||
|
|
@ -53,12 +49,10 @@ pub enum Message {
|
|||
impl Page {
|
||||
pub fn update(&mut self, message: Message) {
|
||||
match message {
|
||||
Message::SameBackground(value) => self.same_background = value,
|
||||
Message::ShowApplicationsButton(value) => self.show_applications_button = value,
|
||||
Message::ShowMaximizeButton(value) => self.show_maximize_button = value,
|
||||
Message::ShowMinimizeButton(value) => self.show_minimize_button = value,
|
||||
Message::ShowWorkspacesButton(value) => self.show_workspaces_button = value,
|
||||
Message::Slideshow(value) => self.slideshow = value,
|
||||
Message::TopLeftHotCorner(value) => self.top_left_hot_corner = value,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,74 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use super::Message;
|
||||
use std::{path::PathBuf, time::Instant};
|
||||
|
||||
use apply::Apply;
|
||||
use cosmic::{
|
||||
iced::widget::{column, container, horizontal_space, image, row, svg, text},
|
||||
iced::alignment::Horizontal,
|
||||
iced::widget::{column, container, horizontal_space, row, text},
|
||||
iced::Length,
|
||||
iced_runtime::core::image::Handle as ImageHandle,
|
||||
theme,
|
||||
widget::{list_column, settings, toggler},
|
||||
Element,
|
||||
};
|
||||
use cosmic_settings_desktop::wallpaper::{self, Entry, Output};
|
||||
use cosmic_settings_page::Section;
|
||||
use cosmic_settings_page::{self as page, section};
|
||||
use slotmap::SlotMap;
|
||||
use slotmap::{DefaultKey, SecondaryMap, SlotMap};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Page;
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Message {
|
||||
SameBackground(bool),
|
||||
Select(DefaultKey),
|
||||
Slideshow(bool),
|
||||
Update((wallpaper::Config, Context)),
|
||||
}
|
||||
|
||||
pub struct Page {
|
||||
pub config: wallpaper::Config,
|
||||
pub selection: Context,
|
||||
pub same_background: bool,
|
||||
pub slideshow: bool,
|
||||
}
|
||||
|
||||
impl Default for Page {
|
||||
fn default() -> Self {
|
||||
Page {
|
||||
config: wallpaper::Config::default(),
|
||||
selection: Context::default(),
|
||||
same_background: true,
|
||||
slideshow: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Context {
|
||||
active: DefaultKey,
|
||||
handles: SlotMap<DefaultKey, ImageHandle>,
|
||||
paths: SecondaryMap<DefaultKey, PathBuf>,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
pub fn update(&mut self, message: Message) {
|
||||
match message {
|
||||
Message::SameBackground(value) => self.same_background = value,
|
||||
Message::Select(id) => {
|
||||
if let Some(path) = self.selection.paths.get(id) {
|
||||
wallpaper::set(&mut self.config, Entry::new(Output::All, path.to_owned()));
|
||||
self.selection.active = id;
|
||||
}
|
||||
}
|
||||
Message::Slideshow(value) => self.slideshow = value,
|
||||
Message::Update((config, selection)) => {
|
||||
self.config = config;
|
||||
self.selection = selection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl page::Page<crate::pages::Message> for Page {
|
||||
fn content(
|
||||
|
|
@ -30,6 +83,32 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
.title(fl!("wallpaper"))
|
||||
.description(fl!("wallpaper", "desc"))
|
||||
}
|
||||
|
||||
fn load(&self, _page: page::Entity) -> Option<page::Task<crate::pages::Message>> {
|
||||
Some(Box::pin(async move {
|
||||
let config = wallpaper::config();
|
||||
|
||||
let mut backgrounds = wallpaper::load_each_from_path("/usr/share/backgrounds".into());
|
||||
let mut update = Context::default();
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
while let Some((path, image)) = backgrounds.recv().await {
|
||||
let handle =
|
||||
ImageHandle::from_pixels(image.width(), image.height(), image.into_vec());
|
||||
|
||||
let id = update.handles.insert(handle);
|
||||
update.paths.insert(id, path);
|
||||
}
|
||||
|
||||
tracing::info!(
|
||||
"loaded wallpapers in {:?}",
|
||||
Instant::now().duration_since(start)
|
||||
);
|
||||
|
||||
crate::pages::Message::DesktopWallpaper(Message::Update((config, update)))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl page::AutoBind<crate::pages::Message> for Page {}
|
||||
|
|
@ -42,57 +121,84 @@ pub fn settings() -> Section<crate::pages::Message> {
|
|||
fl!("wallpaper", "slide"),
|
||||
fl!("wallpaper", "change"),
|
||||
])
|
||||
.view::<Page>(|binder, _page, section| {
|
||||
let desktop = binder
|
||||
.page::<super::Page>()
|
||||
.expect("desktop page not found");
|
||||
.view::<Page>(|_binder, page, section| {
|
||||
let descriptions = §ion.descriptions;
|
||||
let image_paths: Vec<std::path::PathBuf> = Vec::new();
|
||||
|
||||
let mut image_column = Vec::with_capacity(image_paths.len() / 4);
|
||||
for chunk in image_paths.chunks(4) {
|
||||
let mut image_row = Vec::with_capacity(chunk.len());
|
||||
for image_path in chunk.iter() {
|
||||
image_row.push(if image_path.ends_with(".svg") {
|
||||
svg(svg::Handle::from_path(image_path))
|
||||
.width(Length::Fixed(150.))
|
||||
.into()
|
||||
} else {
|
||||
image(image_path).width(Length::Fixed(150.)).into()
|
||||
});
|
||||
let mut image_column = Vec::with_capacity(page.selection.handles.len() / 4);
|
||||
let mut image_handles = page.selection.handles.iter();
|
||||
|
||||
while let Some((id, handle)) = image_handles.next() {
|
||||
let mut image_row = Vec::with_capacity(4);
|
||||
|
||||
image_row.push(wallpaper_button(handle, id));
|
||||
|
||||
for (id, handle) in image_handles.by_ref().take(3) {
|
||||
image_row.push(wallpaper_button(handle, id));
|
||||
}
|
||||
|
||||
image_column.push(row(image_row).spacing(16).into());
|
||||
}
|
||||
|
||||
let children = vec![
|
||||
row!(
|
||||
let mut children = Vec::with_capacity(3);
|
||||
|
||||
if let Some(image) = page.selection.handles.get(page.selection.active) {
|
||||
let display_preview = row!(
|
||||
horizontal_space(Length::Fill),
|
||||
container(
|
||||
image("/usr/share/backgrounds/pop/kate-hazen-COSMIC-desktop-wallpaper.png")
|
||||
.width(Length::Fixed(300.))
|
||||
cosmic::iced::widget::image(image.clone()).width(Length::Fixed(300.0))
|
||||
)
|
||||
.padding(4)
|
||||
.style(theme::Container::Background),
|
||||
horizontal_space(Length::Fill),
|
||||
)
|
||||
.into(),
|
||||
.padding([0, 0, 8, 0])
|
||||
.into();
|
||||
|
||||
children.push(display_preview);
|
||||
}
|
||||
|
||||
children.push(
|
||||
cosmic::widget::text("All Displays")
|
||||
.horizontal_alignment(Horizontal::Center)
|
||||
.width(Length::Fill)
|
||||
.apply(cosmic::iced::widget::container)
|
||||
.width(Length::Fill)
|
||||
.padding([0, 0, 16, 0])
|
||||
.into(),
|
||||
);
|
||||
|
||||
children.push(
|
||||
list_column()
|
||||
.add(settings::item(
|
||||
&descriptions[0],
|
||||
toggler(None, desktop.same_background, Message::SameBackground),
|
||||
toggler(None, page.same_background, Message::SameBackground),
|
||||
))
|
||||
.add(settings::item(&descriptions[1], text("TODO")))
|
||||
.add(settings::item(
|
||||
&descriptions[2],
|
||||
toggler(None, desktop.slideshow, Message::Slideshow),
|
||||
toggler(None, page.slideshow, Message::Slideshow),
|
||||
))
|
||||
.into(),
|
||||
column(image_column).spacing(16).into(),
|
||||
];
|
||||
);
|
||||
|
||||
settings::view_column(children)
|
||||
children.push(column(image_column).spacing(12).padding(0).into());
|
||||
|
||||
cosmic::iced::widget::column(children)
|
||||
.spacing(22)
|
||||
.padding(0)
|
||||
.max_width(683)
|
||||
.apply(Element::from)
|
||||
.map(crate::pages::Message::Desktop)
|
||||
.map(crate::pages::Message::DesktopWallpaper)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn wallpaper_button(handle: &ImageHandle, id: DefaultKey) -> Element<Message> {
|
||||
let image = cosmic::iced::widget::image(handle.clone()).apply(cosmic::iced::Element::from);
|
||||
|
||||
cosmic::iced::widget::button(image)
|
||||
.width(Length::Fixed(158.0))
|
||||
.height(Length::Fixed(105.0))
|
||||
.style(cosmic::theme::Button::Transparent)
|
||||
.on_press(Message::Select(id))
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub enum Message {
|
|||
DateAndTime(time::date::Message),
|
||||
Desktop(desktop::Message),
|
||||
Panel(desktop::panel::Message),
|
||||
DesktopWallpaper(desktop::wallpaper::Message),
|
||||
External { id: String, message: Vec<u8> },
|
||||
Page(Entity),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub fn search_header<Message>(
|
|||
|
||||
column_children.push(
|
||||
text(parent_meta.title.as_str())
|
||||
.size(16)
|
||||
.size(14)
|
||||
.apply(container)
|
||||
.padding([0, 0, 0, 6])
|
||||
.into(),
|
||||
|
|
@ -47,7 +47,7 @@ pub fn search_header<Message>(
|
|||
#[must_use]
|
||||
pub fn search_page_link<Message: 'static>(title: &str) -> Button<Message, cosmic::Renderer> {
|
||||
text(title)
|
||||
.size(32)
|
||||
.size(24)
|
||||
.horizontal_alignment(iced::alignment::Horizontal::Left)
|
||||
.apply(button)
|
||||
.style(cosmic::theme::Button::Link)
|
||||
|
|
@ -56,7 +56,7 @@ pub fn search_page_link<Message: 'static>(title: &str) -> Button<Message, cosmic
|
|||
#[must_use]
|
||||
pub fn page_title<Message: 'static>(page: &page::Info) -> Element<Message> {
|
||||
row!(
|
||||
text(page.title.as_str()).size(32),
|
||||
text(page.title.as_str()).size(24),
|
||||
horizontal_space(Length::Fill)
|
||||
)
|
||||
.into()
|
||||
|
|
@ -71,13 +71,13 @@ pub fn parent_page_button<'a, Message: Clone + 'static>(
|
|||
column!(
|
||||
button(row!(
|
||||
icon("go-previous-symbolic", 20).style(theme::Svg::SymbolicLink),
|
||||
text(parent.title.as_str()).size(20),
|
||||
text(parent.title.as_str()).size(14),
|
||||
))
|
||||
.padding(0)
|
||||
.style(theme::Button::Link)
|
||||
.on_press(on_press),
|
||||
row!(
|
||||
text(sub_page.title.as_str()).size(32),
|
||||
text(sub_page.title.as_str()).size(24),
|
||||
horizontal_space(Length::Fill),
|
||||
)
|
||||
.align_items(iced::alignment::Alignment::Center),
|
||||
|
|
|
|||
2
justfile
2
justfile
|
|
@ -1,7 +1,7 @@
|
|||
name := 'cosmic-settings'
|
||||
appid := 'com.system76.CosmicSettings'
|
||||
|
||||
# Use the lld linker if it is available.
|
||||
# Use lld linker if available
|
||||
ld-args := if `which lld || true` != '' {
|
||||
'-C link-arg=-fuse-ld=lld -C link-arg=-Wl,--build-id=sha1'
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -83,3 +83,12 @@ impl Info {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! update {
|
||||
($binder:expr, $message:expr, $page:ty) => {{
|
||||
if let Some(page) = $binder.page_mut::<$page>() {
|
||||
page.update($message);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
|
|
|||
17
pages/desktop/Cargo.toml
Normal file
17
pages/desktop/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "cosmic-settings-desktop"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cosmic-bg-config = { workspace = true }
|
||||
cosmic-config = { workspace = true }
|
||||
dirs = "5.0.1"
|
||||
freedesktop-icons = "0.2.3"
|
||||
futures-lite = "1.13.0"
|
||||
image = "0.24.6"
|
||||
rayon = "1.7.0"
|
||||
tokio = { version = "1.28.0", features = ["sync"] }
|
||||
tracing = "0.1.37"
|
||||
1
pages/desktop/src/lib.rs
Normal file
1
pages/desktop/src/lib.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod wallpaper;
|
||||
130
pages/desktop/src/wallpaper.rs
Normal file
130
pages/desktop/src/wallpaper.rs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
pub use cosmic_bg_config::{Config, Entry, Output};
|
||||
use image::RgbaImage;
|
||||
use std::{
|
||||
collections::hash_map::DefaultHasher,
|
||||
fs::DirEntry,
|
||||
hash::{Hash, Hasher},
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use tokio::sync::mpsc::{self, Receiver};
|
||||
|
||||
pub fn config() -> Config {
|
||||
let helper = Config::helper().expect("failed to get helper for cosmic bg config");
|
||||
|
||||
match Config::load(&helper) {
|
||||
Ok(conf) => conf,
|
||||
Err(why) => {
|
||||
tracing::warn!(?why, "Config file error, falling back to defaults");
|
||||
Config::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(config: &mut Config, entry: Entry) {
|
||||
if let Ok(context) = Config::helper() {
|
||||
tracing::info!(
|
||||
"setting wallpaper for {} to {}",
|
||||
entry.output.to_string(),
|
||||
entry.source.display()
|
||||
);
|
||||
if let Err(why) = config.set_entry(&context, entry) {
|
||||
tracing::error!(?why, "failed to set background");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Path to directory where wallpaper thumbnails are stored.
|
||||
#[must_use]
|
||||
pub fn cache_dir() -> Option<PathBuf> {
|
||||
dirs::cache_dir().map(|path| {
|
||||
let cache = path.join("cosmic-settings/wallpapers");
|
||||
let _res = std::fs::create_dir_all(&cache);
|
||||
cache
|
||||
})
|
||||
}
|
||||
|
||||
/// Loads wallpapers in parallel by spawning tasks with a rayon thread pool.
|
||||
#[must_use]
|
||||
pub fn load_each_from_path(path: PathBuf) -> Receiver<(PathBuf, RgbaImage)> {
|
||||
let cache_dir = Arc::new(cache_dir());
|
||||
|
||||
let (tx, rx) = mpsc::channel(1);
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut paths = vec![path];
|
||||
|
||||
while let Some(path) = paths.pop() {
|
||||
if let Ok(dir) = path.read_dir() {
|
||||
for entry in dir.filter_map(Result::ok) {
|
||||
let Ok(file_type) = entry.file_type() else {
|
||||
continue
|
||||
};
|
||||
|
||||
let path = entry.path();
|
||||
|
||||
if file_type.is_dir() {
|
||||
paths.push(path);
|
||||
} else if file_type.is_file() {
|
||||
let tx = tx.clone();
|
||||
let cache_dir = cache_dir.clone();
|
||||
rayon::spawn_fifo(move || {
|
||||
let thumbnail =
|
||||
load_thumbnail(cache_dir.as_deref(), &path, &entry, 300, 169);
|
||||
if let Some(image) = thumbnail {
|
||||
let _res = tx.blocking_send((path, image));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rx
|
||||
}
|
||||
|
||||
/// Generates and caches the thumbnail of a wallpaper.
|
||||
///
|
||||
///
|
||||
/// Caching reduces time required to load a wallpaper by 99%.
|
||||
#[must_use]
|
||||
pub fn load_thumbnail(
|
||||
cache_dir: Option<&Path>,
|
||||
path: &Path,
|
||||
entry: &DirEntry,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Option<RgbaImage> {
|
||||
if let Some(cache_dir) = cache_dir {
|
||||
if let Ok(ctime) = entry.metadata().and_then(|meta| meta.created()) {
|
||||
// Search for thumbnail by a unique hash string.
|
||||
let mut hasher = DefaultHasher::new();
|
||||
path.hash(&mut hasher);
|
||||
ctime.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
let thumbnail_path = cache_dir.join(format!("{hash:x}.png"));
|
||||
|
||||
// Load image from thumbnail if it exists and can be opened.
|
||||
if thumbnail_path.exists() {
|
||||
if let Ok(image) = image::open(&thumbnail_path) {
|
||||
return Some(image.into_rgba8());
|
||||
}
|
||||
}
|
||||
|
||||
// Create new thumbnail and save it if not.
|
||||
return image::open(path).ok().map(|mut image| {
|
||||
image = image.thumbnail_exact(width, height);
|
||||
let _res = image.save(&thumbnail_path);
|
||||
image.into_rgba8()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Generate thumbnail from wallpaper without saving it
|
||||
image::open(path).ok().map(|mut image| {
|
||||
image = image.thumbnail_exact(width, height);
|
||||
image.into_rgba8()
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue