Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package cinnamon-screensaver for
openSUSE:Factory checked in at 2026-03-26 21:08:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/cinnamon-screensaver (Old)
and /work/SRC/openSUSE:Factory/.cinnamon-screensaver.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cinnamon-screensaver"
Thu Mar 26 21:08:23 2026 rev:32 rq:1342644 version:6.6.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/cinnamon-screensaver/cinnamon-screensaver.changes
2025-01-20 17:15:05.363466072 +0100
+++
/work/SRC/openSUSE:Factory/.cinnamon-screensaver.new.8177/cinnamon-screensaver.changes
2026-03-27 06:37:47.437004693 +0100
@@ -1,0 +2,13 @@
+Wed Mar 25 23:09:23 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 6.6.1:
+ * Make Caribou dependency optional (#489)
+ * Handle layout switching thru cinnamon, remove use of XApp.
+ * Switch to xapp-symbolic-icons (XSI)
+ * Refactor positioning of floating UI elements.
+ * unlock: Remove additional dimming when unlock dialog is
+ shown.
+ * unlock.py: Don't show password entry and unlock button until
+ prompted by pam.
+
+-------------------------------------------------------------------
Old:
----
cinnamon-screensaver-6.4.0.tar.gz
New:
----
cinnamon-screensaver-6.6.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ cinnamon-screensaver.spec ++++++
--- /var/tmp/diff_new_pack.2WiEGr/_old 2026-03-27 06:37:47.913024312 +0100
+++ /var/tmp/diff_new_pack.2WiEGr/_new 2026-03-27 06:37:47.917024477 +0100
@@ -1,7 +1,7 @@
#
# spec file for package cinnamon-screensaver
#
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%define appid org.cinnamon.ScreenSaver
Name: cinnamon-screensaver
-Version: 6.4.0
+Version: 6.6.1
Release: 0
Summary: Cinnamon screensaver and locker
License: GPL-2.0-or-later
++++++ cinnamon-screensaver-6.4.0.tar.gz -> cinnamon-screensaver-6.6.1.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/debian/changelog
new/cinnamon-screensaver-6.6.1/debian/changelog
--- old/cinnamon-screensaver-6.4.0/debian/changelog 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/debian/changelog 2025-12-16
16:27:23.000000000 +0100
@@ -1,3 +1,29 @@
+cinnamon-screensaver (6.6.1) zena; urgency=medium
+
+ [ Balló György ]
+ * Make Caribou dependency optional (#489)
+
+ -- Clement Lefebvre <[email protected]> Tue, 16 Dec 2025 15:27:17 +0000
+
+cinnamon-screensaver (6.6.0) zena; urgency=medium
+
+ [ Michael Webster ]
+ * Handle layout switching thru cinnamon, remove use of XApp. (#477)
+
+ [ Clement Lefebvre ]
+ * Switch to xapp-symbolic-icons (XSI)
+
+ -- Clement Lefebvre <[email protected]> Tue, 25 Nov 2025 14:16:46 +0000
+
+cinnamon-screensaver (6.4.1) zara; urgency=medium
+
+ [ Michael Webster ]
+ * Refactor positioning of floating UI elements.
+ * unlock: Remove additional dimming when unlock dialog is shown.
+ * unlock.py: Don't show password entry and unlock button until prompted by
pam.
+
+ -- Clement Lefebvre <[email protected]> Tue, 05 Aug 2025 09:50:45 +0200
+
cinnamon-screensaver (6.4.0) xia; urgency=medium
[ Michael Webster ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/debian/control
new/cinnamon-screensaver-6.6.1/debian/control
--- old/cinnamon-screensaver-6.4.0/debian/control 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/debian/control 2025-12-16
16:27:23.000000000 +0100
@@ -34,7 +34,6 @@
gir1.2-gobject-2.0,
gir1.2-gtk-3.0,
gir1.2-pango-1.0,
- gir1.2-xapp-1.0,
iso-flag-png,
libxdo3,
python3,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/meson.build
new/cinnamon-screensaver-6.6.1/meson.build
--- old/cinnamon-screensaver-6.4.0/meson.build 2024-11-26 14:51:33.000000000
+0100
+++ new/cinnamon-screensaver-6.6.1/meson.build 2025-12-16 16:27:23.000000000
+0100
@@ -1,4 +1,4 @@
-project('cinnamon-screensaver', 'c', version : '6.4.0', meson_version :
'>=0.56.0')
+project('cinnamon-screensaver', 'c', version : '6.6.1', meson_version :
'>=0.56.0')
cc = meson.get_compiler('c')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/albumArt.py
new/cinnamon-screensaver-6.6.1/src/albumArt.py
--- old/cinnamon-screensaver-6.4.0/src/albumArt.py 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/albumArt.py 2025-12-16
16:27:23.000000000 +0100
@@ -21,10 +21,9 @@
using a timer which randomizes its halign and valign properties
as well as its current monitor.
"""
- def __init__(self, away_message=None, initial_monitor=0):
- super(AlbumArt, self).__init__(initial_monitor)
+ def __init__(self, initial_monitor=0, low_res=False):
+ super(AlbumArt, self).__init__(initial_monitor, Gtk.Align.END,
Gtk.Align.CENTER)
self.get_style_context().add_class("albumart")
- self.set_halign(Gtk.Align.END)
if not settings.get_show_albumart():
return
@@ -34,7 +33,7 @@
self.current_url = None
- self.image = FramedImage(status.screen.get_low_res_mode(),
scale_up=True)
+ self.image = FramedImage(low_res, scale_up=True)
self.image.show()
self.image.set_opacity(0.0)
self.add(self.image)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/cinnamon-screensaver-6.4.0/src/cinnamon-screensaver.css
new/cinnamon-screensaver-6.6.1/src/cinnamon-screensaver.css
--- old/cinnamon-screensaver-6.4.0/src/cinnamon-screensaver.css 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/cinnamon-screensaver.css 2025-12-16
16:27:23.000000000 +0100
@@ -69,7 +69,7 @@
border-style: solid;
color: white;
background-image: none;
- background-color: transparent;
+ background-color: rgba(0, 0, 0, .6);
border-image: none;
border-width: 1px;
box-shadow: none;
@@ -88,7 +88,7 @@
}
.csstage .passwordentry image.left {
- padding-right: 10px;
+ padding-right: 14px;
}
/* Use :backdrop for alt-text keyboard layout */
@@ -104,7 +104,7 @@
border-image: none;
box-shadow: none;
background-image: none;
- background-color: transparent;
+ background-color: rgba(0, 0, 0, .6);
border-radius: 20px;
-gtk-outline-radius: 20px;
outline-color: transparent;
@@ -123,7 +123,6 @@
.csstage .passwordentry:focus,
.csstage .transparentbutton:focus {
- background-color: alpha(grey, .3);
border-color: @theme_selected_bg_color;
box-shadow: 1px 1px alpha(white, 0.1);
}
@@ -138,21 +137,18 @@
.csstage .passwordentry:hover:focus,
.csstage .transparentbutton:hover:focus {
border-color: @theme_selected_bg_color;
- background-color: alpha(grey, .4);
box-shadow: 1px 1px alpha(white, 0.1);
}
.csstage .passwordentry:active,
.csstage .transparentbutton:active {
border-color: @theme_selected_bg_color;
- background-color: alpha(grey, .6);
box-shadow: 1px 1px alpha(white, 0.1);
}
.csstage .passwordentry:active:focus,
.csstage .transparentbutton:active:focus {
border-color: @theme_selected_bg_color;
- background-color: alpha(grey, .9);
box-shadow: 1px 1px alpha(white, 0.1);
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/clock.py
new/cinnamon-screensaver-6.6.1/src/clock.py
--- old/cinnamon-screensaver-6.4.0/src/clock.py 2024-11-26 14:51:33.000000000
+0100
+++ new/cinnamon-screensaver-6.6.1/src/clock.py 2025-12-16 16:27:23.000000000
+0100
@@ -21,10 +21,8 @@
as well as its current monitor.
"""
def __init__(self, away_message=None, initial_monitor=0, low_res=False):
- super(ClockWidget, self).__init__(initial_monitor)
+ super(ClockWidget, self).__init__(initial_monitor, Gtk.Align.START,
Gtk.Align.CENTER)
self.get_style_context().add_class("clock")
- self.set_halign(Gtk.Align.START)
-
self.set_property("margin", 6)
self.clock = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/cinnamon-screensaver-6.4.0/src/dbusdepot/cinnamonClient.py
new/cinnamon-screensaver-6.6.1/src/dbusdepot/cinnamonClient.py
--- old/cinnamon-screensaver-6.4.0/src/dbusdepot/cinnamonClient.py
2024-11-26 14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/dbusdepot/cinnamonClient.py
2025-12-16 16:27:23.000000000 +0100
@@ -1,27 +1,98 @@
#!/usr/bin/python3
-from gi.repository import Gio, CScreensaver
+from gi.repository import Gio, CScreensaver, GObject
from dbusdepot.baseClient import BaseClient
+from util import trackers
+
+# see cinnamon/files/usr/share/cinnamon/cinnamon-settings/bin/InputSources.py
+class CurrentInputSource:
+ def __init__(self, source):
+ self.type, self.id, self.index, \
+ self.display_name, self.short_name, \
+ self.flag_name, self.xkbid, \
+ self.xkb_layout, self.xkb_variant, \
+ self.preferences, \
+ self.dupe_id, self.active \
+ = source
class CinnamonClient(BaseClient):
"""
- Simple client to talk to Cinnamon's dbus interface. Currently
- its only use is for attempting to force an exit from overview
- and expo mode (both of which do a fullscreen grab and would prevent
- the screensaver from acquiring one.)
+ Client to talk to Cinnamon's dbus interface.
+
+ Used to deactivate special modal cinnamon states and deal with
+ keyboard layout info.
"""
CINNAMON_SERVICE = "org.Cinnamon"
CINNAMON_PATH = "/org/Cinnamon"
-
+ __gsignals__ = {
+ 'current-input-source-changed': (GObject.SignalFlags.RUN_LAST, None,
()),
+ 'input-sources-changed': (GObject.SignalFlags.RUN_LAST, None, ())
+ }
def __init__(self):
super(CinnamonClient, self).__init__(Gio.BusType.SESSION,
CScreensaver.CinnamonProxy,
self.CINNAMON_SERVICE,
self.CINNAMON_PATH)
+ self.sources = []
def on_client_setup_complete(self):
- pass
+ trackers.con_tracker_get().connect(self.proxy, "g-signal",
self.on_cinnamon_signal)
+ self.update_layout_sources()
+
+ def on_cinnamon_signal(self, proxy, sender, signal, params, data=None):
+ if signal == "CurrentInputSourceChanged":
+ self.update_current_layout(params[0])
+ elif signal == "InputSourcesChanged":
+ self.update_layout_sources()
+
+ def update_layout_sources(self):
+
self.proxy.GetInputSources(result_handler=self.get_input_sources_callback,
+ error_handler=self.get_input_sources_error)
+
+ def get_input_sources_callback(self, proxy, sources, data=None):
+ self.sources = []
+
+ for source in sources:
+ input_source = CurrentInputSource(source)
+ if input_source.type == "xkb":
+ self.sources.append(input_source)
+ self.emit("input-sources-changed")
+
+ def get_input_sources_error(self, proxy, error, data=None):
+ print("Failed to get keyboard layouts from Cinnamon - multiple layouts
will not be available: %s" % error.message)
+
+ def has_multiple_keyboard_layouts(self):
+ return len(self.sources) > 1
+
+ def update_current_layout(self, layout):
+ for source in self.sources:
+ source.active = source.id == layout
+ self.emit("current-input-source-changed")
+
+ def get_current_layout_source(self):
+ for source in self.sources:
+ if source.active:
+ return source
+ return None
+
+ def activate_layout_index(self, index):
+ self.proxy.ActivateInputSourceIndex("(i)", index)
+
+ def activate_next_layout(self):
+ current = 0
+
+ for i in range(0, len(self.sources)):
+ source = self.sources[i]
+ if source.active:
+ current = i
+ break
+
+ new = current + 1
+ if new > len(self.sources) - 1:
+ new = 0
+
+ self.proxy.ActivateInputSourceIndex("(i)", self.sources[new].index)
def exit_expo_and_overview(self):
if self.ensure_proxy_alive():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/floating.py
new/cinnamon-screensaver-6.6.1/src/floating.py
--- old/cinnamon-screensaver-6.4.0/src/floating.py 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/floating.py 2025-12-16
16:27:23.000000000 +0100
@@ -7,52 +7,32 @@
from util import trackers
from util import settings
-POSITIONING_TIMEOUT = 30
-ALIGNMENTS = [int(Gtk.Align.START), int(Gtk.Align.END), int(Gtk.Align.CENTER)]
+class PositionInfo():
+ def __init__(self, monitor, halign, valign):
+ self.monitor = monitor
+ self.halign = halign
+ self.valign = valign
class Floating:
- def __init__(self, initial_monitor=0):
+ def __init__(self, initial_monitor=0, halign=Gtk.Align.CENTER,
valign=Gtk.Align.CENTER):
super(Floating, self).__init__()
- self.set_halign(Gtk.Align.CENTER)
- self.set_valign(Gtk.Align.CENTER)
+ self.awake_position = PositionInfo(initial_monitor, halign, valign)
+ self.next_position = self.awake_position
self.current_monitor = initial_monitor
+ self.apply_next_position()
def start_positioning(self):
+ self.apply_next_position()
self.show()
- if settings.get_allow_floating():
- trackers.timer_tracker_get().cancel(str(self) + "positioning")
- trackers.timer_tracker_get().start_seconds(str(self) +
"positioning",
- POSITIONING_TIMEOUT,
-
self.positioning_callback)
- def stop_positioning(self):
- if settings.get_allow_floating():
- trackers.timer_tracker_get().cancel(str(self) + "positioning")
+ def set_next_position(self, monitor, halign, valign):
+ self.next_position = PositionInfo(monitor, halign, valign)
- def positioning_callback(self):
- current_halign = int(self.get_halign())
- horizontal = current_halign
-
- current_valign = int(self.get_valign())
- vertical = current_valign
-
- while horizontal == current_halign:
- horizontal = ALIGNMENTS[random.randint(0, 2)]
- while vertical == current_valign:
- vertical = ALIGNMENTS[random.randint(0, 2)]
-
- self.set_halign(Gtk.Align(horizontal))
- self.set_valign(Gtk.Align(vertical))
-
- if status.screen.get_n_monitors() > 1:
- new_monitor = self.current_monitor
- n = status.screen.get_n_monitors()
-
- while new_monitor == self.current_monitor:
- new_monitor = random.randint(0, n - 1)
-
- self.current_monitor = new_monitor
-
- self.queue_resize()
-
- return True
+ def apply_next_position(self):
+ self.current_monitor = self.next_position.monitor
+ self.set_halign(self.next_position.halign)
+ self.set_valign(self.next_position.valign)
+
+ def set_awake_position(self, monitor):
+ self.awake_position.monitor = monitor
+ self.next_position = self.awake_position
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/monitorView.py
new/cinnamon-screensaver-6.6.1/src/monitorView.py
--- old/cinnamon-screensaver-6.4.0/src/monitorView.py 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/monitorView.py 2025-12-16
16:27:23.000000000 +0100
@@ -69,21 +69,8 @@
significant gradient vertically framing the unlock dialog
when Awake.
"""
- if not status.Awake:
- cr.set_source_rgba(0.0, 0.0, 0.0, 0.7)
- cr.paint()
- return False
-
- r = widget.get_allocation()
-
- pattern = cairo.LinearGradient(0, 0, 0, r.height)
- pattern.add_color_stop_rgba (0, 0, 0, 0, .75)
- pattern.add_color_stop_rgba (.35, 0, 0, 0, .9)
- pattern.add_color_stop_rgba (.65, 0, 0, 0, .9)
- pattern.add_color_stop_rgba (1, 0, 0, 0, .75)
- cr.set_source(pattern)
+ cr.set_source_rgba(0.0, 0.0, 0.0, 0.7)
cr.paint()
-
return False
class MonitorView(BaseWindow):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/osk.py
new/cinnamon-screensaver-6.6.1/src/osk.py
--- old/cinnamon-screensaver-6.4.0/src/osk.py 2024-11-26 14:51:33.000000000
+0100
+++ new/cinnamon-screensaver-6.6.1/src/osk.py 2025-12-16 16:27:23.000000000
+0100
@@ -154,7 +154,7 @@
halign=Gtk.Align.CENTER,
valign=Gtk.Align.END)
- activate_button = TransparentButton("input-keyboard-symbolic",
Gtk.IconSize.LARGE_TOOLBAR)
+ activate_button = TransparentButton("xsi-input-keyboard-symbolic",
Gtk.IconSize.LARGE_TOOLBAR)
activate_button.connect("clicked", self.on_activate_button_clicked)
box.pack_start(activate_button, False, False, 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/passwordEntry.py
new/cinnamon-screensaver-6.6.1/src/passwordEntry.py
--- old/cinnamon-screensaver-6.4.0/src/passwordEntry.py 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/passwordEntry.py 2025-12-16
16:27:23.000000000 +0100
@@ -33,20 +33,13 @@
trackers.con_tracker_get().connect(self, "icon-press",
self.on_icon_pressed)
self.placeholder_text = placeholder_text
- self.current_icon_name = None
- self.current_flag_id = 0
- self.original_group = 0
-
- self.keyboard_controller = singletons.KeyboardLayoutController
- trackers.con_tracker_get().connect(self.keyboard_controller,
- "config-changed",
- self.on_config_changed)
-
- trackers.con_tracker_get().connect(self.keyboard_controller,
- "layout-changed",
- self.on_layout_changed)
+ self.lockscreen_layout_source = None
+ self.system_layout_source = None
- self.set_lockscreen_keyboard_layout()
+ self.cinnamon = singletons.CinnamonClient
+ self.cinnamon.connect("current-input-source-changed",
self.on_current_layout_changed)
+ self.cinnamon.connect("input-sources-changed",
self.on_layout_sources_changed)
+ self.on_layout_sources_changed(self.cinnamon)
trackers.con_tracker_get().connect(self,
"destroy",
@@ -59,9 +52,6 @@
update_layout_icon(), just so GtkEntry thinks there's an icon there,
that way it allocates space for it, and responds to clicks in the area.
"""
- if not self.keyboard_controller.get_enabled():
- return False
-
icon_rect = widget.get_icon_area(Gtk.EntryIconPosition.PRIMARY)
x = icon_rect.x
y = icon_rect.y + 2
@@ -69,15 +59,11 @@
height = icon_rect.height - 4
handled = False
-
if settings.get_show_flags():
- name = self.keyboard_controller.get_current_icon_name()
-
ui_scale = self.get_scale_factor()
- if name:
- filename = "/usr/share/iso-flag-png/%s.png" % name
-
+ if self.lockscreen_layout_source.flag_name != "":
+ filename = "/usr/share/iso-flag-png/%s.png" %
self.lockscreen_layout_source.flag_name
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(filename,
-1, height * ui_scale)
@@ -98,26 +84,37 @@
cr.paint()
- self.keyboard_controller.render_cairo_subscript(cr,
- render_x +
(logical_width / 2),
- render_y +
(logical_height / 2),
-
logical_width / 2,
-
logical_height / 2,
-
self.keyboard_controller.get_current_flag_id())
+ if self.lockscreen_layout_source.dupe_id > 0:
+ x = render_x + logical_width / 2
+ y = render_y + logical_height / 2
+ width = logical_width / 2 + 2
+ height = logical_height / 2 + 2
+
+ cr.set_source_rgba(0, 0, 0, 0.5)
+ cr.rectangle(x, y, width, height)
+ cr.fill()
+
+ cr.set_source_rgba(1.0, 1.0, 1.0, 0.8)
+ cr.rectangle(x + 1, y + 1, width - 2, height - 2)
+ cr.fill()
+
+ cr.set_source_rgba(0.0, 0.0, 0.0, 1.0)
+ cr.select_font_face("sans", cairo.FontSlant.NORMAL,
cairo.FontWeight.BOLD)
+ cr.set_font_size(height - 2.0)
+
+ dupe_str = str(self.lockscreen_layout_source.dupe_id)
+
+ ext = cr.text_extents(dupe_str)
+ cr.move_to((x + (width / 2.0) - (ext.width / 2.0)),
+ (y + (height / 2.0) + (ext.height / 2.0)))
+ cr.show_text(dupe_str)
handled = True
except GLib.Error:
pass
if not handled:
- if settings.get_use_layout_variant_names():
- name = self.keyboard_controller.get_current_variant_label()
- else:
- name = self.keyboard_controller.get_current_short_group_label()
-
- if settings.get_show_upper_case_layout():
- name = name.upper()
-
+ name = self.lockscreen_layout_source.short_name
ctx = widget.get_style_context()
ctx.save()
@@ -167,16 +164,27 @@
self.progress_pulse()
return True
- def on_layout_changed(self, controller, layout):
+ def on_current_layout_changed(self, cinnamon):
+ if not self.cinnamon.has_multiple_keyboard_layouts():
+ return
+
+ self.lockscreen_layout_source =
self.cinnamon.get_current_layout_source()
+
self.grab_focus()
self.update_layout_icon()
- def on_config_changed(self, controller):
+ def on_layout_sources_changed(self, cinnamon):
+ self.system_layout_source = self.cinnamon.get_current_layout_source()
+ self.lockscreen_layout_source = self.system_layout_source
+
+ if not self.cinnamon.has_multiple_keyboard_layouts():
+ return
+
self.set_lockscreen_keyboard_layout()
def on_icon_pressed(self, entry, icon_pos, event):
if icon_pos == Gtk.EntryIconPosition.PRIMARY:
- self.keyboard_controller.next_group()
+ self.cinnamon.activate_next_layout()
elif icon_pos == Gtk.EntryIconPosition.SECONDARY:
if self.get_input_purpose() == Gtk.InputPurpose.FREE_FORM:
self.set_visibility(False)
@@ -195,62 +203,46 @@
also ensures a redraw at the correct time to update the flag image.
"""
self.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY,
"screensaver-blank")
- self.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY,
self.keyboard_controller.get_current_name())
-
- self.update_saved_group(self.keyboard_controller.get_current_group())
+ self.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY,
self.lockscreen_layout_source.display_name)
def on_destroy(self, widget, data=None):
self.stop_progress()
- trackers.con_tracker_get().disconnect(self.keyboard_controller,
- "config-changed",
- self.on_config_changed)
-
- trackers.con_tracker_get().disconnect(self.keyboard_controller,
- "layout-changed",
- self.on_layout_changed)
-
self.restore_original_layout()
def set_lockscreen_keyboard_layout(self):
- if not self.keyboard_controller.get_enabled():
- return
-
# If there are multiple keyboard layouts, we want to store
# the one the user ends up using in the unlock widget, as they'll
# want to use the same one each time, at least until they change
# their password.
- saved_group = settings.get_kb_group()
- self.original_group = self.keyboard_controller.get_current_group()
+ saved_index = settings.get_kb_group()
+ new_index = 0
- new_group = 0
-
- if saved_group == -1:
- new_group = self.original_group
+ if saved_index == -1:
+ new_index = self.system_layout_source.index
+ settings.set_kb_group(new_index)
else:
- new_group = saved_group
+ new_index = saved_index
- self.keyboard_controller.set_current_group(new_group)
- self.update_saved_group(new_group)
- self.update_layout_icon()
+ if new_index != self.system_layout_source.index:
+ self.cinnamon.activate_layout_index(new_index)
- trackers.con_tracker_get().connect(self,
- "draw",
- self.on_draw)
+ self.update_layout_icon()
- def update_saved_group(self, group):
- settings.set_kb_group(group)
+ trackers.con_tracker_get().connect_after(self,
+ "draw",
+ self.on_draw)
def restore_original_layout(self):
"""
Called when the unlock dialog is destroyed, restores
the group that was active before the screensaver was activated.
"""
- if not self.keyboard_controller.get_enabled():
- return
+ if settings.get_kb_group() != self.lockscreen_layout_source.index:
+ settings.set_kb_group(self.lockscreen_layout_source.index)
- self.keyboard_controller.set_current_group(self.original_group)
+ self.cinnamon.activate_layout_index(self.system_layout_source.index)
def grab_focus(self):
Gtk.Widget.grab_focus(self)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/playerControl.py
new/cinnamon-screensaver-6.6.1/src/playerControl.py
--- old/cinnamon-screensaver-6.4.0/src/playerControl.py 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/playerControl.py 2025-12-16
16:27:23.000000000 +0100
@@ -40,7 +40,7 @@
vbox.pack_start(button_box, True, True, 0)
vbox.set_valign(Gtk.Align.CENTER)
- self.previous_button =
TransparentButton("media-skip-backward-symbolic", Gtk.IconSize.BUTTON)
+ self.previous_button =
TransparentButton("xsi-media-skip-backward-symbolic", Gtk.IconSize.BUTTON)
self.previous_button.show()
trackers.con_tracker_get().connect(self.previous_button,
"clicked",
@@ -55,7 +55,7 @@
self.on_play_pause_clicked)
button_box.pack_start(self.play_pause_button, True, True, 2)
- self.next_button = TransparentButton("media-skip-forward-symbolic",
Gtk.IconSize.BUTTON)
+ self.next_button =
TransparentButton("xsi-media-skip-forward-symbolic", Gtk.IconSize.BUTTON)
self.next_button.show()
trackers.con_tracker_get().connect(self.next_button,
"clicked",
@@ -111,9 +111,9 @@
def get_play_pause_icon_name(self, status):
if status == PlaybackStatus.Playing:
- icon_name = "media-playback-pause-symbolic"
+ icon_name = "xsi-media-playback-pause-symbolic"
else:
- icon_name = "media-playback-start-symbolic"
+ icon_name = "xsi-media-playback-start-symbolic"
return icon_name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/singletons.py
new/cinnamon-screensaver-6.6.1/src/singletons.py
--- old/cinnamon-screensaver-6.4.0/src/singletons.py 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/singletons.py 2025-12-16
16:27:23.000000000 +0100
@@ -48,12 +48,6 @@
Backgrounds.load_from_preferences(settings.bg_settings)
settings.bg_settings.connect("changed", lambda s,k:
Backgrounds.load_from_preferences(s))
-# We use XAppKbdLayoutController as a wrapper around libgnomekbd to supply the
icon theme
-# with icons, as well as providing correct group names.
-gi.require_version('XApp', '1.0')
-from gi.repository import XApp
-KeyboardLayoutController = XApp.KbdLayoutController()
-
# This sets up synchronously, as we need to know the fractional scaling state
before
# setting up the screensaver.
MuffinClient = _MuffinClient()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/stage.py
new/cinnamon-screensaver-6.6.1/src/stage.py
--- old/cinnamon-screensaver-6.4.0/src/stage.py 2024-11-26 14:51:33.000000000
+0100
+++ new/cinnamon-screensaver-6.6.1/src/stage.py 2025-12-16 16:27:23.000000000
+0100
@@ -9,18 +9,25 @@
import status
import constants as c
import singletons
+from floating import Floating
from monitorView import MonitorView
from unlock import UnlockDialog
from clock import ClockWidget
from albumArt import AlbumArt
from audioPanel import AudioPanel
from infoPanel import InfoPanel
-from osk import OnScreenKeyboard
-from floating import ALIGNMENTS
from util import utils, trackers, settings
from util.eventHandler import EventHandler
from util.utils import DEBUG
+try:
+ from osk import OnScreenKeyboard
+except Exception as e:
+ print("Failed to import on-screen keyboard: %s" % str(e))
+ OnScreenKeyboard = None
+
+FLOATER_POSITIONING_TIMEOUT = 30
+
class Stage(Gtk.Window):
"""
The Stage is the toplevel window of the entire screensaver while
@@ -75,6 +82,7 @@
self.osk = None
self.floaters = []
+ self.floaters_need_update = False
self.event_handler = EventHandler(manager)
@@ -272,10 +280,13 @@
print("Problem setting up clock widget: %s" % str(e))
self.clock_widget = None
- try:
- self.setup_osk()
- except Exception as e:
- print("Problem setting up on-screen keyboard: %s" % str(e))
+ if OnScreenKeyboard:
+ try:
+ self.setup_osk()
+ except Exception as e:
+ print("Problem setting up on-screen keyboard: %s" % str(e))
+ self.osk = None
+ else:
self.osk = None
trackers.timer_tracker_get().start("setup-delayed-components",
@@ -298,7 +309,28 @@
self.audio_panel = None
self.info_panel = None
+ self.start_float_timer()
+
+ def start_float_timer(self):
+ if settings.get_allow_floating():
+ if status.Debug:
+ timeout = 5
+ else:
+ timeout = FLOATER_POSITIONING_TIMEOUT
+ trackers.timer_tracker_get().start_seconds("floater-update",
timeout, self.update_floaters)
+
+ def update_floaters(self):
+ self.floaters_need_update = True
+ self.overlay.queue_allocate()
+ return GLib.SOURCE_CONTINUE
+
+ def stop_float_timer(self):
+ trackers.timer_tracker_get().cancel("floater-update")
+ self.floaters_need_update = False
+
def destroy_children(self):
+ self.stop_float_timer()
+
try:
self.destroy_monitor_views()
except Exception as e:
@@ -312,14 +344,12 @@
try:
if self.clock_widget is not None:
- self.clock_widget.stop_positioning()
self.clock_widget.destroy()
except Exception as e:
print(e)
try:
if self.albumart_widget is not None:
- self.albumart_widget.stop_positioning()
self.albumart_widget.destroy()
except Exception as e:
print(e)
@@ -496,7 +526,7 @@
Initially invisible, regardless - its visibility is controlled via its
own positioning timer.
"""
- self.albumart_widget = AlbumArt(None,
status.screen.get_mouse_monitor())
+ self.albumart_widget = AlbumArt(status.screen.get_mouse_monitor(),
status.screen.get_low_res_mode())
self.add_child_widget(self.albumart_widget)
self.floaters.append(self.albumart_widget)
@@ -644,21 +674,13 @@
utils.clear_clipboards(self.unlock_dialog)
- if self.clock_widget is not None:
- self.clock_widget.stop_positioning()
- if self.albumart_widget is not None:
- self.albumart_widget.stop_positioning()
+ self.stop_float_timer()
status.Awake = True
if self.info_panel:
self.info_panel.refresh_power_state()
- if self.clock_widget is not None:
- self.clock_widget.show()
- if self.albumart_widget is not None:
- self.albumart_widget.show()
-
self.unlock_dialog.show()
if self.audio_panel is not None:
@@ -677,10 +699,6 @@
if self.unlock_dialog is not None:
self.unlock_dialog.hide()
- if self.clock_widget is not None:
- self.clock_widget.hide()
- if self.albumart_widget is not None:
- self.albumart_widget.hide()
if self.audio_panel is not None:
self.audio_panel.hide()
if self.info_panel is not None:
@@ -691,6 +709,7 @@
status.Awake = False
self.update_monitor_views()
+ self.start_float_timer()
if self.info_panel is not None:
self.info_panel.refresh_power_state()
@@ -700,13 +719,6 @@
Updates all of our MonitorViews based on the power
or Awake states.
"""
-
- if not status.Awake:
- if self.clock_widget is not None and settings.get_show_clock():
- self.clock_widget.start_positioning()
- if self.albumart_widget is not None and
settings.get_show_albumart():
- self.albumart_widget.start_positioning()
-
for monitor in self.monitors:
monitor.show()
@@ -846,7 +858,7 @@
return True
- if isinstance(child, ClockWidget) or isinstance(child, AlbumArt):
+ if isinstance(child, Floating):
"""
ClockWidget and AlbumArt behave differently depending on if
status.Awake is True or not.
@@ -856,19 +868,36 @@
valign, and current monitor every so many seconds, calling a
queue_resize on itself after
each timer tick (which forces this function to run).
"""
- min_rect, nat_rect = child.get_preferred_size()
+ if settings.get_allow_floating():
+ if self.floaters_need_update:
+ alignments = [int(Gtk.Align.START), int(Gtk.Align.END),
int(Gtk.Align.CENTER)]
+ n_monitors = status.screen.get_n_monitors()
+ alignment_positions = []
+ for i in range(n_monitors):
+ for halign in alignments:
+ for valign in alignments:
+ alignment_positions.append((i, halign, valign))
- if status.Awake:
- current_monitor = status.screen.get_mouse_monitor()
- else:
- current_monitor = child.current_monitor
+ for floater in self.floaters:
+ position = alignment_positions.pop(random.randint(0,
len(alignment_positions) - 1))
+ floater.set_next_position(*position)
- monitor_rect = status.screen.get_monitor_geometry(current_monitor)
+ self.floaters_need_update = False
+ child.apply_next_position()
+
+ min_rect, nat_rect = child.get_preferred_size()
+ current_monitor = child.current_monitor
+ monitor_rect = status.screen.get_monitor_geometry(current_monitor)
region_w = monitor_rect.width / 3
- region_h = monitor_rect.height
+ region_h = monitor_rect.height / 3
if status.Awake:
+ current_monitor = status.screen.get_mouse_monitor()
+ monitor_rect =
status.screen.get_monitor_geometry(current_monitor)
+ region_w = monitor_rect.width / 3
+ region_h = monitor_rect.height / 3
+
"""
If we're Awake, force the clock to track to the active
monitor, and be aligned to
the left-center. The albumart widget aligns right-center.
@@ -882,38 +911,8 @@
if unlock_nw > region_w:
region_w = (monitor_rect.width - unlock_nw) / 2
- region_h = monitor_rect.height
-
- if isinstance(child, ClockWidget):
- child.set_halign(Gtk.Align.START)
- else:
- child.set_halign(Gtk.Align.END)
-
- child.set_valign(Gtk.Align.CENTER)
- else:
- if settings.get_allow_floating():
- for floater in self.floaters:
- """
- Don't let our floating widgets end up in the same spot.
- """
- if floater is child:
- continue
- if floater.get_halign() != child.get_halign() and
floater.get_valign() != child.get_valign():
- continue
-
- region_h = monitor_rect.height / 3
-
- fa = floater.get_halign()
- ca = child.get_halign()
- while fa == ca:
- ca = ALIGNMENTS[random.randint(0, 2)]
- child.set_halign(ca)
-
- fa = floater.get_valign()
- ca = child.get_valign()
- while fa == ca:
- ca = ALIGNMENTS[random.randint(0, 2)]
- child.set_valign(ca)
+ child.set_awake_position(current_monitor)
+ child.apply_next_position()
# Restrict the widget size to the allowable region sizes if
necessary.
allocation.width = min(nat_rect.width, region_w)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cinnamon-screensaver-6.4.0/src/unlock.py
new/cinnamon-screensaver-6.6.1/src/unlock.py
--- old/cinnamon-screensaver-6.4.0/src/unlock.py 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/unlock.py 2025-12-16
16:27:23.000000000 +0100
@@ -171,6 +171,8 @@
self.box.show_all()
+ self.password_entry.hide()
+ self.auth_unlock_button.hide()
def initialize_auth_client(self):
return self.auth_client.initialize()
@@ -187,6 +189,9 @@
self.set_busy(False)
self.auth_message_label.set_text(_("Incorrect password"))
+ self.password_entry.hide()
+ self.auth_unlock_button.hide()
+
self.emit("authenticate-failure")
self.emit("uninhibit-timeout")
@@ -211,6 +216,9 @@
self.update_authinfo_label()
def on_authentication_prompt_changed(self, auth_client, prompt):
+ self.password_entry.show_all()
+ self.auth_unlock_button.show_all()
+
if "password:" in prompt.lower():
prompt = _("Please enter your password...")
else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/cinnamon-screensaver-6.4.0/src/widgets/powerWidget.py
new/cinnamon-screensaver-6.6.1/src/widgets/powerWidget.py
--- old/cinnamon-screensaver-6.4.0/src/widgets/powerWidget.py 2024-11-26
14:51:33.000000000 +0100
+++ new/cinnamon-screensaver-6.6.1/src/widgets/powerWidget.py 2025-12-16
16:27:23.000000000 +0100
@@ -101,38 +101,35 @@
if state in (UPOWER_STATE_CHARGING, UPOWER_STATE_DISCHARGING,
UPOWER_STATE_PENDING_CHARGE,
UPOWER_STATE_PENDING_DISCHARGE):
if percentage < 10:
- names = ["battery-level-0", "battery-caution"]
+ names = ["xsi-battery-level-0"]
elif percentage < 20:
- names = ["battery-level-10", "battery-low"]
+ names = ["xsi-battery-level-10"]
elif percentage < 30:
- names = ["battery-level-20", "battery-low"]
+ names = ["xsi-battery-level-20"]
elif percentage < 40:
- names = ["battery-level-30", "battery-good"]
+ names = ["xsi-battery-level-30"]
elif percentage < 50:
- names = ["battery-level-40", "battery-good"]
+ names = ["xsi-battery-level-40"]
elif percentage < 60:
- names = ["battery-level-50", "battery-good"]
+ names = ["xsi-battery-level-50"]
elif percentage < 70:
- names = ["battery-level-60", "battery-full"]
+ names = ["xsi-battery-level-60"]
elif percentage < 80:
- names = ["battery-level-70", "battery-full"]
+ names = ["xsi-battery-level-70"]
elif percentage < 90:
- names = ["battery-level-80", "battery-full"]
+ names = ["xsi-battery-level-80"]
elif percentage < 99:
- names = ["battery-level-90", "battery-full"]
+ names = ["xsi-battery-level-90"]
else:
- names = ["battery-level-100", "battery-full"]
+ names = ["xsi-battery-level-100"]
if state in (UPOWER_STATE_CHARGING, UPOWER_STATE_PENDING_CHARGE):
names[0] += "-charging"
- names[1] += "-charging"
names[0] += "-symbolic"
- names[1] += "-symbolic"
+
elif state == UPOWER_STATE_FULLY_CHARGED:
- names = ["battery-level-100-charged-symbolic",
- "battery-full-charged-symbolic",
- "battery-full-charging-symbolic"]
+ names = ["xsi-battery-level-100-charged-symbolic"]
else:
names = (battery.get_property("icon-name"),)