diff options
Diffstat (limited to 'lib/widgets/ephy-location-entry.c')
-rw-r--r-- | lib/widgets/ephy-location-entry.c | 378 |
1 files changed, 37 insertions, 341 deletions
diff --git a/lib/widgets/ephy-location-entry.c b/lib/widgets/ephy-location-entry.c index 74b590f9c..472d0ab66 100644 --- a/lib/widgets/ephy-location-entry.c +++ b/lib/widgets/ephy-location-entry.c @@ -31,10 +31,11 @@ #include "ephy-gui.h" #include "ephy-lib-type-builtins.h" #include "ephy-signal-accumulator.h" +#include "ephy-suggestion.h" #include "ephy-title-widget.h" #include "ephy-uri-helpers.h" -#include "gd-two-lines-renderer.h" +#include <dazzle.h> #include <gdk/gdkkeysyms.h> #include <glib/gi18n.h> #include <gtk/gtk.h> @@ -54,7 +55,7 @@ */ struct _EphyLocationEntry { - GtkEntry parent_instance; + DzlSuggestionEntry parent_instance; GtkTreeModel *model; @@ -91,12 +92,6 @@ struct _EphyLocationEntry { static gboolean ephy_location_entry_reset_internal (EphyLocationEntry *, gboolean); -static void extracell_data_func (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer data); - enum { PROP_0, PROP_ADDRESS, @@ -115,11 +110,17 @@ static gint signals[LAST_SIGNAL] = { 0 }; static void ephy_location_entry_title_widget_interface_init (EphyTitleWidgetInterface *iface); -G_DEFINE_TYPE_WITH_CODE (EphyLocationEntry, ephy_location_entry, GTK_TYPE_ENTRY, +G_DEFINE_TYPE_WITH_CODE (EphyLocationEntry, ephy_location_entry, DZL_TYPE_SUGGESTION_ENTRY, G_IMPLEMENT_INTERFACE (EPHY_TYPE_TITLE_WIDGET, ephy_location_entry_title_widget_interface_init)) static void +ephy_location_entry_activate (EphyLocationEntry *entry) +{ + g_signal_emit_by_name (entry, "activate"); +} + +static void update_address_state (EphyLocationEntry *entry) { const char *text; @@ -273,8 +274,12 @@ ephy_location_entry_get_property (GObject *object, static void ephy_location_entry_constructed (GObject *object) { + EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (object); + G_OBJECT_CLASS (ephy_location_entry_parent_class)->constructed (object); + dzl_suggestion_entry_set_position_func (DZL_SUGGESTION_ENTRY (entry), dzl_suggestion_entry_window_position_func, NULL, NULL); + #if GTK_CHECK_VERSION(3, 22, 20) gtk_entry_set_input_hints (GTK_ENTRY (object), GTK_INPUT_HINT_NO_EMOJI); #endif @@ -361,6 +366,16 @@ ephy_location_entry_cut_clipboard (GtkEntry *entry) } static void +ephy_location_entry_suggestion_activated (DzlSuggestionEntry *entry, + DzlSuggestion *suggestion) +{ + gtk_entry_set_text (GTK_ENTRY (entry), ephy_suggestion_get_uri (EPHY_SUGGESTION (suggestion))); + + /* Now trigger the load.... */ + ephy_location_entry_activate (EPHY_LOCATION_ENTRY (entry)); +} + +static void ephy_location_entry_title_widget_interface_init (EphyTitleWidgetInterface *iface) { iface->get_address = ephy_location_entry_title_widget_get_address; @@ -375,7 +390,9 @@ ephy_location_entry_class_init (EphyLocationEntryClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GtkEntryClass *entry_class = GTK_ENTRY_CLASS (klass); + DzlSuggestionEntryClass *dzl_entry_class = DZL_SUGGESTION_ENTRY_CLASS (klass); + object_class->constructed = ephy_location_entry_constructed; object_class->get_property = ephy_location_entry_get_property; object_class->set_property = ephy_location_entry_set_property; object_class->constructed = ephy_location_entry_constructed; @@ -387,6 +404,8 @@ ephy_location_entry_class_init (EphyLocationEntryClass *klass) entry_class->copy_clipboard = ephy_location_entry_copy_clipboard; entry_class->cut_clipboard = ephy_location_entry_cut_clipboard; + dzl_entry_class->suggestion_activated = ephy_location_entry_suggestion_activated; + g_object_class_override_property (object_class, PROP_ADDRESS, "address"); g_object_class_override_property (object_class, PROP_SECURITY_LEVEL, "security-level"); @@ -488,103 +507,18 @@ entry_key_press_cb (GtkEntry *entry, /* Make sure the location is activated on CTRL+l even when the * completion popup is shown and have an active keyboard grab. */ - ephy_location_entry_activate (location_entry); - } - - return FALSE; -} - -static gboolean -entry_key_press_after_cb (GtkEntry *entry, - GdkEventKey *event, - EphyLocationEntry *lentry) -{ - guint state = event->state & gtk_accelerator_get_default_mod_mask (); - - if ((event->keyval == GDK_KEY_Return || - event->keyval == GDK_KEY_KP_Enter || - event->keyval == GDK_KEY_ISO_Enter) && - (state == GDK_CONTROL_MASK || - state == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))) { - /* gtk_im_context_reset (entry->im_context); */ - - lentry->needs_reset = TRUE; - g_signal_emit_by_name (entry, "activate"); - - return TRUE; + ephy_location_entry_focus (location_entry); } - if ((event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down) - && state == 0) { - /* If we are focusing the entry, with the cursor at the end of it - * we emit the changed signal, so that the completion popup appears */ - const char *string; - - string = gtk_entry_get_text (entry); - if (gtk_editable_get_position (GTK_EDITABLE (entry)) == (int)strlen (string)) { - g_signal_emit_by_name (entry, "changed", 0); - return TRUE; - } - } + if (event->keyval == GDK_KEY_Return || + event->keyval == GDK_KEY_KP_Enter || + event->keyval == GDK_KEY_ISO_Enter) + ephy_location_entry_activate (location_entry); return FALSE; } static void -entry_activate_after_cb (GtkEntry *entry, - EphyLocationEntry *lentry) -{ - lentry->user_changed = FALSE; - - if (lentry->needs_reset) { - ephy_location_entry_reset_internal (lentry, TRUE); - lentry->needs_reset = FALSE; - } -} - -static gboolean -match_selected_cb (GtkEntryCompletion *completion, - GtkTreeModel *model, - GtkTreeIter *iter, - EphyLocationEntry *entry) -{ - char *item = NULL; - guint state; - - gtk_tree_model_get (model, iter, - entry->action_col, &item, -1); - if (item == NULL) return FALSE; - - ephy_gui_get_current_event (NULL, &state, NULL); - - entry->needs_reset = (state == GDK_CONTROL_MASK || - state == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)); - - ephy_title_widget_set_address (EPHY_TITLE_WIDGET (entry), item); - /* gtk_im_context_reset (GTK_ENTRY (entry)->im_context); */ - g_signal_emit_by_name (entry, "activate"); - - g_free (item); - - return TRUE; -} - -static void -action_activated_after_cb (GtkEntryCompletion *completion, - gint index, - EphyLocationEntry *lentry) -{ - guint state, button; - - ephy_gui_get_current_event (NULL, &state, &button); - if ((state == GDK_CONTROL_MASK || - state == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) || - button == 2) { - ephy_location_entry_reset_internal (lentry, TRUE); - } -} - -static void entry_clear_activate_cb (GtkMenuItem *item, EphyLocationEntry *entry) { @@ -601,7 +535,7 @@ paste_received (GtkClipboard *clipboard, { if (text) { gtk_entry_set_text (GTK_ENTRY (entry), text); - g_signal_emit_by_name (entry, "activate"); + ephy_location_entry_activate (entry); } } @@ -758,11 +692,6 @@ ephy_location_entry_construct_contents (EphyLocationEntry *lentry) "signal::key-press-event", G_CALLBACK (entry_key_press_cb), lentry, "signal::changed", G_CALLBACK (editable_changed_cb), lentry, NULL); - - g_signal_connect_after (entry, "key-press-event", - G_CALLBACK (entry_key_press_after_cb), lentry); - g_signal_connect_after (entry, "activate", - G_CALLBACK (entry_activate_after_cb), lentry); } static void @@ -839,238 +768,6 @@ schedule_dns_prefetch (EphyLocationEntry *entry, guint interval, const gchar *ur } #endif -static gboolean -cursor_on_match_cb (GtkEntryCompletion *completion, - GtkTreeModel *model, - GtkTreeIter *iter, - EphyLocationEntry *le) -{ - char *url = NULL; - GtkWidget *entry; - - gtk_tree_model_get (model, iter, - le->url_col, - &url, -1); - entry = gtk_entry_completion_get_entry (completion); - - /* Prevent the update so we keep the highlight from our input. - * See textcell_data_func(). - */ - le->block_update = TRUE; - gtk_entry_set_text (GTK_ENTRY (entry), url); - gtk_editable_set_position (GTK_EDITABLE (entry), -1); - le->block_update = FALSE; - -#if 0 -/* FIXME: Refactor the DNS prefetch, this is a layering violation */ - schedule_dns_prefetch (le, 250, (const gchar *)url); -#endif - - g_free (url); - - return TRUE; -} - -static void -extracell_data_func (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer data) -{ - EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (data); - gboolean is_bookmark = FALSE; - GValue visible = { 0, }; - - gtk_tree_model_get (tree_model, iter, - entry->extra_col, &is_bookmark, - -1); - - if (is_bookmark) - g_object_set (cell, - "icon-name", "user-bookmarks-symbolic", - NULL); - - g_value_init (&visible, G_TYPE_BOOLEAN); - g_value_set_boolean (&visible, is_bookmark); - g_object_set_property (G_OBJECT (cell), "visible", &visible); - g_value_unset (&visible); -} - -/** - * ephy_location_entry_set_match_func: - * @entry: an #EphyLocationEntry widget - * @match_func: a #GtkEntryCompletionMatchFunc - * @user_data: user_data to pass to the @match_func - * @notify: a #GDestroyNotify, like the one given to - * gtk_entry_completion_set_match_func - * - * Sets the match_func for the internal #GtkEntryCompletion to @match_func. - * - **/ -void -ephy_location_entry_set_match_func (EphyLocationEntry *entry, - GtkEntryCompletionMatchFunc match_func, - gpointer user_data, - GDestroyNotify notify) -{ - GtkEntryCompletion *completion; - - completion = gtk_entry_get_completion (GTK_ENTRY (entry)); - gtk_entry_completion_set_match_func (completion, match_func, user_data, notify); -} - -/** - * ephy_location_entry_set_completion: - * @entry: an #EphyLocationEntry widget - * @model: the #GtkModel for the completion - * @text_col: column id to access #GtkModel relevant data - * @action_col: column id to access #GtkModel relevant data - * @keywords_col: column id to access #GtkModel relevant data - * @relevance_col: column id to access #GtkModel relevant data - * @url_col: column id to access #GtkModel relevant data - * @extra_col: column id to access #GtkModel relevant data - * @favicon_col: column id to access #GtkModel relevant data - * - * Initializes @entry to have a #GtkEntryCompletion using @model as the - * internal #GtkModel. The *_col arguments are for internal data retrieval from - * @model, like when setting the text property of one of the #GtkCellRenderer - * of the completion. - * - **/ -void -ephy_location_entry_set_completion (EphyLocationEntry *entry, - GtkTreeModel *model, - guint text_col, - guint action_col, - guint keywords_col, - guint relevance_col, - guint url_col, - guint extra_col, - guint favicon_col) -{ - GtkEntryCompletion *completion; - GtkCellRenderer *cell; - - entry->text_col = text_col; - entry->action_col = action_col; - entry->keywords_col = keywords_col; - entry->relevance_col = relevance_col; - entry->url_col = url_col; - entry->extra_col = extra_col; - entry->favicon_col = favicon_col; - - completion = gtk_entry_completion_new (); - gtk_entry_completion_set_model (completion, model); - g_signal_connect (completion, "match-selected", - G_CALLBACK (match_selected_cb), entry); - g_signal_connect_after (completion, "action-activated", - G_CALLBACK (action_activated_after_cb), entry); - - cell = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), - cell, FALSE); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion), - cell, "pixbuf", favicon_col); - - /* Pixel-perfect aligment with the location entry favicon - * (16x16). Consider that this /might/ depend on the theme. - * - * The GtkEntryCompletion can not be themed so we work-around - * that with padding and fixed sizes. - * For the first cell, this is: - * - * ___+++++iiiiiiiiiiiiiiii++__ttt...bbb++++++__ - * - * _ = widget spacing, can not be handled (3 px) - * + = padding (5 px) (ICON_PADDING_LEFT) - * i = the icon (16 px) (ICON_CONTENT_WIDTH) - * + = padding (2 px) (ICON_PADDING_RIGHT) (cut by the fixed_size) - * _ = spacing between cells, can not be handled (2 px) - * t = the text (expands) - * b = bookmark icon (16 px) - * + = padding (6 px) (BKMK_PADDING_RIGHT) - * _ = widget spacing, can not be handled (2 px) - * - * Each character is a pixel. - * - * The text cell and the bookmark icon cell are much more - * flexible in its aligment, because they do not have to align - * with anything in the entry. - */ - -#define ROW_PADDING_VERT 4 - -#define ICON_PADDING_LEFT 5 -#define ICON_CONTENT_WIDTH 16 -#define ICON_PADDING_RIGHT 9 - -#define ICON_CONTENT_HEIGHT 16 - -#define TEXT_PADDING_LEFT 0 - -#define BKMK_PADDING_RIGHT 6 - - gtk_cell_renderer_set_padding - (cell, ICON_PADDING_LEFT, ROW_PADDING_VERT); - gtk_cell_renderer_set_fixed_size - (cell, - (ICON_PADDING_LEFT + ICON_CONTENT_WIDTH + ICON_PADDING_RIGHT), - ICON_CONTENT_HEIGHT); - gtk_cell_renderer_set_alignment (cell, 0.0, 0.5); - - cell = gd_two_lines_renderer_new (); - g_object_set (cell, - "ellipsize", PANGO_ELLIPSIZE_END, - "text-lines", 2, - NULL); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), - cell, TRUE); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion), - cell, "text", text_col); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion), - cell, "line-two", url_col); - - /* Pixel-perfect aligment with the text in the location entry. - * See above. - */ - gtk_cell_renderer_set_padding - (cell, TEXT_PADDING_LEFT, ROW_PADDING_VERT); - gtk_cell_renderer_set_alignment (cell, 0.0, 0.5); - - /* - * As the width of the entry completion is known in advance - * (as big as the entry you are completing on), we can set - * any fixed width (the 1 is just this random number here) - * Since the height is known too, we avoid computing the actual - * sizes of the cells, which takes a lot of CPU time and does - * not get used anyway. - */ - gtk_cell_renderer_set_fixed_size (cell, 1, -1); - gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (cell), 2); - - cell = gtk_cell_renderer_pixbuf_new (); - g_object_set (cell, "follow-state", TRUE, NULL); - gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (completion), - cell, FALSE); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), - cell, extracell_data_func, - entry, - NULL); - - /* Pixel-perfect aligment. This just keeps the same margin from - * the border than the favicon on the other side. See above. */ - gtk_cell_renderer_set_padding - (cell, BKMK_PADDING_RIGHT, ROW_PADDING_VERT); - - g_object_set (completion, "inline-selection", TRUE, NULL); - g_signal_connect (completion, "cursor-on-match", - G_CALLBACK (cursor_on_match_cb), entry); - - gtk_entry_set_completion (GTK_ENTRY (entry), completion); - g_object_unref (completion); -} - /** * ephy_location_entry_get_can_undo: * @entry: an #EphyLocationEntry widget @@ -1125,9 +822,8 @@ ephy_location_entry_reset_internal (EphyLocationEntry *entry, ephy_title_widget_set_address (EPHY_TITLE_WIDGET (entry), text); g_free (url); - if (notify) { + if (notify) g_signal_emit (entry, signals[USER_CHANGED], 0); - } entry->user_changed = FALSE; @@ -1167,7 +863,7 @@ ephy_location_entry_reset (EphyLocationEntry *entry) } /** - * ephy_location_entry_activate: + * ephy_location_entry_focus: * @entry: an #EphyLocationEntry widget * * Set focus on @entry and select the text whithin. This is called when the @@ -1175,7 +871,7 @@ ephy_location_entry_reset (EphyLocationEntry *entry) * **/ void -ephy_location_entry_activate (EphyLocationEntry *entry) +ephy_location_entry_focus (EphyLocationEntry *entry) { GtkWidget *toplevel, *widget = GTK_WIDGET (entry); |