Use sizegroup for headerbar instaed of fixed width
[tails-greeter-prototype.git] / greeter.py
blobe0a93ace064293d6f1371dfc4f498e9c5a7d363c
1 #!/usr/bin/env python3
3 # Copyright 2015 Tails developers <tails@boum.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>
18 ################################################################################
19 # TODO
21 # * help button should not look like buttons
22 # * settings change position when added, then removed
23 # * fill formats with formats (cf gnome-control-center)
24 # * show time when timezone is selected (we'll need to have it editable at some poit)
25 # * add a way cancel setting adding
26 ################################################################################
28 import os
29 import sys
31 import gi
33 gi.require_version('GLib', '2.0')
34 from gi.repository import GLib
35 gi.require_version('Gdk', '3.0')
36 from gi.repository import Gdk
37 gi.require_version('Gtk', '3.0')
38 from gi.repository import Gtk
40 import greeterdata
42 # To ease future internationalisation
43 _ = lambda x: x
45 UI_FILE = 'greeter.ui'
46 ICON_DIR = 'icons/'
47 APPLICATION_ICON_NAME = 'gdm-setup'
48 APPLICATION_TITLE = 'Welcome to Tails!'
50 class GreeterMainWindow(Gtk.ApplicationWindow):
52 def __init__(self, app):
53 Gtk.Window.__init__(self, title=APPLICATION_TITLE, application=app)
54 self._app = app
55 self.set_icon_name(APPLICATION_ICON_NAME)
56 self._build_ui()
57 self.set_position(Gtk.WindowPosition.CENTER)
58 self._last_selected_setting_row = []
60 def _build_ui(self):
61 # Load UI interface definition
62 self._builder = Gtk.Builder()
63 self._builder.add_from_file(UI_FILE)
64 self._builder.connect_signals(self)
66 # Map interface objects
67 box_main = self._builder.get_object('box_main')
69 self.label_language_header_status = \
70 self._builder.get_object('label_language_header_status')
71 checkbutton_language_save = \
72 self._builder.get_object('checkbutton_language_save')
73 self.listbox_language = self._builder.get_object('listbox_language')
74 self.listboxrow_text = self._builder.get_object('listboxrow_text')
75 self.label_text_value = self._builder.get_object('label_text_value')
76 self.listboxrow_keyboard = self._builder.get_object('listboxrow_keyboard')
77 self.label_keyboard_value = self._builder.get_object('label_keyboard_value')
78 self.listboxrow_formats = self._builder.get_object('listboxrow_formats')
79 self.label_formats_value = self._builder.get_object('label_formats_value')
80 self.listboxrow_tz = self._builder.get_object('listboxrow_tz')
81 self.label_tz_value = self._builder.get_object('label_tz_value')
83 self.checkbutton_storage_show_passphrase = \
84 self._builder.get_object('checkbutton_storage_show_passphrase')
85 self.button_storage_configure = \
86 self._builder.get_object('button_storage_configure')
87 self.button_storage_state = self._builder.get_object('button_storage_state')
88 self.image_storage_state = self._builder.get_object('image_storage_state')
89 self.button_storage_spinner = \
90 self._builder.get_object('button_storage_spinner')
91 self.spinner_storage_unlock = \
92 self._builder.get_object('spinner_storage_unlock')
93 self.entry_storage_passphrase = \
94 self._builder.get_object('entry_storage_passphrase')
95 self.button_storage_lock = self._builder.get_object('button_storage_lock')
96 self.button_storage_unlock =self._builder.get_object('button_storage_unlock')
97 self.box_storage_unlock = self._builder.get_object('box_storage_unlock')
99 checkbutton_settings_save = \
100 self._builder.get_object('checkbutton_settings_save')
101 self.listbox_settings = self._builder.get_object('listbox_settings')
102 self.listboxrow_settings_admin = \
103 self._builder.get_object('listboxrow_settings_admin')
104 self.label_settings_admin_value = \
105 self._builder.get_object('label_settings_admin_value')
106 self.listboxrow_settings_macspoof = \
107 self._builder.get_object('listboxrow_settings_macspoof')
108 self.label_settings_macspoof_value = \
109 self._builder.get_object('label_settings_macspoof_value')
110 self.listboxrow_settings_network = \
111 self._builder.get_object('listboxrow_settings_network')
112 self.label_settings_network_value = \
113 self._builder.get_object('label_settings_network_value')
114 self.listboxrow_settings_camouflage = \
115 self._builder.get_object('listboxrow_settings_camouflage')
116 self.label_settings_camouflage_value = \
117 self._builder.get_object('label_settings_camouflage_value')
119 label_settings_default = \
120 self._builder.get_object('label_settings_default')
121 self.toolbutton_settings_remove = \
122 self._builder.get_object('toolbutton_settings_remove')
123 self.toolbutton_settings_add = \
124 self._builder.get_object('toolbutton_settings_add')
126 self.window_add_setting = self._builder.get_object('window_add_setting')
127 self.listbox_add_setting = self._builder.get_object('listbox_add_setting')
129 box_text_popover = self._builder.get_object('box_text_popover')
130 searchentry_text = self._builder.get_object('searchentry_text')
131 liststore_text = self._builder.get_object('liststore_text')
132 treeview_text = self._builder.get_object('treeview_text')
133 box_keyboard_popover = self._builder.get_object('box_keyboard_popover')
134 searchentry_keyboard = self._builder.get_object('searchentry_keyboard')
135 liststore_keyboard = self._builder.get_object('liststore_keyboard')
136 treeview_keyboard = self._builder.get_object('treeview_keyboard')
137 box_formats_popover = self._builder.get_object('box_formats_popover')
138 searchentry_formats = self._builder.get_object('searchentry_formats')
139 liststore_formats = self._builder.get_object('liststore_formats')
140 treeview_formats = self._builder.get_object('treeview_formats')
141 box_tz_popover = self._builder.get_object('box_tz_popover')
142 searchentry_tz = self._builder.get_object('searchentry_tz')
143 liststore_tz = self._builder.get_object('liststore_tz')
144 treeview_tz = self._builder.get_object('treeview_tz')
146 box_admin_popover = self._builder.get_object('box_admin_popover')
147 self.entry_admin_password = \
148 self._builder.get_object('entry_admin_password')
149 self.entry_admin_verify = self._builder.get_object('entry_admin_verify')
150 box_macspoof_popover = self._builder.get_object('box_macspoof_popover')
151 switch_macspoof = self._builder.get_object('switch_macspoof')
152 box_network_popover = self._builder.get_object('box_network_popover')
153 self.listbox_network_controls = \
154 self._builder.get_object('listbox_network_controls')
155 self.listboxrow_network_clear = \
156 self._builder.get_object('listboxrow_network_clear')
157 self.image_network_clear = \
158 self._builder.get_object('image_network_clear')
159 self.listboxrow_network_specific = \
160 self._builder.get_object('listboxrow_network_specific')
161 self.image_network_specific = \
162 self._builder.get_object('image_network_specific')
163 self.listboxrow_network_off = \
164 self._builder.get_object('listboxrow_network_off')
165 self.image_network_off = \
166 self._builder.get_object('image_network_off')
167 box_camouflage_popover = \
168 self._builder.get_object('box_camouflage_popover')
169 switch_camouflage = self._builder.get_object('switch_camouflage')
171 # Set preferred size
172 self.set_default_size(600, -1)
174 # Add our icon dir to icon theme
175 icon_theme = Gtk.IconTheme.get_default()
176 icon_theme.prepend_search_path(ICON_DIR)
178 # Add placeholder to settings ListBox
179 self.listbox_settings.set_placeholder(label_settings_default)
181 # Create HeaderBar
182 headerbar = Gtk.HeaderBar()
183 headerbar_sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
185 button_restart = Gtk.Button()
186 button_restart.set_label(_("Restart"))
187 button_restart.connect('clicked', self.cb_button_restart_clicked)
188 headerbar_sizegroup.add_widget(button_restart)
189 headerbar.pack_start(button_restart)
191 button_start = Gtk.Button()
192 button_start.set_label(_("Start Tails"))
193 Gtk.StyleContext.add_class(button_start.get_style_context(),
194 'suggested-action')
195 button_start.connect('clicked', self.cb_button_start_clicked)
196 headerbar_sizegroup.add_widget(button_start)
197 headerbar.pack_end(button_start)
199 button_tour = Gtk.Button()
200 button_tour.set_label(_("Take a Tour"))
201 button_tour.connect('clicked', self.cb_button_tour_clicked)
202 headerbar_sizegroup.add_widget(button_tour)
203 headerbar.pack_end(button_tour)
205 headerbar.show_all()
207 # Align CheckBoxes to the left
208 for cb in [checkbutton_language_save,
209 self.checkbutton_storage_show_passphrase,
210 checkbutton_settings_save]:
211 cb.set_direction(Gtk.TextDirection.RTL)
213 # Add popovers
214 self.popover_text = self.__add_popover(
215 self.listboxrow_text,
216 box_text_popover,
217 closed_cb=self.cb_popover_text_closed)
218 self.popover_keyboard = self.__add_popover(
219 self.listboxrow_keyboard,
220 box_keyboard_popover,
221 closed_cb=self.cb_popover_keyboard_closed)
222 self.popover_formats = self.__add_popover(
223 self.listboxrow_formats,
224 box_formats_popover,
225 closed_cb=self.cb_popover_formats_closed)
226 self.popover_tz = self.__add_popover(
227 self.listboxrow_tz,
228 box_tz_popover,
229 closed_cb=self.cb_popover_tz_closed)
231 self.popover_admin = self.__add_popover(
232 self.listboxrow_settings_admin,
233 box_admin_popover,
234 closed_cb=self.cb_popover_admin_closed)
235 self.popover_macspoof = self.__add_popover(
236 self.listboxrow_settings_macspoof,
237 box_macspoof_popover,
238 closed_cb=self.cb_popover_macspoof_closed)
239 self.popover_network = self.__add_popover(
240 self.listboxrow_settings_network,
241 box_network_popover,
242 closed_cb=self.cb_popover_network_closed)
243 self.popover_camouflage = self.__add_popover(
244 self.listboxrow_settings_camouflage,
245 box_camouflage_popover,
246 closed_cb=self.cb_popover_camouflage_closed)
248 # Add children to ApplicationWindow
249 self.add(box_main)
250 self.set_titlebar(headerbar)
252 # Create "Add Privacy Setting" dialog
253 self.window_add_setting.set_transient_for(self)
255 # Fill language treeviews
256 for language in greeterdata.languages:
257 liststore_text.append(language)
258 self.__fill_tv("Text Language", treeview_text)
259 self.liststore_text_filtered = liststore_text.filter_new()
260 self.liststore_text_filtered.set_visible_func(
261 self.cb_liststore_filtered_visible_func, data=searchentry_text)
262 treeview_text.set_model(self.liststore_text_filtered)
264 for layout in greeterdata.layouts:
265 liststore_keyboard.append(layout)
266 self.__fill_tv("Keyboard Layout", treeview_keyboard)
267 self.liststore_keyboard_filtered = liststore_keyboard.filter_new()
268 self.liststore_keyboard_filtered.set_visible_func(
269 self.cb_liststore_filtered_visible_func, data=searchentry_keyboard)
270 treeview_keyboard.set_model(self.liststore_keyboard_filtered)
272 for locale in greeterdata.locales:
273 liststore_formats.append(locale)
274 self.__fill_tv("Format", treeview_formats)
275 self.liststore_formats_filtered = liststore_formats.filter_new()
276 self.liststore_formats_filtered.set_visible_func(
277 self.cb_liststore_filtered_visible_func, data=searchentry_formats)
278 treeview_formats.set_model(self.liststore_formats_filtered)
280 for timezone in greeterdata.timezones:
281 liststore_tz.append(timezone)
282 self.__fill_tv("Time Zone", treeview_tz)
283 self.liststore_tz_filtered = liststore_tz.filter_new()
284 self.liststore_tz_filtered.set_visible_func(
285 self.cb_liststore_filtered_visible_func, data=searchentry_tz)
286 treeview_tz.set_model(self.liststore_tz_filtered)
288 # Storage configuration/unlocking
289 if os.getenv('TAILS_HAS_PERSISTENCE'):
290 self.button_storage_configure.set_visible(False)
291 self.checkbutton_storage_show_passphrase.set_visible(True)
292 self.box_storage_unlock.set_visible(True)
293 self.button_storage_state.set_visible(True)
294 self.entry_storage_passphrase.set_visible(True)
295 self.button_storage_unlock.set_visible(True)
297 # Settings popovers
298 switch_macspoof.connect('notify::active', self.cb_switch_macspoof_active)
299 switch_camouflage.connect('notify::active', self.cb_switch_camouflage_active)
301 def setting_admin_check(self):
302 password = self.entry_admin_password.get_text()
303 verify = self.entry_admin_verify.get_text()
304 if verify and verify == password:
305 icon = 'emblem-ok-symbolic'
306 elif verify and not (verify == password):
307 icon = 'dialog-warning-symbolic'
308 else:
309 icon = None
310 self.entry_admin_verify.set_icon_from_icon_name(
311 Gtk.EntryIconPosition.SECONDARY, icon)
312 return (verify == password)
314 def setting_admin_apply(self):
315 if self.setting_admin_check():
316 self.label_settings_admin_value.set_text(
317 self.__get_on_off_string(self.entry_admin_password.get_text()))
318 self.popover_admin.set_visible(False)
319 return True
320 else:
321 return False
323 # Utility methods
325 @staticmethod
326 def __add_popover(widget, content, closed_cb=None):
327 popover = Gtk.Popover.new(widget)
328 popover.set_position(Gtk.PositionType.BOTTOM)
329 popover.add(content)
330 if closed_cb:
331 popover.connect('closed', closed_cb)
332 return popover
334 @staticmethod
335 def __fill_tv (name, treeview):
336 assert isinstance(name, str)
337 assert isinstance(treeview, Gtk.TreeView)
338 renderer = Gtk.CellRendererText()
339 column = Gtk.TreeViewColumn(name, renderer, text=1)
340 treeview.append_column(column)
342 @staticmethod
343 def __popover_toggle(popover):
344 if popover.get_visible():
345 popover.set_visible(False)
346 else:
347 popover.set_visible(True)
349 @staticmethod
350 def __get_on_off_string(value):
351 if value:
352 return _("On")
353 else:
354 return _("Off")
356 # Callbacks
358 def cb_button_help_clicked(self, widget, user_data=None):
359 dialog = Gtk.MessageDialog(
360 self,
361 Gtk.DialogFlags.DESTROY_WITH_PARENT,
362 Gtk.MessageType.INFO,
363 Gtk.ButtonsType.CLOSE,
364 _("You would see the help page for this element."))
365 dialog.run()
366 dialog.destroy()
367 return False
369 def cb_button_restart_clicked(self, widget, user_data=None):
370 self._app.quit()
371 return False
373 def cb_button_start_clicked(self, widget, user_data=None):
374 self._app.quit()
375 return False
377 def cb_button_storage_configure_clicked(self, user_data=None):
378 dialog = Gtk.MessageDialog(
379 self,
380 Gtk.DialogFlags.DESTROY_WITH_PARENT,
381 Gtk.MessageType.INFO,
382 Gtk.ButtonsType.CLOSE,
383 _("You would be able to set up an encrypted storage."))
384 dialog.run()
385 dialog.destroy()
386 return False
388 def cb_button_tour_clicked(self, user_data=None):
389 dialog = Gtk.MessageDialog(
390 self,
391 Gtk.DialogFlags.DESTROY_WITH_PARENT,
392 Gtk.MessageType.INFO,
393 Gtk.ButtonsType.CLOSE,
394 _("You would be guided through options by a wizard."))
395 dialog.run()
396 dialog.destroy()
397 return False
400 def cb_button_storage_lock_clicked(self, widget, user_data=None):
401 self.button_storage_lock.set_visible(False)
402 self.checkbutton_storage_show_passphrase.set_visible(True)
403 self.box_storage_unlock.set_visible(True)
404 self.button_storage_state.set_visible(True)
405 self.image_storage_state.set_from_icon_name('tails-locked',
406 Gtk.IconSize.BUTTON)
407 self.entry_storage_passphrase.set_visible(True)
408 self.entry_storage_passphrase.set_sensitive(True)
409 self.button_storage_unlock.set_visible(True)
410 self.button_storage_unlock.set_sensitive(True)
411 self.button_storage_unlock.set_label(_("Unlock"))
412 return False
414 def cb_button_storage_unlock_clicked(self, widget, user_data=None):
415 self.checkbutton_storage_show_passphrase.set_visible(False)
416 self.entry_storage_passphrase.set_sensitive(False)
417 self.button_storage_unlock.set_sensitive(False)
418 self.button_storage_unlock.set_label(_("Unlocking"))
419 self.button_storage_state.set_visible(False)
420 self.button_storage_spinner.set_visible(True)
421 GLib.timeout_add_seconds(2, self.cb_timeout_storage_unlocked, user_data=None)
422 return False
424 def cb_checkbutton_storage_show_passphrase_toggled(self, widget, user_data=None):
425 self.entry_storage_passphrase.set_visibility(widget.get_active())
427 def cb_entry_admin_changed(self, editable, user_data=None):
428 self.setting_admin_check()
429 return False
431 def cb_entry_admin_focus_out_event(self, widget, event, user_data=None):
432 self.setting_admin_apply()
433 return False
435 def cb_entry_admin_password_activate(self, widget, user_data=None):
436 self.entry_admin_verify.grab_focus()
437 return False
439 def cb_entry_admin_verify_activate(self, widget, user_data=None):
440 self.setting_admin_apply()
441 return False
443 def cb_listbox_add_setting_focus(self, widget, direction, user_data=None):
444 # Workaround autoselection of 1st item on focus
445 self.listbox_add_setting.unselect_all()
446 return False
448 def cb_listbox_add_setting_row_activated(self, listbox, row, user_data=None):
449 if not row: # this happens when the row gets unselected
450 return False
451 listbox.remove(row)
452 self.listbox_settings.add(row)
453 self.window_add_setting.set_visible(False)
454 if row == self.listboxrow_settings_admin:
455 self.__popover_toggle(self.popover_admin)
456 elif row == self.listboxrow_settings_macspoof:
457 self.__popover_toggle(self.popover_macspoof)
458 elif row == self.listboxrow_settings_network:
459 self.__popover_toggle(self.popover_network)
460 elif row == self.listboxrow_settings_camouflage:
461 self.__popover_toggle(self.popover_camouflage)
462 if len(listbox.get_children()) == 0:
463 self.toolbutton_settings_add.set_sensitive(False)
464 return False
466 def cb_listbox_language_row_activated(self, listbox, row, user_data=None):
467 if row == self.listboxrow_text:
468 self.__popover_toggle(self.popover_text)
469 elif row == self.listboxrow_keyboard:
470 self.__popover_toggle(self.popover_keyboard)
471 elif row == self.listboxrow_formats:
472 self.__popover_toggle(self.popover_formats)
473 elif row == self.listboxrow_tz:
474 self.__popover_toggle(self.popover_tz)
475 return False
477 def cb_listbox_network_row_activated(self, listbox, row, user_data=None):
478 if row == self.listboxrow_network_clear:
479 self.image_network_clear.set_visible(True)
480 self.image_network_specific.set_visible(False)
481 self.image_network_off.set_visible(False)
482 self.label_settings_network_value.set_text(_("Direct"))
483 elif row == self.listboxrow_network_specific:
484 self.image_network_specific.set_visible(True)
485 self.image_network_clear.set_visible(False)
486 self.image_network_off.set_visible(False)
487 self.label_settings_network_value.set_text(_("Censored"))
488 elif row == self.listboxrow_network_off:
489 self.image_network_off.set_visible(True)
490 self.image_network_specific.set_visible(False)
491 self.image_network_clear.set_visible(False)
492 self.label_settings_network_value.set_text(_("Off"))
493 self.popover_network.set_visible(False)
494 return False
496 def cb_listbox_settings_add(self, listbox, row, user_data=None):
497 self._last_selected_setting_row.append(row)
498 if len(listbox.get_children()) > 0:
499 self.toolbutton_settings_remove.set_sensitive(True)
500 return False
502 def cb_listbox_settings_remove(self, container, object, user_data=None):
503 if len(container.get_children()) == 0:
504 self.toolbutton_settings_remove.set_sensitive(False)
505 return False
507 def cb_listbox_settings_row_selected(self, listbox, row, user_data=None):
508 if row:
509 self._last_selected_setting_row.append(row)
511 def cb_listbox_settings_row_activated(self, listbox, row, user_data=None):
512 if row == self.listboxrow_settings_admin:
513 self.__popover_toggle(self.popover_admin)
514 elif row == self.listboxrow_settings_macspoof:
515 self.__popover_toggle(self.popover_macspoof)
516 elif row == self.listboxrow_settings_network:
517 self.__popover_toggle(self.popover_network)
518 elif row == self.listboxrow_settings_camouflage:
519 self.__popover_toggle(self.popover_camouflage)
520 return False
522 def cb_liststore_filtered_visible_func(self, model, treeiter, searchentry):
523 search_query = searchentry.get_text().lower()
524 value = model.get_value(treeiter, 1).lower()
525 if not search_query:
526 return True
527 elif search_query in value:
528 return True
529 else:
530 return False
532 def cb_popover_text_closed(self, popover, user_data=None):
533 self.listbox_language.unselect_all()
534 return False
536 def cb_popover_keyboard_closed(self, popover, user_data=None):
537 self.listbox_language.unselect_all()
538 return False
540 def cb_popover_formats_closed(self, popover, user_data=None):
541 self.listbox_language.unselect_all()
542 return False
544 def cb_popover_tz_closed(self, popover, user_data=None):
545 self.listbox_language.unselect_all()
546 return False
548 def cb_popover_admin_closed(self, popover, user_data=None):
549 self.listbox_settings.unselect_all()
550 return False
552 def cb_popover_macspoof_closed(self, popover, user_data=None):
553 self.listbox_settings.unselect_all()
554 return False
556 def cb_popover_network_closed(self, popover, user_data=None):
557 self.listbox_settings.unselect_all()
558 return False
560 def cb_popover_camouflage_closed(self, popover, user_data=None):
561 self.listbox_settings.unselect_all()
562 return False
564 def cb_searchentry_formats_search_changed(self, widget, user_data=None):
565 self.liststore_formats_filtered.refilter()
566 return False
568 def cb_searchentry_keyboard_search_changed(self, widget, user_data=None):
569 self.liststore_keyboard_filtered.refilter()
570 return False
572 def cb_searchentry_text_search_changed(self, widget, user_data=None):
573 self.liststore_text_filtered.refilter()
574 return False
576 def cb_searchentry_tz_search_changed(self, widget, user_data=None):
577 self.liststore_tz_filtered.refilter()
578 return False
580 def cb_switch_camouflage_active(self, switch, pspec, user_data=None):
581 self.label_settings_camouflage_value.set_text(
582 self.__get_on_off_string(switch.get_state()))
583 self.popover_camouflage.set_visible(False)
585 def cb_switch_macspoof_active(self, switch, pspec, user_data=None):
586 self.label_settings_macspoof_value.set_text(
587 self.__get_on_off_string(switch.get_state()))
588 self.popover_macspoof.set_visible(False)
590 def cb_timeout_storage_unlocked(self, user_data=None):
591 self.button_storage_spinner.set_visible(False)
592 self.entry_storage_passphrase.set_visible(False)
593 self.button_storage_unlock.set_visible(False)
594 self.image_storage_state.set_from_icon_name('tails-unlocked',
595 Gtk.IconSize.BUTTON)
596 self.button_storage_state.set_visible(True)
597 self.button_storage_lock.set_visible(True)
598 return False
600 def cb_toolbutton_settings_add_clicked(self, user_data=None):
601 self.window_add_setting.show_all()
602 return False
604 def cb_toolbutton_settings_remove_clicked(self, user_data=None):
605 try:
606 row = self._last_selected_setting_row.pop()
607 except IndexError:
608 return False
609 self.listbox_settings.remove(row)
610 self.listbox_add_setting.add(row)
611 return False
613 def cb_treeview_formats_row_activated(self, treeview, path, column, user_data=None):
614 treemodel = treeview.get_model()
615 value = treemodel.get_value(treemodel.get_iter(path), 1)
616 self.label_formats_value.set_text(value)
617 self.label_language_header_status.set_text(_("Custom settings"))
618 self.popover_formats.set_visible(False)
620 def cb_treeview_keyboard_row_activated(self, treeview, path, column, user_data=None):
621 treemodel = treeview.get_model()
622 value = treemodel.get_value(treemodel.get_iter(path), 1)
623 self.label_keyboard_value.set_text(value)
624 self.label_language_header_status.set_text(_("Custom settings"))
625 self.popover_keyboard.set_visible(False)
627 def cb_treeview_text_row_activated(self, treeview, path, column, user_data=None):
628 treemodel = treeview.get_model()
629 value = treemodel.get_value(treemodel.get_iter(path), 1)
630 self.label_text_value.set_text(value)
631 self.label_language_header_status.set_text(_("Custom settings"))
632 self.popover_text.set_visible(False)
634 def cb_treeview_tz_row_activated(self, treeview, path, column, user_data=None):
635 treemodel = treeview.get_model()
636 value = treemodel.get_value(treemodel.get_iter(path), 1)
637 self.label_tz_value.set_text(value)
638 self.label_language_header_status.set_text(_("Custom settings"))
639 self.popover_tz.set_visible(False)
641 class GreeterBackgroundWindow(Gtk.ApplicationWindow):
643 def __init__(self, app):
644 Gtk.Window.__init__(self, title=APPLICATION_TITLE, application=app)
645 self.set_icon_name(APPLICATION_ICON_NAME)
646 self.override_background_color(
647 Gtk.StateFlags.NORMAL, Gdk.RGBA(0, 0, 0, 1))
649 class GreeterApplication(Gtk.Application):
651 def __init__(self):
652 Gtk.Application.__init__(self)
653 self.set_application_id = 'org.boum.tails.greeter'
655 def do_activate(self):
656 backgroundwindow = GreeterBackgroundWindow(self)
657 backgroundwindow.maximize()
658 appwindow = GreeterMainWindow(self)
659 appwindow.set_transient_for(backgroundwindow)
661 if not os.getenv('DEBUG'):
662 backgroundwindow.show()
663 appwindow.show()
665 def do_startup(self):
666 Gtk.Application.do_startup(self)
668 app = GreeterApplication()
669 exit_status = app.run(sys.argv)
670 sys.exit(exit_status)