Skip to content

Editing a panel launcher hangs on OK; orphan cinnamon-custom-launcher-N.desktop files accumulate #13895

Description

@rubinlinux

Distribution

Mint 22.3

Package version

Cinnamon 6.6.9

Graphics hardware in use

NVIDIA (always gpu mode)

Frequency

Always

Bug description

Editing panel icons appears not to work, because cinnamon does not pick up the change unless restarted. Multiple edits in a row cause a hang on "OK"

Steps to reproduce

Right-click a panel launcher → Edit → change the command → click OK. Note that your changes don't appear to be reflected in the icon. Right click it and edit it again. This time the dialog
stops responding and never closes.

The new ~/.local/share/cinnamon/panel-launchers/cinnamon-custom-launcher-N.desktop
file is written, but the applet's launcherList setting is never updated,
and the panel icon doesn't change. Every time I retry it writes another orphaned
cinnamon-custom-launcher-N.desktop file.

Expected behavior

I expect to be able to edit my panel icons and the changes take effect immediately (It used to work this way, some time back)

Additional information

Root cause

In cinnamon-desktop-editor.py, Main.panel_launcher_cb:

i = launchers.index(self.desktop_file)
if i >= 0:
    del launchers[i]
    launchers.insert(i, os.path.split(dest_path)[1])

list.index() raises ValueError when the item is missing — it never returns
-1. The dead if i >= 0: guard suggests the code was written assuming
JavaScript indexOf semantics. When the -f desktop id passed by the applet
is not present in the JSON launcherList, the callback raises, PyGObject
swallows the exception at the signal boundary, and self.end() /
Gtk.main_quit() is never reached — the dialog hangs. Because save() runs
before the callback, the orphan .desktop file has already been written.

Why the id mismatch is guaranteed to arise (second defect)

The editor writes launcherList straight into the applet's JSON settings file
via JsonSettingsWidgets.JSONSettingsHandler and never notifies Cinnamon.
On the JS side, js/ui/settings.js contains no file monitor at all — external
setting changes only reach a running xlet through the
org.Cinnamon.updateSetting D-Bus method (cinnamonDBus.js
remoteUpdate()), which is what cinnamon-settings/xlet-settings.py (line
452) calls after saving. cinnamon-desktop-editor.py contains no D-Bus code.

Consequence on any stock install:

  1. First edit of a regular (non-custom) launcher: JSON is updated — the entry
    is replaced by cinnamon-custom-launcher-N.desktop — but the panel shows
    no change whatsoever until Cinnamon is restarted.
  2. The user, seeing nothing happen, naturally edits the icon again. The
    applet's stale in-memory launcher passes the original desktop id via -f,
    which is no longer in launcherList.
  3. launchers.index() raises ValueError → dialog hangs (defect Configuration: Can't modify favorite apps #1). Every
    retry until a Cinnamon restart hangs identically, each writing another
    orphan cinnamon-custom-launcher-N.desktop.

So the reproduction on a fresh install is simply: edit any panel launcher,
then edit it again without restarting Cinnamon.

Suggested fix

  1. Notify Cinnamon after saving, the same way xlet-settings.py does
    (org.Cinnamon.updateSetting), so the panel refreshes and the second-edit
    id mismatch can't happen in the normal flow.
  2. Make the callback robust anyway:
try:
    i = launchers.index(self.desktop_file)
except ValueError:
    launchers.append(os.path.split(dest_path)[1])
else:
    launchers[i] = os.path.split(dest_path)[1]

(plus a try/finally around the callback body so self.end() always runs and
the dialog can never be left hanging).

Notes

Note

I am a real person, really experiencing this problem. I used Claude's LLM to help me troubleshoot, collect information, and include thorough information in this bug report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions