1#!/usr/local/bin/python3.8
2
3import gi
4gi.require_version("Gtk", "3.0")
5
6from gi.repository import Gtk
7from SettingsWidgets import SidePage, GSettingsDependencySwitch, DependencyCheckInstallButton, GSettingsSoundFileChooser
8from xapp.GSettingsWidgets import *
9
10DPI_FACTOR_LARGE         = 1.25
11DPI_FACTOR_NORMAL        = 1.0
12
13HIGH_CONTRAST_THEME      = "HighContrast"
14KEY_TEXT_SCALING_FACTOR  = "text-scaling-factor"
15KEY_GTK_THEME            = "gtk-theme"
16KEY_GTK_THEME_BACKUP     = "gtk-theme-backup"
17KEY_ICON_THEME           = "icon-theme"
18KEY_ICON_THEME_BACKUP    = "icon-theme-backup"
19KEY_WM_THEME             = "theme"
20KEY_WM_THEME_BACKUP      = "theme-backup"
21
22
23class Module:
24    name = "universal-access"
25    comment = _("Configure accessibility features")
26    category = "prefs"
27
28    def __init__(self, content_box):
29        keywords = _("magnifier, talk, access, zoom, keys, contrast");
30        sidePage = SidePage(_("Accessibility"), "cs-universal-access", keywords, content_box, module=self)
31        self.sidePage = sidePage
32
33    def on_module_selected(self):
34        if not self.loaded:
35            print("Loading Accessibility module")
36
37            self.iface_settings = Gio.Settings(schema_id="org.cinnamon.desktop.interface")
38            self.wm_settings = Gio.Settings(schema_id="org.cinnamon.desktop.wm.preferences");
39            self.mag_settings = Gio.Settings(schema_id="org.cinnamon.desktop.a11y.magnifier");
40
41            self.sidePage.stack = SettingsStack()
42            self.sidePage.add_widget(self.sidePage.stack)
43
44####    Visual
45
46            page = SettingsPage()
47            self.sidePage.stack.add_titled(page, "visual", _("Visual"))
48
49# Visual Aids
50
51            settings = page.add_section(_("Visual Aids"))
52
53            switch = Switch(_("High contrast"))
54            self.iface_settings.bind_with_mapping(KEY_GTK_THEME,
55                                                  switch.content_widget, "active",
56                                                  Gio.SettingsBindFlags.DEFAULT,
57                                                  self.hi_con_get_mapping,
58                                                  self.hi_con_set_mapping)
59            settings.add_row(switch)
60
61            switch = Switch(_("Large text"))
62            self.iface_settings.bind_with_mapping(KEY_TEXT_SCALING_FACTOR,
63                                                  switch.content_widget, "active",
64                                                  Gio.SettingsBindFlags.DEFAULT,
65                                                  self.lg_text_get_mapping,
66                                                  self.lg_text_set_mapping)
67            settings.add_row(switch)
68
69            switch = GSettingsDependencySwitch(_("Screen reader"),
70                                               "org.cinnamon.desktop.a11y.applications",
71                                               "screen-reader-enabled",
72                                               None,
73                                               ["orca"],
74                                               ["gnome-orca"])
75            settings.add_row(switch)
76
77# Desktop Zoom
78
79            settings = page.add_section(_("Desktop Zoom"))
80
81            switch = GSettingsSwitch(_("Enable zoom"), "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")
82            settings.add_row(switch)
83
84            spin = GSettingsSpinButton(_("Magnification"), "org.cinnamon.desktop.a11y.magnifier", "mag-factor", None, 1.0, 15.0, step=0.5)
85            settings.add_reveal_row(spin, "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")
86
87            zoom_key_options = [["", _("Disabled")], ["<Alt>", "<Alt>"],["<Super>", "<Super>"],["<Control>", "<Control>"], ["<Shift>", "<Shift>"]]
88            widget = GSettingsComboBox(_("Mouse wheel modifier"), "org.cinnamon.desktop.wm.preferences", "mouse-button-zoom-modifier", zoom_key_options)
89            widget.set_tooltip_text(_("While this modifier is pressed, mouse scrolling will increase or decrease zoom."))
90            settings.add_reveal_row(widget, "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")
91
92            switch = GSettingsSwitch(_("Scroll at screen edges"), "org.cinnamon.desktop.a11y.magnifier", "scroll-at-edges")
93            settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")
94
95            mouse_track_options = [["centered",     _("Keep cursor centered")],
96                                   ["proportional", _("Cursor moves with contents")],
97                                   ["push",         _("Cursor pushes contents around")]]
98
99            widget = GSettingsComboBox(_("Mouse tracking mode"), "org.cinnamon.desktop.a11y.magnifier", "mouse-tracking", mouse_track_options)
100            settings.add_reveal_row(widget, "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")
101
102            switch = GSettingsSwitch(_("Lens mode"), "org.cinnamon.desktop.a11y.magnifier", "lens-mode")
103            settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")
104
105            self.zoom_stack = SettingsStack()
106            self.zoom_stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
107
108            lens_shape_options = [["square",          _("Square")],
109                                  ["horizontal",      _("Horizontal strip")],
110                                  ["vertical",        _("Vertical strip")]]
111
112            widget = GSettingsComboBox(_("Lens shape"), "org.cinnamon.desktop.a11y.magnifier", "lens-shape", lens_shape_options)
113            self.zoom_stack.add_named(widget, "shape")
114
115            screen_pos_options = [["full-screen",     _("Full screen")],
116                                  ["top-half",        _("Top half")],
117                                  ["bottom-half",     _("Bottom half")],
118                                  ["left-half",       _("Left half")],
119                                  ["right-half",      _("Right half")]]
120
121            widget = GSettingsComboBox(_("Screen position"), "org.cinnamon.desktop.a11y.magnifier", "screen-position", screen_pos_options)
122            self.zoom_stack.add_named(widget, "screen")
123
124            settings.add_reveal_row(self.zoom_stack, "org.cinnamon.desktop.a11y.applications", "screen-magnifier-enabled")
125
126            self.mag_settings.bind_with_mapping("lens-mode",
127                                                self.zoom_stack, "visible-child-name",
128                                                Gio.SettingsBindFlags.GET,
129                                                self.zoom_stack_get,
130                                                None)
131
132            if (self.mag_settings.get_boolean("lens-mode")):
133                self.zoom_stack.set_visible_child_name("shape")
134            else:
135                self.zoom_stack.set_visible_child_name("screen")
136
137#### Keyboard
138
139            page = SettingsPage()
140            self.sidePage.stack.add_titled(page, "keyboard", _("Keyboard"))
141
142# Virtual keyboard
143
144            settings = page.add_section(_("Virtual keyboard"))
145
146            switch = GSettingsSwitch(_("Enable the on-screen keyboard"),
147                                     "org.cinnamon.desktop.a11y.applications",
148                                     "screen-keyboard-enabled",
149                                     None)
150
151            settings.add_row(switch)
152
153            keyboard_type_options = [["tablet",     _("Tablet")],
154                                     ["touch",     _("Touch")],
155                                     ["fullscale", _("Full scale")],
156                                     ["scan",      _("Scanning")]]
157
158            widget = GSettingsComboBox(_("Keyboard layout"), "org.cinnamon.keyboard", "keyboard-type", keyboard_type_options)
159            settings.add_reveal_row(widget, "org.cinnamon.desktop.a11y.applications", "screen-keyboard-enabled")
160
161            keyboard_position_options = [["bottom",     _("At the bottom of the screen")],
162                                         ["top",     _("At the top of the screen")]]
163            widget = GSettingsComboBox(_("Keyboard position"), "org.cinnamon.keyboard", "keyboard-position", keyboard_position_options)
164            settings.add_reveal_row(widget, "org.cinnamon.desktop.a11y.applications", "screen-keyboard-enabled")
165
166            keyboard_size_options = [[4,     _("A quarter of the screen")],
167                                     [3,     _("A third of the screen")],
168                                     [2, _("Half of the screen")]]
169
170            widget = GSettingsComboBox(_("Keyboard size"), "org.cinnamon.keyboard", "keyboard-size", keyboard_size_options)
171            settings.add_reveal_row(widget, "org.cinnamon.desktop.a11y.applications", "screen-keyboard-enabled")
172
173            activation_mode_options = [["accessible", _("Show the keyboard any time something expects input")],
174                                       ["on-demand",  _("Show keyboard only when the user activates it")]];
175
176            widget = GSettingsComboBox(_("Activation mode"), "org.cinnamon.keyboard", "activation-mode", activation_mode_options)
177            settings.add_reveal_row(widget, "org.cinnamon.desktop.a11y.applications", "screen-keyboard-enabled")
178
179# Keyboard indicators
180
181            settings = page.add_section(_("Keyboard indicators"))
182
183            switch = GSettingsSwitch(_("Use visual indicator on Caps and Num Lock"),
184                                     "org.cinnamon.desktop.a11y.keyboard",
185                                     "togglekeys-enable-osd")
186
187            settings.add_row(switch)
188
189            switch = GSettingsSwitch(_("Use audio indicator on Caps and Num Lock"),
190                                     "org.cinnamon.desktop.a11y.keyboard",
191                                     "togglekeys-enable-beep")
192
193            settings.add_row(switch)
194
195            sound_picker = GSettingsSoundFileChooser(_("Sound to use Caps or Num Lock on"),
196                                                     "org.cinnamon.desktop.a11y.keyboard",
197                                                     "togglekeys-sound-on")
198            settings.add_reveal_row(sound_picker, "org.cinnamon.desktop.a11y.keyboard", "togglekeys-enable-beep")
199
200            sound_picker = GSettingsSoundFileChooser(_("Sound to use Caps or Num Lock off"),
201                                                     "org.cinnamon.desktop.a11y.keyboard",
202                                                     "togglekeys-sound-off")
203            settings.add_reveal_row(sound_picker, "org.cinnamon.desktop.a11y.keyboard", "togglekeys-enable-beep")
204
205            settings = page.add_section(_("Event feedback (required for typing assistance alerts)"))
206
207            switch = GSettingsSwitch(_("Enable visual alerts"),
208                                     "org.cinnamon.desktop.wm.preferences",
209                                     "visual-bell")
210            settings.add_row(switch)
211
212            visual_bell_options = [["fullscreen-flash",     _("Flash the entire monitor")],
213                                   ["frame-flash", _("Flash the active window")]]
214
215            widget = GSettingsComboBox(_("Visual style"), "org.cinnamon.desktop.wm.preferences", "visual-bell-type", visual_bell_options)
216            settings.add_reveal_row(widget, "org.cinnamon.desktop.wm.preferences", "visual-bell")
217
218            switch = GSettingsSwitch(_("Enable audio alerts"),
219                                     "org.cinnamon.desktop.wm.preferences",
220                                     "audible-bell")
221            settings.add_row(switch)
222
223            sound_picker = GSettingsSoundFileChooser(_("Sound to use for window alerts"),
224                                                     "org.cinnamon.desktop.wm.preferences",
225                                                     "bell-sound")
226            settings.add_reveal_row(sound_picker, "org.cinnamon.desktop.wm.preferences", "audible-bell")
227
228####    Typing Assistance
229
230            page = SettingsPage()
231            self.sidePage.stack.add_titled(page, "typing", _("Typing assistance"))
232
233# Stickykeys
234
235            settings = page.add_section(_("Sticky keys"))
236
237            switch = GSettingsSwitch(_("Treat a sequence of modifier keys as a combination"),
238                                     "org.cinnamon.desktop.a11y.keyboard",
239                                     "stickykeys-enable",
240                                     None)
241
242            settings.add_row(switch)
243
244            switch = GSettingsSwitch(_("Disable if two modifiers are pressed together"),
245                                     "org.cinnamon.desktop.a11y.keyboard",
246                                     "stickykeys-two-key-off",
247                                     None)
248
249            settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.keyboard", "stickykeys-enable")
250
251            switch = GSettingsSwitch(_("Alert when a modifier key is pressed"),
252                                     "org.cinnamon.desktop.a11y.keyboard",
253                                     "stickykeys-modifier-beep",
254                                     "org.cinnamon.desktop.sound/event-sounds")
255
256            settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.keyboard", "stickykeys-enable")
257
258# Slowkeys
259
260            settings = page.add_section(_("Slow keys"))
261
262            switch = GSettingsSwitch(_("Put a delay between when a key is pressed and when it is accepted"),
263                                     "org.cinnamon.desktop.a11y.keyboard",
264                                     "slowkeys-enable",
265                                     None)
266
267            settings.add_row(switch)
268
269            switch = GSettingsSwitch(_("Alert when a key is pressed"),
270                                     "org.cinnamon.desktop.a11y.keyboard",
271                                     "slowkeys-beep-press",
272                                     "org.cinnamon.desktop.sound/event-sounds")
273
274            settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.keyboard", "slowkeys-enable")
275
276            switch = GSettingsSwitch(_("Alert when a key is accepted"),
277                                     "org.cinnamon.desktop.a11y.keyboard",
278                                     "slowkeys-beep-accept",
279                                     "org.cinnamon.desktop.sound/event-sounds")
280
281            settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.keyboard", "slowkeys-enable")
282
283            switch = GSettingsSwitch(_("Alert when a key is rejected"),
284                                     "org.cinnamon.desktop.a11y.keyboard",
285                                     "slowkeys-beep-reject",
286                                     "org.cinnamon.desktop.sound/event-sounds")
287
288            settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.keyboard", "slowkeys-enable")
289
290            slider = GSettingsRange(_("Acceptance delay"),
291                                    "org.cinnamon.desktop.a11y.keyboard",
292                                    "slowkeys-delay",
293                                    _("Short"), _("Long"),
294                                    0, 500, 10, show_value=False)
295
296            settings.add_reveal_row(slider, "org.cinnamon.desktop.a11y.keyboard", "slowkeys-enable")
297
298# Bouncekeys
299
300            settings = page.add_section(_("Bounce keys"))
301
302            switch = GSettingsSwitch(_("Ignore fast duplicate keypresses"),
303                                     "org.cinnamon.desktop.a11y.keyboard",
304                                     "bouncekeys-enable",
305                                     None)
306
307            settings.add_row(switch)
308
309            switch = GSettingsSwitch(_("Alert when a key is rejected"),
310                                     "org.cinnamon.desktop.a11y.keyboard",
311                                     "bouncekeys-beep-reject",
312                                     "org.cinnamon.desktop.sound/event-sounds")
313
314            settings.add_reveal_row(switch, "org.cinnamon.desktop.a11y.keyboard", "bouncekeys-enable")
315
316            slider = GSettingsRange(_("Acceptance delay"),
317                                    "org.cinnamon.desktop.a11y.keyboard",
318                                    "bouncekeys-delay",
319                                    _("Short"), _("Long"),
320                                    0, 900, 10, show_value=False)
321
322            settings.add_reveal_row(slider, "org.cinnamon.desktop.a11y.keyboard", "bouncekeys-enable")
323
324####    Pointing and Clicking
325
326            page = SettingsPage()
327            self.sidePage.stack.add_titled(page, "mouse", _("Mouse"))
328
329# Mousekeys
330
331            settings = page.add_section(_("Mouse keys"))
332
333            switch = GSettingsSwitch(_("Control the pointer using the keypad"),
334                                     "org.cinnamon.desktop.a11y.keyboard",
335                                     "mousekeys-enable",
336                                     None)
337
338            settings.add_row(switch)
339
340            slider = GSettingsRange(_("Initial delay"),
341                                    "org.cinnamon.desktop.a11y.keyboard",
342                                    "mousekeys-init-delay",
343                                    _("Shorter"), _("Longer"),
344                                    10, 2000, 10, show_value=False)
345
346            settings.add_reveal_row(slider, "org.cinnamon.desktop.a11y.keyboard", "mousekeys-enable")
347
348            slider = GSettingsRange(_("Acceleration time"),
349                                    "org.cinnamon.desktop.a11y.keyboard",
350                                    "mousekeys-accel-time",
351                                    _("Shorter"), _("Longer"),
352                                    10, 2000, 10, show_value=False)
353
354            settings.add_reveal_row(slider, "org.cinnamon.desktop.a11y.keyboard", "mousekeys-enable")
355
356            slider = GSettingsRange(_("Maximum speed"),
357                                    "org.cinnamon.desktop.a11y.keyboard",
358                                    "mousekeys-max-speed",
359                                    _("Slower"), _("Faster"),
360                                    1, 500, 1, show_value=False)
361
362            settings.add_reveal_row(slider, "org.cinnamon.desktop.a11y.keyboard", "mousekeys-enable")
363
364# Dependency Checker
365
366            settings = page.add_reveal_section(_("Simulated secondary click and hover click"))
367            self.dc_section = settings
368
369            install_widget = SettingsWidget()
370
371            self.dep_button = DependencyCheckInstallButton(_("Checking dependencies"),
372                                                           _("Please install: %s") % ("mousetweaks"),
373                                                           ["mousetweaks"],
374                                                           Gtk.Alignment(),
375                                                           self.on_dep_satisfied)
376
377            install_widget.pack_start(self.dep_button, True, False, 0)
378
379            settings.add_row(install_widget)
380
381            self.dc_section._revealer.set_reveal_child(True)
382
383# Secondary click
384
385            settings = page.add_reveal_section(_("Simulated secondary click"))
386            self.ssc_section = settings
387
388            switch = GSettingsSwitch(_("Trigger a secondary click by holding down the primary button"),
389                                     "org.cinnamon.desktop.a11y.mouse",
390                                     "secondary-click-enabled",
391                                     None)
392
393            settings.add_row(switch)
394
395            slider = GSettingsRange(_("Acceptance delay"),
396                                    "org.cinnamon.desktop.a11y.mouse",
397                                    "secondary-click-time",
398                                    _("Shorter"), _("Longer"),
399                                    0.5, 3.0, 0.1, show_value=False)
400
401            settings.add_reveal_row(slider, "org.cinnamon.desktop.a11y.mouse", "secondary-click-enabled")
402
403# Hover Click
404
405            settings = page.add_reveal_section(_("Hover click"))
406            self.hc_section = settings
407
408            switch = GSettingsSwitch(_("Trigger a click when the pointer hovers"),
409                                     "org.cinnamon.desktop.a11y.mouse",
410                                     "dwell-click-enabled",
411                                     None)
412
413            settings.add_row(switch)
414
415            slider = GSettingsRange(_("Delay"),
416                                    "org.cinnamon.desktop.a11y.mouse",
417                                    "dwell-time",
418                                    _("Short"), _("Long"),
419                                    0.2, 3.0, 0.1, show_value=False)
420
421            settings.add_reveal_row(slider, "org.cinnamon.desktop.a11y.mouse", "dwell-click-enabled")
422
423            slider = GSettingsRange(_("Motion threshold"),
424                                    "org.cinnamon.desktop.a11y.mouse",
425                                    "dwell-threshold",
426                                    _("Small"), _("Large"),
427                                    1, 30, 1, show_value=False)
428
429            settings.add_reveal_row(slider, "org.cinnamon.desktop.a11y.mouse", "dwell-click-enabled")
430
431    def on_dep_satisfied(self):
432        self.ssc_section._revealer.set_reveal_child(True)
433        self.hc_section._revealer.set_reveal_child(True)
434        self.dc_section._revealer.destroy()
435
436    def zoom_stack_get(self, lens_mode):
437        ret = "screen"
438
439        if lens_mode:
440            ret = "shape"
441        else:
442            ret = "screen"
443
444        return ret
445
446    def hi_con_get_mapping(self, string):
447        return string == HIGH_CONTRAST_THEME
448
449    def hi_con_set_mapping(self, active):
450        ret = None
451
452        if active:
453            ret = HIGH_CONTRAST_THEME
454
455            theme = self.iface_settings.get_string(KEY_GTK_THEME)
456            self.iface_settings.set_string(KEY_GTK_THEME_BACKUP, theme)
457
458            theme = self.iface_settings.get_string(KEY_ICON_THEME)
459            self.iface_settings.set_string(KEY_ICON_THEME_BACKUP, theme)
460            self.iface_settings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME)
461
462            theme = self.wm_settings.get_string(KEY_WM_THEME)
463            self.wm_settings.set_string(KEY_WM_THEME_BACKUP, theme)
464            self.wm_settings.set_string(KEY_WM_THEME, HIGH_CONTRAST_THEME)
465        else:
466            ret = self.iface_settings.get_string(KEY_GTK_THEME_BACKUP)
467
468            theme = self.iface_settings.get_string(KEY_ICON_THEME_BACKUP)
469            self.iface_settings.set_string(KEY_ICON_THEME, theme)
470
471            theme = self.wm_settings.get_string(KEY_WM_THEME_BACKUP)
472            self.wm_settings.set_string(KEY_WM_THEME, theme)
473
474        return ret
475
476    def lg_text_get_mapping(self, factor):
477        return factor > DPI_FACTOR_NORMAL
478
479    def lg_text_set_mapping(self, active):
480        ret = None
481
482        if active:
483            ret = DPI_FACTOR_LARGE
484        else:
485            ret = self.iface_settings.get_default_value(KEY_TEXT_SCALING_FACTOR).get_double()
486
487        return ret
488