From 7be72e3003e5411cfd8b9c45ca937943399112b4 Mon Sep 17 00:00:00 2001 From: Hans-Fritz Pommes Date: Sun, 1 Feb 2026 19:25:19 +0100 Subject: [PATCH 1/3] Fixed ugliness and not-working "cancel all jobs" --- .../applets/printers@cinnamon.org/applet.js | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js index 83f94f501a..482a4928f6 100644 --- a/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js @@ -11,6 +11,22 @@ const PANEL_EDIT_MODE_KEY = "panel-edit-mode"; const APPLET_PATH = imports.ui.appletManager.appletMeta['printers@cinnamon.org'].path; +function formatBytes(bytesStr) { + const bytes = parseInt(bytesStr, 10); + if (isNaN(bytes) || bytes === 0) return "0 Bytes"; + + const k = 1024; + const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + const value = bytes / Math.pow(k, i); + + return value.toLocaleString(undefined, { + minimumFractionDigits: 1, + maximumFractionDigits: 1 + }) + " " + sizes[i]; +} + + class CinnamonPrintersApplet extends Applet.TextIconApplet { constructor(metadata, orientation, panel_height, instance_id) { super(orientation, panel_height, instance_id); @@ -39,6 +55,7 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { this.updating = false; this.showLater = false; this.printers = []; + this.jobs = []; this.set_applet_icon_symbolic_name('xsi-printer'); this.update(); } @@ -104,8 +121,8 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { onCancelAllJobsClicked() { Util.spawn_async(['python3', APPLET_PATH + '/cancel-print-dialog.py', 'all'], Lang.bind(this, function(out) { if(out.trim() == "Cancel") { - for(var n = 0; n < this.printers.length; n++) { - Util.spawn(['cancel', '-a', this.printers[n]]); + for(var n = 0; n < this.jobs.length; n++) { + Util.spawn(['cancel', this.jobs[n].job]); } } })); @@ -162,6 +179,7 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { //Add Jobs Util.spawn_async(['/usr/bin/lpstat', '-o'], Lang.bind(this, function(out) { + this.jobs = []; //Cancel all Jobs if(out.length > 0) { let cancelAll = new PopupMenu.PopupIconMenuItem(_("Cancel all jobs"), 'xsi-edit-delete', St.IconType.SYMBOLIC); @@ -176,7 +194,7 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { //Cancel Job out = out.split(/\n/); this.jobsCount = out.length - 1; - Util.spawn_async(['/usr/bin/lpstat', '-o'], Lang.bind(this, function(out2) { + Util.spawn_async(['/usr/bin/lpq', '-a'], Lang.bind(this, function(out2) { out2 = out2.replace(/\n/g, ' ').split(/\s+/); let sendJobs = []; for(var n = 0; n < out.length - 1; n++) { @@ -184,24 +202,24 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { let job = line.slice(-1)[0]; let printer = line.slice(0, -1).join('-'); let doc = out2[out2.indexOf(job) + 1]; - for(var m = out2.indexOf(job) + 2; m < out2.length - 1; m++) { - if(isNaN(out2[m]) || out2[m + 1] != 'bytes') { - doc = doc + ' ' + out2[m]; - } else { - break; - } - } + let user = out2[out2.indexOf(job) - 1]; + let size = formatBytes(out2[out2.indexOf(job) + 2]); if(doc.length > 30) { doc = doc + '...'; } + let text = '(' + job + ') ' + _("'%s' on %s").format(doc, printer); + text = text + ' (' + size + ')' + _(" - by %s").format(user); let jobItem = new PopupMenu.PopupIconMenuItem(text, 'xsi-edit-delete', St.IconType.SYMBOLIC); if(out2[out2.indexOf(job) - 2] == 'active') { - jobItem.addActor(new St.Icon({ style_class: 'popup-menu-icon', icon_name: 'xsi-emblem-default', icon_type: St.IconType.SYMBOLIC })); + jobItem.addActor(new St.Icon({ style_class: 'popup-menu-icon', icon_name: 'xsi-printer-printing', icon_type: St.IconType.SYMBOLIC })); + } else { + jobItem.addActor(new St.Icon({ style_class: 'popup-menu-icon', icon_name: 'xsi-time', icon_type: St.IconType.SYMBOLIC })); } jobItem.job = job; jobItem.connect('activate', Lang.bind(jobItem, this.onCancelJobClicked)); this.cancelSubMenu.addMenuItem(jobItem); + this.jobs.push(jobItem); if(out2[out2.indexOf(job) - 2] != 'active' && out2[out2.indexOf(job) - 2] != '1st') { sendJobs.push(new PopupMenu.PopupIconMenuItem(text, 'xsi-go-up', St.IconType.SYMBOLIC)); sendJobs[sendJobs.length - 1].job = job; From 55ba527756883f894e063c2a81379822d5472c49 Mon Sep 17 00:00:00 2001 From: Hans-Fritz Pommes Date: Sun, 1 Feb 2026 21:51:47 +0100 Subject: [PATCH 2/3] Update applet.js Fix mini-problem (See https://github.com/linuxmint/cinnamon/pull/13524) --- .../usr/share/cinnamon/applets/printers@cinnamon.org/applet.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js index 482a4928f6..228af4293f 100644 --- a/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js @@ -207,6 +207,8 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { if(doc.length > 30) { doc = doc + '...'; } + out2[out2.indexOf(job) + 1] = "used"; + out2[out2.indexOf(job) + 2] = "used"; let text = '(' + job + ') ' + _("'%s' on %s").format(doc, printer); text = text + ' (' + size + ')' + _(" - by %s").format(user); From 58917a3e9298e52e77cd4c13b962a39863e3c57b Mon Sep 17 00:00:00 2001 From: Hans-Fritz Pommes Date: Mon, 2 Feb 2026 15:07:46 +0100 Subject: [PATCH 3/3] Update applet.js Support filenames with whitespaces --- .../applets/printers@cinnamon.org/applet.js | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js index 228af4293f..debbe9a339 100644 --- a/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/printers@cinnamon.org/applet.js @@ -27,6 +27,27 @@ function formatBytes(bytesStr) { } +function parseLpq(lpq_output) { + var parsedData = {}; + lpq_output = lpq_output.split(/\n/); + let line = []; + let joined_line = []; + + for(var n = 0; n < lpq_output.length - 1; n++) { + line = lpq_output[n].split(/\s+/); + if (line.length < 5) continue; + joined_line = []; + joined_line.push(line[0]); + joined_line.push(line[1]); + joined_line.push(line.slice(3, -2).join(' ')); + joined_line.push(line[line.length-2]); + parsedData[line[2]] = joined_line; + } + + return parsedData; +} + + class CinnamonPrintersApplet extends Applet.TextIconApplet { constructor(metadata, orientation, panel_height, instance_id) { super(orientation, panel_height, instance_id); @@ -137,7 +158,7 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { } onSendToFrontClicked(item) { - Util.spawn(['lp', '-i', item.job, '-q 100']); + Util.spawn(['lp', '-i', item.job, '-H', 'immediate']); } update() { @@ -195,25 +216,24 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { out = out.split(/\n/); this.jobsCount = out.length - 1; Util.spawn_async(['/usr/bin/lpq', '-a'], Lang.bind(this, function(out2) { - out2 = out2.replace(/\n/g, ' ').split(/\s+/); + let jobInfo = parseLpq(out2); let sendJobs = []; for(var n = 0; n < out.length - 1; n++) { let line = out[n].split(' ')[0].split('-'); let job = line.slice(-1)[0]; let printer = line.slice(0, -1).join('-'); - let doc = out2[out2.indexOf(job) + 1]; - let user = out2[out2.indexOf(job) - 1]; - let size = formatBytes(out2[out2.indexOf(job) + 2]); + let doc = jobInfo[job][2]; + let user = jobInfo[job][1]; + let size = formatBytes(jobInfo[job][3]); + if(doc.length > 30) { doc = doc + '...'; } - out2[out2.indexOf(job) + 1] = "used"; - out2[out2.indexOf(job) + 2] = "used"; let text = '(' + job + ') ' + _("'%s' on %s").format(doc, printer); text = text + ' (' + size + ')' + _(" - by %s").format(user); let jobItem = new PopupMenu.PopupIconMenuItem(text, 'xsi-edit-delete', St.IconType.SYMBOLIC); - if(out2[out2.indexOf(job) - 2] == 'active') { + if(jobInfo[job][0] == 'active') { jobItem.addActor(new St.Icon({ style_class: 'popup-menu-icon', icon_name: 'xsi-printer-printing', icon_type: St.IconType.SYMBOLIC })); } else { jobItem.addActor(new St.Icon({ style_class: 'popup-menu-icon', icon_name: 'xsi-time', icon_type: St.IconType.SYMBOLIC })); @@ -222,7 +242,7 @@ class CinnamonPrintersApplet extends Applet.TextIconApplet { jobItem.connect('activate', Lang.bind(jobItem, this.onCancelJobClicked)); this.cancelSubMenu.addMenuItem(jobItem); this.jobs.push(jobItem); - if(out2[out2.indexOf(job) - 2] != 'active' && out2[out2.indexOf(job) - 2] != '1st') { + if(jobInfo[job][0] != 'active' && jobInfo[job][0] != '1st') { sendJobs.push(new PopupMenu.PopupIconMenuItem(text, 'xsi-go-up', St.IconType.SYMBOLIC)); sendJobs[sendJobs.length - 1].job = job; sendJobs[sendJobs.length - 1].connect('activate', Lang.bind(sendJobs[sendJobs.length - 1], this.onSendToFrontClicked));