Warn when a device is unplugged while still mounted - #13899
Conversation
…fication. 'xapp-media-removable' does not exist in the icon set Cinnamon uses. Icon names were switched to XSI in 890f6f7, and xapp-symbolic-icons only ships xsi-* names, so the unmount notification has been falling back to a missing icon since it was added. 'xsi-media-removable' is the direct equivalent and shows the same removable drive. Assisted-by: Claude Code:claude-opus-5
…ted. Users who physically pull out a drive without ejecting it get no feedback at all, so nothing tells them that they risk losing data. This cannot be prevented, but it can be reported after the fact. GVfs makes the distinction detectable: update_all() in gvfsudisks2volumemonitor.c emits drive-disconnected before volume-removed and mount-removed for everything that disappeared in the same update. A device that is unplugged while mounted therefore still has its mounts recorded when drive-disconnected arrives, while a device that was unmounted or ejected first had mount-removed delivered by an earlier update. Traced against GVfs 1.54 with a USB stick: eject, safe removal and a plain command line unmount all leave the record empty, while unplugging a mounted stick does not. The mounts are tracked in a cache keyed on the mount point, because GMount has no volume left by the time mount-removed is emitted, and drive.get_volumes() is unreliable here: it is empty for a clean removal and can still list a volume after a clean unmount. Report this with a notification rather than a modal dialog, matching how CinnamonUnmountNotifier already reports unmount progress: the user did not ask for this and there is nothing to answer. Warn at most once per minute per device, since a failing connector can produce repeated connect/disconnect cycles. Also add js/ui/automountManager.js to POTFILES.in, which never listed it, so its strings can be translated. Assisted-by: Claude Code:claude-opus-5
'xsi-drive-removable-media' draws a plain rounded rectangle that reads as a floppy or an optical drive, so at panel size it doesn't suggest removable devices at all. 'xsi-media-removable' draws a USB stick, which is what users are looking for, and is the icon the unmount notification uses as well. Assisted-by: Claude Code:claude-opus-5
|
Hi, I've got a branch already I've been working on this for Cinnamon and Nemo, I'll make sure I'm covering this stuff also |
|
I'm not sure about a dialog, though, after the fact. Honestly, if they can't be bothered to read a notification warning them not to do something, they deserve what they get. |
|
Some users do it on purpose and you could be right (even if it's not a good thing to have a vindictive attitude), while other users are really inexperienced or have "too little logical skills" and I think it's useful to help them, for example there's already the applet icon which is not easily intuitive and I suppose the USB stick icon would be better, then that warning in case of removal without unmounting I think helps (at least for those who don't insist on doing it anyway) |
Related to https://github.com/orgs/linuxmint/discussions/1565 ("Please make it more clear that properly ejecting storage mediums is very important on Linux").
When a user physically pulls out a drive without ejecting it, nothing happens: no sound, no message, no hint that anything went wrong. The removal itself can't be prevented or delayed, but it can be reported afterwards, so that the user learns what the consequence of that action is.
This adds a notification for that case only. Clean removals — eject, safe removal, or a plain unmount — stay silent.
How the detection works
GVfs makes the two cases distinguishable through the order in which it emits its removal signals. In
update_all()(monitor/udisks2/gvfsudisks2volumemonitor.c), everything that disappeared in the same update is announced as:So a device that is unplugged while mounted still has its mounts recorded when
drive-disconnectedarrives, while a device that was unmounted or ejected first had itsmount-removeddelivered by an earlier update, leaving nothing behind.The mounts are tracked in a small cache keyed on the mount point. Two details forced that choice, and both are worth knowing if this code is ever revisited:
GMounthas no volume left by the timemount-removedis emitted, so a cache keyed on the volume never gets cleared;drive.get_volumes()cannot be used instead: it is empty for a clean removal, and it can still list a volume after a clean unmount.Why a notification and not a dialog
CinnamonUnmountNotifieralready reports unmount progress through the message tray, while the dialogs added in 9bdd28c are used where the user asked for something and has to answer (password, busy device). This warning belongs to the first group: nobody asked for it and there is nothing to answer, so a modal dialog would only steal focus from whatever the user is doing.It is rate limited to one warning per minute per device, because a failing connector can produce repeated connect/disconnect cycles.
Testing
Signal order and liveness were traced with a GVolumeMonitor + UDisks2 job monitor on GVfs 1.54, with a USB stick, in three scenarios:
udisksctl unmountthen unpluggedThe last one is the interesting negative case, since it doesn't go through the GIO API at all.
The feature was then verified end to end on a Mint 23 VM (Ubuntu 26.04 + the
alfarepo, cinnamon 6.7.4): unplugging a mounted stick shows the notification in a real session.Known limitations
Two unrelated fixes included
They are separate commits and can be dropped or taken independently:
cinnamonMountOperation.jsusedxapp-media-removable, which doesn't exist in the icon set Cinnamon uses since icon names were switched to XSI in 890f6f7 — the unmount notification has been falling back to a missing icon.xsi-media-removableis the direct equivalent.xsi-drive-removable-media, which draws a plain rounded rectangle that reads as a floppy or an optical drive at panel size.xsi-media-removabledraws a USB stick and is immediately recognizable.js/ui/automountManager.jswas also added toPOTFILES.in, which never listed it: its strings — including the existing ones — were not being extracted for translation.