Replace the path-local [patch] redirect with a git redirect to
https://forge.aditua.com/leyoda/cosmic-text.git (branch local/pr-503,
which carries upstream PR #503 plus the EAW monospace width fix). No
more absolute path dependency on /home/lionel/Devels/cosmic-text.
Leyoda 2026 – GPLv3
Replace the path-local [patch] redirect with a git redirect to
https://forge.aditua.com/leyoda/window_clipboard.git (branch
yoda-x11-optional). Removes the absolute path dependency on
/home/lionel/Devels/window_clipboard so any clone can build.
The patch is still needed to consolidate the upstream pop-os/libcosmic
chain (pulled by cosmic-settings-daemon) onto the same fork iced uses,
otherwise cargo would compile two versions of window_clipboard.
Leyoda 2026 – GPLv3
Parse text/uri-list according to the real clipboard format, make unsupported trash search explicit, and update the lockfile so the local cosmic-text patch is actually used instead of reported as unused.
Avoid synchronous child counts during item construction, use extension-based MIME detection for initial scans, and defer expensive MIME icon resolution by using generic file icons for ordinary files. Document the local xdg-desktop-portal FileChooser workaround for COSMIC portal crashes.
User feedback: segmented visual was noisy; only want icons, no labels.
Changes:
- rebuild_toolbar_model no longer sets .text() on entities, so the
segmented_button widget draws icon-only squares.
- toolbar renders with style(SegmentedButton::Control), button_height
+ min/max_button_width pinned at 32 px (square icon buttons),
button_spacing = space_xs for clear separation (was space_xxs which
looked conjoined), Alignment::Center.
- container width = Length::Shrink so the toolbar only takes the space
it needs instead of stretching across the window.
The generic dnd_source+dnd_destination pairing didn't reliably fire
on intra-window reorders in this setup, while segmented_button's
built-in drag (same primitive powering tab_bar, which does work) is
proven. Switched the toolbar rendering to segmented_button::horizontal
with drag enabled — each segment carries its ToolbarAction as data.
App state:
- new toolbar_model: segmented_button::Model<SingleSelect>
- rebuild_toolbar_model() mirrors config.toolbar into the model on
every update_config (including the initial app.update_config at
startup)
- sync_toolbar_config_from_model() is the reverse: walk the model's
entity order after a reorder, write the new Vec<ToolbarAction>
directly via config.set_toolbar (without calling update_config so
we don't rebuild the model and wipe the reorder the user just did)
Messages:
- ToolbarTabActivate(Entity): look up action via model.data(), clear
the model's active selection (segmented_button single-select would
keep the last click highlighted; we don't want that for action
buttons), dispatch the action's message.
- ToolbarTabReorder(ReorderEvent): model.reorder then sync.
View:
- replaces the row-of-dnd-wrapped-icon-buttons with
segmented_button::horizontal(&self.toolbar_model)
.enable_tab_drag("x-cosmic-files/toolbar-dnd") .on_reorder(...) .on_activate(...)
- fixed 36-px square buttons so it still looks toolbar-y rather than
stretched pill-segmented-control
Kept: Settings panel ↑↓/add/remove UI (no regression).
Removed: dnd_source/dnd_destination wrappers from the toolbar (but
the ToolbarActionPayload + MIME constant remain in case Settings DnD
gets unstuck later).
User feedback: going through Settings to reorder is too indirect. Now
each toolbar button is wrapped in dnd_source + dnd_destination so the
user can grab an icon in the live toolbar and drop it onto another
icon to reorder in-place. The underlying icon button keeps firing its
on_press for quick clicks (dnd_source only starts a drag past the
default 8 px motion threshold), so regular clicks continue to run the
associated Action — no mode-switch needed.
Settings retains the ↑↓/add/remove UI as a fallback (discoverability
+ keyboard-friendly) and for the same drag-drop if the user prefers
working from the panel. The config model (Vec<ToolbarAction> +
ToolbarReorder message) is already shared, so both paths mutate the
same state.
DnD source+destination wiring from 1cf17dc builds but the drag-drop
doesn't fire reliably in practice (suspected: either dnd_source's
shell.capture_event() on CursorMoved swallows events the destination
needs to see, or intra-window DnD has a Wayland-specific hiccup on the
current sctk/cosmic-comp pairing).
Adds two plain click-handled buttons per enabled row (↑ go-up-symbolic,
↓ go-down-symbolic, both disabled at list edges) so reorder is
functional regardless of DnD state. Backed by new messages
ToolbarMoveUp / ToolbarMoveDown that swap adjacent positions in the
Vec<ToolbarAction>.
The drag handle + DnD source/destination wrapping stays in place — if
DnD gets fixed upstream or on a future libcosmic it'll Just Work, and
the arrows remain as a keyboard-friendly fallback.
Migrates the config model from the phase-2 bag-of-bools (ToolbarItems)
to an ordered Vec<ToolbarAction> so the user can pick BOTH the set of
buttons AND their order in the toolbar.
Config (config.rs):
- new ToolbarAction enum with 11 variants (LocationUp, Reload,
NewFolder, NewFile, Rename, Delete, Cut, Copy, Paste,
ToggleShowHidden, OpenTerminal) + to_u8/from_u8 for DnD payload
- Config.toolbar: Vec<ToolbarAction>, default = default_toolbar()
(NewFolder, Rename, Delete, Cut, Copy, Paste — same 6 as phase 2)
Rendering (view()):
- iterate self.config.toolbar in order and emit a tooltip'd icon button
per entry via the new toolbar_action_ui(action) helper shared with
the Settings page. Paste stays disabled when clipboard empty.
- No hardcoded groups or auto-dividers anymore — order is 100% user.
Settings page (toolbar_settings_section):
- two stacked lists:
* 'Toolbar': currently-enabled actions in their Vec order. Each row
is wrapped in dnd_source (drags a ToolbarActionPayload carrying
the enum discriminant) + dnd_destination (accepts drops from other
rows, fires Message::ToolbarReorder { src, target } to move src
before target in the Vec). A list-drag-handle icon + a minus button
(ToolbarRemove) per row.
* 'Available': actions not yet enabled, each with a plus button
(ToolbarAdd) that pushes to the end of the Vec.
- 'Reset to defaults' button at the bottom (ToolbarReset).
DnD infra (app.rs top):
- TOOLBAR_MIME constant: 'application/x-cosmic-files-toolbar-action'
- ToolbarActionPayload(u8) with AsMimeTypes + AllowedMimeTypes +
TryFrom<(Vec<u8>, String)> impls — single-byte wire format matching
the enum discriminant.
Messages:
- ToolbarAdd(ToolbarAction) — append to toolbar vec if absent
- ToolbarRemove(ToolbarAction)
- ToolbarReorder { src, target } — remove src, reinsert before target
- ToolbarReset — restore default_toolbar()
i18n (en + fr):
- new keys: toolbar-available, toolbar-empty-hint, toolbar-reset
Migration: existing installs with a phase-2 ToolbarItems struct in
their config will error at load time (different shape); cosmic_config
falls back to Self::default() which gives the phase-2 minimal-6 set —
a safe reset rather than a broken partial read.
Phase 1 shipped a fixed 6-button toolbar. Phase 2 moves visibility to
the config so users pick which buttons appear.
Config (config.rs):
- new ToolbarItems struct (CosmicConfigEntry) with one bool per button
- Config.toolbar: ToolbarItems, default = 'minimal 6' set from phase 1
(new_folder, rename, delete, cut, copy, paste) + 5 extras off
(new_file, reload, toggle_show_hidden, open_terminal, location_up)
Rendering (view()):
- iterate through self.config.toolbar fields in fixed logical order
(location → create/edit → clipboard → view toggles)
- dividers inserted only between non-empty groups
- whole toolbar hidden if every button is off (no empty container)
Settings page (settings()):
- new 'Toolbar' section with one toggler per button, wired through
Message::SetToolbar(ToolbarItems) which persists via config_set!
i18n (en + fr):
- added 'toolbar' + 'parent-directory' strings
- reused existing new-folder / new-file / rename / delete / cut / copy /
paste / reload-folder / show-hidden-files / open-in-terminal
All actions dispatch through Action::message so keybindings and toolbar
share one code path.
document-edit-symbolic isn't in the Cosmic theme (checked Cosmic, Pop,
Adwaita, WhiteSur-dark ship lists) so it rendered empty. The Cosmic
theme ships pencil-symbolic which matches the edit/rename semantics
and is guaranteed to resolve through the current icon theme chain.
edit-rename-symbolic isn't part of the COSMIC/Pop/Adwaita/WhiteSur-dark
icon sets, so the Rename button rendered empty. Swap to
document-edit-symbolic which is present in Adwaita (the standard fallback
in the freedesktop-icons resolution chain) and semantically fits edit/rename.
Adds a full-width row of 6 icon buttons between the tab bar and the
tab view: New folder · Rename · Delete | Cut · Copy · Paste. Paste is
disabled when the clipboard is empty (existing self.clipboard_has_content
check). A vertical divider separates file-ops (3 first) from clipboard
ops (3 last).
Implementation reuses Action::message(entity_opt = None) so keybinding
and toolbar dispatch share exactly the same code path — no duplication.
Icons are freedesktop *-symbolic names so they inherit the COSMIC
theme's symbolic color. Tooltips use the existing fl!() strings
(new-folder / rename / delete / cut / copy / paste, EN + FR).
Customization (pick which buttons show up) is deferred to a follow-up
commit — this first pass is fixed at the minimal-6 set per the user's
spec.
Propagates the [patch] blocks added in cosmic-yoterm v5 to keep the
whole yoda app family on a single Wayland-only stack. Without these,
iced_winit fails to select a window_clipboard version because our
fork exposes a `wayland` feature that upstream doesn't.
- window_clipboard → /home/lionel/Devels/window_clipboard (x11 gated
behind opt-in feature)
- cosmic-text → /home/lionel/Devels/cosmic-text (EAW terminal_cells +
upstream PR#503 applied)
The 'Open with...' dialog let you pick an app but never remembered your
choice — you'd see the same dialog again next time. The infrastructure
was already there (MimeAppCache::set_default writes to mimeapps.list),
just never wired to the UI.
Adds a toggler below the app list labelled 'Always use this app for this
file type' (EN) / 'Toujours utiliser cette application pour ce type de
fichier' (FR). When enabled, after spawning the selected app, the
default handler for the file's mime type is persisted via
self.mime_app_cache.set_default(mime, app.id).
Implementation:
- DialogPage::OpenWith gains a set_default: bool field (defaulted false)
- Message::OpenWithToggleDefault(bool) + handler mutates the dialog state
- DialogComplete handler for OpenWith calls set_default after a clean
spawn when the flag is set
- Dialog rendering adds a .control(widget::row) with label + toggler,
between the scrollable list and the action buttons
- i18n strings added: en/fr open-with-set-default
mime_app::MimeAppCache::terminal() hardcoded "com.system76.CosmicTerm"
as the only non-xdg-default fallback. On a yoda stack the relevant
terminal is our fork cosmic-yoterm (desktop id com.aditua.CosmicYoterm),
so we add it first in preference_order. xdg-mime default still wins
when set — this just covers the case where it isn't.
Fixes "Open in terminal" launching Konsole (or first random terminal in
apps list) instead of cosmic-yoterm when xdg-mime default is unset or
points to something else.
Rewire cosmic-files (lib + file manager) onto the yoda fork of libcosmic.
- [dependencies.libcosmic] removed, replaced by [dependencies.libcosmic-yoda]
pointing at ../libcosmic (local path; the leyoda/libcosmic-yoda clone)
- Features: winit dropped, wayland added explicitly in the default set
- Feature refs "libcosmic/xxx" rewritten to "libcosmic-yoda/xxx"
- [patch] block removed — transitive libcosmic refs no longer exist
cosmic-files lib and the file manager binary build clean against
libcosmic-yoda 0.1.0-yoda (3 warnings, all pre-existing unused-var
in search code).
Activates the [patch.'https://github.com/pop-os/libcosmic'] override
pointing at ../libcosmic, enabling local development against a
patched libcosmic checkout (e.g. to pick up
WindowControlsPosition / macOS-style window controls).
This branch is intentionally dev-local: do NOT merge upstream.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tokio recommends using a sync mutex with a notifier instead of the
async mutex where possible. Rust forbids holding a sync mutex guard
across await points so we can prevent a potential deadlock this way.
This adds a custom channel based on the tokio mpmc example for
handling gvfs events from callbacks to avoid the async mutex
requirement. Messages are held in a `VecDeque` behind a sync mutex
and the receiver will get notified via the notifier when a message
is added to the queue.
Weak references used in gio callbacks in case the sender is dropped
by the application.
This caused the tab subscription to block the tokio executor.
Instead store the image dimensions in the `Item`, which is
created on a background thread.