Skip to content

printers@cinnamon.org: Update the applet when the printer list is empty or unavailable, and check for system-config-printer - #13936

Open
Fantu wants to merge 2 commits into
linuxmint:masterfrom
Fantu:printers-applet-handle-lpstat-failure
Open

printers@cinnamon.org: Update the applet when the printer list is empty or unavailable, and check for system-config-printer#13936
Fantu wants to merge 2 commits into
linuxmint:masterfrom
Fantu:printers-applet-handle-lpstat-failure

Conversation

@Fantu

@Fantu Fantu commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

The applet assumes that the CUPS command line tools and system-config-printer are always there. On a system installed without the printing stack neither is true, and the applet ends up in a broken state instead of quietly staying out of the way. Two commits, each usable on its own.

1. Update the applet even when lpstat fails

On a system where lpstat is not available the printers applet never updates itself, and with the default settings its icon stays in the panel forever.

_bootstrapPrinters() fetches the initial printer list with Util.spawn_async(), which runs the command through cinnamon-subprocess-wrapper and pushes the output back over DBus. PushSubprocessResult() only invokes the callback when the command succeeded:

    PushSubprocessResult(process_id, result, success) {
        if (Util.subprocess_callbacks[process_id]) {
            if (success)
                Util.subprocess_callbacks[process_id](result);
            delete Util.subprocess_callbacks[process_id];
        }
    }

So if lpstat is missing, or exits non-zero, the callback is silently dropped: _updateApplet() is never reached, and neither is the _updateVisibility() it calls. The try/catch around the call cannot help, since the failure happens in the wrapper process, not in Cinnamon. The result is that the applet keeps whatever visibility it had when it was created — with the default show-icon value (printers, i.e. "when printers exist") and no printers configured, the icon is shown even though it should be hidden. The same happened when lpstat did run but printed nothing, because the callback returned early on empty output.

This is not an exotic case: the applet is enabled by default in panel1:right, and lpstat is packaged separately from CUPS on Debian and derivatives (cups-client), so it can easily be absent on a machine with no printing setup. It was the cause of Debian bug #993152, which used to be worse before the rework — with the old code the missing command broke the nested spawn_async chain and left updating = true, so the menu would not open at all.

Fix

Use Util.spawnAsyncIO() instead: it passes the exit status and stderr to the callback, and it throws immediately (Gio.Subprocess.init() fails with G_SPAWN_ERROR_NOENT) when the binary cannot be executed at all. Both failure paths now log a warning and still call _updateApplet(), so the applet ends up in a consistent state — hidden, with the default setting and no printers. The hardcoded /usr/bin path is dropped as well, so lpstat is looked up in PATH.

Testing

Tested on Cinnamon 6.7.5, show-icon left at its default (printers), asking the applet itself for its state over org.Cinnamon.Eval:

case before after
lpstat not installed {visible: true, printers: 0} — icon stuck in the panel, nothing logged {visible: false, printers: 0} + printers@cinnamon.org: could not list printers: Failed to execute child process “lpstat” (No such file or directory)
lpstat installed, no printer configured {visible: true, printers: 0} {visible: false, printers: 0}
one printer configured {visible: true, printers: 1} {visible: true, printers: 1}, menu opens and lists the printer

2. Don't offer system-config-printer when it is missing

Three places spawn system-config-printer unconditionally: the context menu entry, the item shown when no printer is configured, and the activation of a printer row. Where the printing stack was never installed that program is not there either, so those actions can only end in an Execution of 'system-config-printer' failed error notification. Cinnamon's own settings already handle this properly — the Printers entry of System Settings is a standalone module, and SAModule.process() only lists it when the executable is found in PATH.

The commit looks the binary up with GLib.find_program_in_path() and, when it is missing, leaves the context menu entry out, does not connect the activation handler of the printer rows, and shows the placeholder item as insensitive instead of pretending it can open something. No new translatable strings.

Same test setup, this time with the applet's menus inspected over org.Cinnamon.Eval:

case menu context menu
system-config-printer missing, one printer printer row present, no activation handler no Printers entry
system-config-printer missing, no printer Printers placeholder, reactive: false no Printers entry
system-config-printer installed, one printer printer row with its activation handler Printers entry, as before

The initial printer list is fetched with Util.spawn_async(), which runs
the command through cinnamon-subprocess-wrapper and pushes the result
back over DBus. PushSubprocessResult() only invokes the callback when
the command succeeded, so when lpstat is missing (cups-client is not
installed, or CUPS is not installed at all) or exits non-zero, the
callback is silently dropped and _updateApplet() is never reached. The
applet then keeps the visibility it had at creation time: with the
default "show icon when printers exist" setting and no printers, the
icon stays in the panel forever. The same happened when lpstat succeeded
but printed nothing, because the callback returned early on empty
output.

Use Util.spawnAsyncIO() instead: it reports the exit status and stderr
to the callback, and throws right away if the binary cannot be executed
at all, so both failure paths can log a warning and still call
_updateApplet(). Also drop the hardcoded /usr/bin path so lpstat is
looked up in PATH.

Assisted-by: Claude Code:claude-opus-5
@mtwebster

Copy link
Copy Markdown
Member

Can you use Cinnamon.find_program_in_path() instead of GLib? It's asynchronous with a callback.

ref: d62a19f

@Fantu
Fantu force-pushed the printers-applet-handle-lpstat-failure branch from 42a4103 to be3a39a Compare August 17, 2026 18:29
@Fantu

Fantu commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Done, the second commit now uses Cinnamon.find_program_in_path(). The lookup runs once in the constructor and the result is kept in this._hasConfigTool; the callback adds the context menu entry and schedules a menu rebuild, so a menu built before the lookup completed picks up the result.

One thing worth knowing for other conversions: since the callback runs after finalizeContextMenu(), appending the entry puts it below "Remove '…'" and leaves it without a separator (the separator is only created when the context menu is non-empty at that point). So the entry is inserted at position 0 and the separator is created there as well, assigned to this.context_menu_separator so a later finalizeContextMenu() doesn't add a second one.

Retested on 6.7.5 in the same way as before, with the applet queried over org.Cinnamon.Eval:

case menu context menu
system-config-printer missing, one printer printer row present, no activation handler no Printers entry
system-config-printer missing, no printer Printers placeholder, reactive: false no Printers entry
system-config-printer installed, one printer printer row with its activation handler Printers entry on top, as before
system-config-printer installed, no printer Printers placeholder, reactive: true Printers entry on top, as before

@mtwebster

Copy link
Copy Markdown
Member

Maybe construct the full menu like normal (before Cinnamon.find_program_in_path()), and just update the launcher item's visibility in the callback? I'm pretty sure popupMenu separators are smart enough to hide themselves if they have no visible item to either side)

…issing

The applet menu item shown when no printer is configured, the context
menu entry and the activation of a printer row all spawn
system-config-printer unconditionally. On a system installed without the
printing stack that program is not there, so those actions can only
produce an "Execution of 'system-config-printer' failed" error
notification. Cinnamon's own settings already deal with this: the
Printers entry of System Settings is a standalone module, and
SAModule.process() only lists it when the executable is found in PATH.

Look the binary up once at construction time with
Cinnamon.find_program_in_path() and keep the result in
this._hasConfigTool. The context menu entry is built as before but
starts out hidden, and the callback only makes it visible again, so the
menu keeps its usual order and the separator finalizeContextMenu() adds
hides itself along with the entry when the program is missing. The
callback also schedules a menu rebuild, so a menu built before the
lookup completed picks up the result.

When the program is missing the activation handler of the printer rows
is not connected and the placeholder item is shown as insensitive,
instead of pretending it can open something.

Assisted-by: Claude Code:claude-opus-5
@Fantu
Fantu force-pushed the printers-applet-handle-lpstat-failure branch from be3a39a to ef8d969 Compare August 17, 2026 19:48
@Fantu

Fantu commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Much nicer, thanks — done that way. The entry is built as before and just starts out hidden; the callback only shows it, so the menu keeps its usual order and finalizeContextMenu() adds the separator itself. You were right about the separators: _updateSeparatorVisibility() hides it once the entry next to it is invisible.

One detail I ran into while testing: that runs on open-state-changed, so the separator still reports visible: true until the menu is opened for the first time. Nothing an user can see, but worth knowing if you ever inspect the menu state without opening it.

Retested on 6.7.5, applet queried over org.Cinnamon.Eval with the context menu opened:

case menu context menu
system-config-printer missing, one printer printer row present, no activation handler Printers entry and its separator hidden
system-config-printer missing, no printer Printers placeholder, reactive: false Printers entry and its separator hidden
system-config-printer installed, one printer printer row with its activation handler Printers entry on top, as before
system-config-printer installed, no printer Printers placeholder, reactive: true Printers entry on top, as before

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.

2 participants