Compare commits

...

30 commits

Author SHA1 Message Date
b284e754fd chore: update iced submodule pointer 2026-05-25 11:37:02 +02:00
8a1d3cf10a yoda: use local dbus settings bindings 2026-05-25 09:55:11 +02:00
b1b8203a3b fix: gate reorderable flex row shadow constant 2026-05-24 10:01:43 +02:00
Hojjat
7dd0ee835d feat: reorderable flex row 2026-05-24 09:50:50 +02:00
675f3b59e3 chore: reduce local stack warnings 2026-05-23 20:55:59 +02:00
4743bb8ec9 yoda: cargo clippy --fix on libcosmic-yoda (115→33 warnings)
Auto-applied clippy lint suggestions across 23 files: collapse
`else { if … }` ladders, drop unneeded `return` statements, remove
needless borrows that were immediately auto-dereffed, swap `iter().next()`
for `first()`, drop redundant `.into()` to the same type, and similar
mechanical cleanups. Behavior is unchanged; the diff is -67 lines net.

The 33 remaining warnings are architectural and need manual attention
(very-complex-type aliases, too-many-arguments on internal helpers,
redundant must_use, needs-is_empty, etc.).

Leyoda 2026 – GPLv3
2026-05-05 19:10:03 +02:00
999db0a4bd yoda: cosmic-theme cleanup (4→0 warnings) — workspace at 0 warnings total
theme::Builder::build:
- #[allow(unused_assignments)] with a note explaining the pattern: the
  component_hovered/pressed_overlay seeds at the top of the function
  are overwritten by every container block (primary, secondary, …)
  before being read, which is what unused_assignments flagged.

vs_code.rs:
- Add doc + # Errors section to Theme::apply_vs_code and the
  associated Theme::reset_vs_code (was missing under #![warn(missing_docs)]).

Cargo.toml profile move:
- cosmic-theme had a [profile.dev.package] block that Cargo silently
  ignores in non-root manifests. Move the insta/similar opt-level=3
  hint to the workspace root and drop the dead block from the
  cosmic-theme manifest. Removes the cargo-level "profiles for the
  non root package will be ignored" notice that came up on every check.

Leyoda 2026 – GPLv3
2026-05-05 19:07:35 +02:00
84437e219b yoda: libcosmic-yoda dead-code purge (14→0 warnings)
Real bug fixes:
- spin_button::vertical(): was constructing the SpinButton with
  Orientation::Horizontal — vertical() rendered horizontally. Fixed
  to use Orientation::Vertical, which also resolves the
  'Vertical never constructed' warning.
- text_input/input.rs: rewrite the iterator-skip logic for trailing
  icon layout. The previous `let mut icon_layout = ...; if has_start
  ... = ...; ... = ...;` triggered two value-never-read warnings and
  obscured the intent. Now it reads as 'skip text, optionally skip
  start-icon, then take the trailing-icon layout'.

Dead code removed:
- core::Core::portal_is_high_contrast — assigned at construction,
  never read anywhere
- widget::menu::menu_bar::bar_pressed field and the
  pub fn get_mut_or_default helper — no callers
- widget::popover::State — declared, never constructed
- widget::segmented_button::widget::Focus.now — sibling of updated_at,
  never read
- widget::wayland::tooltip::widget::Variant — orphan enum (and the
  cargo fix follow-up dropped a now-unused Element import)
- widget::button::widget::Button::is_hovered method — trivial getter
  with no callers; the underlying `is_hovered` field is still used

Visibility / nits:
- segmented_button::widget::TabDragSource: gain pub(super) so the
  pub(super) field tab_drag stops exposing a more private type
- widget::menu::flex::resolve: #[allow(dead_code)] (170-line public
  helper, kept for future use)
- app/cosmic.rs: drop one unreachable arm in the surface-message match
- widget::dropdown::multi: drop unused Paragraph import

Leyoda 2026 – GPLv3
2026-05-05 19:02:31 +02:00
a9492d764c yoda: bump iced submodule → all iced crates at 0 warnings
iced_core, iced_wgpu, iced_winit, iced_widget, iced_runtime,
iced_graphics, iced_tiny_skia all now build warning-free.

Leyoda 2026 – GPLv3
2026-05-05 18:50:41 +02:00
b94c03d996 yoda: bump iced submodule → iced_widget cleanup (0 left)
Pulls in the menu wrapping bug fix and slider/lazy warning sweep.

Leyoda 2026 – GPLv3
2026-05-05 18:39:03 +02:00
301bbf6e93 yoda: bump iced submodule → iced_winit warning cleanup (0 left)
iced/yoda-wayland-only e42448770 brings iced_winit down to 0 warnings
(was 45 before the cleanup pass).

Leyoda 2026 – GPLv3
2026-05-05 18:26:51 +02:00
38a988cbd1 yoda: cargo fix on cosmic-config + bump iced auto-fix commit
cosmic-config: drop 1 unused import (Stream).
iced submodule: bump to 8a7a32ff9 (~115 trivial warnings auto-fixed
across iced_core / iced_widget / iced_runtime / iced_winit / iced_wgpu /
iced_graphics / iced_tiny_skia).

Leyoda 2026 – GPLv3
2026-05-05 16:45:49 +02:00
cdf349385b yoda: cargo fix --lib (libcosmic-yoda) — drop 99 trivial warnings
Auto-applied suggestions on libcosmic-yoda lib only: unused imports,
unused-by-name params (prefixed with _), redundant mutability. From 113
warnings down to 14 (the 14 remaining are real signals: never-read
fields, unreachable patterns, etc., to be reviewed manually).

Leyoda 2026 – GPLv3
2026-05-05 16:27:29 +02:00
282813c80e yoda: bump iced → window_clipboard via public Forgejo fork
Lets libcosmic build standalone again — no longer relies on cosmic-files'
[patch] redirect to /home/lionel/Devels/window_clipboard.

Leyoda 2026 – GPLv3
2026-05-05 12:52:52 +02:00
5117ce4799 feat(cosmic-theme): add apply_gtk_decoration_layout helper
Writes the gtk-decoration-layout key to ~/.config/gtk-{3,4}.0/settings.ini
and best-effort updates GNOME's button-layout GSettings key for apps that
still consult it. Factors out write_gtk_settings_key for reuse.

Leyoda 2026 – GPLv3
2026-05-05 09:29:47 +02:00
9b2a3643f3 Update iced warning fixes
Point the iced submodule at the commit that fixes high-signal widget and Wayland warnings. Leaves existing cosmic-theme local changes untouched.
2026-05-05 08:27:18 +02:00
388e06552f yoda: bump iced submodule → softbuffer + window_clipboard cuts
Pick up yoda-wayland-only HEAD on leyoda/iced-yoda with softbuffer +
window_clipboard workspace default-features=false — drops the last
x11 crates. See cosmic-yoterm yoda-v5 for full cut metrics.
2026-04-24 06:53:37 +02:00
c118f5a2f6 yoda: bump iced submodule ref → yoda-wayland-only HEAD 8f6be798
Picks up two commits on leyoda/iced-yoda yoda-wayland-only branch:
- winit workspace dep default-features = false (drops winit/x11 backend)
- iced_wgpu gated x11 backend behind opt-in feature

Companion to libcosmic-yoda 8d1d8739 (drop x11 defaults on iced_winit +
iced_tiny_skia) for the yoda-v4 Wayland-only cut.
2026-04-24 06:41:28 +02:00
8d1d873918 yoda: drop x11 defaults on iced_winit + iced_tiny_skia
Dep chain audit showed winit, iced_winit and iced_tiny_skia all had
"x11" in their default features. Even though our Wayland-only build
doesn't use any X11 code path, the defaults were propagating through
cargo feature unification — winit-x11, tiny-xlib, x11-dl, etc. were
all being linked.

Fix, at the dep declaration level:
- [dependencies.iced_winit] default-features = false + wayland/wayland-dlopen
- [dependencies.iced_tiny_skia] default-features = false + wayland
- iced submodule's workspace winit = { ..., default-features = false }

Result on cosmic-yoterm binary:
- size:  55.4 MB -> 53.8 MB (-1.6 MB, ~3%)
- winit symbols: 2151 -> 1340 (-811)
- x11 symbols:   1526 -> 503  (-1023)

Remaining x11 footprint (~500 symbols):
- clipboard_x11 / x11rb: window_clipboard pulls both x11 + wayland
  backends unconditionally on unix targets. Would need forking
  window_clipboard to gate x11 behind a feature.
- tiny-xlib / as-raw-xcb-connection: low-level window-handle bindings
  pulled by wgpu/softbuffer even when no X11 windows ever exist.
  Dead code at runtime, probably best left alone until wgpu/raw-window-handle
  upstream make these optional.
2026-04-24 06:00:03 +02:00
8ab7b15807 yoda-v2: color_picker Theme ref + context_menu/menu ungate winit
Two perf + correctness wins packaged as +yoda-v2 (version bump 0.1.0-yoda
-> 0.1.0-yoda.2):

1. color_picker::draw() — use the theme: &Theme parameter already passed
   to draw() instead of THEME.lock().unwrap().clone() which cloned the
   whole Theme on every redraw (src/widget/color_picker/mod.rs:622).
   Upstreamable.

2. Dropped feature = "winit" from 21 combined cfg attrs in context_menu.rs,
   menu/menu_bar.rs, menu/menu_inner.rs. These triple-gates (wayland +
   winit + surface-message) were silently disabling all context-menu and
   menubar popup creation in yoda apps (which don't activate the winit
   feature). Now the code only gates on wayland + surface-message, which
   is our actual runtime path. Matches the ungate we already did on
   surface/action.rs in Phase 3d.

cargo check --lib passes. All 4 consumer apps rebuilt + installed as
+yoda-v2 (backup of previous yoda binaries in .pre-yoda-v2 siblings).
2026-04-23 18:43:52 +02:00
aec3eb615f yoda: ungate remaining winit+wayland combined cfgs
During Phase 3d it surfaced that several widgets keep a three-clause
cfg `#[cfg(all(feature = "winit", feature = "wayland", target_os = "linux"))]`
(e.g. dropdown::widget::with_popup, widget/mod.rs menu bits,
theme/style/mod.rs). Since the yoda fork is wayland-only the "winit"
clause is vestigial — dropping it unhides these methods for Wayland
consumers (cosmic-settings needs Dropdown::with_popup on the wallpaper
page).

Also fixed a cfg asymmetry in responsive_menu_bar.rs: the fallback
block was gated `cfg(not(all(winit, wayland, linux)))` while the
primary block was `cfg(all(wayland, linux))`. With winit removed both
blocks were active and we got E0308 expected-() — aligned the cfgs so
exactly one branch compiles.
2026-04-23 17:36:21 +02:00
3e23d08728 yoda: re-apply hard rename — libcosmic → libcosmic-yoda (0.1.0-yoda)
Reverts the soft-fork pivot (6736a596). Strategy chosen with user:
full cascade fork. Every consumer (leyoda/cosmic-files + each leyoda/app)
depends on libcosmic-yoda by explicit path, so there are no transitive
deps left asking for the upstream 'libcosmic' crate — no [patch]
unification issues, no two-version traps.

Changes:
- Cargo.toml: name = libcosmic-yoda, version = 0.1.0-yoda
- i18n/*/libcosmic.ftl -> libcosmic_yoda.ftl (71 locales)
- examples/*/Cargo.toml dep refs back to libcosmic-yoda
- compat stub features (winit=[], x11=[]) kept for upstream deps that
  might still request them during the migration window

cargo check --lib passes.
2026-04-23 15:32:29 +02:00
6736a596ac yoda: soft-fork pivot — keep Cargo name "libcosmic" for dep unification
The initial hard rename (255cf7cc) broke because Cargo's [patch] with
`package = libcosmic-yoda` does NOT unify across the transitive graph.
cosmic-files (still upstream) asks for "libcosmic"; patched with a
renamed package it ends up as a separate crate, leading to two copies
of cosmic::Theme/Action with incompatible types.

Soft fork keeps the yoda identity where it counts and stays compatible:
- Cargo name  : libcosmic (for patch/unification)
- Version     : 1.0.0 (same major as upstream so [patch] semver-accepts it)
- Lib name    : cosmic (unchanged)
- Repo        : leyoda/libcosmic-yoda on Forgejo (yoda lineage)
- Branch      : main (vs upstream master)

Revert parts:
- examples/*/Cargo.toml dep refs back to libcosmic
- i18n/*/libcosmic_yoda.ftl renamed back to libcosmic.ftl

Added:
- Compat stub features: winit = [], x11 = [] — empty so Cargo can satisfy
  upstream deps asking for these, but no code is actually gated on them
  any more (all removed in Phase 2).

Ungates done to make the Wayland path self-sufficient after winit removal:
- src/lib.rs: pub mod app + pub use Application/ApplicationExt no longer
  gated on winit; prelude exports ApplicationExt unconditionally
- src/surface/action.rs: 6 functions had #[cfg(all(wayland, linux, winit))]
  triple-gates; simplified to #[cfg(all(wayland, linux))] since winit is
  no longer a meaningful gate (wayland is now the only shell)
- 12 standalone #[cfg(feature = "winit")] annotations removed from src/
  (their gated code is now always compiled)

cargo check --lib + cargo check in cosmic-yoterm both pass with a single
libcosmic v1.0.0 in the tree.
2026-04-23 15:05:31 +02:00
8701aa31d8 feat(yoda): Wayland-only cut — drop winit and x11 features
Part of the yoda fork direction: libcosmic-yoda is Wayland-only going forward.

Cargo.toml changes:
- default features: remove winit, x11, iced-wayland, multi-window -> add wayland
- applet feature: remove winit dep
- merge iced-wayland into wayland (simpler feature graph)
- remove winit, winit_debug, winit_tokio, winit_wgpu, x11, iced-wayland features
- keep iced_winit dep (it's a misnomer — also hosts the wayland/cctk runtime)

Workspace:
- examples/* excluded (many depend on winit/x11) — revisited in a later phase

Behavior:
- Library builds clean in release with default features (cargo check + cargo build --release --lib OK)
- 58 lines in src/ gated on feature "winit" become unreachable (dead-code warnings — cleanup deferred)
- 108 lines gated on feature "wayland" now always active via default

--all-features is known-broken because tokio/async-std/smol are mutually
exclusive — this is pre-existing, not a Phase 2 regression.
2026-04-23 14:29:08 +02:00
255cf7cc0b rename: libcosmic → libcosmic-yoda (fork 0.1.0-yoda)
Fork point: pop-os/libcosmic 1.0.0 + perf/quickwins-bundle + macOS
window controls feature. From here the crate diverges under the yoda
lineage with its own versioning.

Changes:
- Cargo.toml: name = libcosmic-yoda, version = 0.1.0-yoda
- [lib] name = cosmic kept unchanged — consumer code still does 'use cosmic::...'
- examples/*/Cargo.toml: updated all libcosmic dep references to libcosmic-yoda
- i18n/*/libcosmic.ftl renamed to libcosmic_yoda.ftl (71 locales) to match
  the new name expected by fluent_language_loader!() macro

cargo check --lib passes. Examples not yet validated — Phase 2 (Wayland-only
cut) will rework them anyway.
2026-04-23 07:35:22 +02:00
5c3319351c header_bar: add WindowControlsPosition (macOS-style left controls)
Adds a new public enum `WindowControlsPosition { Start, End }` and a
matching field on `HeaderBar`, allowing window controls (close / minimize
/ maximize) to be packed on the start side of the headerbar (macOS
style, icon order close → minimize → maximize) instead of the default
end side (Linux / GNOME style, minimize → maximize → close).

Wiring:
- `crate::widget::WindowControlsPosition` re-exported alongside
  `HeaderBar`.
- `HeaderBar::controls_position(Option<WindowControlsPosition>)` setter;
  when left unset, falls back to `crate::config::window_controls_position()`
  (reads `CosmicTk.window_controls_position`), mirroring how `density`
  falls back to `header_size()`.
- New `CosmicTk.window_controls_position` field with default `End` for
  backwards compatibility; serde-friendly enum so existing configs keep
  working via `#[serde(default)]` semantics.

Tested with cosmic-yoterm, cosmic-settings, cosmic-edit, cosmic-files
rebuilt against this libcosmic via a local `[patch]` override. Config
changes picked up live through the existing cosmic-config subscription.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:08:12 +02:00
a322516f33 segmented_button: fix internal tab reorder end-to-end
Two independent bugs prevented tab drag-and-drop reorder from working
on cosmic-comp (and likely other compositors):

1. allow_reorder required DndAction::Move to be negotiated via
   OfferEvent::SelectedAction, which cosmic-comp does not always emit
   for self-drops (the SelectedAction event either never arrives or
   arrives with DndAction::empty()). Add a fallback: accept self-drops
   whenever state.dragging_tab is set. dragging_tab is only populated
   by start_tab_drag on this same widget, so this is safe; mime match
   and on_reorder presence are checked below.

2. reorder_event_for_drop preferred drop_hint.side over positional
   swap, producing counter-intuitive no-ops: dropping A (pos 0) on the
   left half of B (pos 1) resolved to "Before B" which, after removing
   A, lands at pos 0 again — the tab appeared not to move. Always use
   default_insert_position, which derives direction from dragged vs
   target positions (Konsole/Firefox/Chrome-style swap semantics).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 11:09:46 +02:00
108441ef61 segmented_button: add on_double_click callback
Fires in addition to on_activate when the same entity is left-clicked
twice within 400 ms. Lets applications bind quick actions (e.g. rename
a tab) without blocking the normal single-click activation path.

- New Widget::on_double_click builder mirroring on_activate/on_close.
- last_click field on LocalState for timestamp tracking.
- Detection branch in the mouse handler after on_activate fires, so the
  target entity is already focused when the callback runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 21:26:35 +02:00
1d98eee6de perf(widget): avoid VecDeque clone in segmented_button/table Model::clear
Model::clear() cloned the entire order VecDeque to iterate while
remove() mutated it, producing an O(n) allocation proportional to the
number of items — needless on a clear() which is going to drop all of
them anyway.

Replace the clone with std::mem::take(&mut self.order): we iterate the
taken VecDeque (transferring ownership), and the inner self.order.remove(index)
in each remove() call now finds position()==None and no-ops, since
self.order has been swapped with an empty default.

Same semantics, zero allocation. Noticeable on large nav/table models
(>100 items) and on apps that reset state frequently (settings pages,
file lists, context menus).
2026-04-19 16:29:02 +02:00
77262dd0af perf(malloc): throttle malloc_trim to 1 Hz in hot paths
malloc_trim(0) was called at the end of every update() and view(),
reaching 60-200 Hz during typical scrolling, resize, or animation.
Each call walks the glibc heap (10 us to several ms depending on
fragmentation) and could consume a substantial fraction of the frame
budget in worst cases.

Throttle trim() to once per second using a thread-local Instant,
preserving the existing API. RSS stays bounded (1 Hz is enough to
release collectable pages soon after) while per-frame cost becomes
a single thread-local check plus a duration comparison.

No call-site changes required; the three existing trim(0) invocations
in src/app/cosmic.rs (update, view multi-window, view single-window)
now fall under the throttle transparently.
2026-04-19 15:14:22 +02:00
160 changed files with 1914 additions and 492 deletions

View file

@ -1,6 +1,11 @@
[package]
name = "libcosmic"
version = "1.0.0"
# Yoda fork: hard-renamed. Every consumer (leyoda/cosmic-files fork + each
# leyoda/cosmic-* app) depends directly on `libcosmic-yoda` by path, bypassing
# pop-os/libcosmic entirely. No [patch] shenanigans needed — transitive deps
# that used to ask for `libcosmic` are replaced by deps on our forks that ask
# for `libcosmic-yoda`.
name = "libcosmic-yoda"
version = "0.1.0-yoda.2"
edition = "2024"
rust-version = "1.90"
@ -9,12 +14,10 @@ name = "cosmic"
[features]
default = [
"winit",
"tokio",
"a11y",
"dbus-config",
"x11",
"iced-wayland",
"wayland",
"multi-window",
]
advanced-shaping = ["iced/advanced-shaping"]
@ -35,7 +38,6 @@ animated-image = [
autosize = []
applet = [
"autosize",
"winit",
"wayland",
"tokio",
"cosmic-panel-config",
@ -81,32 +83,34 @@ tokio = [
"cosmic-config/tokio",
]
# Tokio async runtime
# Wayland window support
iced-wayland = [
# Wayland window support (yoda fork is Wayland-only; always active in default).
# We still need iced/winit because pop-os/iced hosts the runtime dispatcher
# (`iced_winit as shell`) there — the name is a misnomer, it's the same crate
# that provides both the winit path AND the sctk/cctk wayland path.
wayland = [
"ashpd?/wayland",
"autosize",
"iced/winit",
"iced/wayland",
"iced_winit/wayland",
"surface-message",
]
wayland = [
"iced-wayland",
"iced_runtime/cctk",
"iced_winit/cctk",
"iced_wgpu/cctk",
"iced/cctk",
"dep:iced_winit",
"dep:cctk",
"surface-message",
]
surface-message = []
# multi-window support
multi-window = []
# Render with wgpu
wgpu = ["iced/wgpu", "iced_wgpu"]
# X11 window support via winit
winit = ["iced/winit", "iced_winit"]
winit_debug = ["winit", "debug"]
winit_tokio = ["winit", "tokio"]
winit_wgpu = ["winit", "wgpu"]
# Compat stubs — kept empty so upstream deps (cosmic-files, cosmic-text, …)
# that still ask for `winit` / `x11` features resolve cleanly against the
# yoda fork. Activating them has no effect: no code is gated on these.
winit = []
x11 = []
# Enables XDG portal integrations
xdg-portal = ["ashpd"]
qr_code = ["iced/qr_code"]
@ -119,7 +123,6 @@ async-std = [
"zbus?/async-io",
"iced/async-std",
]
x11 = ["iced/x11", "iced_winit/x11"]
[dependencies]
apply = "0.3.0"
@ -173,7 +176,7 @@ float-cmp = "0.10.0"
# Enable DBus feature on Linux targets
[target.'cfg(target_os = "linux")'.dependencies]
cosmic-config = { path = "cosmic-config", features = ["dbus"] }
cosmic-settings-daemon = { git = "https://github.com/pop-os/dbus-settings-bindings" }
cosmic-settings-daemon = { path = "../dbus-settings-bindings/cosmic-settings-daemon" }
zbus = { version = "5.14.0", default-features = false }
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
@ -223,10 +226,17 @@ optional = true
[dependencies.iced_tiny_skia]
path = "./iced/tiny_skia"
# Yoda: drop the x11 default → softbuffer no longer pulls tiny-xlib/x11-dl/etc.
default-features = false
features = ["wayland"]
[dependencies.iced_winit]
path = "./iced/winit"
optional = true
# Yoda: drop the x11 default → winit won't pull winit-x11/tiny-xlib/x11-dl.
# Keep wayland + wayland-dlopen (default behaviour minus x11).
default-features = false
features = ["wayland", "wayland-dlopen"]
[dependencies.iced_wgpu]
path = "./iced/wgpu"
@ -246,12 +256,21 @@ members = [
"cosmic-config",
"cosmic-config-derive",
"cosmic-theme",
"examples/*",
]
exclude = ["iced"]
# examples/* excluded — many depend on the removed winit/x11 features.
# They will be revisited and adapted in a later phase.
exclude = ["iced", "examples"]
[workspace.dependencies]
dirs = "6.0.0"
# Speed up snapshot diffing in cosmic-theme tests. Cargo silently ignores
# [profile.*] blocks in non-root manifests, so this lives at the
# workspace root.
[profile.dev.package.insta]
opt-level = 3
[profile.dev.package.similar]
opt-level = 3
[dev-dependencies]
tempfile = "3.27.0"

View file

@ -10,7 +10,7 @@ macro = ["cosmic-config-derive"]
subscription = ["iced_futures"]
[dependencies]
cosmic-settings-daemon = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
cosmic-settings-daemon = { path = "../../dbus-settings-bindings/cosmic-settings-daemon", optional = true }
zbus = { version = "5.14.0", default-features = false, optional = true }
atomicwrites = { git = "https://github.com/jackpot51/rust-atomicwrites" }
calloop = { version = "0.14.4", optional = true }

View file

@ -1,4 +1,4 @@
use iced_futures::futures::{SinkExt, Stream};
use iced_futures::futures::SinkExt;
use iced_futures::{futures::channel::mpsc, stream};
use notify::RecommendedWatcher;
use std::{borrow::Cow, hash::Hash};

View file

@ -34,6 +34,3 @@ thiserror = "2.0.18"
[dev-dependencies]
insta = "1.47.2"
[profile.dev.package]
insta.opt-level = 3
similar.opt-level = 3

View file

@ -953,6 +953,12 @@ impl ThemeBuilder {
}
#[allow(clippy::too_many_lines)]
// The component_hovered/pressed_overlay vars are seeded once near the
// top of this fn and then reassigned inside each container block
// (primary, secondary, …) before being read again. The initial seed
// is therefore overwritten before any read, which is what the
// unused_assignments lint flags below.
#[allow(unused_assignments)]
/// build the theme
pub fn build(self) -> Theme {
let Self {

View file

@ -1,10 +1,12 @@
use crate::{Component, Theme, composite::over, steps::steps};
use configparser::ini::Ini;
use palette::{Darken, IntoColor, Lighten, Srgba, WithAlpha, rgb::Rgba};
use std::{
fs::{self, File},
io::{self, Write},
num::NonZeroUsize,
path::Path,
process::Command,
};
use super::{OutputError, to_rgba};
@ -217,6 +219,50 @@ impl Theme {
Ok(())
}
/// Apply the preferred GTK client-side decoration button layout.
///
/// This writes the GTK 3/4 `settings.ini` value used by GTK header bars and
/// also best-effort updates GNOME's `button-layout` GSettings key for apps
/// that still consult it.
///
/// # Errors
///
/// Returns an `OutputError` if the GTK settings files cannot be written.
#[cold]
pub fn apply_gtk_decoration_layout(buttons_at_start: bool) -> Result<(), OutputError> {
let Some(config_dir) = dirs::config_dir() else {
return Err(OutputError::MissingConfigDir);
};
let layout = if buttons_at_start {
"close,minimize,maximize:"
} else {
":minimize,maximize,close"
};
for gtk_version in ["gtk-3.0", "gtk-4.0"] {
let gtk_dir = config_dir.join(gtk_version);
fs::create_dir_all(&gtk_dir).map_err(OutputError::Io)?;
Self::write_gtk_settings_key(
&gtk_dir.join("settings.ini"),
"gtk-decoration-layout",
layout,
)?;
}
// best-effort: gsettings is absent on non-GNOME systems
let _ = Command::new("gsettings")
.args([
"set",
"org.gnome.desktop.wm.preferences",
"button-layout",
layout,
])
.status();
Ok(())
}
/// Reset the applied gtk css
///
/// # Errors
@ -256,6 +302,20 @@ impl Theme {
Ok(())
}
#[cold]
fn write_gtk_settings_key(path: &Path, key: &str, value: &str) -> Result<(), OutputError> {
let mut ini = Ini::new_cs();
if path.exists() {
let file_content = fs::read_to_string(path).map_err(OutputError::Io)?;
ini.read(file_content).map_err(OutputError::Ini)?;
}
ini.setstr("Settings", key, Some(value));
ini.pretty_write(path, &super::qt_settings_ini_style())
.map_err(OutputError::Io)
}
fn is_cosmic_css(path: &Path, cosmic_css: &Path) -> io::Result<Option<bool>> {
if !path.exists() {
return Ok(None);

View file

@ -266,6 +266,14 @@ impl From<Theme> for VsTheme {
}
impl Theme {
/// Write this theme to VS Code's `settings.json` as a
/// `workbench.colorCustomizations` entry, and enable
/// `window.autoDetectColorScheme` so VS Code follows the system theme.
///
/// # Errors
///
/// Returns an `OutputError` if the user config dir is missing, the
/// settings file cannot be read/written, or its JSON is invalid.
#[cold]
pub fn apply_vs_code(self) -> Result<(), OutputError> {
let vs_theme = VsTheme::from(self);
@ -291,6 +299,13 @@ impl Theme {
Ok(())
}
/// Remove the `workbench.colorCustomizations` entry previously written
/// by [`Theme::apply_vs_code`] from VS Code's `settings.json`.
///
/// # Errors
///
/// Returns an `OutputError` if the user config dir is missing, the
/// settings file cannot be read/written, or its JSON is invalid.
#[cold]
pub fn reset_vs_code() -> Result<(), OutputError> {
let mut config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?;

View file

@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
open = "5.3.3"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = [
"debug",

View file

@ -12,7 +12,7 @@ tracing = "0.1"
env_logger = "0.10.2"
log = "0.4.29"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
default-features = false
features = ["applet-token"]

View file

@ -5,12 +5,12 @@ edition = "2021"
[features]
default = ["wayland"]
wayland = ["libcosmic/wayland"]
wayland = ["libcosmic-yoda/wayland"]
[dependencies]
env_logger = "0.11"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = [
"debug",

View file

@ -8,6 +8,6 @@ edition = "2024"
[dependencies]
jiff = "0.2"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = ["debug", "winit", "tokio", "xdg-portal", "wgpu"]

View file

@ -8,7 +8,7 @@ tracing = "0.1.44"
tracing-subscriber = "0.3.22"
tracing-log = "0.2.0"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = [
"debug",

View file

@ -8,7 +8,7 @@ publish = false
[dependencies]
apply = "0.3.0"
fraction = "0.15.3"
libcosmic = { path = "../..", features = [
libcosmic-yoda = { path = "../..", features = [
"debug",
"winit",
"tokio",

View file

@ -7,6 +7,6 @@ edition = "2021"
tracing = "0.1.44"
tracing-subscriber = "0.3.22"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = ["debug", "winit", "wgpu", "tokio"]

View file

@ -8,6 +8,6 @@ tracing = "0.1.44"
tracing-subscriber = "0.3.22"
tracing-log = "0.2.0"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = ["debug", "winit", "tokio", "xdg-portal", "wgpu"]

View file

@ -6,4 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libcosmic = { path = "../..", features = ["debug", "winit", "tokio", "single-instance", "wgpu", "wayland"] }
libcosmic-yoda = { path = "../..", features = ["debug", "winit", "tokio", "single-instance", "wgpu", "wayland"] }

View file

@ -8,6 +8,6 @@ tracing = "0.1.44"
tracing-subscriber = "0.3.22"
tracing-log = "0.2.0"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = ["debug", "winit", "tokio", "xdg-portal", "wgpu"]

View file

@ -5,8 +5,8 @@ edition = "2021"
[features]
default = ["xdg-portal"]
rfd = ["libcosmic/rfd"]
xdg-portal = ["libcosmic/xdg-portal"]
rfd = ["libcosmic-yoda/rfd"]
xdg-portal = ["libcosmic-yoda/xdg-portal"]
[dependencies]
apply = "0.3.0"
@ -15,6 +15,6 @@ tracing = "0.1.44"
tracing-subscriber = "0.3.22"
url = "2.5.8"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
features = ["debug", "winit", "wgpu", "wayland", "tokio"]
path = "../../"

View file

@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
fraction = "0.15.3"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
features = ["debug", "wgpu", "winit", "desktop", "tokio"]
path = "../.."
default-features = false

View file

@ -5,6 +5,6 @@ edition = "2024"
[dependencies]
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = ["debug", "winit", "wgpu", "tokio", "xdg-portal"]

View file

@ -9,6 +9,6 @@ tracing-subscriber = "0.3.22"
tracing-log = "0.2.0"
chrono = "*"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
features = ["debug", "wgpu", "winit", "desktop", "tokio"]
path = "../.."

View file

@ -8,6 +8,6 @@ tracing = "0.1.44"
tracing-subscriber = "0.3.22"
tracing-log = "0.2.0"
[dependencies.libcosmic]
[dependencies.libcosmic-yoda]
path = "../../"
features = ["debug", "winit", "wgpu", "tokio", "xdg-portal"]

2
iced

@ -1 +1 @@
Subproject commit 78caabba7ef91cd1030da6f70b41d266704ffece
Subproject commit 81639935398a856f3164dc406fbac78922c258fc

View file

@ -1,7 +1,6 @@
// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: MPL-2.0
#[cfg(feature = "winit")]
use crate::app;
#[cfg(feature = "single-instance")]
use crate::dbus_activation;
@ -9,7 +8,6 @@ use crate::dbus_activation;
pub const fn app<M>(message: M) -> Action<M> {
Action::App(message)
}
#[cfg(feature = "winit")]
pub const fn cosmic<M>(message: app::Action) -> Action<M> {
Action::Cosmic(message)
}
@ -23,7 +21,6 @@ pub const fn none<M>() -> Action<M> {
pub enum Action<M> {
/// Messages from the application, for the application.
App(M),
#[cfg(feature = "winit")]
/// Internal messages to be handled by libcosmic.
Cosmic(app::Action),
#[cfg(feature = "single-instance")]

View file

@ -100,9 +100,10 @@ impl<T: Application> Cosmic<T>
where
T::Message: Send + 'static,
{
pub fn init(
(mut core, flags): (Core, T::Flags),
) -> (Self, iced::Task<crate::Action<T::Message>>) {
pub fn init((core, flags): (Core, T::Flags)) -> (Self, iced::Task<crate::Action<T::Message>>) {
#[cfg(all(feature = "dbus-config", target_os = "linux"))]
let mut core = core;
#[cfg(all(feature = "dbus-config", target_os = "linux"))]
{
use iced_futures::futures::executor::block_on;
@ -364,7 +365,6 @@ where
crate::surface::Action::Task(f) => {
f().map(|sm| crate::Action::Cosmic(Action::Surface(sm)))
}
_ => iced::Task::none(),
}
#[cfg(not(feature = "surface-message"))]
@ -408,7 +408,7 @@ where
f64::from(self.app.core().scale_factor())
}
pub fn style(&self, theme: &Theme) -> theme::Style {
pub fn style(&self, _theme: &Theme) -> theme::Style {
if let Some(style) = self.app.style() {
style
} else if self.app.core().window.is_maximized {
@ -480,12 +480,11 @@ where
.into_iter()
.filter(cosmic_config::Error::is_err)
{
if let cosmic_config::Error::GetKey(_, err) = &why {
if err.kind() == std::io::ErrorKind::NotFound {
if let cosmic_config::Error::GetKey(_, err) = &why
&& err.kind() == std::io::ErrorKind::NotFound {
// No system default config installed; don't error
continue;
}
}
tracing::error!(?why, "cosmic toolkit config update error");
}
@ -621,15 +620,15 @@ impl<T: Application> Cosmic<T> {
#[allow(clippy::too_many_lines)]
fn cosmic_update(&mut self, message: Action) -> iced::Task<crate::Action<T::Message>> {
match message {
Action::WindowMaximized(id, maximized) => {
Action::WindowMaximized(_id, _maximized) => {
#[cfg(not(all(feature = "wayland", target_os = "linux")))]
if self
.app
.core()
.main_window_id()
.is_some_and(|main_id| main_id == id)
.is_some_and(|main_id| main_id == _id)
{
self.app.core_mut().window.sharp_corners = maximized;
self.app.core_mut().window.sharp_corners = _maximized;
}
}

View file

@ -136,7 +136,7 @@ pub fn run<App: Application>(settings: Settings, flags: App::Flags) -> iced::Res
crate::malloc::limit_mmap_threshold(threshold);
}
let default_font = settings.default_font;
let _default_font = settings.default_font;
let (settings, (mut core, flags), window_settings) = iced_settings::<App>(settings, flags);
#[cfg(not(feature = "multi-window"))]
{
@ -284,7 +284,7 @@ where
// app = app.window(window_settings);
core.main_window = Some(iced_core::window::Id::RESERVED);
}
let mut app = iced::daemon(
let app = iced::daemon(
BootData(Rc::new(RefCell::new(Some(BootDataInner::<App> {
flags,
core,

View file

@ -1,7 +1,7 @@
//! Distribute content vertically.
use crate::iced;
use iced::core::alignment::{self, Alignment};
use iced::core::event::{self, Event};
use iced::core::event::Event;
use iced::core::layout;
use iced::core::mouse;
use iced::core::overlay;

View file

@ -10,11 +10,7 @@ use crate::{
widget::{
self,
autosize::{self, Autosize, autosize},
column::Column,
layer_container,
row::Row,
space::horizontal,
space::vertical,
},
};
@ -217,12 +213,6 @@ impl Context {
icon: widget::icon::Handle,
) -> crate::widget::Button<'a, Message> {
let suggested = self.suggested_size(icon.symbolic);
let (applet_padding_major_axis, applet_padding_minor_axis) = self.suggested_padding(true);
let (horizontal_padding, vertical_padding) = if self.is_horizontal() {
(applet_padding_major_axis, applet_padding_minor_axis)
} else {
(applet_padding_minor_axis, applet_padding_major_axis)
};
let symbolic = icon.symbolic;
let icon = widget::icon(icon)
.class(if symbolic {
@ -465,10 +455,8 @@ impl Context {
&self,
content: impl Into<Element<'a, Message>>,
) -> Autosize<'a, Message, crate::Theme, crate::Renderer> {
let force_configured = matches!(&self.panel_type, PanelType::Other(n) if n.is_empty());
let w = autosize(content, AUTOSIZE_MAIN_ID.clone());
let mut limits = Limits::NONE;
let suggested_window_size = self.suggested_window_size();
if let Some(width) = self
.suggested_bounds
@ -579,7 +567,7 @@ pub fn run<App: Application>(flags: App::Flags) -> iced::Result {
// window_settings = window_settings.clone();
core.main_window = Some(iced_core::window::Id::RESERVED);
}
let mut app = iced::daemon(
let app = iced::daemon(
BootData(Rc::new(RefCell::new(Some(BootDataInner::<App> {
flags,
core,

View file

@ -1,7 +1,7 @@
//! Distribute content horizontally.
use crate::iced;
use iced::core::alignment::{self, Alignment};
use iced::core::event::{self, Event};
use iced::core::event::Event;
use iced::core::layout::{self, Layout};
use iced::core::mouse;
use iced::core::overlay;
@ -10,7 +10,6 @@ use iced::core::widget::{Operation, Tree};
use iced::core::{
Clipboard, Element, Length, Padding, Pixels, Rectangle, Shell, Size, Vector, Widget, widget,
};
use iced::touch;
/// A container that distributes its contents horizontally.
///

Some files were not shown because too many files have changed in this diff Show more