Exemple #1
0
 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
Exemple #2
0
    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
Exemple #3
0
 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
Exemple #4
0
 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
Exemple #5
0
 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
Exemple #6
0
 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
Exemple #7
0
    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)
Exemple #8
0
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
Exemple #9
0
    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)
Exemple #10
0
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
Exemple #11
0
    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()
Exemple #12
0
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
Exemple #13
0
    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()
Exemple #14
0
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
Exemple #15
0
    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()