Hide confusing icon from "Configure encrypted storage" button
[tails-greeter-prototype.git] / greeter.py
blobffe52e8e8193fdcc9fffa8cbee0a94b42c3276ea
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 an icon representing encrypted storage
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.listbox_add_setting = self._builder.get_object('listbox_add_setting')
128 box_text_popover = self._builder.get_object('box_text_popover')
129 searchentry_text = self._builder.get_object('searchentry_text')
130 liststore_text = self._builder.get_object('liststore_text')
131 treeview_text = self._builder.get_object('treeview_text')
132 box_keyboard_popover = self._builder.get_object('box_keyboard_popover')
133 searchentry_keyboard = self._builder.get_object('searchentry_keyboard')
134 liststore_keyboard = self._builder.get_object('liststore_keyboard')
135 treeview_keyboard = self._builder.get_object('treeview_keyboard')
136 box_formats_popover = self._builder.get_object('box_formats_popover')
137 searchentry_formats = self._builder.get_object('searchentry_formats')
138 liststore_formats = self._builder.get_object('liststore_formats')
139 treeview_formats = self._builder.get_object('treeview_formats')
140 box_tz_popover = self._builder.get_object('box_tz_popover')
141 searchentry_tz = self._builder.get_object('searchentry_tz')
142 liststore_tz = self._builder.get_object('liststore_tz')
143 treeview_tz = self._builder.get_object('treeview_tz')
145 self.box_admin_popover = self._builder.get_object('box_admin_popover')
146 self.entry_admin_password = \
147 self._builder.get_object('entry_admin_password')
148 self.entry_admin_verify = self._builder.get_object('entry_admin_verify')
149 self.box_macspoof_popover = self._builder.get_object('box_macspoof_popover')
150 switch_macspoof = self._builder.get_object('switch_macspoof')
151 self.box_network_popover = self._builder.get_object('box_network_popover')
152 self.listbox_network_controls = \
153 self._builder.get_object('listbox_network_controls')
154 self.listboxrow_network_clear = \
155 self._builder.get_object('listboxrow_network_clear')
156 self.image_network_clear = \
157 self._builder.get_object('image_network_clear')
158 self.listboxrow_network_specific = \
159 self._builder.get_object('listboxrow_network_specific')
160 self.image_network_specific = \
161 self._builder.get_object('image_network_specific')
162 self.listboxrow_network_off = \
163 self._builder.get_object('listboxrow_network_off')
164 self.image_network_off = \
165 self._builder.get_object('image_network_off')
166 self.box_camouflage_popover = \
167 self._builder.get_object('box_camouflage_popover')
168 switch_camouflage = self._builder.get_object('switch_camouflage')
170 # Set preferred size
171 self.set_default_size(600, -1)
173 # Add our icon dir to icon theme
174 icon_theme = Gtk.IconTheme.get_default()
175 icon_theme.prepend_search_path(ICON_DIR)
177 # Add placeholder to settings ListBox
178 self.listbox_settings.set_placeholder(label_settings_default)
180 # Create HeaderBar
181 headerbar = Gtk.HeaderBar()
182 headerbar_sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
184 button_restart = Gtk.Button()
185 button_restart.set_label(_("Restart"))
186 button_restart.connect('clicked', self.cb_button_restart_clicked)
187 headerbar_sizegroup.add_widget(button_restart)
188 headerbar.pack_start(button_restart)
190 button_start = Gtk.Button()
191 button_start.set_label(_("Start Tails"))
192 Gtk.StyleContext.add_class(button_start.get_style_context(),
193 'suggested-action')
194 button_start.connect('clicked', self.cb_button_start_clicked)
195 headerbar_sizegroup.add_widget(button_start)
196 headerbar.pack_end(button_start)
198 button_tour = Gtk.Button()
199 button_tour.set_label(_("Take a Tour"))
200 button_tour.connect('clicked', self.cb_button_tour_clicked)
201 headerbar_sizegroup.add_widget(button_tour)
202 headerbar.pack_end(button_tour)
204 headerbar.show_all()
206 # Align CheckBoxes to the left
207 for cb in [checkbutton_language_save,
208 self.checkbutton_storage_show_passphrase,
209 checkbutton_settings_save]:
210 cb.set_direction(Gtk.TextDirection.RTL)
212 # Add popovers
213 self.popover_text = self.__add_popover(
214 self.listboxrow_text,
215 box_text_popover,
216 closed_cb=self.cb_popover_text_closed)
217 self.popover_keyboard = self.__add_popover(
218 self.listboxrow_keyboard,
219 box_keyboard_popover,
220 closed_cb=self.cb_popover_keyboard_closed)
221 self.popover_formats = self.__add_popover(
222 self.listboxrow_formats,
223 box_formats_popover,
224 closed_cb=self.cb_popover_formats_closed)
225 self.popover_tz = self.__add_popover(
226 self.listboxrow_tz,
227 box_tz_popover,
228 closed_cb=self.cb_popover_tz_closed)
230 # Add children to ApplicationWindow
231 self.add(box_main)
232 self.set_titlebar(headerbar)
234 # Create "Add Privacy Setting" dialog
235 self.dialog_add_setting = Gtk.Dialog(use_header_bar=True)
236 self.dialog_add_setting.set_transient_for(self)
237 self.dialog_add_setting.set_title(_("Add Privacy Setting"))
238 self.dialog_add_setting.set_default_size(-1, 400)
240 dialog_add_setting_sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
242 self.button_add_setting_cancel = self.dialog_add_setting.add_button(
243 _("Cancel"), Gtk.ResponseType.CANCEL)
244 dialog_add_setting_sizegroup.add_widget(self.button_add_setting_cancel)
246 self.button_add_setting_add = self.dialog_add_setting.add_button(
247 _("Add"), Gtk.ResponseType.YES)
248 Gtk.StyleContext.add_class(self.button_add_setting_add.get_style_context(),
249 'suggested-action')
250 dialog_add_setting_sizegroup.add_widget(self.button_add_setting_add)
252 self.button_add_setting_add.set_visible(False)
253 self.button_add_setting_back = Gtk.Button.new_with_label(_("Back"))
254 self.button_add_setting_back.set_visible(False)
255 self.button_add_setting_back.connect(
256 'clicked', self.cb_button_add_setting_back_clicked, None)
257 dialog_add_setting_sizegroup.add_widget(self.button_add_setting_back)
258 self.dialog_add_setting.get_header_bar().pack_end(self.button_add_setting_back)
260 self.stack_add_setting = Gtk.Stack()
261 self.stack_add_setting.add_named(self.listbox_add_setting, "setting-type")
262 self.listbox_add_setting.set_valign(Gtk.Align.FILL)
263 self.listbox_add_setting.set_vexpand(True)
264 self.stack_add_setting.set_visible(True)
265 self.stack_add_setting.set_transition_type(
266 Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
267 self.dialog_add_setting.get_content_area().add(self.stack_add_setting)
269 # Fill language treeviews
270 for language in greeterdata.languages:
271 liststore_text.append(language)
272 self.__fill_tv("Text Language", treeview_text)
273 self.liststore_text_filtered = liststore_text.filter_new()
274 self.liststore_text_filtered.set_visible_func(
275 self.cb_liststore_filtered_visible_func, data=searchentry_text)
276 treeview_text.set_model(self.liststore_text_filtered)
278 for layout in greeterdata.layouts:
279 liststore_keyboard.append(layout)
280 self.__fill_tv("Keyboard Layout", treeview_keyboard)
281 self.liststore_keyboard_filtered = liststore_keyboard.filter_new()
282 self.liststore_keyboard_filtered.set_visible_func(
283 self.cb_liststore_filtered_visible_func, data=searchentry_keyboard)
284 treeview_keyboard.set_model(self.liststore_keyboard_filtered)
286 for locale in greeterdata.locales:
287 liststore_formats.append(locale)
288 self.__fill_tv("Format", treeview_formats)
289 self.liststore_formats_filtered = liststore_formats.filter_new()
290 self.liststore_formats_filtered.set_visible_func(
291 self.cb_liststore_filtered_visible_func, data=searchentry_formats)
292 treeview_formats.set_model(self.liststore_formats_filtered)
294 for timezone in greeterdata.timezones:
295 liststore_tz.append(timezone)
296 self.__fill_tv("Time Zone", treeview_tz)
297 self.liststore_tz_filtered = liststore_tz.filter_new()
298 self.liststore_tz_filtered.set_visible_func(
299 self.cb_liststore_filtered_visible_func, data=searchentry_tz)
300 treeview_tz.set_model(self.liststore_tz_filtered)
302 # Storage configuration/unlocking
303 if os.getenv('TAILS_HAS_PERSISTENCE'):
304 self.button_storage_configure.set_visible(False)
305 self.checkbutton_storage_show_passphrase.set_visible(True)
306 self.box_storage_unlock.set_visible(True)
307 self.button_storage_state.set_visible(True)
308 self.entry_storage_passphrase.set_visible(True)
309 self.button_storage_unlock.set_visible(True)
311 # Settings popovers
312 switch_macspoof.connect('notify::active', self.cb_switch_macspoof_active)
313 switch_camouflage.connect('notify::active', self.cb_switch_camouflage_active)
315 def setting_admin_check(self):
316 password = self.entry_admin_password.get_text()
317 verify = self.entry_admin_verify.get_text()
318 if verify and verify == password:
319 icon = 'emblem-ok-symbolic'
320 elif verify and not (verify == password):
321 icon = 'dialog-warning-symbolic'
322 else:
323 icon = None
324 self.entry_admin_verify.set_icon_from_icon_name(
325 Gtk.EntryIconPosition.SECONDARY, icon)
326 return (verify == password)
328 def setting_admin_apply(self):
329 if self.setting_admin_check():
330 self.label_settings_admin_value.set_text(
331 self.__get_on_off_string(self.entry_admin_password.get_text()))
332 if hasattr(self, 'popover_admin'):
333 self.popover_admin.set_visible(False)
334 return True
335 else:
336 return False
338 # Utility methods
340 @staticmethod
341 def __add_popover(widget, content, closed_cb=None):
342 popover = Gtk.Popover.new(widget)
343 popover.set_position(Gtk.PositionType.BOTTOM)
344 popover.add(content)
345 if closed_cb:
346 popover.connect('closed', closed_cb)
347 return popover
349 @staticmethod
350 def __fill_tv (name, treeview):
351 assert isinstance(name, str)
352 assert isinstance(treeview, Gtk.TreeView)
353 renderer = Gtk.CellRendererText()
354 column = Gtk.TreeViewColumn(name, renderer, text=1)
355 treeview.append_column(column)
357 @staticmethod
358 def __popover_toggle(popover):
359 if popover.get_visible():
360 popover.set_visible(False)
361 else:
362 popover.set_visible(True)
364 @staticmethod
365 def __get_on_off_string(value):
366 if value:
367 return _("On")
368 else:
369 return _("Off")
371 # Callbacks
373 def cb_button_add_setting_back_clicked(self, widget, user_data=None):
374 self.stack_add_setting.set_visible_child_name('setting-type')
375 self.stack_add_setting.remove(
376 self.stack_add_setting.get_child_by_name('setting-details'))
377 return False
379 def cb_button_help_clicked(self, widget, user_data=None):
380 dialog = Gtk.MessageDialog(
381 self,
382 Gtk.DialogFlags.DESTROY_WITH_PARENT,
383 Gtk.MessageType.INFO,
384 Gtk.ButtonsType.CLOSE,
385 _("You would see the help page for this element."))
386 dialog.run()
387 dialog.destroy()
388 return False
390 def cb_button_restart_clicked(self, widget, user_data=None):
391 self._app.quit()
392 return False
394 def cb_button_start_clicked(self, widget, user_data=None):
395 self._app.quit()
396 return False
398 def cb_button_storage_configure_clicked(self, user_data=None):
399 dialog = Gtk.MessageDialog(
400 self,
401 Gtk.DialogFlags.DESTROY_WITH_PARENT,
402 Gtk.MessageType.INFO,
403 Gtk.ButtonsType.CLOSE,
404 _("You would be able to set up an encrypted storage."))
405 dialog.run()
406 dialog.destroy()
407 return False
409 def cb_button_tour_clicked(self, user_data=None):
410 dialog = Gtk.MessageDialog(
411 self,
412 Gtk.DialogFlags.DESTROY_WITH_PARENT,
413 Gtk.MessageType.INFO,
414 Gtk.ButtonsType.CLOSE,
415 _("You would be guided through options by a wizard."))
416 dialog.run()
417 dialog.destroy()
418 return False
420 def cb_button_storage_lock_clicked(self, widget, user_data=None):
421 self.button_storage_lock.set_visible(False)
422 self.checkbutton_storage_show_passphrase.set_visible(True)
423 self.box_storage_unlock.set_visible(True)
424 self.button_storage_state.set_visible(True)
425 self.image_storage_state.set_from_icon_name('tails-locked',
426 Gtk.IconSize.BUTTON)
427 self.entry_storage_passphrase.set_visible(True)
428 self.entry_storage_passphrase.set_sensitive(True)
429 self.button_storage_unlock.set_visible(True)
430 self.button_storage_unlock.set_sensitive(True)
431 self.button_storage_unlock.set_label(_("Unlock"))
432 return False
434 def cb_button_storage_unlock_clicked(self, widget, user_data=None):
435 self.checkbutton_storage_show_passphrase.set_visible(False)
436 self.entry_storage_passphrase.set_sensitive(False)
437 self.button_storage_unlock.set_sensitive(False)
438 self.button_storage_unlock.set_label(_("Unlocking"))
439 self.button_storage_state.set_visible(False)
440 self.button_storage_spinner.set_visible(True)
441 GLib.timeout_add_seconds(2, self.cb_timeout_storage_unlocked, user_data=None)
442 return False
444 def cb_checkbutton_storage_show_passphrase_toggled(self, widget, user_data=None):
445 self.entry_storage_passphrase.set_visibility(widget.get_active())
447 def cb_entry_admin_changed(self, editable, user_data=None):
448 self.setting_admin_check()
449 return False
451 def cb_entry_admin_focus_out_event(self, widget, event, user_data=None):
452 self.setting_admin_apply()
453 return False
455 def cb_entry_admin_password_activate(self, widget, user_data=None):
456 self.entry_admin_verify.grab_focus()
457 return False
459 def cb_entry_admin_verify_activate(self, widget, user_data=None):
460 self.setting_admin_apply()
461 return False
463 def cb_listbox_add_setting_focus(self, widget, direction, user_data=None):
464 # Workaround autoselection of 1st item on focus
465 self.listbox_add_setting.unselect_all()
466 return False
468 def cb_listbox_add_setting_row_activated(self, listbox, row, user_data=None):
469 if row == self.listboxrow_settings_admin:
470 box = self.box_admin_popover
471 elif row == self.listboxrow_settings_macspoof:
472 box = self.box_macspoof_popover
473 elif row == self.listboxrow_settings_network:
474 box = self.box_network_popover
475 elif row == self.listboxrow_settings_camouflage:
476 box = self.box_camouflage_popover
477 else: # this happens when the row gets unselected
478 return False
479 self.stack_add_setting.add_named(box, 'setting-details')
480 self.stack_add_setting.set_visible_child_name('setting-details')
481 self.button_add_setting_back.set_visible(True)
482 self.button_add_setting_add.set_visible(True)
483 return False
485 def cb_listbox_language_row_activated(self, listbox, row, user_data=None):
486 if row == self.listboxrow_text:
487 self.__popover_toggle(self.popover_text)
488 elif row == self.listboxrow_keyboard:
489 self.__popover_toggle(self.popover_keyboard)
490 elif row == self.listboxrow_formats:
491 self.__popover_toggle(self.popover_formats)
492 elif row == self.listboxrow_tz:
493 self.__popover_toggle(self.popover_tz)
494 return False
496 def cb_listbox_network_row_activated(self, listbox, row, user_data=None):
497 if row == self.listboxrow_network_clear:
498 self.image_network_clear.set_visible(True)
499 self.image_network_specific.set_visible(False)
500 self.image_network_off.set_visible(False)
501 self.label_settings_network_value.set_text(_("Direct"))
502 elif row == self.listboxrow_network_specific:
503 self.image_network_specific.set_visible(True)
504 self.image_network_clear.set_visible(False)
505 self.image_network_off.set_visible(False)
506 self.label_settings_network_value.set_text(_("Censored"))
507 elif row == self.listboxrow_network_off:
508 self.image_network_off.set_visible(True)
509 self.image_network_specific.set_visible(False)
510 self.image_network_clear.set_visible(False)
511 self.label_settings_network_value.set_text(_("Off"))
512 if hasattr(self, 'popover_network'):
513 self.popover_network.set_visible(False)
514 return False
516 def cb_listbox_settings_add(self, listbox, row, user_data=None):
517 self._last_selected_setting_row.append(row)
518 if len(listbox.get_children()) > 0:
519 self.toolbutton_settings_remove.set_sensitive(True)
520 return False
522 def cb_listbox_settings_remove(self, container, object, user_data=None):
523 if len(container.get_children()) == 0:
524 self.toolbutton_settings_remove.set_sensitive(False)
525 return False
527 def cb_listbox_settings_row_selected(self, listbox, row, user_data=None):
528 if row:
529 self._last_selected_setting_row.append(row)
531 def cb_listbox_settings_row_activated(self, listbox, row, user_data=None):
532 if row == self.listboxrow_settings_admin:
533 self.__popover_toggle(self.popover_admin)
534 elif row == self.listboxrow_settings_macspoof:
535 self.__popover_toggle(self.popover_macspoof)
536 elif row == self.listboxrow_settings_network:
537 self.__popover_toggle(self.popover_network)
538 elif row == self.listboxrow_settings_camouflage:
539 self.__popover_toggle(self.popover_camouflage)
540 return False
542 def cb_liststore_filtered_visible_func(self, model, treeiter, searchentry):
543 search_query = searchentry.get_text().lower()
544 value = model.get_value(treeiter, 1).lower()
545 if not search_query:
546 return True
547 elif search_query in value:
548 return True
549 else:
550 return False
552 def cb_popover_text_closed(self, popover, user_data=None):
553 self.listbox_language.unselect_all()
554 return False
556 def cb_popover_keyboard_closed(self, popover, user_data=None):
557 self.listbox_language.unselect_all()
558 return False
560 def cb_popover_formats_closed(self, popover, user_data=None):
561 self.listbox_language.unselect_all()
562 return False
564 def cb_popover_tz_closed(self, popover, user_data=None):
565 self.listbox_language.unselect_all()
566 return False
568 def cb_popover_admin_closed(self, popover, user_data=None):
569 self.listbox_settings.unselect_all()
570 return False
572 def cb_popover_macspoof_closed(self, popover, user_data=None):
573 self.listbox_settings.unselect_all()
574 return False
576 def cb_popover_network_closed(self, popover, user_data=None):
577 self.listbox_settings.unselect_all()
578 return False
580 def cb_popover_camouflage_closed(self, popover, user_data=None):
581 self.listbox_settings.unselect_all()
582 return False
584 def cb_searchentry_formats_search_changed(self, widget, user_data=None):
585 self.liststore_formats_filtered.refilter()
586 return False
588 def cb_searchentry_keyboard_search_changed(self, widget, user_data=None):
589 self.liststore_keyboard_filtered.refilter()
590 return False
592 def cb_searchentry_text_search_changed(self, widget, user_data=None):
593 self.liststore_text_filtered.refilter()
594 return False
596 def cb_searchentry_tz_search_changed(self, widget, user_data=None):
597 self.liststore_tz_filtered.refilter()
598 return False
600 def cb_switch_camouflage_active(self, switch, pspec, user_data=None):
601 self.label_settings_camouflage_value.set_text(
602 self.__get_on_off_string(switch.get_state()))
603 if hasattr(self, 'popover_camouflage'):
604 self.popover_camouflage.set_visible(False)
606 def cb_switch_macspoof_active(self, switch, pspec, user_data=None):
607 self.label_settings_macspoof_value.set_text(
608 self.__get_on_off_string(switch.get_state()))
609 if hasattr(self, 'popover_macspoof'):
610 self.popover_macspoof.set_visible(False)
612 def cb_timeout_storage_unlocked(self, user_data=None):
613 self.button_storage_spinner.set_visible(False)
614 self.entry_storage_passphrase.set_visible(False)
615 self.button_storage_unlock.set_visible(False)
616 self.image_storage_state.set_from_icon_name('tails-unlocked',
617 Gtk.IconSize.BUTTON)
618 self.button_storage_state.set_visible(True)
619 self.button_storage_lock.set_visible(True)
620 return False
622 def cb_toolbutton_settings_add_clicked(self, user_data=None):
623 self.stack_add_setting.set_visible_child_name('setting-type')
624 self.button_add_setting_back.set_visible(False)
625 self.button_add_setting_add.set_visible(False)
626 response = self.dialog_add_setting.run()
627 if response == Gtk.ResponseType.YES:
628 row = self.listbox_add_setting.get_selected_row()
629 self.listbox_add_setting.remove(row)
630 self.listbox_settings.add(row)
631 self.dialog_add_setting.set_visible(False)
632 if row == self.listboxrow_settings_admin:
633 self.stack_add_setting.remove(self.box_admin_popover)
634 self.popover_admin = self.__add_popover(
635 self.listboxrow_settings_admin,
636 self.box_admin_popover,
637 closed_cb=self.cb_popover_admin_closed)
638 elif row == self.listboxrow_settings_macspoof:
639 self.stack_add_setting.remove(self.box_macspoof_popover)
640 self.popover_macspoof = self.__add_popover(
641 self.listboxrow_settings_macspoof,
642 self.box_macspoof_popover,
643 closed_cb=self.cb_popover_macspoof_closed)
644 elif row == self.listboxrow_settings_network:
645 self.stack_add_setting.remove(self.box_network_popover)
646 self.popover_network = self.__add_popover(
647 self.listboxrow_settings_network,
648 self.box_network_popover,
649 closed_cb=self.cb_popover_network_closed)
650 elif row == self.listboxrow_settings_camouflage:
651 self.stack_add_setting.remove(self.box_camouflage_popover)
652 self.popover_camouflage = self.__add_popover(
653 self.listboxrow_settings_camouflage,
654 self.box_camouflage_popover,
655 closed_cb=self.cb_popover_camouflage_closed)
656 self.listbox_settings.unselect_all()
657 if len(self.listbox_add_setting.get_children()) == 0:
658 self.toolbutton_settings_add.set_sensitive(False)
659 self.dialog_add_setting.set_visible(False)
660 self.dialog_add_setting.set_visible(False)
661 return False
663 def cb_toolbutton_settings_remove_clicked(self, user_data=None):
664 try:
665 row = self._last_selected_setting_row.pop()
666 except IndexError:
667 return False
668 self.listbox_settings.remove(row)
669 self.listbox_add_setting.add(row)
670 return False
672 def cb_treeview_formats_row_activated(self, treeview, path, column, user_data=None):
673 treemodel = treeview.get_model()
674 value = treemodel.get_value(treemodel.get_iter(path), 1)
675 self.label_formats_value.set_text(value)
676 self.label_language_header_status.set_text(_("Custom settings"))
677 self.popover_formats.set_visible(False)
679 def cb_treeview_keyboard_row_activated(self, treeview, path, column, user_data=None):
680 treemodel = treeview.get_model()
681 value = treemodel.get_value(treemodel.get_iter(path), 1)
682 self.label_keyboard_value.set_text(value)
683 self.label_language_header_status.set_text(_("Custom settings"))
684 self.popover_keyboard.set_visible(False)
686 def cb_treeview_text_row_activated(self, treeview, path, column, user_data=None):
687 treemodel = treeview.get_model()
688 value = treemodel.get_value(treemodel.get_iter(path), 1)
689 self.label_text_value.set_text(value)
690 self.label_language_header_status.set_text(_("Custom settings"))
691 self.popover_text.set_visible(False)
693 def cb_treeview_tz_row_activated(self, treeview, path, column, user_data=None):
694 treemodel = treeview.get_model()
695 value = treemodel.get_value(treemodel.get_iter(path), 1)
696 self.label_tz_value.set_text(value)
697 self.label_language_header_status.set_text(_("Custom settings"))
698 self.popover_tz.set_visible(False)
700 class GreeterBackgroundWindow(Gtk.ApplicationWindow):
702 def __init__(self, app):
703 Gtk.Window.__init__(self, title=APPLICATION_TITLE, application=app)
704 self.set_icon_name(APPLICATION_ICON_NAME)
705 self.override_background_color(
706 Gtk.StateFlags.NORMAL, Gdk.RGBA(0, 0, 0, 1))
708 class GreeterApplication(Gtk.Application):
710 def __init__(self):
711 Gtk.Application.__init__(self)
712 self.set_application_id = 'org.boum.tails.greeter'
714 def do_activate(self):
715 backgroundwindow = GreeterBackgroundWindow(self)
716 backgroundwindow.maximize()
717 appwindow = GreeterMainWindow(self)
718 appwindow.set_transient_for(backgroundwindow)
720 if not os.getenv('DEBUG'):
721 backgroundwindow.show()
722 appwindow.show()
724 def do_startup(self):
725 Gtk.Application.do_startup(self)
727 app = GreeterApplication()
728 exit_status = app.run(sys.argv)
729 sys.exit(exit_status)