Skip to content

Commit e056e8c

Browse files
authored
Cosmic advanced text (#103)
* wip: update to use cosmic-advanced-text * use cosmic-advanced-text branch of iced * fix: line height and spacing for segmented button and update to get svg fix * fix: spin button styling & spacing * update iced to fix segmented button border radius * feat: example improvements * feat: helper for loading fonts * feat: add focus style to button * fix: slider height and iced fixed * feat: hash icon width and height * cleanup * update ci * refactor: always use lazy feature of iced * update iced * update iced * cleanup & update iced * update iced: new slider & tiny-skia quad updates * update iced: fixes for tiny-skia quad rendering with edge case border radius * re-export iced_runtime & iced_widget * merge master * udpate iced * update iced * update iced * update iced * fix: make rectangle_tracker subscription only return update if there is some * feat: derive macro for loading a cosmic-config * feat (cosmic-config): iced subscription * fix (example): update to rectangle tracker subscription * fix (cosmic-config) * refactor(cosmic-config-derive): add support for types with generic parameters * fix (cosmic-config): feature gate updates for subscription helpers * feat: support for custom & system themes + move cosmic-theme to libcosmic * feat: sorta hacky way of creating header bars for libcosmic + update iced to get support for resizable windows in iced-sctk * update iced * update and reexport sctk * fix: applet border radius * feat (cosmic-theme): add id and name methods * fix(cosmic-theme): reexport palette from cosmic-theme * fix(cosmic-config-derive): allow use with reexported cosmic-config * feat: update iced with fix and refactor applet env vars * update iced
1 parent a173794 commit e056e8c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+3431
-405
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ jobs:
4141
fail-fast: false
4242
matrix:
4343
features:
44-
- 'winit_softbuffer debug'
45-
- 'winit_softbuffer tokio'
46-
- winit_softbuffer
44+
- 'winit_tiny_skia debug'
45+
- 'winit_tiny_skia tokio'
46+
- winit_tiny_skia
4747
- winit_wgpu
48-
- softbuffer
48+
- tiny_skia
4949
- wayland
5050
- applet
5151
runs-on: ubuntu-22.04

Cargo.toml

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ edition = "2021"
77
name = "cosmic"
88

99
[features]
10-
default = ["dyrend", "winit", "tokio"]
10+
default = ["tiny_skia", "winit", "tokio", "a11y"]
1111
debug = ["iced/debug"]
12-
softbuffer = ["iced/softbuffer", "iced_softbuffer"]
13-
dyrend = ["iced/dyrend"]
14-
wayland = ["iced/wayland", "iced/dyrend", "iced_sctk"]
12+
a11y = ["iced/a11y", "iced_accessibility"]
13+
tiny_skia = ["iced/tiny-skia", "iced_tiny_skia"]
14+
wayland = ["iced/wayland", "iced_sctk", "sctk",]
1515
wgpu = ["iced/wgpu", "iced_wgpu"]
1616
tokio = ["dep:tokio", "iced/tokio"]
1717
winit = ["iced/winit", "iced_winit"]
18-
applet = ["cosmic-panel-config", "sctk", "wayland"]
19-
winit_softbuffer = ["winit", "softbuffer"]
18+
applet = ["cosmic-panel-config", "wayland", "ron", "serde"]
19+
winit_tiny_skia = ["winit", "tiny_skia"]
2020
winit_wgpu = ["winit", "wgpu"]
2121

2222
[dependencies]
@@ -25,37 +25,40 @@ derive_setters = "0.1.5"
2525
lazy_static = "1.4.0"
2626
palette = "0.6.1"
2727
tokio = { version = "1.24.2", optional = true }
28-
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", optional = true }
29-
sctk = { package = "smithay-client-toolkit", git = "https://github.com/Smithay/client-toolkit", optional = true, rev = "389a4f2" }
28+
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", branch = "bg_jammy", optional = true }
29+
sctk = { package = "smithay-client-toolkit", git = "https://github.com/pop-os/client-toolkit", optional = true, tag = "themed-pointer"}
3030
slotmap = "1.0.6"
3131
fraction = "0.13.0"
32+
cosmic-config = { path = "cosmic-config" }
33+
ron = { version = "0.8", optional = true }
34+
serde = { version = "1.0", optional = true }
3235

3336
[target.'cfg(unix)'.dependencies]
3437
freedesktop-icons = "0.2.2"
3538

3639
[dependencies.cosmic-theme]
37-
git = "https://github.com/pop-os/cosmic-theme.git"
40+
path = "cosmic-theme"
3841

3942
[dependencies.iced]
4043
path = "iced"
4144
default-features = false
42-
features = ["image", "svg"]
45+
features = ["image", "svg", "lazy"]
46+
47+
[dependencies.iced_runtime]
48+
path = "iced/runtime"
4349

4450
[dependencies.iced_core]
4551
path = "iced/core"
4652

47-
[dependencies.iced_lazy]
48-
path = "iced/lazy"
53+
[dependencies.iced_widget]
54+
path = "iced/widget"
4955

50-
[dependencies.iced_native]
51-
path = "iced/native"
56+
[dependencies.iced_accessibility]
57+
path = "iced/accessibility"
5258

53-
[dependencies.iced_softbuffer]
54-
path = "iced/softbuffer"
5559
optional = true
56-
57-
[dependencies.iced_dyrend]
58-
path = "iced/dyrend"
60+
[dependencies.iced_tiny_skia]
61+
path = "iced/tiny_skia"
5962
optional = true
6063

6164
[dependencies.iced_style]
@@ -73,13 +76,11 @@ optional = true
7376
path = "iced/wgpu"
7477
optional = true
7578

76-
[dependencies.iced_glow]
77-
path = "iced/glow"
78-
optional = true
79-
8079
[workspace]
8180
members = [
8281
"cosmic-config",
82+
"cosmic-config-derive",
83+
"cosmic-theme",
8384
"examples/*",
8485
]
8586
exclude = [

cosmic-config-derive/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "cosmic-config-derive"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
[lib]
8+
proc-macro = true
9+
10+
[dependencies]
11+
syn = "1.0"
12+
quote = "1.0"

cosmic-config-derive/src/lib.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use proc_macro::TokenStream;
2+
use quote::quote;
3+
use syn::{self};
4+
5+
#[proc_macro_derive(CosmicConfigEntry)]
6+
pub fn cosmic_config_entry_derive(input: TokenStream) -> TokenStream {
7+
// Construct a representation of Rust code as a syntax tree
8+
// that we can manipulate
9+
let ast = syn::parse(input).unwrap();
10+
11+
// Build the trait implementation
12+
impl_cosmic_config_entry_macro(&ast)
13+
}
14+
15+
fn impl_cosmic_config_entry_macro(ast: &syn::DeriveInput) -> TokenStream {
16+
let name = &ast.ident;
17+
// let generics = &ast.generics;
18+
19+
// Get the fields of the struct
20+
let fields = match ast.data {
21+
syn::Data::Struct(ref data_struct) => match data_struct.fields {
22+
syn::Fields::Named(ref fields) => &fields.named,
23+
_ => unimplemented!("Only named fields are supported"),
24+
},
25+
_ => unimplemented!("Only structs are supported"),
26+
};
27+
28+
let write_each_config_field = fields.iter().map(|field| {
29+
let field_name = &field.ident;
30+
quote! {
31+
config.set(stringify!(#field_name), &self.#field_name)?;
32+
}
33+
});
34+
35+
let get_each_config_field = fields.iter().map(|field| {
36+
let field_name = &field.ident;
37+
let field_type = &field.ty;
38+
quote! {
39+
match config.get::<#field_type>(stringify!(#field_name)) {
40+
Ok(#field_name) => default.#field_name = #field_name,
41+
Err(e) => errors.push(e),
42+
}
43+
}
44+
});
45+
46+
// // Get the existing where clause or create a new one if it doesn't exist
47+
// let mut where_clause = ast
48+
// .generics
49+
// .where_clause
50+
// .clone()
51+
// .unwrap_or_else(|| parse_quote!(where));
52+
53+
// // Add your additional constraints to the where clause
54+
// // Here, we add the constraint 'T: Debug' to all generic parameters
55+
// for param in ast.generics.params.iter() {
56+
// where_clause
57+
// .predicates
58+
// .push(parse_quote!(#param: ::std::default::Default + ::serde::Serialize + ::serde::de::DeserializeOwned));
59+
// }
60+
61+
let gen = quote! {
62+
impl CosmicConfigEntry for #name {
63+
fn write_entry(&self, config: &Config) -> Result<(), cosmic_config::Error> {
64+
let tx = config.transaction();
65+
#(#write_each_config_field)*
66+
tx.commit()
67+
}
68+
69+
fn get_entry(config: &Config) -> Result<Self, (Vec<cosmic_config::Error>, Self)> {
70+
let mut default = Self::default();
71+
let mut errors = Vec::new();
72+
73+
#(#get_each_config_field)*
74+
75+
if errors.is_empty() {
76+
Ok(default)
77+
} else {
78+
Err((errors, default))
79+
}
80+
}
81+
}
82+
};
83+
84+
gen.into()
85+
}

cosmic-config/Cargo.toml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,19 @@ name = "cosmic-config"
33
version = "0.1.0"
44
edition = "2021"
55

6+
[features]
7+
default = ["macro", "subscription"]
8+
macro = ["cosmic-config-derive"]
9+
subscription = ["iced_futures"]
10+
611
[dependencies]
712
atomicwrites = "0.4.0"
813
calloop = { version = "0.10.5", optional = true }
9-
dirs = "4.0.0"
10-
notify = "5.1.0"
14+
dirs = "5.0.1"
15+
notify = "6.0.0"
1116
ron = "0.8.0"
1217
serde = "1.0.152"
18+
cosmic-config-derive = { path = "../cosmic-config-derive/", optional = true }
19+
iced = { path = "../iced/", optional = true }
20+
iced_futures = { path = "../iced/futures/", optional = true }
21+

cosmic-config/src/lib.rs

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1-
use notify::Watcher;
1+
#[cfg(feature = "subscription")]
2+
use iced_futures::futures::channel::mpsc;
3+
#[cfg(feature = "subscription")]
4+
use iced_futures::subscription;
5+
use notify::{RecommendedWatcher, Watcher};
26
use serde::{de::DeserializeOwned, Serialize};
37
use std::{
8+
borrow::Cow,
49
fs,
10+
hash::Hash,
511
io::Write,
612
path::{Path, PathBuf},
713
sync::Mutex,
814
};
915

16+
#[cfg(feature = "macro")]
17+
pub use cosmic_config_derive;
18+
1019
#[cfg(feature = "calloop")]
1120
pub mod calloop;
1221

@@ -251,3 +260,123 @@ impl<'a> ConfigSet for ConfigTransaction<'a> {
251260
Ok(())
252261
}
253262
}
263+
264+
#[cfg(feature = "subscription")]
265+
pub enum ConfigState<T> {
266+
Init(Cow<'static, str>, u64),
267+
Waiting(T, RecommendedWatcher, mpsc::Receiver<()>, Config),
268+
Failed,
269+
}
270+
271+
#[cfg(feature = "subscription")]
272+
pub enum ConfigUpdate<T> {
273+
Update(T),
274+
UpdateError(T, Vec<crate::Error>),
275+
Failed,
276+
}
277+
278+
pub trait CosmicConfigEntry
279+
where
280+
Self: Sized,
281+
{
282+
fn write_entry(&self, config: &Config) -> Result<(), crate::Error>;
283+
fn get_entry(config: &Config) -> Result<Self, (Vec<crate::Error>, Self)>;
284+
}
285+
286+
#[cfg(feature = "subscription")]
287+
pub fn config_subscription<
288+
I: 'static + Copy + Send + Sync + Hash,
289+
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,
290+
>(
291+
id: I,
292+
config_id: Cow<'static, str>,
293+
config_version: u64,
294+
) -> iced_futures::Subscription<(I, Result<T, (Vec<crate::Error>, T)>)> {
295+
subscription::unfold(
296+
id,
297+
ConfigState::Init(config_id, config_version),
298+
move |state| start_listening_loop(id, state),
299+
)
300+
}
301+
302+
#[cfg(feature = "subscription")]
303+
async fn start_listening<
304+
I: Copy,
305+
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,
306+
>(
307+
id: I,
308+
state: ConfigState<T>,
309+
) -> (
310+
Option<(I, Result<T, (Vec<crate::Error>, T)>)>,
311+
ConfigState<T>,
312+
) {
313+
use iced_futures::futures::{future::pending, StreamExt};
314+
315+
match state {
316+
ConfigState::Init(config_id, version) => {
317+
let (tx, rx) = mpsc::channel(100);
318+
let config = match Config::new(&config_id, version) {
319+
Ok(c) => c,
320+
Err(_) => return (None, ConfigState::Failed),
321+
};
322+
let watcher = match config.watch(move |_helper, _keys| {
323+
let mut tx = tx.clone();
324+
let _ = tx.try_send(());
325+
}) {
326+
Ok(w) => w,
327+
Err(_) => return (None, ConfigState::Failed),
328+
};
329+
330+
match T::get_entry(&config) {
331+
Ok(t) => (
332+
Some((id, Ok(t.clone()))),
333+
ConfigState::Waiting(t, watcher, rx, config),
334+
),
335+
Err((errors, t)) => (
336+
Some((id, Err((errors, t.clone())))),
337+
ConfigState::Waiting(t, watcher, rx, config),
338+
),
339+
}
340+
}
341+
ConfigState::Waiting(old, watcher, mut rx, config) => match rx.next().await {
342+
Some(_) => match T::get_entry(&config) {
343+
Ok(t) => (
344+
if t != old {
345+
Some((id, Ok(t.clone())))
346+
} else {
347+
None
348+
},
349+
ConfigState::Waiting(t, watcher, rx, config),
350+
),
351+
Err((errors, t)) => (
352+
if t != old {
353+
Some((id, Err((errors, t.clone()))))
354+
} else {
355+
None
356+
},
357+
ConfigState::Waiting(t, watcher, rx, config),
358+
),
359+
},
360+
361+
None => (None, ConfigState::Failed),
362+
},
363+
ConfigState::Failed => pending().await,
364+
}
365+
}
366+
367+
#[cfg(feature = "subscription")]
368+
async fn start_listening_loop<
369+
I: Copy,
370+
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,
371+
>(
372+
id: I,
373+
mut state: ConfigState<T>,
374+
) -> ((I, Result<T, (Vec<crate::Error>, T)>), ConfigState<T>) {
375+
loop {
376+
let (update, new_state) = start_listening(id, state).await;
377+
state = new_state;
378+
if let Some(update) = update {
379+
return (update, state);
380+
}
381+
}
382+
}

0 commit comments

Comments
 (0)