Skip to content

Add native screensaver#13432

Merged
clefebvre merged 4 commits intolinuxmint:masterfrom
mtwebster:screensaver
Feb 24, 2026
Merged

Add native screensaver#13432
clefebvre merged 4 commits intolinuxmint:masterfrom
mtwebster:screensaver

Conversation

@mtwebster
Copy link
Member

@mtwebster mtwebster commented Jan 17, 2026

Implement a screensaver.

  • Functional in wayland or x11
  • Add a native 'away message' dialog
  • Unify 'switch-to-greeter' code from multiple sources
  • Add systemd/consolekit support for session states
  • Provide cinnamon-screensaver-command (still utilized by csd-
    power for pre-power-event activation).
  • Remove cinnamon-screensaver as a required session component.
  • Allow disabling of the internal screensaver to continue using
    cinnamon-screensaver.
  • Unify mpris code for the sound applet and albumArtWidget.js
  • Unify power code for the power applet and powerWidget.js

TODO:

  • Wallpaper in wayland sessions (postponed until there is layer-
    shell support in muffin).

Imported from cinnamon-screensaver:

  • PAM-related files, cinnamon-screensaver-pam-helper
  • cinnamon-screensaver-command and cinnamon-unlock-desktop: Both
    remain compatible with cinnamon-screensaver (> 6.7).

The screenShield actor contains all other related widgets like the
unlock dialog, and is placed in the new screenShieldGroup, the top-
most child of the global.stage.

Requires:
linuxmint/muffin#797
linuxmint/cinnamon-screensaver#491
linuxmint/cinnamon-settings-daemon#442

Backup locker info:

Add backup-locker support for screensaver.
Imported from cinnamon-screensaver, but improved...

  • Relies on dbus-activation now, which allows easier interaction
    between cinnamon and the locker process to coordinate grabs.
  • Add a simple dbus service to cinnamon-launcher, to allow restart
    from the backup locker (still falling back to tty instructions
    if the launcher isn't available).
  • Re-use event-grabber and event-filter from cinnamon-screensaver

The backup window spawns when the screensaver shows, and is placed
in global.top_window_group (where other override-redirect/POPUP-type
windows are placed automatically).

In the event of a crash/restart, the backup window will try to raise
itself to the top, and will continue to until Cinnamon restarts.

When Cinnamon restarts, if its stored state (gsettings) shows it
should be locked, it will negotiate the modal grab from the backup
locker, and immediately lock the screensaver again.

@mtwebster mtwebster changed the title Add native screensaver [WIP] Add native screensaver Jan 17, 2026
@mtwebster mtwebster requested a review from Copilot January 17, 2026 14:21

This comment was marked as outdated.

@mtwebster
Copy link
Member Author

/generate-test-packages

@github-actions
Copy link

Test packages generated successfully!

Download from the workflow run (available for 7 days).

@github-actions

This comment was marked as outdated.

@github-actions
Copy link

Pattern Check Results

Found 1 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.


Automated pattern check.

@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 1 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.


Automated pattern check.

1 similar comment
@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 1 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.


Automated pattern check.

@github-actions

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 13 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

js/ui/keybindings.js:381

Lang.bind(this, this.on_media_key_pressed, i),

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

⚠️ raw_mpris_dbus

js/misc/mprisPlayer.js:10

const MEDIA_PLAYER_2_NAME = "org.mpris.MediaPlayer2";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:11

const MEDIA_PLAYER_2_PLAYER_NAME = "org.mpris.MediaPlayer2.Player";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:37

this._mediaServer = null;       // org.mpris.MediaPlayer2

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:38

this._mediaServerPlayer = null; // org.mpris.MediaPlayer2.Player

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:111

let displayName = this._busName.replace('org.mpris.MediaPlayer2.', '');

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

⚠️ raw_screensaver_dbus

js/misc/screenSaver.js:35

* Implements the org.cinnamon.ScreenSaver DBus interface.

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:51

Gio.DBus.session.own_name('org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:60

global.log('ScreenSaverService: providing org.cinnamon.ScreenSaver interface');

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:136

g_name: 'org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

⚠️ sync_spawn_command_line

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Synchronous process spawning blocks the main loop.
Use GLib.spawn_command_line_async() or Gio.Subprocess instead.

ℹ️ shell_string_spawn

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Prefer argument vector spawn functions over shell command strings.
This is especially important when arguments include untrusted input (user data,
filenames, settings values, etc.) as shell strings are vulnerable to injection.
Static command strings are generally fine, but argv is always safer.
Use Util.spawn(["cmd", "arg1", "arg2"]) or Util.trySpawn() instead.


Automated pattern check.

2 similar comments
@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 13 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

js/ui/keybindings.js:381

Lang.bind(this, this.on_media_key_pressed, i),

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

⚠️ raw_mpris_dbus

js/misc/mprisPlayer.js:10

const MEDIA_PLAYER_2_NAME = "org.mpris.MediaPlayer2";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:11

const MEDIA_PLAYER_2_PLAYER_NAME = "org.mpris.MediaPlayer2.Player";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:37

this._mediaServer = null;       // org.mpris.MediaPlayer2

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:38

this._mediaServerPlayer = null; // org.mpris.MediaPlayer2.Player

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:111

let displayName = this._busName.replace('org.mpris.MediaPlayer2.', '');

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

⚠️ raw_screensaver_dbus

js/misc/screenSaver.js:35

* Implements the org.cinnamon.ScreenSaver DBus interface.

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:51

Gio.DBus.session.own_name('org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:60

global.log('ScreenSaverService: providing org.cinnamon.ScreenSaver interface');

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:136

g_name: 'org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

⚠️ sync_spawn_command_line

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Synchronous process spawning blocks the main loop.
Use GLib.spawn_command_line_async() or Gio.Subprocess instead.

ℹ️ shell_string_spawn

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Prefer argument vector spawn functions over shell command strings.
This is especially important when arguments include untrusted input (user data,
filenames, settings values, etc.) as shell strings are vulnerable to injection.
Static command strings are generally fine, but argv is always safer.
Use Util.spawn(["cmd", "arg1", "arg2"]) or Util.trySpawn() instead.


Automated pattern check.

@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 13 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

js/ui/keybindings.js:381

Lang.bind(this, this.on_media_key_pressed, i),

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

⚠️ raw_mpris_dbus

js/misc/mprisPlayer.js:10

const MEDIA_PLAYER_2_NAME = "org.mpris.MediaPlayer2";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:11

const MEDIA_PLAYER_2_PLAYER_NAME = "org.mpris.MediaPlayer2.Player";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:37

this._mediaServer = null;       // org.mpris.MediaPlayer2

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:38

this._mediaServerPlayer = null; // org.mpris.MediaPlayer2.Player

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:111

let displayName = this._busName.replace('org.mpris.MediaPlayer2.', '');

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

⚠️ raw_screensaver_dbus

js/misc/screenSaver.js:35

* Implements the org.cinnamon.ScreenSaver DBus interface.

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:51

Gio.DBus.session.own_name('org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:60

global.log('ScreenSaverService: providing org.cinnamon.ScreenSaver interface');

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:136

g_name: 'org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

⚠️ sync_spawn_command_line

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Synchronous process spawning blocks the main loop.
Use GLib.spawn_command_line_async() or Gio.Subprocess instead.

ℹ️ shell_string_spawn

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Prefer argument vector spawn functions over shell command strings.
This is especially important when arguments include untrusted input (user data,
filenames, settings values, etc.) as shell strings are vulnerable to injection.
Static command strings are generally fine, but argv is always safer.
Use Util.spawn(["cmd", "arg1", "arg2"]) or Util.trySpawn() instead.


Automated pattern check.

@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 13 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

js/ui/keybindings.js:381

Lang.bind(this, this.on_media_key_pressed, i),

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

⚠️ raw_mpris_dbus

js/misc/mprisPlayer.js:10

const MEDIA_PLAYER_2_NAME = "org.mpris.MediaPlayer2";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:11

const MEDIA_PLAYER_2_PLAYER_NAME = "org.mpris.MediaPlayer2.Player";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:37

this._mediaServer = null;       // org.mpris.MediaPlayer2

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:38

this._mediaServerPlayer = null; // org.mpris.MediaPlayer2.Player

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:111

let displayName = this._busName.replace('org.mpris.MediaPlayer2.', '');

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

⚠️ raw_screensaver_dbus

js/misc/screenSaver.js:35

* Implements the org.cinnamon.ScreenSaver DBus interface.

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:51

Gio.DBus.session.own_name('org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:60

global.log('ScreenSaverService: providing org.cinnamon.ScreenSaver interface');

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:136

g_name: 'org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

⚠️ sync_spawn_command_line

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Synchronous process spawning blocks the main loop.
Use GLib.spawn_command_line_async() or Gio.Subprocess instead.

ℹ️ shell_string_spawn

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Prefer argument vector spawn functions over shell command strings.
This is especially important when arguments include untrusted input (user data,
filenames, settings values, etc.) as shell strings are vulnerable to injection.
Static command strings are generally fine, but argv is always safer.
Use Util.spawn(["cmd", "arg1", "arg2"]) or Util.trySpawn() instead.


Automated pattern check.

1 similar comment
@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 13 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

js/ui/keybindings.js:381

Lang.bind(this, this.on_media_key_pressed, i),

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

⚠️ raw_mpris_dbus

js/misc/mprisPlayer.js:10

const MEDIA_PLAYER_2_NAME = "org.mpris.MediaPlayer2";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:11

const MEDIA_PLAYER_2_PLAYER_NAME = "org.mpris.MediaPlayer2.Player";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:37

this._mediaServer = null;       // org.mpris.MediaPlayer2

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:38

this._mediaServerPlayer = null; // org.mpris.MediaPlayer2.Player

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:111

let displayName = this._busName.replace('org.mpris.MediaPlayer2.', '');

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

⚠️ raw_screensaver_dbus

js/misc/screenSaver.js:35

* Implements the org.cinnamon.ScreenSaver DBus interface.

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:51

Gio.DBus.session.own_name('org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:60

global.log('ScreenSaverService: providing org.cinnamon.ScreenSaver interface');

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:136

g_name: 'org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

⚠️ sync_spawn_command_line

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Synchronous process spawning blocks the main loop.
Use GLib.spawn_command_line_async() or Gio.Subprocess instead.

ℹ️ shell_string_spawn

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Prefer argument vector spawn functions over shell command strings.
This is especially important when arguments include untrusted input (user data,
filenames, settings values, etc.) as shell strings are vulnerable to injection.
Static command strings are generally fine, but argv is always safer.
Use Util.spawn(["cmd", "arg1", "arg2"]) or Util.trySpawn() instead.


Automated pattern check.

- Functional in wayland or x11
- Add a native 'away message' dialog
- Unify 'switch-to-greeter' code from multiple sources
- Add systemd/consolekit support for session states
- Provide cinnamon-screensaver-command (still utilized by csd-
  power for pre-power-event activation).
- Remove cinnamon-screensaver as a required session component.
- Allow disabling of the internal screensaver to continue using
  cinnamon-screensaver.
- Unify mpris code for the sound applet and albumArtWidget.js
- Unify power code for the power applet and powerWidget.js

TODO:
- Wallpaper in wayland sessions (postponed until there is layer-
  shell support in muffin).

Imported from cinnamon-screensaver:
- PAM-related files, cinnamon-screensaver-pam-helper
- cinnamon-screensaver-command and cinnamon-unlock-desktop: Both
  remain compatible with cinnamon-screensaver (> 6.7).

The screenShield actor contains all other related widgets like the
unlock dialog, and is placed in the new screenShieldGroup, the top-
most child of the global.stage.

Requires:
linuxmint/muffin#797
linuxmint/cinnamon-screensaver#491
linuxmint/cinnamon-settings-daemon#442
Imported from cinnamon-screensaver, but improved...

- Relies on dbus-activation now, which allows easier interaction
  between cinnamon and the locker process to coordinate grabs.
- Add a simple dbus service to cinnamon-launcher, to allow restart
  from the backup locker (still falling back to tty instructions
  if the launcher isn't available).
- Re-use event-grabber and event-filter from cinnamon-screensaver

The backup window spawns when the screensaver shows, and is placed
in global.top_window_group (where other override-redirect/POPUP-type
windows are placed automatically).

In the event of a crash/restart, the backup window will try to raise
itself to the top, and will continue to until Cinnamon restarts.

When Cinnamon restarts, if its stored state (gsettings) shows it
should be locked, it will negotiate the modal grab from the backup
locker, and immediately lock the screensaver again.
@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 13 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

js/ui/keybindings.js:381

Lang.bind(this, this.on_media_key_pressed, i),

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

⚠️ raw_mpris_dbus

js/misc/mprisPlayer.js:10

const MEDIA_PLAYER_2_NAME = "org.mpris.MediaPlayer2";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:11

const MEDIA_PLAYER_2_PLAYER_NAME = "org.mpris.MediaPlayer2.Player";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:37

this._mediaServer = null;       // org.mpris.MediaPlayer2

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:38

this._mediaServerPlayer = null; // org.mpris.MediaPlayer2.Player

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:111

let displayName = this._busName.replace('org.mpris.MediaPlayer2.', '');

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

⚠️ raw_screensaver_dbus

js/misc/screenSaver.js:35

* Implements the org.cinnamon.ScreenSaver DBus interface.

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:51

Gio.DBus.session.own_name('org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:60

global.log('ScreenSaverService: providing org.cinnamon.ScreenSaver interface');

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:136

g_name: 'org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

⚠️ sync_spawn_command_line

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Synchronous process spawning blocks the main loop.
Use GLib.spawn_command_line_async() or Gio.Subprocess instead.

ℹ️ shell_string_spawn

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Prefer argument vector spawn functions over shell command strings.
This is especially important when arguments include untrusted input (user data,
filenames, settings values, etc.) as shell strings are vulnerable to injection.
Static command strings are generally fine, but argv is always safer.
Use Util.spawn(["cmd", "arg1", "arg2"]) or Util.trySpawn() instead.


Automated pattern check.

@github-actions
Copy link

Best-practices scanner

This is a regex-based check for API usage that can pose security, performance or
maintainability issues, or that may already be provided by Cinnamon. Having code flagged
by it doesn't automatically disqualify a pull request.

This check is not perfect will not replace a normal review.


Found 13 potential issue(s):

⚠️ lang_bind

files/usr/share/cinnamon/applets/user@cinnamon.org/applet.js:87

item.connect('activate', Lang.bind(this, function() {

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

js/ui/keybindings.js:381

Lang.bind(this, this.on_media_key_pressed, i),

Lang.bind() is deprecated. Use arrow functions (() => {}) or Function.prototype.bind() instead.

⚠️ raw_mpris_dbus

js/misc/mprisPlayer.js:10

const MEDIA_PLAYER_2_NAME = "org.mpris.MediaPlayer2";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:11

const MEDIA_PLAYER_2_PLAYER_NAME = "org.mpris.MediaPlayer2.Player";

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:37

this._mediaServer = null;       // org.mpris.MediaPlayer2

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:38

this._mediaServerPlayer = null; // org.mpris.MediaPlayer2.Player

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

js/misc/mprisPlayer.js:111

let displayName = this._busName.replace('org.mpris.MediaPlayer2.', '');

Use imports.misc.interfaces.getDBusProxyWithOwner("org.mpris.MediaPlayer2", owner)
or imports.misc.mprisPlayer.getMprisPlayerManager() for a higher-level API.

⚠️ raw_screensaver_dbus

js/misc/screenSaver.js:35

* Implements the org.cinnamon.ScreenSaver DBus interface.

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:48

Gio.DBus.session.own_name('org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:57

global.log('ScreenSaverService: providing org.cinnamon.ScreenSaver interface');

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

js/misc/screenSaver.js:133

g_name: 'org.cinnamon.ScreenSaver',

Use imports.misc.screenSaver.ScreenSaverProxy() instead of creating a raw DBus proxy.

⚠️ sync_spawn_command_line

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Synchronous process spawning blocks the main loop.
Use GLib.spawn_command_line_async() or Gio.Subprocess instead.

ℹ️ shell_string_spawn

js/misc/util.js:839

let [success, stdout] = GLib.spawn_command_line_sync('pidof ' + name);

Prefer argument vector spawn functions over shell command strings.
This is especially important when arguments include untrusted input (user data,
filenames, settings values, etc.) as shell strings are vulnerable to injection.
Static command strings are generally fine, but argv is always safer.
Use Util.spawn(["cmd", "arg1", "arg2"]) or Util.trySpawn() instead.


Automated pattern check.

@clefebvre clefebvre merged commit 3eca438 into linuxmint:master Feb 24, 2026
2 of 5 checks passed
fredcw added a commit to fredcw/cinnamon that referenced this pull request Feb 25, 2026
"Uninstall" calls cinnamon-remove-application, a simple mint only script. Replace with "App Info" to open mintinstall or pamac-manager on the app details page so user can view an app's details and optionally uninstall using the OS's software manager.

Revert "userWidget.js: Fix updating the image when the user avatar changes."

This reverts commit 347c39c.

The texture cache properly drops the image when the underlying file
changes, but the theme context itself has created its own cogl
resource and caches it also. We can monitor the texture cache there.

st-theme-context.c: Hook up texture cache's texture-file-changed
signal and invalidate any theme nodes using the passed file.

If the underlying file contents changed, this forces a reload of
the background/border image.

main.js: Fix enum in _stageEventHandler.

This is needed as a result of an introspection fix in muffin:
linuxmint/muffin@7453e8de7689934

power_applet: rearrange battery label, so the percentage is on left (linuxmint#13262)

old: <battery logo> <battery name> <percentage>
new: <battery logo> <percentage>\t<battery name>

Co-authored-by: Mohamed A. Elmeligy <mohamed.a.elmeligy@protonmail.com>

theme: Add a couple of generic button styles (linuxmint#13319)

cinnamon-desktop-editor.py: Add import path.

Since 0344b11, cinnamon-menu-editor crashes at startup
when it imports JsonSettingsWidgets.

cinnamon-settings: Make imports consistent, instead of a mix of
absolute and relative throughout.

ref: 6d15343, 0344b11

messageTray.js: Fix cursor name.

ref: 03e9990

endSessionDialog.js: Don't close the dialog immediately when
selecting 'suspend' or 'hibernate'.

This was preventing the session manager from responding with an
inhibitor list and giving the user the option to ignore them and
'force' the action, as happens correctly with other options. It
was also breaking the lifecycle of this dialog and disable it
from showing again.

Also fix an issue with the inhibitor list not clearing existing
items when receiving an updated list from the session manager.

Fixes linuxmint/cinnamon-session#193.

ui: Add a new placeholder object (linuxmint#13304)

Gives a simple reusable object to show when no active items are available.
Make use of this new object in menu@cinnamon.org when the recent and favorite
categories are empty.

panel.js: Remove the panel corners implementation (linuxmint#13487)

This isn't used by anything and adds a lot of extra code complexity.

st-button: Add an :icon-name property (linuxmint#13491)

Adds a convenient way to create an icon only button

hotcorner.js: Port to GObject and ripples.js (linuxmint#13544)

We have had the ripples code duplicated for quite some time. Remove the
duplicate code from here.

Port to the hotcorners to GObject and clean up some variable naming and
code styling.

keybindings.js: Allow auto-repeat only on certain media keybindings.

Use a new Meta.Display.add_custom_keybinding_full() to be able to
specify Meta.KeyBindingFlags. The default flag via the old method
was NONE, which enabled autorepeat for all keybindings. Make the
new default IGNORE_AUTOREPEAT, with the exception of certain media
keybindings.

Xlet keybindings can make use of these flags with an extra argument
in addXletHotKey() if they want to re-enable autorepeat.

ref: linuxmint/muffin@baf3c23992b.

menu@cinnamon.org: hide sidebar config options when sidebar is hidden (linuxmint#13323)

menu: Add context menu actions for favorites/recents (linuxmint#13220)

* menu: Add context menu actions for favorites/recents

Add `Remove from favorites` and `Open containing folder` action for favorites/recents.

* menu: Add fallback action for the `Open containing folder`

FIX: Disable "Disable all" button when no extensions installed (linuxmint#13455)

Fixes issue where the "Disable all" button in Extensions settings
remained enabled even when no extensions were installed.

The button state is now correctly updated in update_button_states()
to check if extension_rows is empty, and load_extensions() calls
update_button_states() to ensure proper initialization.

Fixes: linuxmint#13021

Fix wrong attribute and method name usage (linuxmint#13515)

checkBox.js: Use the new checkBox object (linuxmint#13564)

Remove all the old checkbox code and move to the use of the new one. Removes
a use of CinnamonGenericContainer. This is hardly used in any spices so
shouldn't have many side effects. Most themes should also just work.

style: Add a slight blue tint to the theme (linuxmint#13568)

Many themes use this styling. Since people installing Cinnamon outside of
will likely be using Adwaita or a something similar, tint the default theme
a slight blue to fit in better with these other themes.

Separator cleanup (linuxmint#13573)

* separator.js: Convert to GObject

We only had one user of this in Cinnamon's codebase. Should be a pretty easy
fix for any spice that uses it. Also removes the use of Lang.bind()

* popupmenu.js: Use the standalone separator object

We are duplicating the code for drawing the separator in object in menus for
no real reason. Just use the the standalone separtor object instead.

backgroundManager.js: Fix variable names and remove uses of Lang.bind() (linuxmint#13574)

Remove the edgeFlip feature (linuxmint#13581)

This has been unused for years. Go ahead and remove it.

radioButton.js: Modernize and clean up unused object (linuxmint#13567)

Port the radio button to GObject. Removes a use of CinnamonGenericContainer.
Nothing else in here seems to be used in either Cinnamon or any of the
spices. This removes the radio group but this could be modernized and brought
back if there is an actual call for it.

st-texture-cache.c: Fix st_texture_cache_load_image_from_file_async.

This was applying the scale factor to images even though in many
places it's used this was already being done by its caller. This
resulted in inconsistencies depending on how the returned actor
was used.

Remove the internal scaling and fix callers that were unknowingly
relying on this behavior.

cinnamonEntry: Modernize and clean up (linuxmint#13571)

Move to new style classes and remove all uses of Lang.bind. No functional
changes.

locatePointer: Fix and object name and cleanup (linuxmint#13585)

Properly case the LocatePointer object, remove usage of Lang.bind, and
clean up unused imports

Port Lightbox and Flashspot to GObject (linuxmint#13586)

The port requires renaming the show/hide methods of the Lightbox object.
Update several other things while at it. Use connectObject, clean up some
clutter deprecations, and use better comparison operators.

Lightbox isn't really used in any spices, so this shouldn't have any real
effect on them.

lookingGlass.js: Port the inspector to GObject (linuxmint#13589)

This allows us to get rid of another use CinnamonGenericContainer. No
functional changes

layout.js: Port all objects to classes (linuxmint#13590)

While at it, remove all uses of Lang.bind and make use of connectObject for
some of the signal tracking.

github: Add pattern-check workflow.

polkit: Show the reveal icon to reveal the password

The button should reflect its action, not the status of the entry.

This is better because:

- It's a button, it should reflect what it does.
- It aligns with the way this is done in other parts of Cinnamon,
slick-greeter, Mint tools and Firefox
- The default icon depicts an eye to reveal, that's an easier concept
to grasp than a hidden status with an icon representing the negation
of a simpler one.

keyboardManager.js: Ensure the drawing area fills its parent size
so the keyboard layout subscript can be drawn.

Regression from c25b61d.

Add native screensaver (linuxmint#13432)

* Implement a screensaver.

- Functional in wayland or x11
- Add a native 'away message' dialog
- Unify 'switch-to-greeter' code from multiple sources
- Add systemd/consolekit support for session states
- Provide cinnamon-screensaver-command (still utilized by csd-
  power for pre-power-event activation).
- Remove cinnamon-screensaver as a required session component.
- Allow disabling of the internal screensaver to continue using
  cinnamon-screensaver.
- Unify mpris code for the sound applet and albumArtWidget.js
- Unify power code for the power applet and powerWidget.js

TODO:
- Wallpaper in wayland sessions (postponed until there is layer-
  shell support in muffin).

Imported from cinnamon-screensaver:
- PAM-related files, cinnamon-screensaver-pam-helper
- cinnamon-screensaver-command and cinnamon-unlock-desktop: Both
  remain compatible with cinnamon-screensaver (> 6.7).

The screenShield actor contains all other related widgets like the
unlock dialog, and is placed in the new screenShieldGroup, the top-
most child of the global.stage.

Requires:
linuxmint/muffin#797
linuxmint/cinnamon-screensaver#491
linuxmint/cinnamon-settings-daemon#442

* Add backup-locker support for screensaver.

Imported from cinnamon-screensaver, but improved...

- Relies on dbus-activation now, which allows easier interaction
  between cinnamon and the locker process to coordinate grabs.
- Add a simple dbus service to cinnamon-launcher, to allow restart
  from the backup locker (still falling back to tty instructions
  if the launcher isn't available).
- Re-use event-grabber and event-filter from cinnamon-screensaver

The backup window spawns when the screensaver shows, and is placed
in global.top_window_group (where other override-redirect/POPUP-type
windows are placed automatically).

In the event of a crash/restart, the backup window will try to raise
itself to the top, and will continue to until Cinnamon restarts.

When Cinnamon restarts, if its stored state (gsettings) shows it
should be locked, it will negotiate the modal grab from the backup
locker, and immediately lock the screensaver again.

* debian/control: Add Breaks/Replaces cinnamon-screensaver.

* Restrict access to screenShield instance and screensaver service.

unlockDialog, authClient: remove unnecessary import.

cinnamon-screen.c: Update warnings.

main.js: Only allow the internal screensaver for wayland sessions.

extensions: Simplify code used for loading xlets, improve startup (linuxmint#13479)

speed, fix backtrace uselessness.

- Drop 'custom' importer code, use native cjs importer
- Leave compatibility functions for require() and module.exports

Fixes/improves:
- Faster Cinnamon startup (for my random configuration, ~1550ms down
  to ~1200ms).
- Improved logging.
- More consistent code (use of deprecated features will start getting
  flagged and/or blocked for PRs in Cinnamon and spice repositories.
- Previous code was practically unmaintainable by sane people.

Logging - where before we'd see this useless garbage:

(cinnamon:4334): St-CRITICAL **: 22:19:57.081: st_widget_get_theme_node called on the widget [0x622f6579b3c0 StLabel.hourly-data ("...")] which is not in the stage.
== Stack trace for context 0x622f63105b50 ==
0   7ffd484001c0 b   /usr/share/cinnamon/js/misc/fileUtils.js line 211 > Function:19086 (359f8e6c9c0 @ 279)
1   622f632b5d08 i   /usr/share/cinnamon/js/misc/fileUtils.js line 211 > Function:19059 (359f8e6c970 @ 23)
2   7ffd48400ca0 b   /usr/share/cinnamon/js/misc/fileUtils.js line 211 > Function:18976 (359f8e6c6a0 @ 807)
3   622f632b5b68 i   /usr/share/cinnamon/js/misc/fileUtils.js line 211 > Function:19550 (359f8e6d650 @ 104)
4   622f632b5ab8 i   /usr/share/cinnamon/js/misc/fileUtils.js line 211 > Function:19842 (359f8e6e2e0 @ 681)
5   622f632b5a08 i   self-hosted:1461 (1eb5245b46f0 @ 30)
6   7ffd484015a0 b   self-hosted:852 (359f8e92dd0 @ 15)

we now get:

(cinnamon:4334): St-CRITICAL **: 22:20:36.263: st_widget_get_theme_node called on the widget [0x58cf71ab5180 StLabel.hourly-data ("...")] which is not in the stage.
== Stack trace for context 0x58cf6ee74250 ==
0   7fffae294e10 b   /home/mtwebster/.local/share/cinnamon/applets/weather@mockturtl/3.8/weather-applet.js:19084 (387d8e1fd1a0 @ 279)
1   58cf6eeac1f8 i   /home/mtwebster/.local/share/cinnamon/applets/weather@mockturtl/3.8/weather-applet.js:19057 (387d8e1fd150 @ 23)
2   7fffae2958f0 b   /home/mtwebster/.local/share/cinnamon/applets/weather@mockturtl/3.8/weather-applet.js:18974 (387d8e1fce20 @ 807)
3   58cf6eeac058 i   /home/mtwebster/.local/share/cinnamon/applets/weather@mockturtl/3.8/weather-applet.js:19548 (387d8e1fddd0 @ 104)
4   58cf6eeabfa8 i   /home/mtwebster/.local/share/cinnamon/applets/weather@mockturtl/3.8/weather-applet.js:19840 (387d8e1fea60 @ 681)
5   58cf6eeabef8 i   self-hosted:1461 (2daaca0bf470 @ 30)
6   7fffae2961f0 b   self-hosted:852 (e85adf8c6a0 @ 15)

Requires linuxmint/cjs#136 for xlet 'reload'
functionality to work.

popupMenu.js: Fix copy/paste error from 731d2f7.
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.

3 participants