Skip to content

Conversation

@ehamiter
Copy link

@ehamiter ehamiter commented Oct 12, 2025

This adds the ability to assign keyboard shortcuts via the Cosmic keyboard custom settings to activate, search, select, and copy from the UI.

The command to add is:

cosmic-ext-applet-clipboard-manager --toggle

and you can assign it to any shortcut. This will show/hide the clipboard manager, and allow you to type to search, use the arrow keys to select an item, and enter to copy and close the interface. Escape also works to exit without selecting anything.

Full disclosure: I am not an expert in Rust; I'm scratching my own itch to add this feature, so there may be a more suitable way of doing this.


Copy link
Collaborator

@wiiznokes wiiznokes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for this pr. This is a good work arround while waiting for the flatpak portal implementation.

I have some questions/suggestions. I understand you're not familiar with rust, so you can ask me if you don't understand something.

  • Did you test your code? Does it works?
  • get_signal_file_path is duplicated
  • You seems to write the timestamp but never actually use it in the code
  • It would be nice if these change be in one module, e.i, the functions to read/write the signal file, and the subscription
  • The subscription should be a file watcher, especially if we are doing io every 100ms
  • why you define a shortcut in the app code? If i understand correctly, it should only be in the cosmic-comp config

@wiiznokes
Copy link
Collaborator

Note that the approach looks good otherwise

@ehamiter
Copy link
Author

Thanks @wiiznokes -- I believe I addressed everything, please let me know if not.

Tested fully on my local machine-- able to activate, start typing to search, use arrow keys to select, and enter to populate clipboard with selection and close the UI. Escape also exits the UI without altering the clipboard.

@wiiznokes
Copy link
Collaborator

So i wanted to make some minor modif before merging the pr (see this branch https://github.com/cosmic-utils/clipboard-manager/tree/pr160-modif), but i've realised that the popup doesn't show near the applet icon now.
This is unfortunate. Futhermore, i think the layer surface stuff was meant to be removed from cosmic-panel, so idt it's a good idea to start using this.

Maybe @wash2 have some insight about this problem 🙏
tldr: We want to show the popup programatically. The popup doesn't show up when using get_popup, but does when using get_layer_surface

@ehamiter
Copy link
Author

Yep, I noticed the positioning as well- I think it's due to how Wayland treats the layers, so I'm not sure how to align it with the applet icon if it goes that route.

Whatever you think is best-- I have a local copy that works for me, so I'm happy to do anything else needed to get the functionality available to others.

@OmarAhmed-A
Copy link

I LOVEE this, is it possible to have the selection ENTER trigger the paste directly?

This would help someone transitioning from windows with my muscle memory.

@OmarAhmed-A
Copy link

There's an issue where having more items in history than length and using down arrow to scroll doesn't actually scroll them into view.

@OmarAhmed-A
Copy link

OmarAhmed-A commented Nov 23, 2025

There's an issue where having more items in history than length and using down arrow to scroll doesn't actually scroll them into view.

fixed in 8a94319
#177

@mbchristoff
Copy link

Been testing this for a week. functions fine on pop-os 24.04.
Only found out that from the first time it gets toggled it will use 200% cpu untill it is killed, am I the only one with that problem?
It seems to loop around this small snippet from strace:

madvise(0x7d308802b000, 4096, MADV_DONTNEED) = 0
madvise(0x7d3088059000, 4096, MADV_DONTNEED) = 0
madvise(0x7d3088064000, 4096, MADV_DONTNEED) = 0
madvise(0x7d3088041000, 4096, MADV_DONTNEED) = 0
madvise(0x7d308803d000, 4096, MADV_DONTNEED) = 0
madvise(0x7d308805f000, 8192, MADV_DONTNEED) = 0
madvise(0x7d3088053000, 12288, MADV_DONTNEED) = 0
madvise(0x7d3088066000, 12288, MADV_DONTNEED) = 0
write(11, "\1\0\0\0\0\0\0\0", 8)        = 8
write(11, "\1\0\0\0\0\0\0\0", 8)        = 8
write(11, "\1\0\0\0\0\0\0\0", 8)        = 8
write(11, "\1\0\0\0\0\0\0\0", 8)        = 8
timerfd_settime(6, 0, {it_interval={tv_sec=0, tv_nsec=0}, it_value={tv_sec=0, tv_nsec=0}}, {it_interval={tv_sec=0, tv_nsec=0}, it_value={tv_sec=0, tv_nsec=0}}) = 0
epoll_ctl(4, EPOLL_CTL_MOD, 6, {events=EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLONESHOT, data={u32=4294967295, u64=18446744073709551615}}) = 0
epoll_pwait(4, [{events=EPOLLIN, data={u32=0, u64=4294967296}}], 1024, -1, NULL, 1000000000) = 1
read(5, 0x7fffb4abbc98, 8)              = -1 EAGAIN (Resource temporarily unavailable)
epoll_ctl(4, EPOLL_CTL_MOD, 5, {events=EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLONESHOT, data={u32=4294967295, u64=18446744073709551615}}) = 0
read(8, "\2\0\0\0\0\0\0\0", 8)          = 8
write(11, "\1\0\0\0\0\0\0\0", 8)        = 8
write(11, "\1\0\0\0\0\0\0\0", 8)        = 8
write(11, "\1\0\0\0\0\0\0\0", 8)        = 8
openat(AT_FDCWD, "/run/user/1000/cosmic-clipboard-manager-toggle", O_RDONLY|O_CLOEXEC) = 24
statx(24, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0664, stx_size=13, ...}) = 0
read(24, "1765188137517", 13)           = 13
read(24, "", 32)                        = 0
close(24)                               = 0
madvise(0x56928c431000, 4096, MADV_DONTNEED) = 0
madvise(0x56928c43a000, 4096, MADV_DONTNEED) = 0
madvise(0x56928c44c000, 4096, MADV_DONTNEED) = 0
madvise(0x56928c475000, 4096, MADV_DONTNEED) = 0
madvise(0x56928c451000, 4096, MADV_DONTNEED) = 0
madvise(0x56928c504000, 4096, MADV_DONTNEED) = 0

Could it be that it's missing a pause somewhere?

Added a 10ms to file watcher to reduce CPU stress.
Implement delay in signal_file_watcher function
@wiiznokes
Copy link
Collaborator

i'm not sure but i think the line that block us to use a regular xdg shell popup is this one: https://github.com/pop-os/cosmic-panel/blob/8eb8a1b6305213ec7402cb2ec24bef6b501b978a/cosmic-panel-bin/src/xdg_shell_wrapper/server/handlers/xdg_shell.rs#L45

Maybe we could add a check to bypass this if the client is not sandboxed

@GonzRon
Copy link

GonzRon commented Feb 6, 2026

sorry, i use this now and want to pull in the latest greatest changes so excuse me for butting in but hopefully this can help move this along:

The 200% CPU bug is: The toggle file watcher subscription spinning in a tight loop. Look at the strace cycle:

openat("/run/user/1000/cosmic-clipboard-manager-toggle") → open file
read("1765188137517") → read timestamp
close(24) → close file
write(11, "\1\0\0\0\0\0\0\0") ×4 → wake eventfd (trigger re-render)
epoll_pwait(...) → wait for events
→ immediately wakes up again → repeat forever

The problem is a feedback loop in the toggle subscription:

  1. The file watcher sees /run/user/1000/cosmic-clipboard-manager-toggle exists
  2. It reads the timestamp, fires a toggle event
  3. The toggle event causes a UI update, which writes wake events to the eventfd (the 4x write(11, ...))
  4. The UI re-render cycles back to the subscription, which checks the file again
  5. The file still has the same timestamp — but nothing marks it as "already handled"
  6. So it fires the toggle event again → goto 3

The fix needs to be in the toggle subscription logic itself — either:

  • Delete the file after reading it (so the next poll finds nothing)
  • Track the last-seen timestamp and ignore if unchanged
  • Replace the file-polling mechanism entirely with a Unix socket or D-Bus signal that's inherently one-shot

This is a bug in PR #160's toggle implementation, not in the clipboard data path that PR #170 touches.

Lcstyle added a commit to Lcstyle/clipboard-manager that referenced this pull request Feb 6, 2026
- Add --toggle/-t CLI flag to toggle popup via keyboard shortcut
- Add --help/-h with setup instructions for COSMIC custom shortcuts
- Add file-based IPC (polling) for external toggle signaling
- Fix popup positioning: icon click uses XDG popup (anchored),
  --toggle uses centered layer surface
- Fix close_popup to correctly destroy layer surfaces vs XDG popups
- Switch clipboard pipe reads from blocking std::io to async tokio
  with 500ms timeout (based on PR cosmic-utils#170)
- Fix search input to support Enter-to-copy focused item
- Add db lock file to .gitignore

Incorporates and fixes issues from PR cosmic-utils#170 and PR cosmic-utils#160:
- Replaces notify-based file watcher with simple 250ms polling to
  prevent CPU busy-loop caused by inotify on busy /run/user/ dir
- Uses Anchor::empty() for centered popup instead of edge-anchored

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Lcstyle
Copy link

Lcstyle commented Feb 6, 2026

I decided to go more with a dbus approach -> https://github.com/Lcstyle/clipboard-manager/tree/feat/dbus-toggle for a oneshot event based trigger rather than polling - reason being :

Three crash waves — all SIGABRT (Rust panic). The panic message from the coredump:

called Result::unwrap() on an Err value: PoisonError { .. }
thread 'main' panicked: panic in a destructor during cleanup

And the root cause of the CPU loop is in our ipc.rs. The notify watcher on /run/user/1000/ is problematic — that directory is extremely busy. But the critical bug is here:

loop {
rx.recv().await; // ← returns None instantly if sender drops
output.send(AppMsg::CheckSignalFile).await.ok();
}

If the notify watcher thread dies for any reason, rx.recv() returns None instantly and we never check the return value — creating an infinite tight loop flooding the app with CheckSignalFile messages. That's the 200% CPU,
eventually leading to the PoisonError and abort.

The notify-based approach is fundamentally fragile for /run/user/1000/. Let me replace it with a simple polling approach — one stat() call every 250ms uses negligible CPU and can't possibly loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Toggle with keyboard shortcut and navigate using arrows

6 participants