Skip to content

Commit 93b7b95

Browse files
committed
Handle layout switching thru cinnamon, remove use of XApp.
ref: linuxmint/cinnamon#12758
1 parent 8137ba2 commit 93b7b95

File tree

4 files changed

+138
-82
lines changed

4 files changed

+138
-82
lines changed

debian/control

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ Depends:
3434
gir1.2-gobject-2.0,
3535
gir1.2-gtk-3.0,
3636
gir1.2-pango-1.0,
37-
gir1.2-xapp-1.0,
3837
iso-flag-png,
3938
libxdo3,
4039
python3,

src/dbusdepot/cinnamonClient.py

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,98 @@
11
#!/usr/bin/python3
22

3-
from gi.repository import Gio, CScreensaver
3+
from gi.repository import Gio, CScreensaver, GObject
44

55
from dbusdepot.baseClient import BaseClient
6+
from util import trackers
7+
8+
# see cinnamon/files/usr/share/cinnamon/cinnamon-settings/bin/InputSources.py
9+
class CurrentInputSource:
10+
def __init__(self, source):
11+
self.type, self.id, self.index, \
12+
self.display_name, self.short_name, \
13+
self.flag_name, self.xkbid, \
14+
self.xkb_layout, self.xkb_variant, \
15+
self.preferences, \
16+
self.dupe_id, self.active \
17+
= source
618

719
class CinnamonClient(BaseClient):
820
"""
9-
Simple client to talk to Cinnamon's dbus interface. Currently
10-
its only use is for attempting to force an exit from overview
11-
and expo mode (both of which do a fullscreen grab and would prevent
12-
the screensaver from acquiring one.)
21+
Client to talk to Cinnamon's dbus interface.
22+
23+
Used to deactivate special modal cinnamon states and deal with
24+
keyboard layout info.
1325
"""
1426
CINNAMON_SERVICE = "org.Cinnamon"
1527
CINNAMON_PATH = "/org/Cinnamon"
16-
28+
__gsignals__ = {
29+
'current-input-source-changed': (GObject.SignalFlags.RUN_LAST, None, ()),
30+
'input-sources-changed': (GObject.SignalFlags.RUN_LAST, None, ())
31+
}
1732
def __init__(self):
1833
super(CinnamonClient, self).__init__(Gio.BusType.SESSION,
1934
CScreensaver.CinnamonProxy,
2035
self.CINNAMON_SERVICE,
2136
self.CINNAMON_PATH)
37+
self.sources = []
2238

2339
def on_client_setup_complete(self):
24-
pass
40+
trackers.con_tracker_get().connect(self.proxy, "g-signal", self.on_cinnamon_signal)
41+
self.update_layout_sources()
42+
43+
def on_cinnamon_signal(self, proxy, sender, signal, params, data=None):
44+
if signal == "CurrentInputSourceChanged":
45+
self.update_current_layout(params[0])
46+
elif signal == "InputSourcesChanged":
47+
self.update_layout_sources()
48+
49+
def update_layout_sources(self):
50+
self.proxy.GetInputSources(result_handler=self.get_input_sources_callback,
51+
error_handler=self.get_input_sources_error)
52+
53+
def get_input_sources_callback(self, proxy, sources, data=None):
54+
self.sources = []
55+
56+
for source in sources:
57+
input_source = CurrentInputSource(source)
58+
if input_source.type == "xkb":
59+
self.sources.append(input_source)
60+
self.emit("input-sources-changed")
61+
62+
def get_input_sources_error(self, proxy, error, data=None):
63+
print("Failed to get keyboard layouts from Cinnamon - multiple layouts will not be available: %s" % error.message)
64+
65+
def has_multiple_keyboard_layouts(self):
66+
return len(self.sources) > 1
67+
68+
def update_current_layout(self, layout):
69+
for source in self.sources:
70+
source.active = source.id == layout
71+
self.emit("current-input-source-changed")
72+
73+
def get_current_layout_source(self):
74+
for source in self.sources:
75+
if source.active:
76+
return source
77+
return None
78+
79+
def activate_layout_index(self, index):
80+
self.proxy.ActivateInputSourceIndex("(i)", index)
81+
82+
def activate_next_layout(self):
83+
current = 0
84+
85+
for i in range(0, len(self.sources)):
86+
source = self.sources[i]
87+
if source.active:
88+
current = i
89+
break
90+
91+
new = current + 1
92+
if new > len(self.sources) - 1:
93+
new = 0
94+
95+
self.proxy.ActivateInputSourceIndex("(i)", self.sources[new].index)
2596

2697
def exit_expo_and_overview(self):
2798
if self.ensure_proxy_alive():

src/passwordEntry.py

Lines changed: 60 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,13 @@ def __init__(self):
3333
trackers.con_tracker_get().connect(self, "icon-press", self.on_icon_pressed)
3434

3535
self.placeholder_text = placeholder_text
36-
self.current_icon_name = None
37-
self.current_flag_id = 0
38-
self.original_group = 0
36+
self.lockscreen_layout_source = None
37+
self.system_layout_source = None
3938

40-
self.keyboard_controller = singletons.KeyboardLayoutController
41-
trackers.con_tracker_get().connect(self.keyboard_controller,
42-
"config-changed",
43-
self.on_config_changed)
44-
45-
trackers.con_tracker_get().connect(self.keyboard_controller,
46-
"layout-changed",
47-
self.on_layout_changed)
48-
49-
self.set_lockscreen_keyboard_layout()
39+
self.cinnamon = singletons.CinnamonClient
40+
self.cinnamon.connect("current-input-source-changed", self.on_current_layout_changed)
41+
self.cinnamon.connect("input-sources-changed", self.on_layout_sources_changed)
42+
self.on_layout_sources_changed(self.cinnamon)
5043

5144
trackers.con_tracker_get().connect(self,
5245
"destroy",
@@ -59,25 +52,18 @@ def on_draw(self, widget, cr, data=None):
5952
update_layout_icon(), just so GtkEntry thinks there's an icon there,
6053
that way it allocates space for it, and responds to clicks in the area.
6154
"""
62-
if not self.keyboard_controller.get_enabled():
63-
return False
64-
6555
icon_rect = widget.get_icon_area(Gtk.EntryIconPosition.PRIMARY)
6656
x = icon_rect.x
6757
y = icon_rect.y + 2
6858
width = (icon_rect.width // 2) * 2
6959
height = icon_rect.height - 4
7060

7161
handled = False
72-
7362
if settings.get_show_flags():
74-
name = self.keyboard_controller.get_current_icon_name()
75-
7663
ui_scale = self.get_scale_factor()
7764

78-
if name:
79-
filename = "/usr/share/iso-flag-png/%s.png" % name
80-
65+
if self.lockscreen_layout_source.flag_name != "":
66+
filename = "/usr/share/iso-flag-png/%s.png" % self.lockscreen_layout_source.flag_name
8167
try:
8268
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(filename, -1, height * ui_scale)
8369

@@ -98,26 +84,37 @@ def on_draw(self, widget, cr, data=None):
9884

9985
cr.paint()
10086

101-
self.keyboard_controller.render_cairo_subscript(cr,
102-
render_x + (logical_width / 2),
103-
render_y + (logical_height / 2),
104-
logical_width / 2,
105-
logical_height / 2,
106-
self.keyboard_controller.get_current_flag_id())
87+
if self.lockscreen_layout_source.dupe_id > 0:
88+
x = render_x + logical_width / 2
89+
y = render_y + logical_height / 2
90+
width = logical_width / 2 + 2
91+
height = logical_height / 2 + 2
92+
93+
cr.set_source_rgba(0, 0, 0, 0.5)
94+
cr.rectangle(x, y, width, height)
95+
cr.fill()
96+
97+
cr.set_source_rgba(1.0, 1.0, 1.0, 0.8)
98+
cr.rectangle(x + 1, y + 1, width - 2, height - 2)
99+
cr.fill()
100+
101+
cr.set_source_rgba(0.0, 0.0, 0.0, 1.0)
102+
cr.select_font_face("sans", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
103+
cr.set_font_size(height - 2.0)
104+
105+
dupe_str = str(self.lockscreen_layout_source.dupe_id)
106+
107+
ext = cr.text_extents(dupe_str)
108+
cr.move_to((x + (width / 2.0) - (ext.width / 2.0)),
109+
(y + (height / 2.0) + (ext.height / 2.0)))
110+
cr.show_text(dupe_str)
107111

108112
handled = True
109113
except GLib.Error:
110114
pass
111115

112116
if not handled:
113-
if settings.get_use_layout_variant_names():
114-
name = self.keyboard_controller.get_current_variant_label()
115-
else:
116-
name = self.keyboard_controller.get_current_short_group_label()
117-
118-
if settings.get_show_upper_case_layout():
119-
name = name.upper()
120-
117+
name = self.lockscreen_layout_source.short_name
121118
ctx = widget.get_style_context()
122119
ctx.save()
123120

@@ -167,16 +164,27 @@ def pulse(self):
167164
self.progress_pulse()
168165
return True
169166

170-
def on_layout_changed(self, controller, layout):
167+
def on_current_layout_changed(self, cinnamon):
168+
if not self.cinnamon.has_multiple_keyboard_layouts():
169+
return
170+
171+
self.lockscreen_layout_source = self.cinnamon.get_current_layout_source()
172+
171173
self.grab_focus()
172174
self.update_layout_icon()
173175

174-
def on_config_changed(self, controller):
176+
def on_layout_sources_changed(self, cinnamon):
177+
if not self.cinnamon.has_multiple_keyboard_layouts():
178+
return
179+
180+
self.system_layout_source = self.cinnamon.get_current_layout_source()
181+
self.lockscreen_layout_source = self.system_layout_source
182+
175183
self.set_lockscreen_keyboard_layout()
176184

177185
def on_icon_pressed(self, entry, icon_pos, event):
178186
if icon_pos == Gtk.EntryIconPosition.PRIMARY:
179-
self.keyboard_controller.next_group()
187+
self.cinnamon.activate_next_layout()
180188
elif icon_pos == Gtk.EntryIconPosition.SECONDARY:
181189
if self.get_input_purpose() == Gtk.InputPurpose.FREE_FORM:
182190
self.set_visibility(False)
@@ -195,62 +203,46 @@ def update_layout_icon(self):
195203
also ensures a redraw at the correct time to update the flag image.
196204
"""
197205
self.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY, "screensaver-blank")
198-
self.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY, self.keyboard_controller.get_current_name())
199-
200-
self.update_saved_group(self.keyboard_controller.get_current_group())
206+
self.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY, self.lockscreen_layout_source.display_name)
201207

202208
def on_destroy(self, widget, data=None):
203209
self.stop_progress()
204210

205-
trackers.con_tracker_get().disconnect(self.keyboard_controller,
206-
"config-changed",
207-
self.on_config_changed)
208-
209-
trackers.con_tracker_get().disconnect(self.keyboard_controller,
210-
"layout-changed",
211-
self.on_layout_changed)
212-
213211
self.restore_original_layout()
214212

215213
def set_lockscreen_keyboard_layout(self):
216-
if not self.keyboard_controller.get_enabled():
217-
return
218-
219214
# If there are multiple keyboard layouts, we want to store
220215
# the one the user ends up using in the unlock widget, as they'll
221216
# want to use the same one each time, at least until they change
222217
# their password.
223218

224-
saved_group = settings.get_kb_group()
225-
self.original_group = self.keyboard_controller.get_current_group()
226-
227-
new_group = 0
219+
saved_index = settings.get_kb_group()
220+
new_index = 0
228221

229-
if saved_group == -1:
230-
new_group = self.original_group
222+
if saved_index == -1:
223+
new_index = self.system_layout_source.index
224+
settings.set_kb_group(new_index)
231225
else:
232-
new_group = saved_group
226+
new_index = saved_index
227+
228+
if new_index != self.system_layout_source.index:
229+
self.cinnamon.activate_layout_index(new_index)
233230

234-
self.keyboard_controller.set_current_group(new_group)
235-
self.update_saved_group(new_group)
236231
self.update_layout_icon()
237232

238233
trackers.con_tracker_get().connect(self,
239234
"draw",
240235
self.on_draw)
241236

242-
def update_saved_group(self, group):
243-
settings.set_kb_group(group)
244-
245237
def restore_original_layout(self):
246238
"""
247239
Called when the unlock dialog is destroyed, restores
248240
the group that was active before the screensaver was activated.
249241
"""
250-
if not self.keyboard_controller.get_enabled():
251-
return
242+
if settings.get_kb_group() != self.lockscreen_layout_source.index:
243+
settings.set_kb_group(self.lockscreen_layout_source.index)
252244

253-
self.keyboard_controller.set_current_group(self.original_group)
245+
self.cinnamon.activate_layout_index(self.system_layout_source.index)
254246

255247
def grab_focus(self):
256248
Gtk.Widget.grab_focus(self)

src/singletons.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,6 @@
4848
Backgrounds.load_from_preferences(settings.bg_settings)
4949
settings.bg_settings.connect("changed", lambda s,k: Backgrounds.load_from_preferences(s))
5050

51-
# We use XAppKbdLayoutController as a wrapper around libgnomekbd to supply the icon theme
52-
# with icons, as well as providing correct group names.
53-
gi.require_version('XApp', '1.0')
54-
from gi.repository import XApp
55-
KeyboardLayoutController = XApp.KbdLayoutController()
56-
5751
# This sets up synchronously, as we need to know the fractional scaling state before
5852
# setting up the screensaver.
5953
MuffinClient = _MuffinClient()

0 commit comments

Comments
 (0)