def terminal_spawn(self, directory=None): terminal = GuakeTerminal(self.guake) terminal.grab_focus() terminal.connect( "key-press-event", lambda x, y: self.guake.accel_group.activate(x, y) if self.guake.accel_group else False, ) if not isinstance(directory, str): directory = os.environ["HOME"] try: if self.guake.settings.general.get_boolean("open-tab-cwd"): # Do last focused terminal still alive? active_terminal = self.get_current_terminal() if not active_terminal: # If not alive, can we get any focused terminal? active_terminal = self.get_focused_terminal() directory = os.path.expanduser("~") if active_terminal: # If found, we will use its directory as new terminal's directory directory = active_terminal.get_current_directory() except BaseException: pass log.info("Spawning new terminal at %s", directory) terminal.spawn_sync_pid(directory) return terminal
def new_page(self, directory=None): terminal = GuakeTerminal(self.guake) terminal.grab_focus() if not isinstance(directory, str): directory = os.environ['HOME'] try: if self.guake.settings.general.get_boolean('open-tab-cwd'): active_terminal = self.get_focused_terminal() directory = os.path.expanduser('~') if active_terminal: directory = active_terminal.get_current_directory() except Exception as e: pass terminal.spawn_sync_pid(directory) terminal_box = TerminalBox() terminal_box.set_terminal(terminal) root_terminal_box = RootTerminalBox(self.guake) root_terminal_box.set_child(terminal_box) page_num = self.append_page(root_terminal_box, None) self.set_tab_reorderable(root_terminal_box, True) self.show_all() # needed to show newly added tabs and pages # this is needed to initially set the last_terminal_focused, # one could also call terminal.get_parent().on_terminal_focus() terminal.emit("focus", Gtk.DirectionType.TAB_FORWARD) self.emit('terminal-spawned', terminal, terminal.pid) return root_terminal_box, page_num, terminal
def terminal_spawn(self, directory=None): terminal = GuakeTerminal(self.guake) terminal.grab_focus() if not isinstance(directory, str): directory = os.environ['HOME'] try: if self.guake.settings.general.get_boolean('open-tab-cwd'): active_terminal = self.get_focused_terminal() directory = os.path.expanduser('~') if active_terminal: directory = active_terminal.get_current_directory() except Exception as e: pass log.info("Spawning new terminal at %s", directory) terminal.spawn_sync_pid(directory) return terminal
def terminal_spawn(self, directory=None): terminal = GuakeTerminal(self.guake) terminal.grab_focus() if not isinstance(directory, str): directory = os.environ['HOME'] try: if self.guake.settings.general.get_boolean('open-tab-cwd'): # Do last focused terminal still alive? active_terminal = self.get_current_terminal() if not active_terminal: # If not alive, can we get any focused terminal? active_terminal = self.get_focused_terminal() directory = os.path.expanduser('~') if active_terminal: # If found, we will use its directory as new terminal's directory directory = active_terminal.get_current_directory() except Exception as e: pass log.info("Spawning new terminal at %s", directory) terminal.spawn_sync_pid(directory) return terminal
def terminal_spawn(self, directory=None): terminal = GuakeTerminal(self.guake) terminal.grab_focus() if not isinstance(directory, str): directory = os.environ['HOME'] try: if self.guake.settings.general.get_boolean('open-tab-cwd'): active_terminal = self.get_focused_terminal() directory = os.path.expanduser('~') if active_terminal: directory = active_terminal.get_current_directory() except Exception as e: pass terminal.spawn_sync_pid(directory) return terminal
def __init__(self): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.add_callbacks(PrefsCallbacks(self)) self.client = gconf.client_get_default() # window cleanup handler self.get_widget('config-window').connect('destroy', self.on_destroy) # setting evtbox title bg eventbox = self.get_widget('eventbox-title') eventbox.modify_bg(gtk.STATE_NORMAL, eventbox.get_colormap().alloc_color("#ffffff")) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # the first position in tree will store the keybinding path in gconf, # and the user doesn't worry with this, let's hide that =D model = gtk.TreeStore(str, str, object, bool) treeview = self.get_widget('treeview-keys') treeview.set_model(model) treeview.set_rules_hint(True) treeview.connect('button-press-event', self.start_editing) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn('keypath', renderer, text=0) column.set_visible(False) treeview.append_column(column) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_key_edited, model) renderer.connect('accel-cleared', self.on_key_cleared, model) column = gtk.TreeViewColumn(_('Shortcut'), renderer) column.set_cell_data_func(renderer, self.cell_data_func) column.set_property('expand', False) treeview.append_column(column) self.demo_terminal = GuakeTerminal() demo_terminal_box = self.get_widget('demo_terminal_box') demo_terminal_box.add(self.demo_terminal) default_params = {} pid = self.demo_terminal.fork_command(**default_params) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide() # Preview when selecting a bgimage self.selection_preview = gtk.Image() self.file_filter = gtk.FileFilter() self.file_filter.add_pattern("*.jpg") self.file_filter.add_pattern("*.png") self.file_filter.add_pattern("*.svg") self.file_filter.add_pattern("*.jpeg") self.bgfilechooser = self.get_widget('background_image') self.bgfilechooser.set_preview_widget(self.selection_preview) self.bgfilechooser.set_filter(self.file_filter) self.bgfilechooser.connect('update-preview', self.update_preview, self.selection_preview)
class PrefsDialog(SimpleGladeApp): """The Guake Preferences dialog. """ def __init__(self): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.add_callbacks(PrefsCallbacks(self)) self.client = gconf.client_get_default() # window cleanup handler self.get_widget('config-window').connect('destroy', self.on_destroy) # setting evtbox title bg eventbox = self.get_widget('eventbox-title') eventbox.modify_bg(gtk.STATE_NORMAL, eventbox.get_colormap().alloc_color("#ffffff")) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # the first position in tree will store the keybinding path in gconf, # and the user doesn't worry with this, let's hide that =D model = gtk.TreeStore(str, str, object, bool) treeview = self.get_widget('treeview-keys') treeview.set_model(model) treeview.set_rules_hint(True) treeview.connect('button-press-event', self.start_editing) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn('keypath', renderer, text=0) column.set_visible(False) treeview.append_column(column) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_key_edited, model) renderer.connect('accel-cleared', self.on_key_cleared, model) column = gtk.TreeViewColumn(_('Shortcut'), renderer) column.set_cell_data_func(renderer, self.cell_data_func) column.set_property('expand', False) treeview.append_column(column) self.demo_terminal = GuakeTerminal() demo_terminal_box = self.get_widget('demo_terminal_box') demo_terminal_box.add(self.demo_terminal) default_params = {} pid = self.demo_terminal.fork_command(**default_params) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide() # Preview when selecting a bgimage self.selection_preview = gtk.Image() self.file_filter = gtk.FileFilter() self.file_filter.add_pattern("*.jpg") self.file_filter.add_pattern("*.png") self.file_filter.add_pattern("*.svg") self.file_filter.add_pattern("*.jpeg") self.bgfilechooser = self.get_widget('background_image') self.bgfilechooser.set_preview_widget(self.selection_preview) self.bgfilechooser.set_filter(self.file_filter) self.bgfilechooser.connect('update-preview', self.update_preview, self.selection_preview) def show(self): """Calls the main window show_all method and presents the window in the desktop. """ self.get_widget('config-window').show_all() self.get_widget('config-window').present() def hide(self): """Calls the main window hide function. """ self.get_widget('config-window').hide() def on_destroy(self, window): self.demo_terminal.kill() self.demo_terminal.destroy() def update_preview(self, file_chooser, preview): """Used by filechooser to preview image files """ filename = file_chooser.get_preview_filename() if filename and os.path.isfile(filename or ''): try: mkpb = gtk.gdk.pixbuf_new_from_file_at_size pixbuf = mkpb(filename, 256, 256) preview.set_from_pixbuf(pixbuf) file_chooser.set_preview_widget_active(True) except gobject.GError: # this exception is raised when user chooses a # non-image file or a directory warnings.warn('File %s is not an image' % filename) else: file_chooser.set_preview_widget_active(False) def toggle_prompt_on_quit_sensitivity(self, combo): """If toggle_on_close_tabs is set to 2 (Always), prompt_on_quit has no effect. """ self.get_widget('prompt_on_quit').set_sensitive(combo.get_active() != 2) def toggle_style_sensitivity(self, chk): """If the user chooses to use the gnome default font configuration it means that he will not be able to use the font selector. """ self.get_widget('font_style').set_sensitive(not chk.get_active()) def toggle_use_font_background_sensitivity(self, chk): """If the user chooses to use the gnome default font configuration it means that he will not be able to use the font selector. """ self.get_widget('palette_16').set_sensitive(chk.get_active()) self.get_widget('palette_17').set_sensitive(chk.get_active()) def toggle_display_n_sensitivity(self, chk): """When the user unchecks 'on mouse display', the option to select an alternate display should be enabeld. """ self.get_widget('display_n').set_sensitive(not chk.get_active()) def toggle_quick_open_command_line_sensitivity(self, chk): """When the user unchecks 'enable quick open', the command line should be disabled """ self.get_widget('quick_open_command_line').set_sensitive(chk.get_active()) self.get_widget('quick_open_in_current_terminal').set_sensitive(chk.get_active()) def toggle_use_vte_titles(self, chk): """When vte titles aren't used, there is nothing to abbreviate """ self.update_vte_subwidgets_states() def update_vte_subwidgets_states(self): do_use_vte_titles = self.get_widget('use_vte_titles').get_active() max_tab_name_length_wdg = self.get_widget('max_tab_name_length') max_tab_name_length_wdg.set_sensitive(do_use_vte_titles) self.get_widget('lbl_max_tab_name_length').set_sensitive(do_use_vte_titles) self.get_widget('abbreviate_tab_names').set_sensitive(do_use_vte_titles) def clear_background_image(self, btn): """Unset the gconf variable that holds the name of the background image of all terminals. """ self.client.unset(KEY('/style/background/image')) self.bgfilechooser.unselect_all() def on_reset_compat_defaults_clicked(self, bnt): """Reset default values to compat_{backspace,delete} gconf keys. The default values are retrivied from the guake.schemas file. """ self.client.unset(KEY('/general/compat_backspace')) self.client.unset(KEY('/general/compat_delete')) self.reload_erase_combos() def on_palette_name_changed(self, combo): """Changes the value of palette in gconf """ palette_name = combo.get_active_text() if palette_name not in PALETTES: return self.client.set_string(KEY('/style/font/palette'), PALETTES[palette_name]) self.client.set_string(KEY('/style/font/palette_name'), palette_name) self.set_palette_colors(PALETTES[palette_name]) self.update_demo_palette(PALETTES[palette_name]) def on_cursor_shape_changed(self, combo): """Changes the value of cursor_shape in gconf """ index = combo.get_active() self.client.set_int(KEY('/style/cursor_shape'), index) def on_blink_cursor_toggled(self, chk): """Changes the value of blink_cursor in gconf """ self.client.set_int(KEY('/style/cursor_blink_mode'), chk.get_active()) def on_palette_color_set(self, btn): """Changes the value of palette in gconf """ palette = [] for i in range(18): palette.append(hexify_color( self.get_widget('palette_%d' % i).get_color())) palette = ':'.join(palette) self.client.set_string(KEY('/style/font/palette'), palette) self.client.set_string(KEY('/style/font/palette_name'), _('Custom')) self.set_palette_name('Custom') self.update_demo_palette(palette) def set_palette_name(self, palette_name): """If the given palette matches an existing one, shows it in the combobox """ combo = self.get_widget('palette_name') found = False log.debug("wanting palette: %r", palette_name) for i in combo.get_model(): if i[0] == palette_name: combo.set_active_iter(i.iter) found = True break if not found: combo.set_active(self.custom_palette_index) def update_demo_palette(self, palette): fgcolor = gtk.gdk.color_parse( self.client.get_string(KEY('/style/font/color'))) bgcolor = gtk.gdk.color_parse( self.client.get_string(KEY('/style/background/color'))) palette = [gtk.gdk.color_parse(color) for color in palette.split(':')] font_name = self.client.get_string(KEY('/style/font/style')) font = FontDescription(font_name) use_palette_font_and_background_color = self.client.get_bool( KEY('/general/use_palette_font_and_background_color')) if use_palette_font_and_background_color and len(palette) > 16: fgcolor = palette[16] bgcolor = palette[17] self.demo_terminal.set_color_dim(fgcolor) self.demo_terminal.set_color_foreground(fgcolor) self.demo_terminal.set_color_bold(fgcolor) self.demo_terminal.set_color_background(bgcolor) self.demo_terminal.set_background_tint_color(bgcolor) self.demo_terminal.set_colors(fgcolor, bgcolor, palette[:16]) self.demo_terminal.set_font(font) def fill_palette_names(self): combo = self.get_widget('palette_name') for palette_name in sorted(PALETTES.keys()): combo.append_text(palette_name) self.custom_palette_index = len(PALETTES) combo.append_text(_('Custom')) def set_cursor_shape(self, shape_index): self.get_widget('cursor_shape').set_active(shape_index) def set_cursor_blink_mode(self, mode_index): self.get_widget('cursor_blink_mode').set_active(mode_index) def set_palette_colors(self, palette): """Updates the color buttons with the given palette """ palette = palette.split(':') for i, pal in enumerate(palette): color = gtk.gdk.color_parse(pal) self.get_widget('palette_%d' % i).set_color(color) def reload_erase_combos(self, btn=None): """Read from gconf the value of compat_{backspace,delete} vars and select the right option in combos. """ # backspace erase binding combo = self.get_widget('backspace-binding-combobox') binding = self.client.get_string(KEY('/general/compat_backspace')) for i in combo.get_model(): if ERASE_BINDINGS.get(i[0]) == binding: combo.set_active_iter(i.iter) # delete erase binding combo = self.get_widget('delete-binding-combobox') binding = self.client.get_string(KEY('/general/compat_delete')) for i in combo.get_model(): if ERASE_BINDINGS.get(i[0]) == binding: combo.set_active_iter(i.iter) def load_configs(self): """Load configurations for all widgets in General, Scrolling and Appearance tabs from gconf. """ # default_shell combo = self.get_widget('default_shell') # get the value for defualt shell. If unset, set to USER_SHELL_VALUE. value = self.client.get_string(KEY('/general/default_shell')) or USER_SHELL_VALUE for i in combo.get_model(): if i[0] == value: combo.set_active_iter(i.iter) # login shell value = self.client.get_bool(KEY('/general/use_login_shell')) self.get_widget('use_login_shell').set_active(value) # tray icon value = self.client.get_bool(KEY('/general/use_trayicon')) self.get_widget('use_trayicon').set_active(value) # popup value = self.client.get_bool(KEY('/general/use_popup')) self.get_widget('use_popup').set_active(value) # prompt on quit value = self.client.get_bool(KEY('/general/prompt_on_quit')) self.get_widget('prompt_on_quit').set_active(value) # prompt on close_tab value = self.client.get_int(KEY('/general/prompt_on_close_tab')) self.get_widget('prompt_on_close_tab').set_active(value) self.get_widget('prompt_on_quit').set_sensitive(value != 2) # ontop value = self.client.get_bool(KEY('/general/window_ontop')) self.get_widget('window_ontop').set_active(value) # tab ontop value = self.client.get_bool(KEY('/general/tab_ontop')) self.get_widget('tab_ontop').set_active(value) # losefocus value = self.client.get_bool(KEY('/general/window_losefocus')) self.get_widget('window_losefocus').set_active(value) # use VTE titles value = self.client.get_bool(KEY('/general/use_vte_titles')) self.get_widget('use_vte_titles').set_active(value) # abbreviate tab names self.get_widget('abbreviate_tab_names').set_sensitive(value) value = self.client.get_bool(KEY('/general/abbreviate_tab_names')) self.get_widget('abbreviate_tab_names').set_active(value) # max tab name length value = self.client.get_int(KEY('/general/max_tab_name_length')) self.get_widget('max_tab_name_length').set_value(value) self.update_vte_subwidgets_states() value = self.client.get_float(KEY('/general/window_height_f')) if not value: value = self.client.get_int(KEY('/general/window_height')) self.get_widget('window_height').set_value(value) value = self.client.get_float(KEY('/general/window_width_f')) if not value: value = self.client.get_int(KEY('/general/window_width')) self.get_widget('window_width').set_value(value) value = self.client.get_int(KEY('/general/window_halignment')) which_button = { ALIGN_RIGHT: 'radiobutton_align_right', ALIGN_LEFT: 'radiobutton_align_left', ALIGN_CENTER: 'radiobutton_align_center' } self.get_widget(which_button[value]).set_active(True) value = self.client.get_bool(KEY('/general/open_tab_cwd')) self.get_widget('open_tab_cwd').set_active(value) # tab bar value = self.client.get_bool(KEY('/general/window_tabbar')) self.get_widget('window_tabbar').set_active(value) # start fullscreen value = self.client.get_bool(KEY('/general/start_fullscreen')) self.get_widget('start_fullscreen').set_active(value) # use visible bell value = self.client.get_bool(KEY('/general/use_visible_bell')) self.get_widget('use_visible_bell').set_active(value) # use audible bell value = self.client.get_bool(KEY('/general/use_audible_bell')) self.get_widget('use_audible_bell').set_active(value) # display number / use primary display combo = self.get_widget('display_n') dest_screen = self.client.get_int(KEY('/general/display_n')) value = self.client.get_bool(KEY('/general/quick_open_enable')) self.get_widget('quick_open_enable').set_active(value) self.get_widget('quick_open_command_line').set_sensitive(value) self.get_widget('quick_open_in_current_terminal').set_sensitive(value) text = gtk.TextBuffer() text = self.get_widget('quick_open_supported_patterns').get_buffer() for title, matcher, _useless in QUICK_OPEN_MATCHERS: text.insert_at_cursor("%s: %s\n" % (title, matcher)) self.get_widget('quick_open_supported_patterns').set_buffer(text) value = self.client.get_string(KEY('/general/quick_open_command_line')) if value is None: value = "subl %(file_path)s:%(line_number)s" self.get_widget('quick_open_command_line').set_text(value) value = self.client.get_bool(KEY('/general/quick_open_in_current_terminal')) self.get_widget('quick_open_in_current_terminal').set_active(value) value = self.client.get_string(KEY('/general/startup_script')) self.get_widget('startup_script').set_text(value) # If Guake is configured to use a screen that is not currently attached, # default to 'primary display' option. screen = self.get_widget('config-window').get_screen() n_screens = screen.get_n_monitors() if dest_screen > n_screens - 1: self.client.set_bool(KEY('/general/mouse_display'), False) dest_screen = screen.get_primary_monitor() self.client.set_int(KEY('/general/display_n'), dest_screen) if dest_screen == ALWAYS_ON_PRIMARY: first_item = combo.get_model().get_iter_first() combo.set_active_iter(first_item) else: seen_first = False # first item "always on primary" is special for i in combo.get_model(): if seen_first: i_int = int(i[0].split()[0]) # extracts 1 from '1' or from '1 (primary)' if i_int == dest_screen: combo.set_active_iter(i.iter) else: seen_first = True # use display where the mouse is currently value = self.client.get_bool(KEY('/general/mouse_display')) self.get_widget('mouse_display').set_active(value) # scrollbar value = self.client.get_bool(KEY('/general/use_scrollbar')) self.get_widget('use_scrollbar').set_active(value) # history size value = self.client.get_int(KEY('/general/history_size')) self.get_widget('history_size').set_value(value) # scroll output value = self.client.get_bool(KEY('/general/scroll_output')) self.get_widget('scroll_output').set_active(value) # scroll keystroke value = self.client.get_bool(KEY('/general/scroll_keystroke')) self.get_widget('scroll_keystroke').set_active(value) # default font value = self.client.get_bool(KEY('/general/use_default_font')) self.get_widget('use_default_font').set_active(value) self.get_widget('font_style').set_sensitive(not value) # use font and background color value = self.client.get_bool(KEY('/general/use_palette_font_and_background_color')) self.get_widget('use_palette_font_and_background_color').set_active(value) self.get_widget('palette_16').set_sensitive(value) self.get_widget('palette_17').set_sensitive(value) # font value = self.client.get_string(KEY('/style/font/style')) if value: self.get_widget('font_style').set_font_name(value) # font color val = self.client.get_string(KEY('/style/font/color')) try: color = gtk.gdk.color_parse(val) self.get_widget('font_color').set_color(color) except (ValueError, TypeError): warnings.warn('Unable to parse color %s' % val, Warning) # background color value = self.client.get_string(KEY('/style/background/color')) try: color = gtk.gdk.color_parse(value) self.get_widget('background_color').set_color(color) except (ValueError, TypeError): warnings.warn('Unable to parse color %s' % val, Warning) # allow bold font value = self.client.get_bool(KEY('/style/font/allow_bold')) self.get_widget('allow_bold').set_active(value) # palette self.fill_palette_names() value = self.client.get_string(KEY('/style/font/palette_name')) self.set_palette_name(value) value = self.client.get_string(KEY('/style/font/palette')) self.set_palette_colors(value) self.update_demo_palette(value) # cursor shape value = self.client.get_int(KEY('/style/cursor_shape')) self.set_cursor_shape(value) # cursor blink value = self.client.get_int(KEY('/style/cursor_blink_mode')) self.set_cursor_blink_mode(value) # background image value = self.client.get_string(KEY('/style/background/image')) if os.path.isfile(value or ''): self.get_widget('background_image').set_filename(value) value = self.client.get_int(KEY('/style/background/transparency')) self.get_widget('background_transparency').set_value(value) value = self.client.get_int(KEY('/general/window_valignment')) self.get_widget('top_align').set_active(value) # it's a separated method, to be reused. self.reload_erase_combos() # custom command context-menu configuration file custom_command_file = self.client.get_string(KEY('/general/custom_command_file')) if custom_command_file: custom_command_file_name = os.path.expanduser(custom_command_file) else: custom_command_file_name = None custom_cmd_filter = gtk.FileFilter() custom_cmd_filter.set_name(_("JSON files")) custom_cmd_filter.add_pattern("*.json") self.get_widget('custom_command_file_chooser').add_filter(custom_cmd_filter) all_files_filter = gtk.FileFilter() all_files_filter.set_name(_("All files")) all_files_filter.add_pattern("*") self.get_widget('custom_command_file_chooser').add_filter(all_files_filter) if custom_command_file_name: self.get_widget('custom_command_file_chooser').set_filename(custom_command_file_name) # -- populate functions -- def populate_shell_combo(self): """Read the /etc/shells and looks for installed shells to fill the default_shell combobox. """ cb = self.get_widget('default_shell') # append user shell as first option cb.append_text(USER_SHELL_VALUE) if os.path.exists(SHELLS_FILE): lines = open(SHELLS_FILE).readlines() for i in lines: possible = i.strip() if possible and not possible.startswith('#') and os.path.exists(possible): cb.append_text(possible) for i in get_binaries_from_path(PYTHONS): cb.append_text(i) def populate_keys_tree(self): """Reads the HOTKEYS global variable and insert all data in the TreeStore used by the preferences window treeview. """ model = self.get_widget('treeview-keys').get_model() for group in HOTKEYS: giter = model.append(None) model.set(giter, 0, '', 1, _(group['label'])) for item in group['keys']: child = model.append(giter) accel = self.client.get_string(item['key']) if accel: params = gtk.accelerator_parse(accel) hotkey = KeyEntry(*params) else: hotkey = KeyEntry(0, 0) model.set(child, 0, item['key'], 1, _(item['label']), 2, hotkey, 3, True) self.get_widget('treeview-keys').expand_all() def populate_display_n(self): """Get the number of displays and populate this drop-down box with them all. Prepend the "always on primary" option. """ cb = self.get_widget('display_n') screen = self.get_widget('config-window').get_screen() cb.append_text("always on primary") for m in range(0, int(screen.get_n_monitors())): if m == int(screen.get_primary_monitor()): # TODO l10n cb.append_text(str(m) + ' ' + '(primary)') else: cb.append_text(str(m)) # -- key handling -- def on_key_edited(self, renderer, path, keycode, mask, keyval, model): """Callback that handles key edition in cellrenderer. It makes some tests to validate the key, like looking for already in use keys and look for [A-Z][a-z][0-9] to avoid problems with these common keys. If all tests are ok, the value will be stored in gconf. """ giter = model.get_iter(path) gconf_path = model.get_value(giter, 0) oldkey = model.get_value(giter, 2) hotkey = KeyEntry(keycode, mask) key = gtk.accelerator_name(keycode, mask) keylabel = gtk.accelerator_get_label(keycode, mask) # we needn't to change anything, the user is trying to set the # same key that is already set. if oldkey == hotkey: return False # looking for already used keybindings def each_key(model, path, subiter): keyentry = model.get_value(subiter, 2) if keyentry and keyentry == hotkey: msg = _("The shortcut \"%s\" is already in use.") % keylabel raise ShowableError(_('Error setting keybinding.'), msg, -1) model.foreach(each_key) # avoiding problems with common keys if ((mask == 0 and keycode != 0) and ( (keycode >= ord('a') and keycode <= ord('z')) or (keycode >= ord('A') and keycode <= ord('Z')) or (keycode >= ord('0') and keycode <= ord('9')))): dialog = gtk.MessageDialog( self.get_widget('config-window'), gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, _("The shortcut \"%s\" cannot be used " "because it will become impossible to " "type using this key.\n\n" "Please try with a key such as " "Control, Alt or Shift at the same " "time.\n") % key) dialog.run() dialog.destroy() return False # setting new value in ui giter = model.get_iter(path) model.set_value(giter, 2, hotkey) # setting the new value in gconf self.client.set_string(gconf_path, key) def on_key_cleared(self, renderer, path, model): """If the user tries to clear a keybinding with the backspace key this callback will be called and it just fill the model with an empty key and set the 'disabled' string in gconf path. """ giter = model.get_iter(path) gconf_path = model.get_value(giter, 0) self.client.get_string(gconf_path) model.set_value(giter, 2, KeyEntry(0, 0)) self.client.set_string(gconf_path, 'disabled') def cell_data_func(self, column, renderer, model, giter): """Defines the way that each renderer will handle the key object and the mask it sets the properties for a cellrenderer key. """ obj = model.get_value(giter, 2) if obj: renderer.set_property('visible', True) renderer.set_property('accel-key', obj.keycode) renderer.set_property('accel-mods', obj.mask) else: renderer.set_property('visible', False) renderer.set_property('accel-key', 0) renderer.set_property('accel-mods', 0) def start_editing(self, treeview, event): """Make the treeview grab the focus and start editing the cell that the user has clicked to avoid confusion with two or three clicks before editing a keybinding. Thanks to gnome-keybinding-properties.c =) """ if event.window != treeview.get_bin_window(): return False x, y = int(event.x), int(event.y) ret = treeview.get_path_at_pos(x, y) if not ret: return False path, column, cellx, celly = ret if path and len(path) > 1: def real_cb(): treeview.grab_focus() treeview.set_cursor(path, column, True) treeview.stop_emission('button-press-event') gobject.idle_add(real_cb) return True
def __init__(self): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.add_callbacks(PrefsCallbacks()) self.client = gconf.client_get_default() # setting evtbox title bg eventbox = self.get_widget('eventbox-title') eventbox.modify_bg(gtk.STATE_NORMAL, eventbox.get_colormap().alloc_color("#ffffff")) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # the first position in tree will store the keybinding path in gconf, # and the user doesn't worry with this, let's hide that =D model = gtk.TreeStore(str, str, object, bool) treeview = self.get_widget('treeview-keys') treeview.set_model(model) treeview.set_rules_hint(True) treeview.connect('button-press-event', self.start_editing) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn('keypath', renderer, text=0) column.set_visible(False) treeview.append_column(column) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_key_edited, model) renderer.connect('accel-cleared', self.on_key_cleared, model) column = gtk.TreeViewColumn(_('Shortcut'), renderer) column.set_cell_data_func(renderer, self.cell_data_func) column.set_property('expand', False) treeview.append_column(column) self.demo_terminal = GuakeTerminal() demo_terminal_box = self.get_widget('demo_terminal_box') demo_terminal_box.add(self.demo_terminal) default_params = {} pid = self.demo_terminal.fork_command(**default_params) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide() # Preview when selecting a bgimage self.selection_preview = gtk.Image() self.file_filter = gtk.FileFilter() self.file_filter.add_pattern("*.jpg") self.file_filter.add_pattern("*.png") self.file_filter.add_pattern("*.svg") self.file_filter.add_pattern("*.jpeg") self.bgfilechooser = self.get_widget('background_image') self.bgfilechooser.set_preview_widget(self.selection_preview) self.bgfilechooser.set_filter(self.file_filter) self.bgfilechooser.connect('update-preview', self.update_preview, self.selection_preview)
class PrefsDialog(SimpleGladeApp): """The Guake Preferences dialog. """ def __init__(self): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.add_callbacks(PrefsCallbacks()) self.client = gconf.client_get_default() # setting evtbox title bg eventbox = self.get_widget('eventbox-title') eventbox.modify_bg(gtk.STATE_NORMAL, eventbox.get_colormap().alloc_color("#ffffff")) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # the first position in tree will store the keybinding path in gconf, # and the user doesn't worry with this, let's hide that =D model = gtk.TreeStore(str, str, object, bool) treeview = self.get_widget('treeview-keys') treeview.set_model(model) treeview.set_rules_hint(True) treeview.connect('button-press-event', self.start_editing) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn('keypath', renderer, text=0) column.set_visible(False) treeview.append_column(column) renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_key_edited, model) renderer.connect('accel-cleared', self.on_key_cleared, model) column = gtk.TreeViewColumn(_('Shortcut'), renderer) column.set_cell_data_func(renderer, self.cell_data_func) column.set_property('expand', False) treeview.append_column(column) self.demo_terminal = GuakeTerminal() demo_terminal_box = self.get_widget('demo_terminal_box') demo_terminal_box.add(self.demo_terminal) default_params = {} pid = self.demo_terminal.fork_command(**default_params) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide() # Preview when selecting a bgimage self.selection_preview = gtk.Image() self.file_filter = gtk.FileFilter() self.file_filter.add_pattern("*.jpg") self.file_filter.add_pattern("*.png") self.file_filter.add_pattern("*.svg") self.file_filter.add_pattern("*.jpeg") self.bgfilechooser = self.get_widget('background_image') self.bgfilechooser.set_preview_widget(self.selection_preview) self.bgfilechooser.set_filter(self.file_filter) self.bgfilechooser.connect('update-preview', self.update_preview, self.selection_preview) def show(self): """Calls the main window show_all method and presents the window in the desktop. """ self.get_widget('config-window').show_all() self.get_widget('config-window').present() def hide(self): """Calls the main window hide function. """ self.get_widget('config-window').hide() def update_preview(self, file_chooser, preview): """Used by filechooser to preview image files """ filename = file_chooser.get_preview_filename() if filename and os.path.isfile(filename or ''): try: mkpb = gtk.gdk.pixbuf_new_from_file_at_size pixbuf = mkpb(filename, 256, 256) preview.set_from_pixbuf(pixbuf) file_chooser.set_preview_widget_active(True) except gobject.GError: # this exception is raised when user chooses a # non-image file or a directory warnings.warn('File %s is not an image' % filename) else: file_chooser.set_preview_widget_active(False) def toggle_prompt_on_quit_sensitivity(self, combo): """If toggle_on_close_tabs is set to 2 (Always), prompt_on_quit has no effect. """ self.get_widget('prompt_on_quit').set_sensitive(combo.get_active() != 2) def toggle_style_sensitivity(self, chk): """If the user chooses to use the gnome default font configuration it means that he will not be able to use the font selector. """ self.get_widget('font_style').set_sensitive(not chk.get_active()) def toggle_use_font_background_sensitivity(self, chk): """If the user chooses to use the gnome default font configuration it means that he will not be able to use the font selector. """ self.get_widget('palette_16').set_sensitive(chk.get_active()) self.get_widget('palette_17').set_sensitive(chk.get_active()) def toggle_display_n_sensitivity(self, chk): """When the user unchecks 'on mouse display', the option to select an alternate display should be enabeld. """ self.get_widget('display_n').set_sensitive(not chk.get_active()) def toggle_quick_open_command_line_sensitivity(self, chk): """When the user unchecks 'enable quick open', the command line should be disabled """ self.get_widget('quick_open_command_line').set_sensitive(chk.get_active()) self.get_widget('quick_open_in_current_terminal').set_sensitive(chk.get_active()) def clear_background_image(self, btn): """Unset the gconf variable that holds the name of the background image of all terminals. """ self.client.unset(KEY('/style/background/image')) self.bgfilechooser.unselect_all() def on_reset_compat_defaults_clicked(self, bnt): """Reset default values to compat_{backspace,delete} gconf keys. The default values are retrivied from the guake.schemas file. """ self.client.unset(KEY('/general/compat_backspace')) self.client.unset(KEY('/general/compat_delete')) self.reload_erase_combos() def on_palette_name_changed(self, combo): """Changes the value of palette in gconf """ palette_name = combo.get_active_text() if palette_name not in PALETTES: return self.client.set_string(KEY('/style/font/palette'), PALETTES[palette_name]) self.client.set_string(KEY('/style/font/palette_name'), palette_name) self.set_palette_colors(PALETTES[palette_name]) self.update_demo_palette(PALETTES[palette_name]) def on_cursor_shape_changed(self, combo): """Changes the value of cursor_shape in gconf """ index = combo.get_active() self.client.set_int(KEY('/style/cursor_shape'), index) def on_blink_cursor_toggled(self, chk): """Changes the value of blink_cursor in gconf """ self.client.set_int(KEY('/style/cursor_blink_mode'), chk.get_active()) def on_palette_color_set(self, btn): """Changes the value of palette in gconf """ palette = [] for i in range(18): palette.append(hexify_color( self.get_widget('palette_%d' % i).get_color())) palette = ':'.join(palette) self.client.set_string(KEY('/style/font/palette'), palette) self.client.set_string(KEY('/style/font/palette_name'), _('Custom')) self.set_palette_name('Custom') self.update_demo_palette(palette) def set_palette_name(self, palette_name): """If the given palette matches an existing one, shows it in the combobox """ combo = self.get_widget('palette_name') found = False log.debug("wanting palette: %r", palette_name) for i in combo.get_model(): if i[0] == palette_name: combo.set_active_iter(i.iter) found = True break if not found: combo.set_active(self.custom_palette_index) def update_demo_palette(self, palette): fgcolor = gtk.gdk.color_parse( self.client.get_string(KEY('/style/font/color'))) bgcolor = gtk.gdk.color_parse( self.client.get_string(KEY('/style/background/color'))) palette = [gtk.gdk.color_parse(color) for color in palette.split(':')] font_name = self.client.get_string(KEY('/style/font/style')) font = FontDescription(font_name) use_palette_font_and_background_color = self.client.get_bool( KEY('/general/use_palette_font_and_background_color')) if use_palette_font_and_background_color and len(palette) > 16: fgcolor = palette[16] bgcolor = palette[17] self.demo_terminal.set_color_dim(fgcolor) self.demo_terminal.set_color_foreground(fgcolor) self.demo_terminal.set_color_bold(fgcolor) self.demo_terminal.set_color_background(bgcolor) self.demo_terminal.set_background_tint_color(bgcolor) self.demo_terminal.set_colors(fgcolor, bgcolor, palette[:16]) self.demo_terminal.set_font(font) def fill_palette_names(self): combo = self.get_widget('palette_name') for palette_name in sorted(PALETTES.keys()): combo.append_text(palette_name) self.custom_palette_index = len(PALETTES) combo.append_text(_('Custom')) def set_cursor_shape(self, shape_index): self.get_widget('cursor_shape').set_active(shape_index) def set_cursor_blink_mode(self, mode_index): self.get_widget('cursor_blink_mode').set_active(mode_index) def set_palette_colors(self, palette): """Updates the color buttons with the given palette """ palette = palette.split(':') for i in range(len(palette)): color = gtk.gdk.color_parse(palette[i]) self.get_widget('palette_%d' % i).set_color(color) def reload_erase_combos(self, btn=None): """Read from gconf the value of compat_{backspace,delete} vars and select the right option in combos. """ # backspace erase binding combo = self.get_widget('backspace-binding-combobox') binding = self.client.get_string(KEY('/general/compat_backspace')) for i in combo.get_model(): if ERASE_BINDINGS.get(i[0]) == binding: combo.set_active_iter(i.iter) # delete erase binding combo = self.get_widget('delete-binding-combobox') binding = self.client.get_string(KEY('/general/compat_delete')) for i in combo.get_model(): if ERASE_BINDINGS.get(i[0]) == binding: combo.set_active_iter(i.iter) def load_configs(self): """Load configurations for all widgets in General, Scrolling and Appearance tabs from gconf. """ # default_shell combo = self.get_widget('default_shell') # get the value for defualt shell. If unset, set to USER_SHELL_VALUE. value = self.client.get_string(KEY('/general/default_shell')) or USER_SHELL_VALUE for i in combo.get_model(): if i[0] == value: combo.set_active_iter(i.iter) # login shell value = self.client.get_bool(KEY('/general/use_login_shell')) self.get_widget('use_login_shell').set_active(value) # tray icon value = self.client.get_bool(KEY('/general/use_trayicon')) self.get_widget('use_trayicon').set_active(value) # popup value = self.client.get_bool(KEY('/general/use_popup')) self.get_widget('use_popup').set_active(value) # prompt on quit value = self.client.get_bool(KEY('/general/prompt_on_quit')) self.get_widget('prompt_on_quit').set_active(value) # prompt on close_tab value = self.client.get_int(KEY('/general/prompt_on_close_tab')) self.get_widget('prompt_on_close_tab').set_active(value) self.get_widget('prompt_on_quit').set_sensitive(value != 2) # ontop value = self.client.get_bool(KEY('/general/window_ontop')) self.get_widget('window_ontop').set_active(value) # tab ontop value = self.client.get_bool(KEY('/general/tab_ontop')) self.get_widget('tab_ontop').set_active(value) # losefocus value = self.client.get_bool(KEY('/general/window_losefocus')) self.get_widget('window_losefocus').set_active(value) # use VTE titles value = self.client.get_bool(KEY('/general/use_vte_titles')) self.get_widget('use_vte_titles').set_active(value) # max tab name length value = self.client.get_int(KEY('/general/max_tab_name_length')) self.get_widget('max_tab_name_length').set_value(value) value = self.client.get_float(KEY('/general/window_height_f')) if not value: value = self.client.get_int(KEY('/general/window_height')) self.get_widget('window_height').set_value(value) value = self.client.get_float(KEY('/general/window_width_f')) if not value: value = self.client.get_int(KEY('/general/window_width')) self.get_widget('window_width').set_value(value) value = self.client.get_int(KEY('/general/window_halignment')) which_button = { ALIGN_RIGHT: 'radiobutton_align_right', ALIGN_LEFT: 'radiobutton_align_left', ALIGN_CENTER: 'radiobutton_align_center' } self.get_widget(which_button[value]).set_active(True) value = self.client.get_bool(KEY('/general/open_tab_cwd')) self.get_widget('open_tab_cwd').set_active(value) # tab bar value = self.client.get_bool(KEY('/general/window_tabbar')) self.get_widget('window_tabbar').set_active(value) # start fullscreen value = self.client.get_bool(KEY('/general/start_fullscreen')) self.get_widget('start_fullscreen').set_active(value) # use visible bell value = self.client.get_bool(KEY('/general/use_visible_bell')) self.get_widget('use_visible_bell').set_active(value) # use audible bell value = self.client.get_bool(KEY('/general/use_audible_bell')) self.get_widget('use_audible_bell').set_active(value) # display number / use primary display combo = self.get_widget('display_n') dest_screen = self.client.get_int(KEY('/general/display_n')) value = self.client.get_bool(KEY('/general/quick_open_enable')) self.get_widget('quick_open_enable').set_active(value) self.get_widget('quick_open_command_line').set_sensitive(value) self.get_widget('quick_open_in_current_terminal').set_sensitive(value) text = gtk.TextBuffer() text = self.get_widget('quick_open_supported_patterns').get_buffer() for title, matcher, _useless in QUICK_OPEN_MATCHERS: text.insert_at_cursor("%s: %s\n" % (title, matcher)) self.get_widget('quick_open_supported_patterns').set_buffer(text) value = self.client.get_string(KEY('/general/quick_open_command_line')) if value is None: value = "subl %(file_path)s:%(line_number)s" self.get_widget('quick_open_command_line').set_text(value) value = self.client.get_bool(KEY('/general/quick_open_in_current_terminal')) self.get_widget('quick_open_in_current_terminal').set_active(value) value = self.client.get_string(KEY('/general/startup_script')) self.get_widget('startup_script').set_text(value) # If Guake is configured to use a screen that is not currently attached, # default to 'primary display' option. screen = self.get_widget('config-window').get_screen() n_screens = screen.get_n_monitors() if dest_screen > n_screens - 1: self.client.set_bool(KEY('/general/mouse_display'), False) dest_screen = screen.get_primary_monitor() self.client.set_int(KEY('/general/display_n'), dest_screen) if dest_screen == ALWAYS_ON_PRIMARY: first_item = combo.get_model().get_iter_first() combo.set_active_iter(first_item) else: seen_first = False # first item "always on primary" is special for i in combo.get_model(): if seen_first: i_int = int(i[0].split()[0]) # extracts 1 from '1' or from '1 (primary)' if i_int == dest_screen: combo.set_active_iter(i.iter) else: seen_first = True # use display where the mouse is currently value = self.client.get_bool(KEY('/general/mouse_display')) self.get_widget('mouse_display').set_active(value) # scrollbar value = self.client.get_bool(KEY('/general/use_scrollbar')) self.get_widget('use_scrollbar').set_active(value) # history size value = self.client.get_int(KEY('/general/history_size')) self.get_widget('history_size').set_value(value) # scroll output value = self.client.get_bool(KEY('/general/scroll_output')) self.get_widget('scroll_output').set_active(value) # scroll keystroke value = self.client.get_bool(KEY('/general/scroll_keystroke')) self.get_widget('scroll_keystroke').set_active(value) # default font value = self.client.get_bool(KEY('/general/use_default_font')) self.get_widget('use_default_font').set_active(value) self.get_widget('font_style').set_sensitive(not value) # use font and background color value = self.client.get_bool(KEY('/general/use_palette_font_and_background_color')) self.get_widget('use_palette_font_and_background_color').set_active(value) self.get_widget('palette_16').set_sensitive(value) self.get_widget('palette_17').set_sensitive(value) # font value = self.client.get_string(KEY('/style/font/style')) if value: self.get_widget('font_style').set_font_name(value) # font color val = self.client.get_string(KEY('/style/font/color')) try: color = gtk.gdk.color_parse(val) self.get_widget('font_color').set_color(color) except (ValueError, TypeError): warnings.warn('Unable to parse color %s' % val, Warning) # background color value = self.client.get_string(KEY('/style/background/color')) try: color = gtk.gdk.color_parse(value) self.get_widget('background_color').set_color(color) except (ValueError, TypeError): warnings.warn('Unable to parse color %s' % val, Warning) # allow bold font value = self.client.get_bool(KEY('/style/font/allow_bold')) self.get_widget('allow_bold').set_active(value) # palette self.fill_palette_names() value = self.client.get_string(KEY('/style/font/palette_name')) self.set_palette_name(value) value = self.client.get_string(KEY('/style/font/palette')) self.set_palette_colors(value) self.update_demo_palette(value) # cursor shape value = self.client.get_int(KEY('/style/cursor_shape')) self.set_cursor_shape(value) # cursor blink value = self.client.get_int(KEY('/style/cursor_blink_mode')) self.set_cursor_blink_mode(value) # background image value = self.client.get_string(KEY('/style/background/image')) if os.path.isfile(value or ''): self.get_widget('background_image').set_filename(value) value = self.client.get_int(KEY('/style/background/transparency')) self.get_widget('background_transparency').set_value(value) value = self.client.get_int(KEY('/general/window_valignment')) self.get_widget('top_align').set_active(value) # it's a separated method, to be reused. self.reload_erase_combos() # custom command context-menu configuration file custom_command_file = self.client.get_string(KEY('/general/custom_command_file')) if custom_command_file: custom_command_file_name = os.path.expanduser(custom_command_file) else: custom_command_file_name = None custom_cmd_filter = gtk.FileFilter() custom_cmd_filter.set_name(_("JSON files")) custom_cmd_filter.add_pattern("*.json") self.get_widget('custom_command_file_chooser').add_filter(custom_cmd_filter) all_files_filter = gtk.FileFilter() all_files_filter.set_name(_("All files")) all_files_filter.add_pattern("*") self.get_widget('custom_command_file_chooser').add_filter(all_files_filter) if custom_command_file_name: self.get_widget('custom_command_file_chooser').set_filename(custom_command_file_name) # -- populate functions -- def populate_shell_combo(self): """Read the /etc/shells and looks for installed shells to fill the default_shell combobox. """ cb = self.get_widget('default_shell') # append user shell as first option cb.append_text(USER_SHELL_VALUE) if os.path.exists(SHELLS_FILE): lines = open(SHELLS_FILE).readlines() for i in lines: possible = i.strip() if possible and not possible.startswith('#') and os.path.exists(possible): cb.append_text(possible) for i in get_binaries_from_path(PYTHONS): cb.append_text(i) def populate_keys_tree(self): """Reads the HOTKEYS global variable and insert all data in the TreeStore used by the preferences window treeview. """ model = self.get_widget('treeview-keys').get_model() for group in HOTKEYS: giter = model.append(None) model.set(giter, 0, '', 1, _(group['label'])) for item in group['keys']: child = model.append(giter) accel = self.client.get_string(item['key']) if accel: params = gtk.accelerator_parse(accel) hotkey = KeyEntry(*params) else: hotkey = KeyEntry(0, 0) model.set(child, 0, item['key'], 1, _(item['label']), 2, hotkey, 3, True) self.get_widget('treeview-keys').expand_all() def populate_display_n(self): """Get the number of displays and populate this drop-down box with them all. Prepend the "always on primary" option. """ cb = self.get_widget('display_n') screen = self.get_widget('config-window').get_screen() cb.append_text("always on primary") for m in range(0, int(screen.get_n_monitors())): if m == int(screen.get_primary_monitor()): # TODO l10n cb.append_text(str(m) + ' ' + '(primary)') else: cb.append_text(str(m)) # -- key handling -- def on_key_edited(self, renderer, path, keycode, mask, keyval, model): """Callback that handles key edition in cellrenderer. It makes some tests to validate the key, like looking for already in use keys and look for [A-Z][a-z][0-9] to avoid problems with these common keys. If all tests are ok, the value will be stored in gconf. """ giter = model.get_iter(path) gconf_path = model.get_value(giter, 0) oldkey = model.get_value(giter, 2) hotkey = KeyEntry(keycode, mask) key = gtk.accelerator_name(keycode, mask) keylabel = gtk.accelerator_get_label(keycode, mask) # we needn't to change anything, the user is trying to set the # same key that is already set. if oldkey == hotkey: return False # looking for already used keybindings def each_key(model, path, subiter): keyentry = model.get_value(subiter, 2) if keyentry and keyentry == hotkey: msg = _("The shortcut \"%s\" is already in use.") % keylabel raise ShowableError(_('Error setting keybinding.'), msg, -1) model.foreach(each_key) # avoiding problems with common keys if ((mask == 0 and keycode != 0) and ( (keycode >= ord('a') and keycode <= ord('z')) or (keycode >= ord('A') and keycode <= ord('Z')) or (keycode >= ord('0') and keycode <= ord('9')))): dialog = gtk.MessageDialog( self.get_widget('config-window'), gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, _("The shortcut \"%s\" cannot be used " "because it will become impossible to " "type using this key.\n\n" "Please try with a key such as " "Control, Alt or Shift at the same " "time.\n") % key) dialog.run() dialog.destroy() return False # setting new value in ui giter = model.get_iter(path) model.set_value(giter, 2, hotkey) # setting the new value in gconf self.client.set_string(gconf_path, key) def on_key_cleared(self, renderer, path, model): """If the user tries to clear a keybinding with the backspace key this callback will be called and it just fill the model with an empty key and set the 'disabled' string in gconf path. """ giter = model.get_iter(path) gconf_path = model.get_value(giter, 0) self.client.get_string(gconf_path) model.set_value(giter, 2, KeyEntry(0, 0)) self.client.set_string(gconf_path, 'disabled') def cell_data_func(self, column, renderer, model, giter): """Defines the way that each renderer will handle the key object and the mask it sets the properties for a cellrenderer key. """ obj = model.get_value(giter, 2) if obj: renderer.set_property('visible', True) renderer.set_property('accel-key', obj.keycode) renderer.set_property('accel-mods', obj.mask) else: renderer.set_property('visible', False) renderer.set_property('accel-key', 0) renderer.set_property('accel-mods', 0) def start_editing(self, treeview, event): """Make the treeview grab the focus and start editing the cell that the user has clicked to avoid confusion with two or three clicks before editing a keybinding. Thanks to gnome-keybinding-properties.c =) """ if event.window != treeview.get_bin_window(): return False x, y = int(event.x), int(event.y) ret = treeview.get_path_at_pos(x, y) if not ret: return False path, column, cellx, celly = ret if path and len(path) > 1: def real_cb(): treeview.grab_focus() treeview.set_cursor(path, column, True) treeview.stop_emission('button-press-event') gobject.idle_add(real_cb) return True
def __init__(self, settings): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ self.hotkey_alread_used = False self.store = None super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.settings = settings self.add_callbacks(PrefsCallbacks(self)) # window cleanup handler self.window = self.get_widget('config-window') self.get_widget('config-window').connect('destroy', self.on_destroy) # setting evtbox title bg eventbox = self.get_widget('eventbox-title') eventbox.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(255, 255, 255, 255)) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # Model format: # 0: the keybinding path in gsettings (str, hidden), # 1: label (str) # 2: human readable accelerator (str) # 3: gtk accelerator (str, hidden) self.store = Gtk.TreeStore(str, str, str, str) treeview = self.get_widget('treeview-keys') treeview.set_model(self.store) treeview.set_rules_hint(True) # TODO PORT this is killing the editing of the accl # treeview.connect('button-press-event', self.start_editing) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = Gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_accel_edited) renderer.connect('accel-cleared', self.on_accel_cleared) column = Gtk.TreeViewColumn(_('Shortcut'), renderer, text=2) column.pack_start(renderer, True) column.set_property('expand', False) column.add_attribute(renderer, "accel-mods", 0) column.add_attribute(renderer, "accel-key", 1) treeview.append_column(column) self.demo_terminal = GuakeTerminal(self.settings) self.demo_terminal_box = self.get_widget('demo_terminal_box') self.demo_terminal_box.add(self.demo_terminal) pid = self.spawn_sync_pid(None, self.demo_terminal) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide()
class PrefsDialog(SimpleGladeApp): """The Guake Preferences dialog. """ def __init__(self, settings): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ self.hotkey_alread_used = False self.store = None super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.settings = settings self.add_callbacks(PrefsCallbacks(self)) # window cleanup handler self.window = self.get_widget('config-window') self.get_widget('config-window').connect('destroy', self.on_destroy) # setting evtbox title bg eventbox = self.get_widget('eventbox-title') eventbox.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(255, 255, 255, 255)) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # Model format: # 0: the keybinding path in gsettings (str, hidden), # 1: label (str) # 2: human readable accelerator (str) # 3: gtk accelerator (str, hidden) self.store = Gtk.TreeStore(str, str, str, str) treeview = self.get_widget('treeview-keys') treeview.set_model(self.store) treeview.set_rules_hint(True) # TODO PORT this is killing the editing of the accl # treeview.connect('button-press-event', self.start_editing) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = Gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_accel_edited) renderer.connect('accel-cleared', self.on_accel_cleared) column = Gtk.TreeViewColumn(_('Shortcut'), renderer, text=2) column.pack_start(renderer, True) column.set_property('expand', False) column.add_attribute(renderer, "accel-mods", 0) column.add_attribute(renderer, "accel-key", 1) treeview.append_column(column) self.demo_terminal = GuakeTerminal(self.settings) self.demo_terminal_box = self.get_widget('demo_terminal_box') self.demo_terminal_box.add(self.demo_terminal) pid = self.spawn_sync_pid(None, self.demo_terminal) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide() def spawn_sync_pid(self, directory=None, terminal=None): argv = list() user_shell = self.settings.general.get_string('default-shell') if user_shell and os.path.exists(user_shell): argv.append(user_shell) else: argv.append(os.environ['SHELL']) login_shell = self.settings.general.get_boolean('use-login-shell') if login_shell: argv.append('--login') if isinstance(directory, str): wd = directory else: wd = os.environ['HOME'] pid = terminal.spawn_sync(Vte.PtyFlags.DEFAULT, wd, argv, [], GLib.SpawnFlags.DO_NOT_REAP_CHILD, None, None, None) return pid def show(self): """Calls the main window show_all method and presents the window in the desktop. """ self.get_widget('config-window').show_all() self.get_widget('config-window').present() def hide(self): """Calls the main window hide function. """ self.get_widget('config-window').hide() def on_destroy(self, window): self.demo_terminal.kill() self.demo_terminal.destroy() def toggle_prompt_on_quit_sensitivity(self, combo): """If toggle_on_close_tabs is set to 2 (Always), prompt_on_quit has no effect. """ self.get_widget('prompt_on_quit').set_sensitive( combo.get_active() != 2) def toggle_style_sensitivity(self, chk): """If the user chooses to use the gnome default font configuration it means that he will not be able to use the font selector. """ self.get_widget('font_style').set_sensitive(not chk.get_active()) def toggle_use_font_background_sensitivity(self, chk): """If the user chooses to use the gnome default font configuration it means that he will not be able to use the font selector. """ self.get_widget('palette_16').set_sensitive(chk.get_active()) self.get_widget('palette_17').set_sensitive(chk.get_active()) def toggle_display_n_sensitivity(self, chk): """When the user unchecks 'on mouse display', the option to select an alternate display should be enabeld. """ self.get_widget('display_n').set_sensitive(not chk.get_active()) def toggle_quick_open_command_line_sensitivity(self, chk): """When the user unchecks 'enable quick open', the command line should be disabled """ self.get_widget('quick_open_command_line').set_sensitive( chk.get_active()) self.get_widget('quick_open_in_current_terminal').set_sensitive( chk.get_active()) def toggle_use_vte_titles(self, chk): """When vte titles aren't used, there is nothing to abbreviate """ self.update_vte_subwidgets_states() def update_vte_subwidgets_states(self): do_use_vte_titles = self.get_widget('use_vte_titles').get_active() max_tab_name_length_wdg = self.get_widget('max_tab_name_length') max_tab_name_length_wdg.set_sensitive(do_use_vte_titles) self.get_widget('lbl_max_tab_name_length').set_sensitive( do_use_vte_titles) self.get_widget('abbreviate_tab_names').set_sensitive( do_use_vte_titles) def on_reset_compat_defaults_clicked(self, bnt): """Reset default values to compat_{backspace,delete} gconf keys. The default values are retrivied from the guake.schemas file. """ self.settings.general.reset('compat-backspace') self.settings.general.reset('compat-delete') self.reload_erase_combos() def on_palette_name_changed(self, combo): """Changes the value of palette in gconf """ palette_name = combo.get_active_text() if palette_name not in PALETTES: return self.settings.styleFont.set_string('palette', PALETTES[palette_name]) self.settings.styleFont.set_string('palette-name', palette_name) self.set_palette_colors(PALETTES[palette_name]) self.update_demo_palette(PALETTES[palette_name]) def on_cursor_shape_changed(self, combo): """Changes the value of cursor_shape in gconf """ index = combo.get_active() self.settings.style.set_int('cursor-shape', index) def on_blink_cursor_toggled(self, chk): """Changes the value of blink_cursor in gconf """ self.settings.style.set_int('cursor-blink-mode', chk.get_active()) def on_palette_color_set(self, btn): """Changes the value of palette in gconf """ palette = [] for i in range(18): palette.append( hexify_color(self.get_widget('palette_%d' % i).get_color())) palette = ':'.join(palette) self.settings.styleFont.set_string('palette', palette) self.settings.styleFont.set_string('palette-name', _('Custom')) self.set_palette_name('Custom') self.update_demo_palette(palette) # this methods should be moved to the GuakeTerminal class FROM HERE def set_palette_name(self, palette_name): """If the given palette matches an existing one, shows it in the combobox """ combo = self.get_widget('palette_name') found = False log.debug("wanting palette: %r", palette_name) for i in combo.get_model(): if i[0] == palette_name: combo.set_active_iter(i.iter) found = True break if not found: combo.set_active(self.custom_palette_index) def update_demo_palette(self, palette): self.set_colors_from_settings() def set_colors_from_settings(self): transparency = self.settings.styleBackground.get_int('transparency') colorRGBA = Gdk.RGBA(0, 0, 0, 0) palette_list = list() for color in self.settings.styleFont.get_string("palette").split(':'): colorRGBA.parse(color) palette_list.append(colorRGBA.copy()) if len(palette_list) > 16: bg_color = palette_list[17] else: bg_color = Gdk.RGBA(255, 255, 255, 0) bg_color.alpha = 1 / 100 * transparency if len(palette_list) > 16: font_color = palette_list[16] else: font_color = Gdk.RGBA(0, 0, 0, 0) self.demo_terminal.set_color_foreground(font_color) self.demo_terminal.set_color_bold(font_color) self.demo_terminal.set_colors(font_color, bg_color, palette_list[:16]) # TO HERE (see above) def fill_palette_names(self): combo = self.get_widget('palette_name') for palette in sorted(PALETTES): combo.append_text(palette) self.custom_palette_index = len(PALETTES) combo.append_text(_('Custom')) def set_cursor_shape(self, shape_index): self.get_widget('cursor_shape').set_active(shape_index) def set_cursor_blink_mode(self, mode_index): self.get_widget('cursor_blink_mode').set_active(mode_index) def set_palette_colors(self, palette): """Updates the color buttons with the given palette """ palette = palette.split(':') for i, pal in enumerate(palette): x, color = Gdk.Color.parse(pal) self.get_widget('palette_%d' % i).set_color(color) def reload_erase_combos(self, btn=None): """Read from gconf the value of compat_{backspace,delete} vars and select the right option in combos. """ # backspace erase binding combo = self.get_widget('backspace-binding-combobox') binding = self.settings.general.get_string('compat-backspace') for i in combo.get_model(): if ERASE_BINDINGS.get(i[0]) == binding: combo.set_active_iter(i.iter) # delete erase binding combo = self.get_widget('delete-binding-combobox') binding = self.settings.general.get_string('compat-delete') for i in combo.get_model(): if ERASE_BINDINGS.get(i[0]) == binding: combo.set_active_iter(i.iter) def _load_hooks_settings(self): """load hooks settings""" log.debug("executing _load_hooks_settings") hook_show_widget = self.get_widget("hook_show") hook_show_setting = self.settings.hooks.get_string("show") if hook_show_widget is not None: if hook_show_setting is not None: hook_show_widget.set_text(hook_show_setting) return def _load_default_shell_settings(self): combo = self.get_widget('default_shell') # get the value for defualt shell. If unset, set to USER_SHELL_VALUE. value = self.settings.general.get_string( 'default-shell') or USER_SHELL_VALUE for i in combo.get_model(): if i[0] == value: combo.set_active_iter(i.iter) def _load_screen_settings(self): """Load screen settings""" # display number / use primary display combo = self.get_widget('display_n') dest_screen = self.settings.general.get_int('display-n') # If Guake is configured to use a screen that is not currently attached, # default to 'primary display' option. screen = self.get_widget('config-window').get_screen() n_screens = screen.get_n_monitors() if dest_screen > n_screens - 1: self.settings.general.set_boolean('mouse-display', False) dest_screen = screen.get_primary_monitor() self.settings.general.set_int('display_n', dest_screen) if dest_screen == ALWAYS_ON_PRIMARY: first_item = combo.get_model().get_iter_first() combo.set_active_iter(first_item) else: seen_first = False # first item "always on primary" is special for i in combo.get_model(): if seen_first: i_int = int( i[0].split() [0]) # extracts 1 from '1' or from '1 (primary)' if i_int == dest_screen: combo.set_active_iter(i.iter) else: seen_first = True def load_configs(self): """Load configurations for all widgets in General, Scrolling and Appearance tabs from gconf. """ self._load_default_shell_settings() # login shell value = self.settings.general.get_boolean('use-login-shell') self.get_widget('use_login_shell').set_active(value) # tray icon value = self.settings.general.get_boolean('use-trayicon') self.get_widget('use_trayicon').set_active(value) # popup value = self.settings.general.get_boolean('use-popup') self.get_widget('use_popup').set_active(value) # prompt on quit value = self.settings.general.get_boolean('prompt-on-quit') self.get_widget('prompt_on_quit').set_active(value) # prompt on close_tab value = self.settings.general.get_int('prompt-on-close-tab') self.get_widget('prompt_on_close_tab').set_active(value) self.get_widget('prompt_on_quit').set_sensitive(value != 2) # ontop value = self.settings.general.get_boolean('window-ontop') self.get_widget('window_ontop').set_active(value) # tab ontop value = self.settings.general.get_boolean('tab-ontop') self.get_widget('tab_ontop').set_active(value) # refocus value = self.settings.general.get_boolean('window-refocus') self.get_widget('window_refocus').set_active(value) # losefocus value = self.settings.general.get_boolean('window-losefocus') self.get_widget('window_losefocus').set_active(value) # use VTE titles value = self.settings.general.get_boolean('use-vte-titles') self.get_widget('use_vte_titles').set_active(value) # set window title value = self.settings.general.get_boolean('set-window-title') self.get_widget('set_window_title').set_active(value) # abbreviate tab names self.get_widget('abbreviate_tab_names').set_sensitive(value) value = self.settings.general.get_boolean('abbreviate-tab-names') self.get_widget('abbreviate_tab_names').set_active(value) # max tab name length value = self.settings.general.get_int('max-tab-name-length') self.get_widget('max_tab_name_length').set_value(value) self.update_vte_subwidgets_states() value = self.settings.general.get_int('window-height') self.get_widget('window_height').set_value(value) value = self.settings.general.get_int('window-width') self.get_widget('window_width').set_value(value) value = self.settings.general.get_int('window-halignment') which_button = { ALIGN_RIGHT: 'radiobutton_align_right', ALIGN_LEFT: 'radiobutton_align_left', ALIGN_CENTER: 'radiobutton_align_center' } self.get_widget(which_button[value]).set_active(True) value = self.settings.general.get_boolean('open-tab-cwd') self.get_widget('open_tab_cwd').set_active(value) # tab bar value = self.settings.general.get_boolean('window-tabbar') self.get_widget('window_tabbar').set_active(value) # start fullscreen value = self.settings.general.get_boolean('start-fullscreen') self.get_widget('start_fullscreen').set_active(value) # use audible bell value = self.settings.general.get_boolean('use-audible-bell') self.get_widget('use_audible_bell').set_active(value) self._load_screen_settings() value = self.settings.general.get_boolean('quick-open-enable') self.get_widget('quick_open_enable').set_active(value) self.get_widget('quick_open_command_line').set_sensitive(value) self.get_widget('quick_open_in_current_terminal').set_sensitive(value) text = Gtk.TextBuffer() text = self.get_widget('quick_open_supported_patterns').get_buffer() for title, matcher, _useless in QUICK_OPEN_MATCHERS: text.insert_at_cursor("%s: %s\n" % (title, matcher)) self.get_widget('quick_open_supported_patterns').set_buffer(text) value = self.settings.general.get_string('quick-open-command-line') if value is None: value = "subl %(file_path)s:%(line_number)s" self.get_widget('quick_open_command_line').set_text(value) value = self.settings.general.get_boolean( 'quick-open-in-current-terminal') self.get_widget('quick_open_in_current_terminal').set_active(value) value = self.settings.general.get_string('startup-script') if value: self.get_widget('startup_script').set_text(value) # use display where the mouse is currently value = self.settings.general.get_boolean('mouse-display') self.get_widget('mouse_display').set_active(value) # scrollbar value = self.settings.general.get_boolean('use-scrollbar') self.get_widget('use_scrollbar').set_active(value) # history size value = self.settings.general.get_int('history-size') self.get_widget('history_size').set_value(value) # infinite history value = self.settings.general.get_boolean('infinite-history') self.get_widget('infinite_history').set_active(value) print("infinite history: ", value) # scroll output value = self.settings.general.get_boolean('scroll-output') self.get_widget('scroll_output').set_active(value) # scroll keystroke value = self.settings.general.get_boolean('scroll-keystroke') self.get_widget('scroll_keystroke').set_active(value) # default font value = self.settings.general.get_boolean('use-default-font') self.get_widget('use_default_font').set_active(value) self.get_widget('font_style').set_sensitive(not value) # font value = self.settings.styleFont.get_string('style') if value: self.get_widget('font_style').set_font_name(value) # allow bold font value = self.settings.styleFont.get_boolean('allow-bold') self.get_widget('allow_bold').set_active(value) # palette self.fill_palette_names() value = self.settings.styleFont.get_string('palette-name') self.set_palette_name(value) value = self.settings.styleFont.get_string('palette') self.set_palette_colors(value) self.update_demo_palette(value) # cursor shape value = self.settings.style.get_int('cursor-shape') self.set_cursor_shape(value) # cursor blink value = self.settings.style.get_int('cursor-blink-mode') self.set_cursor_blink_mode(value) value = self.settings.styleBackground.get_int('transparency') self.get_widget('background_transparency').set_value(value) value = self.settings.general.get_int('window-valignment') self.get_widget('top_align').set_active(value) # it's a separated method, to be reused. self.reload_erase_combos() # custom command context-menu configuration file custom_command_file = self.settings.general.get_string( 'custom-command-file') if custom_command_file: custom_command_file_name = os.path.expanduser(custom_command_file) else: custom_command_file_name = None custom_cmd_filter = Gtk.FileFilter() custom_cmd_filter.set_name(_("JSON files")) custom_cmd_filter.add_pattern("*.json") self.get_widget('custom_command_file_chooser').add_filter( custom_cmd_filter) all_files_filter = Gtk.FileFilter() all_files_filter.set_name(_("All files")) all_files_filter.add_pattern("*") self.get_widget('custom_command_file_chooser').add_filter( all_files_filter) if custom_command_file_name: self.get_widget('custom_command_file_chooser').set_filename( custom_command_file_name) # hooks self._load_hooks_settings() # -- populate functions -- def populate_shell_combo(self): """Read the /etc/shells and looks for installed shells to fill the default_shell combobox. """ cb = self.get_widget('default_shell') # append user shell as first option cb.append_text(USER_SHELL_VALUE) if os.path.exists(SHELLS_FILE): lines = open(SHELLS_FILE).readlines() for i in lines: possible = i.strip() if possible and not possible.startswith( '#') and os.path.exists(possible): cb.append_text(possible) for i in get_binaries_from_path(PYTHONS): cb.append_text(i) def populate_keys_tree(self): """Reads the HOTKEYS global variable and insert all data in the TreeStore used by the preferences window treeview. """ for group in HOTKEYS: parent = self.store.append(None, [None, group['label'], None, None]) for item in group['keys']: if item['key'] == "show-hide" or item['key'] == "show-focus": accel = self.settings.keybindingsGlobal.get_string( item['key']) else: accel = self.settings.keybindingsLocal.get_string( item['key']) gsettings_path = item['key'] keycode, mask = Gtk.accelerator_parse(accel) keylabel = Gtk.accelerator_get_label(keycode, mask) self.store.append( parent, [gsettings_path, item['label'], keylabel, accel]) self.get_widget('treeview-keys').expand_all() def populate_display_n(self): """Get the number of displays and populate this drop-down box with them all. Prepend the "always on primary" option. """ cb = self.get_widget('display_n') screen = self.get_widget('config-window').get_screen() cb.append_text("always on primary") for m in range(0, int(screen.get_n_monitors())): if m == int(screen.get_primary_monitor()): # TODO l10n cb.append_text(str(m) + ' ' + '(primary)') else: cb.append_text(str(m)) # -- key handling -- def on_accel_edited(self, cellrendereraccel, path, key, mods, hwcode): """Callback that handles key edition in cellrenderer. It makes some tests to validate the key, like looking for already in use keys and look for [A-Z][a-z][0-9] to avoid problems with these common keys. If all tests are ok, the value will be stored in gconf. """ accelerator = Gtk.accelerator_name(key, mods) dconf_path = self.store[path][HOTKET_MODEL_INDEX_DCONF] old_accel = self.store[path][HOTKET_MODEL_INDEX_HUMAN_ACCEL] keylabel = Gtk.accelerator_get_label(key, mods) # we needn't to change anything, the user is trying to set the # same key that is already set. if old_accel == accelerator: return False self.hotkey_alread_used = False # looking for already used keybindings def each_key(model, path, subiter): keyentry = model.get_value(subiter, HOTKET_MODEL_INDEX_ACCEL) if keyentry and keyentry == accelerator: self.hotkey_alread_used = True msg = _("The shortcut \"%s\" is already in use." ) % html_escape(accelerator) ShowableError(self.window, _('Error setting keybinding.'), msg, -1) raise Exception( 'This is ok, we just use it to break the foreach loop!') self.store.foreach(each_key) if self.hotkey_alread_used: return False # avoiding problems with common keys if ((mods == 0 and key != 0) and ((key >= ord('a') and key <= ord('z')) or (key >= ord('A') and key <= ord('Z')) or (key >= ord('0') and key <= ord('9')))): dialog = Gtk.MessageDialog( self.get_widget('config-window'), Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, _("The shortcut \"%s\" cannot be used " "because it will become impossible to " "type using this key.\n\n" "Please try with a key such as " "Control, Alt or Shift at the same " "time.\n") % html_escape(key)) dialog.run() dialog.destroy() return False self.store[path][HOTKET_MODEL_INDEX_HUMAN_ACCEL] = keylabel if dconf_path == "show-hide" or dconf_path == "show-focus": self.settings.keybindingsGlobal.set_string(dconf_path, accelerator) else: self.settings.keybindingsLocal.set_string(dconf_path, accelerator) self.store[path][HOTKET_MODEL_INDEX_ACCEL] = accelerator def on_accel_cleared(self, cellrendereraccel, path): """If the user tries to clear a keybinding with the backspace key this callback will be called and it just fill the model with an empty key and set the 'disabled' string in gconf path. """ dconf_path = self.store[path][HOTKET_MODEL_INDEX_DCONF] if dconf_path == "show-hide": # cannot disable 'show-hide' hotkey log.warn("Cannot disable 'show-hide' hotkey") self.settings.keybindingsGlobal.set_string(dconf_path, old_accel) else: self.store[path][HOTKET_MODEL_INDEX_HUMAN_ACCEL] = "" self.store[path][HOTKET_MODEL_INDEX_ACCEL] = "None" if dconf_path == "show-focus": self.settings.keybindingsGlobal.set_string( dconf_path, 'disabled') else: self.settings.keybindingsLocal.set_string( dconf_path, 'disabled') def start_editing(self, treeview, event): """Make the treeview grab the focus and start editing the cell that the user has clicked to avoid confusion with two or three clicks before editing a keybinding. Thanks to gnome-keybinding-properties.c =) """ # TODO PORT some thing in here is breaking stuff if event.window != treeview.get_bin_window(): return False x, y = int(event.x), int(event.y) ret = treeview.get_path_at_pos(x, y) if not ret: return False path, column, cellx, celly = ret if path and len(path) > 1: def real_cb(): treeview.grab_focus() treeview.set_cursor(path, column, True) treeview.stop_emission('button-press-event') GObject.idle_add(real_cb) return True
def __init__(self, settings): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ self.hotkey_alread_used = False self.store = None super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.settings = settings self.add_callbacks(PrefsCallbacks(self)) # window cleanup handler self.window = self.get_widget('config-window') self.get_widget('config-window').connect('destroy', self.on_destroy) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # Model format: # 0: the keybinding path in gsettings (str, hidden), # 1: label (str) # 2: human readable accelerator (str) # 3: gtk accelerator (str, hidden) self.store = Gtk.TreeStore(str, str, str, str) treeview = self.get_widget('treeview-keys') treeview.set_model(self.store) treeview.set_rules_hint(True) # TODO PORT this is killing the editing of the accl # treeview.connect('button-press-event', self.start_editing) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = Gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_accel_edited) renderer.connect('accel-cleared', self.on_accel_cleared) column = Gtk.TreeViewColumn(_('Shortcut'), renderer, text=2) column.pack_start(renderer, True) column.set_property('expand', False) column.add_attribute(renderer, "accel-mods", 0) column.add_attribute(renderer, "accel-key", 1) treeview.append_column(column) self.demo_terminal = GuakeTerminal(self.settings) self.demo_terminal_box = self.get_widget('demo_terminal_box') self.demo_terminal_box.add(self.demo_terminal) pid = self.spawn_sync_pid(None, self.demo_terminal) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide()
class PrefsDialog(SimpleGladeApp): """The Guake Preferences dialog. """ def __init__(self, settings): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ self.hotkey_alread_used = False self.store = None super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.settings = settings self.add_callbacks(PrefsCallbacks(self)) # window cleanup handler self.window = self.get_widget('config-window') self.get_widget('config-window').connect('destroy', self.on_destroy) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # Model format: # 0: the keybinding path in gsettings (str, hidden), # 1: label (str) # 2: human readable accelerator (str) # 3: gtk accelerator (str, hidden) self.store = Gtk.TreeStore(str, str, str, str) treeview = self.get_widget('treeview-keys') treeview.set_model(self.store) treeview.set_rules_hint(True) # TODO PORT this is killing the editing of the accl # treeview.connect('button-press-event', self.start_editing) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = Gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_accel_edited) renderer.connect('accel-cleared', self.on_accel_cleared) column = Gtk.TreeViewColumn(_('Shortcut'), renderer, text=2) column.pack_start(renderer, True) column.set_property('expand', False) column.add_attribute(renderer, "accel-mods", 0) column.add_attribute(renderer, "accel-key", 1) treeview.append_column(column) self.demo_terminal = GuakeTerminal(self.settings) self.demo_terminal_box = self.get_widget('demo_terminal_box') self.demo_terminal_box.add(self.demo_terminal) pid = self.spawn_sync_pid(None, self.demo_terminal) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide() def spawn_sync_pid(self, directory=None, terminal=None): argv = list() user_shell = self.settings.general.get_string('default-shell') if user_shell and os.path.exists(user_shell): argv.append(user_shell) else: argv.append(os.environ['SHELL']) login_shell = self.settings.general.get_boolean('use-login-shell') if login_shell: argv.append('--login') if isinstance(directory, str): wd = directory else: wd = os.environ['HOME'] pid = terminal.spawn_sync( Vte.PtyFlags.DEFAULT, wd, argv, [], GLib.SpawnFlags.DO_NOT_REAP_CHILD, None, None, None ) return pid def show(self): """Calls the main window show_all method and presents the window in the desktop. """ self.get_widget('config-window').show_all() self.get_widget('config-window').present() def hide(self): """Calls the main window hide function. """ self.get_widget('config-window').hide() def on_destroy(self, window): self.demo_terminal.kill() self.demo_terminal.destroy() def toggle_prompt_on_quit_sensitivity(self, combo): """If toggle_on_close_tabs is set to 2 (Always), prompt_on_quit has no effect. """ self.get_widget('prompt_on_quit').set_sensitive(combo.get_active() != 2) def toggle_style_sensitivity(self, chk): """If the user chooses to use the gnome default font configuration it means that he will not be able to use the font selector. """ self.get_widget('font_style').set_sensitive(not chk.get_active()) def toggle_use_font_background_sensitivity(self, chk): """If the user chooses to use the gnome default font configuration it means that he will not be able to use the font selector. """ self.get_widget('palette_16').set_sensitive(chk.get_active()) self.get_widget('palette_17').set_sensitive(chk.get_active()) def toggle_display_n_sensitivity(self, chk): """When the user unchecks 'on mouse display', the option to select an alternate display should be enabeld. """ self.get_widget('display_n').set_sensitive(not chk.get_active()) def toggle_quick_open_command_line_sensitivity(self, chk): """When the user unchecks 'enable quick open', the command line should be disabled """ self.get_widget('quick_open_command_line').set_sensitive(chk.get_active()) self.get_widget('quick_open_in_current_terminal').set_sensitive(chk.get_active()) def toggle_use_vte_titles(self, chk): """When vte titles aren't used, there is nothing to abbreviate """ self.update_vte_subwidgets_states() def update_vte_subwidgets_states(self): do_use_vte_titles = self.get_widget('use_vte_titles').get_active() max_tab_name_length_wdg = self.get_widget('max_tab_name_length') max_tab_name_length_wdg.set_sensitive(do_use_vte_titles) self.get_widget('lbl_max_tab_name_length').set_sensitive(do_use_vte_titles) self.get_widget('abbreviate_tab_names').set_sensitive(do_use_vte_titles) def on_reset_compat_defaults_clicked(self, bnt): """Reset default values to compat_{backspace,delete} gconf keys. The default values are retrivied from the guake.schemas file. """ self.settings.general.reset('compat-backspace') self.settings.general.reset('compat-delete') self.reload_erase_combos() def on_palette_name_changed(self, combo): """Changes the value of palette in gconf """ palette_name = combo.get_active_text() if palette_name not in PALETTES: return self.settings.styleFont.set_string('palette', PALETTES[palette_name]) self.settings.styleFont.set_string('palette-name', palette_name) self.set_palette_colors(PALETTES[palette_name]) self.update_demo_palette(PALETTES[palette_name]) def on_cursor_shape_changed(self, combo): """Changes the value of cursor_shape in gconf """ index = combo.get_active() self.settings.style.set_int('cursor-shape', index) def on_blink_cursor_toggled(self, chk): """Changes the value of blink_cursor in gconf """ self.settings.style.set_int('cursor-blink-mode', chk.get_active()) def on_palette_color_set(self, btn): """Changes the value of palette in gconf """ palette = [] for i in range(18): palette.append(hexify_color(self.get_widget('palette_%d' % i).get_color())) palette = ':'.join(palette) self.settings.styleFont.set_string('palette', palette) self.settings.styleFont.set_string('palette-name', _('Custom')) self.set_palette_name('Custom') self.update_demo_palette(palette) # this methods should be moved to the GuakeTerminal class FROM HERE def set_palette_name(self, palette_name): """If the given palette matches an existing one, shows it in the combobox """ combo = self.get_widget('palette_name') found = False log.debug("wanting palette: %r", palette_name) for i in combo.get_model(): if i[0] == palette_name: combo.set_active_iter(i.iter) found = True break if not found: combo.set_active(self.custom_palette_index) def update_demo_palette(self, palette): self.set_colors_from_settings() def set_colors_from_settings(self): transparency = self.settings.styleBackground.get_int('transparency') colorRGBA = Gdk.RGBA(0, 0, 0, 0) palette_list = list() for color in self.settings.styleFont.get_string("palette").split(':'): colorRGBA.parse(color) palette_list.append(colorRGBA.copy()) if len(palette_list) > 16: bg_color = palette_list[17] else: bg_color = Gdk.RGBA(255, 255, 255, 0) bg_color.alpha = 1 / 100 * transparency if len(palette_list) > 16: font_color = palette_list[16] else: font_color = Gdk.RGBA(0, 0, 0, 0) self.demo_terminal.set_color_foreground(font_color) self.demo_terminal.set_color_bold(font_color) self.demo_terminal.set_colors(font_color, bg_color, palette_list[:16]) # TO HERE (see above) def fill_palette_names(self): combo = self.get_widget('palette_name') for palette in sorted(PALETTES): combo.append_text(palette) self.custom_palette_index = len(PALETTES) combo.append_text(_('Custom')) def set_cursor_shape(self, shape_index): self.get_widget('cursor_shape').set_active(shape_index) def set_cursor_blink_mode(self, mode_index): self.get_widget('cursor_blink_mode').set_active(mode_index) def set_palette_colors(self, palette): """Updates the color buttons with the given palette """ palette = palette.split(':') for i, pal in enumerate(palette): x, color = Gdk.Color.parse(pal) self.get_widget('palette_%d' % i).set_color(color) def reload_erase_combos(self, btn=None): """Read from gconf the value of compat_{backspace,delete} vars and select the right option in combos. """ # backspace erase binding combo = self.get_widget('backspace-binding-combobox') binding = self.settings.general.get_string('compat-backspace') for i in combo.get_model(): if ERASE_BINDINGS.get(i[0]) == binding: combo.set_active_iter(i.iter) # delete erase binding combo = self.get_widget('delete-binding-combobox') binding = self.settings.general.get_string('compat-delete') for i in combo.get_model(): if ERASE_BINDINGS.get(i[0]) == binding: combo.set_active_iter(i.iter) def _load_hooks_settings(self): """load hooks settings""" log.debug("executing _load_hooks_settings") hook_show_widget = self.get_widget("hook_show") hook_show_setting = self.settings.hooks.get_string("show") if hook_show_widget is not None: if hook_show_setting is not None: hook_show_widget.set_text(hook_show_setting) return def _load_default_shell_settings(self): combo = self.get_widget('default_shell') # get the value for defualt shell. If unset, set to USER_SHELL_VALUE. value = self.settings.general.get_string('default-shell') or USER_SHELL_VALUE for i in combo.get_model(): if i[0] == value: combo.set_active_iter(i.iter) def _load_screen_settings(self): """Load screen settings""" # display number / use primary display combo = self.get_widget('display_n') dest_screen = self.settings.general.get_int('display-n') # If Guake is configured to use a screen that is not currently attached, # default to 'primary display' option. screen = self.get_widget('config-window').get_screen() n_screens = screen.get_n_monitors() if dest_screen > n_screens - 1: self.settings.general.set_boolean('mouse-display', False) dest_screen = screen.get_primary_monitor() self.settings.general.set_int('display_n', dest_screen) if dest_screen == ALWAYS_ON_PRIMARY: first_item = combo.get_model().get_iter_first() combo.set_active_iter(first_item) else: seen_first = False # first item "always on primary" is special for i in combo.get_model(): if seen_first: i_int = int(i[0].split()[0]) # extracts 1 from '1' or from '1 (primary)' if i_int == dest_screen: combo.set_active_iter(i.iter) else: seen_first = True def load_configs(self): """Load configurations for all widgets in General, Scrolling and Appearance tabs from gconf. """ self._load_default_shell_settings() # login shell value = self.settings.general.get_boolean('use-login-shell') self.get_widget('use_login_shell').set_active(value) # tray icon value = self.settings.general.get_boolean('use-trayicon') self.get_widget('use_trayicon').set_active(value) # popup value = self.settings.general.get_boolean('use-popup') self.get_widget('use_popup').set_active(value) # prompt on quit value = self.settings.general.get_boolean('prompt-on-quit') self.get_widget('prompt_on_quit').set_active(value) # prompt on close_tab value = self.settings.general.get_int('prompt-on-close-tab') self.get_widget('prompt_on_close_tab').set_active(value) self.get_widget('prompt_on_quit').set_sensitive(value != 2) # ontop value = self.settings.general.get_boolean('window-ontop') self.get_widget('window_ontop').set_active(value) # tab ontop value = self.settings.general.get_boolean('tab-ontop') self.get_widget('tab_ontop').set_active(value) # refocus value = self.settings.general.get_boolean('window-refocus') self.get_widget('window_refocus').set_active(value) # losefocus value = self.settings.general.get_boolean('window-losefocus') self.get_widget('window_losefocus').set_active(value) # use VTE titles value = self.settings.general.get_boolean('use-vte-titles') self.get_widget('use_vte_titles').set_active(value) # set window title value = self.settings.general.get_boolean('set-window-title') self.get_widget('set_window_title').set_active(value) # abbreviate tab names self.get_widget('abbreviate_tab_names').set_sensitive(value) value = self.settings.general.get_boolean('abbreviate-tab-names') self.get_widget('abbreviate_tab_names').set_active(value) # max tab name length value = self.settings.general.get_int('max-tab-name-length') self.get_widget('max_tab_name_length').set_value(value) self.update_vte_subwidgets_states() value = self.settings.general.get_int('window-height') self.get_widget('window_height').set_value(value) value = self.settings.general.get_int('window-width') self.get_widget('window_width').set_value(value) # window displacements value = self.settings.general.get_int('window-vertical-displacement') self.get_widget('window_vertical_displacement').set_value(value) value = self.settings.general.get_int('window-horizontal-displacement') self.get_widget('window_horizontal_displacement').set_value(value) value = self.settings.general.get_int('window-halignment') which_button = { ALIGN_RIGHT: 'radiobutton_align_right', ALIGN_LEFT: 'radiobutton_align_left', ALIGN_CENTER: 'radiobutton_align_center' } self.get_widget(which_button[value]).set_active(True) self.get_widget("window_horizontal_displacement").set_sensitive(value != ALIGN_CENTER) value = self.settings.general.get_boolean('open-tab-cwd') self.get_widget('open_tab_cwd').set_active(value) # tab bar value = self.settings.general.get_boolean('window-tabbar') self.get_widget('window_tabbar').set_active(value) # start fullscreen value = self.settings.general.get_boolean('start-fullscreen') self.get_widget('start_fullscreen').set_active(value) # use audible bell value = self.settings.general.get_boolean('use-audible-bell') self.get_widget('use_audible_bell').set_active(value) self._load_screen_settings() value = self.settings.general.get_boolean('quick-open-enable') self.get_widget('quick_open_enable').set_active(value) self.get_widget('quick_open_command_line').set_sensitive(value) self.get_widget('quick_open_in_current_terminal').set_sensitive(value) text = Gtk.TextBuffer() text = self.get_widget('quick_open_supported_patterns').get_buffer() for title, matcher, _useless in QUICK_OPEN_MATCHERS: text.insert_at_cursor("%s: %s\n" % (title, matcher)) self.get_widget('quick_open_supported_patterns').set_buffer(text) value = self.settings.general.get_string('quick-open-command-line') if value is None: value = "subl %(file_path)s:%(line_number)s" self.get_widget('quick_open_command_line').set_text(value) value = self.settings.general.get_boolean('quick-open-in-current-terminal') self.get_widget('quick_open_in_current_terminal').set_active(value) value = self.settings.general.get_string('startup-script') if value: self.get_widget('startup_script').set_text(value) # use display where the mouse is currently value = self.settings.general.get_boolean('mouse-display') self.get_widget('mouse_display').set_active(value) # scrollbar value = self.settings.general.get_boolean('use-scrollbar') self.get_widget('use_scrollbar').set_active(value) # history size value = self.settings.general.get_int('history-size') self.get_widget('history_size').set_value(value) # infinite history value = self.settings.general.get_boolean('infinite-history') self.get_widget('infinite_history').set_active(value) print("infinite history: ", value) # scroll output value = self.settings.general.get_boolean('scroll-output') self.get_widget('scroll_output').set_active(value) # scroll keystroke value = self.settings.general.get_boolean('scroll-keystroke') self.get_widget('scroll_keystroke').set_active(value) # default font value = self.settings.general.get_boolean('use-default-font') self.get_widget('use_default_font').set_active(value) self.get_widget('font_style').set_sensitive(not value) # font value = self.settings.styleFont.get_string('style') if value: self.get_widget('font_style').set_font_name(value) # allow bold font value = self.settings.styleFont.get_boolean('allow-bold') self.get_widget('allow_bold').set_active(value) # palette self.fill_palette_names() value = self.settings.styleFont.get_string('palette-name') self.set_palette_name(value) value = self.settings.styleFont.get_string('palette') self.set_palette_colors(value) self.update_demo_palette(value) # cursor shape value = self.settings.style.get_int('cursor-shape') self.set_cursor_shape(value) # cursor blink value = self.settings.style.get_int('cursor-blink-mode') self.set_cursor_blink_mode(value) value = self.settings.styleBackground.get_int('transparency') self.get_widget('background_transparency').set_value(value) value = self.settings.general.get_int('window-valignment') self.get_widget('top_align').set_active(value) # it's a separated method, to be reused. self.reload_erase_combos() # custom command context-menu configuration file custom_command_file = self.settings.general.get_string('custom-command-file') if custom_command_file: custom_command_file_name = os.path.expanduser(custom_command_file) else: custom_command_file_name = None custom_cmd_filter = Gtk.FileFilter() custom_cmd_filter.set_name(_("JSON files")) custom_cmd_filter.add_pattern("*.json") self.get_widget('custom_command_file_chooser').add_filter(custom_cmd_filter) all_files_filter = Gtk.FileFilter() all_files_filter.set_name(_("All files")) all_files_filter.add_pattern("*") self.get_widget('custom_command_file_chooser').add_filter(all_files_filter) if custom_command_file_name: self.get_widget('custom_command_file_chooser').set_filename(custom_command_file_name) # hooks self._load_hooks_settings() # -- populate functions -- def populate_shell_combo(self): """Read the /etc/shells and looks for installed shells to fill the default_shell combobox. """ cb = self.get_widget('default_shell') # append user shell as first option cb.append_text(USER_SHELL_VALUE) if os.path.exists(SHELLS_FILE): lines = open(SHELLS_FILE).readlines() for i in lines: possible = i.strip() if possible and not possible.startswith('#') and os.path.exists(possible): cb.append_text(possible) for i in get_binaries_from_path(PYTHONS): cb.append_text(i) def populate_keys_tree(self): """Reads the HOTKEYS global variable and insert all data in the TreeStore used by the preferences window treeview. """ for group in HOTKEYS: parent = self.store.append(None, [None, group['label'], None, None]) for item in group['keys']: if item['key'] == "show-hide" or item['key'] == "show-focus": accel = self.settings.keybindingsGlobal.get_string(item['key']) else: accel = self.settings.keybindingsLocal.get_string(item['key']) gsettings_path = item['key'] keycode, mask = Gtk.accelerator_parse(accel) keylabel = Gtk.accelerator_get_label(keycode, mask) self.store.append(parent, [gsettings_path, item['label'], keylabel, accel]) self.get_widget('treeview-keys').expand_all() def populate_display_n(self): """Get the number of displays and populate this drop-down box with them all. Prepend the "always on primary" option. """ cb = self.get_widget('display_n') screen = self.get_widget('config-window').get_screen() cb.append_text("always on primary") for m in range(0, int(screen.get_n_monitors())): if m == int(screen.get_primary_monitor()): # TODO l10n cb.append_text(str(m) + ' ' + '(primary)') else: cb.append_text(str(m)) # -- key handling -- def on_accel_edited(self, cellrendereraccel, path, key, mods, hwcode): """Callback that handles key edition in cellrenderer. It makes some tests to validate the key, like looking for already in use keys and look for [A-Z][a-z][0-9] to avoid problems with these common keys. If all tests are ok, the value will be stored in gconf. """ accelerator = Gtk.accelerator_name(key, mods) dconf_path = self.store[path][HOTKET_MODEL_INDEX_DCONF] old_accel = self.store[path][HOTKET_MODEL_INDEX_HUMAN_ACCEL] keylabel = Gtk.accelerator_get_label(key, mods) # we needn't to change anything, the user is trying to set the # same key that is already set. if old_accel == accelerator: return False self.hotkey_alread_used = False # looking for already used keybindings def each_key(model, path, subiter): keyentry = model.get_value(subiter, HOTKET_MODEL_INDEX_ACCEL) if keyentry and keyentry == accelerator: self.hotkey_alread_used = True msg = _("The shortcut \"%s\" is already in use.") % html_escape(accelerator) ShowableError(self.window, _('Error setting keybinding.'), msg, -1) raise Exception('This is ok, we just use it to break the foreach loop!') self.store.foreach(each_key) if self.hotkey_alread_used: return False # avoiding problems with common keys if ((mods == 0 and key != 0) and ((key >= ord('a') and key <= ord('z')) or (key >= ord('A') and key <= ord('Z')) or (key >= ord('0') and key <= ord('9')))): dialog = Gtk.MessageDialog( self.get_widget('config-window'), Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, _( "The shortcut \"%s\" cannot be used " "because it will become impossible to " "type using this key.\n\n" "Please try with a key such as " "Control, Alt or Shift at the same " "time.\n" ) % html_escape(key) ) dialog.run() dialog.destroy() return False self.store[path][HOTKET_MODEL_INDEX_HUMAN_ACCEL] = keylabel if dconf_path == "show-hide" or dconf_path == "show-focus": self.settings.keybindingsGlobal.set_string(dconf_path, accelerator) else: self.settings.keybindingsLocal.set_string(dconf_path, accelerator) self.store[path][HOTKET_MODEL_INDEX_ACCEL] = accelerator def on_accel_cleared(self, cellrendereraccel, path): """If the user tries to clear a keybinding with the backspace key this callback will be called and it just fill the model with an empty key and set the 'disabled' string in gconf path. """ dconf_path = self.store[path][HOTKET_MODEL_INDEX_DCONF] if dconf_path == "show-hide": # cannot disable 'show-hide' hotkey log.warn("Cannot disable 'show-hide' hotkey") self.settings.keybindingsGlobal.set_string(dconf_path, old_accel) else: self.store[path][HOTKET_MODEL_INDEX_HUMAN_ACCEL] = "" self.store[path][HOTKET_MODEL_INDEX_ACCEL] = "None" if dconf_path == "show-focus": self.settings.keybindingsGlobal.set_string(dconf_path, 'disabled') else: self.settings.keybindingsLocal.set_string(dconf_path, 'disabled') def start_editing(self, treeview, event): """Make the treeview grab the focus and start editing the cell that the user has clicked to avoid confusion with two or three clicks before editing a keybinding. Thanks to gnome-keybinding-properties.c =) """ # TODO PORT some thing in here is breaking stuff if event.window != treeview.get_bin_window(): return False x, y = int(event.x), int(event.y) ret = treeview.get_path_at_pos(x, y) if not ret: return False path, column, cellx, celly = ret if path and len(path) > 1: def real_cb(): treeview.grab_focus() treeview.set_cursor(path, column, True) treeview.stop_emission('button-press-event') GObject.idle_add(real_cb) return True
def __init__(self, settings): """Setup the preferences dialog interface, loading images, adding filters to file choosers and connecting some signals. """ super(PrefsDialog, self).__init__(gladefile('prefs.glade'), root='config-window') self.settings = settings self.add_callbacks(PrefsCallbacks(self)) # window cleanup handler self.window = self.get_widget('config-window') self.get_widget('config-window').connect('destroy', self.on_destroy) # setting evtbox title bg eventbox = self.get_widget('eventbox-title') eventbox.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(255, 255, 255, 255)) # images ipath = pixmapfile('guake-notification.png') self.get_widget('image_logo').set_from_file(ipath) ipath = pixmapfile('quick-open.png') self.get_widget('image_quick_open').set_from_file(ipath) # the first position in tree will store the keybinding path in gconf, # and the user doesn't worry with this, let's hide that =D model = Gtk.TreeStore(str, str, object, bool) treeview = self.get_widget('treeview-keys') treeview.set_model(model) treeview.set_rules_hint(True) # TODO PORT this is killing the editing of the accl # treeview.connect('button-press-event', self.start_editing) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn('keypath', renderer, text=0) column.set_visible(False) treeview.append_column(column) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn(_('Action'), renderer, text=1) column.set_property('expand', True) treeview.append_column(column) renderer = Gtk.CellRendererAccel() renderer.set_property('editable', True) renderer.connect('accel-edited', self.on_key_edited, model) renderer.connect('accel-cleared', self.on_key_cleared, model) column = Gtk.TreeViewColumn(_('Shortcut'), renderer) column.set_cell_data_func(renderer, self.cell_data_func) column.set_property('expand', False) treeview.append_column(column) self.demo_terminal = GuakeTerminal(self.settings) demo_terminal_box = self.get_widget('demo_terminal_box') demo_terminal_box.add(self.demo_terminal) pid = self.spawn_sync_pid(None, self.demo_terminal) self.demo_terminal.pid = pid self.populate_shell_combo() self.populate_keys_tree() self.populate_display_n() self.load_configs() self.get_widget('config-window').hide()