midori/midori/midori-locationaction.c
Christian Dywan 08691b7745 Cope with unset history in midori_location_action_toggle_arrow_cb
If history is unset, we don't have any items to populate the
combobox dropdown with. So we should always hide the button. Also
suppress the popup if we have no history.
2010-09-29 01:35:41 +02:00

1832 lines
62 KiB
C

/*
Copyright (C) 2008-2010 Christian Dywan <christian@twotoasts.de>
Copyright (C) 2008-2010 Dale Whittaker <dayul@users.sf.net>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-locationaction.h"
#include "gtkiconentry.h"
#include "marshal.h"
#include "sokoke.h"
#include "midori-browser.h"
#include <string.h>
#include <glib/gi18n.h>
#include <gdk/gdkkeysyms.h>
#include <sqlite3.h>
#define COMPLETION_DELAY 200
#define MAX_ITEMS 25
struct _MidoriLocationAction
{
GtkAction parent_instance;
gchar* text;
gchar* uri;
KatzeArray* search_engines;
gdouble progress;
gchar* secondary_icon;
guint completion_timeout;
gchar* key;
GtkWidget* popup;
GtkWidget* treeview;
GtkTreeModel* completion_model;
gint completion_index;
GtkWidget* entry;
GdkPixbuf* default_icon;
KatzeArray* history;
};
struct _MidoriLocationActionClass
{
GtkActionClass parent_class;
};
G_DEFINE_TYPE (MidoriLocationAction, midori_location_action, GTK_TYPE_ACTION)
enum
{
PROP_0,
PROP_PROGRESS,
PROP_SECONDARY_ICON,
PROP_HISTORY
};
enum
{
ACTIVE_CHANGED,
FOCUS_IN,
FOCUS_OUT,
SECONDARY_ICON_RELEASED,
RESET_URI,
SUBMIT_URI,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
enum
{
FAVICON_COL,
URI_COL,
TITLE_COL,
VISITS_COL,
VISIBLE_COL,
YALIGN_COL,
BACKGROUND_COL,
STYLE_COL,
N_COLS
};
static void
midori_location_action_finalize (GObject* object);
static void
midori_location_action_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_location_action_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
midori_location_action_activate (GtkAction* object);
static GtkWidget*
midori_location_action_create_tool_item (GtkAction* action);
static void
midori_location_action_connect_proxy (GtkAction* action,
GtkWidget* proxy);
static void
midori_location_action_disconnect_proxy (GtkAction* action,
GtkWidget* proxy);
static void
midori_location_entry_render_text_cb (GtkCellLayout* layout,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
gpointer data);
static void
midori_location_action_popdown_completion (MidoriLocationAction* location_action);
static void
midori_location_action_class_init (MidoriLocationActionClass* class)
{
GObjectClass* gobject_class;
GtkActionClass* action_class;
signals[ACTIVE_CHANGED] = g_signal_new ("active-changed",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE, 1,
G_TYPE_INT);
/**
* MidoriLocationAction:focus-in:
*
* The focus-in signal is emitted when the entry obtains the focus.
*
* Since 0.1.8
*/
signals[FOCUS_IN] = g_signal_new ("focus-in",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[FOCUS_OUT] = g_signal_new ("focus-out",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* MidoriLocationAction:secondary-icon-released:
*
* The secondary-icon-released signal is emitted when the mouse button
* is released above the secondary icon.
*
* Since 0.1.10 a signal handler can return %TRUE to stop signal
* emission, for instance to suppress default behavior.
*/
signals[SECONDARY_ICON_RELEASED] = g_signal_new ("secondary-icon-released",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
g_signal_accumulator_true_handled,
NULL,
midori_cclosure_marshal_BOOLEAN__OBJECT,
G_TYPE_BOOLEAN, 1,
GTK_TYPE_WIDGET);
signals[RESET_URI] = g_signal_new ("reset-uri",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[SUBMIT_URI] = g_signal_new ("submit-uri",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
0,
NULL,
midori_cclosure_marshal_VOID__STRING_BOOLEAN,
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_BOOLEAN);
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_location_action_finalize;
gobject_class->set_property = midori_location_action_set_property;
gobject_class->get_property = midori_location_action_get_property;
action_class = GTK_ACTION_CLASS (class);
action_class->activate = midori_location_action_activate;
action_class->create_tool_item = midori_location_action_create_tool_item;
action_class->connect_proxy = midori_location_action_connect_proxy;
action_class->disconnect_proxy = midori_location_action_disconnect_proxy;
g_object_class_install_property (gobject_class,
PROP_PROGRESS,
g_param_spec_double (
"progress",
"Progress",
"The current progress of the action",
0.0, 1.0, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_SECONDARY_ICON,
g_param_spec_string (
"secondary-icon",
"Secondary",
"The stock ID of the secondary icon",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* MidoriLocationAction:history:
*
* The list of history items.
*
* This is actually a reference to a history instance.
*
* Since 0.1.8
*/
g_object_class_install_property (gobject_class,
PROP_HISTORY,
g_param_spec_object (
"history",
"History",
"The list of history items",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* We want location entries to have appears-as-list applied */
gtk_rc_parse_string ("style \"midori-location-entry-style\" {\n"
" GtkComboBox::appears-as-list = 1\n }\n"
"widget \"*MidoriLocationEntry\" "
"style \"midori-location-entry-style\"\n");
}
static GtkTreeModel*
midori_location_action_create_model (void)
{
GtkTreeModel* model = (GtkTreeModel*) gtk_list_store_new (N_COLS,
GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_FLOAT,
GDK_TYPE_COLOR, G_TYPE_BOOLEAN);
return model;
}
static void
midori_location_action_popup_position (GtkWidget* popup,
GtkWidget* widget)
{
gint wx, wy;
GtkRequisition menu_req;
GtkRequisition widget_req;
GdkScreen* screen;
gint monitor_num;
GdkRectangle monitor;
gdk_window_get_origin (widget->window, &wx, &wy);
gtk_widget_size_request (popup, &menu_req);
gtk_widget_size_request (widget, &widget_req);
screen = gtk_widget_get_screen (widget);
monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
if (wy + widget_req.height + menu_req.height <= monitor.y + monitor.height
|| wy - monitor.y < (monitor.y + monitor.height) - (wy + widget_req.height))
wy += widget_req.height;
else
wy -= menu_req.height;
gtk_window_move (GTK_WINDOW (popup), wx, wy);
gtk_window_resize (GTK_WINDOW (popup), widget->allocation.width, 1);
}
static gboolean
midori_location_action_treeview_button_press_cb (GtkWidget* treeview,
GdkEventButton* event,
MidoriLocationAction* action)
{
GtkTreePath* path;
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview),
event->x, event->y, &path, NULL, NULL, NULL))
{
GtkTreeIter iter;
gchar* uri;
gtk_tree_model_get_iter (action->completion_model, &iter, path);
gtk_tree_path_free (path);
midori_location_action_popdown_completion (action);
gtk_tree_model_get (action->completion_model, &iter, URI_COL, &uri, -1);
gtk_entry_set_text (GTK_ENTRY (action->entry), uri);
g_signal_emit (action, signals[SUBMIT_URI], 0, uri,
MIDORI_MOD_NEW_TAB (event->state));
g_free (uri);
return TRUE;
}
return FALSE;
}
static gboolean
midori_location_action_popup_timeout_cb (gpointer data)
{
MidoriLocationAction* action = data;
GtkTreeViewColumn* column;
GtkListStore* store;
gchar* effective_key;
gint i;
gint result;
static sqlite3_stmt* stmt;
const gchar* sqlcmd;
gint matches, searches, height, screen_height, browser_height, sep;
MidoriBrowser* browser;
GtkStyle* style;
if (!action->entry || !gtk_widget_has_focus (action->entry) || !action->history)
return FALSE;
if (!(action->key && *action->key))
{
midori_location_action_popdown_completion (action);
return FALSE;
}
if (!stmt)
{
sqlite3* db;
db = g_object_get_data (G_OBJECT (action->history), "db");
sqlcmd = "SELECT type, uri, title FROM ("
" SELECT 1 AS type, uri, title, count() AS ct FROM history "
" WHERE uri LIKE ?1 OR title LIKE ?1 GROUP BY uri "
" UNION ALL "
" SELECT 2 AS type, replace(uri, '%s', keywords) AS uri, "
" keywords AS title, count() AS ct FROM search "
" WHERE uri LIKE ?1 OR title LIKE ?1 GROUP BY uri "
" UNION ALL "
" SELECT 1 AS type, uri, title, 50 AS ct FROM bookmarks "
" WHERE title LIKE ?1 OR uri LIKE ?1 AND uri !='' "
") GROUP BY uri ORDER BY ct DESC LIMIT ?2";
sqlite3_prepare_v2 (db, sqlcmd, strlen (sqlcmd) + 1, &stmt, NULL);
}
effective_key = g_strdup_printf ("%%%s%%", action->key);
i = 0;
do
{
if (effective_key[i] == ' ')
effective_key[i] = '%';
i++;
}
while (effective_key[i] != '\0');
sqlite3_bind_text (stmt, 1, effective_key, -1, g_free);
sqlite3_bind_int64 (stmt, 2, MAX_ITEMS);
result = sqlite3_step (stmt);
if (result != SQLITE_ROW && !action->search_engines)
{
if (result == SQLITE_ERROR)
g_print (_("Failed to select from history\n"));
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
midori_location_action_popdown_completion (action);
return FALSE;
}
if (G_UNLIKELY (!action->popup))
{
GtkTreeModel* model = NULL;
GtkWidget* popup;
GtkWidget* popup_frame;
GtkWidget* scrolled;
GtkWidget* treeview;
GtkCellRenderer* renderer;
model = midori_location_action_create_model ();
action->completion_model = model;
popup = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_type_hint (GTK_WINDOW (popup), GDK_WINDOW_TYPE_HINT_COMBO);
popup_frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (popup_frame), GTK_SHADOW_ETCHED_IN);
gtk_container_add (GTK_CONTAINER (popup), popup_frame);
scrolled = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"hscrollbar-policy", GTK_POLICY_NEVER,
"vscrollbar-policy", GTK_POLICY_AUTOMATIC, NULL);
gtk_container_add (GTK_CONTAINER (popup_frame), scrolled);
treeview = gtk_tree_view_new_with_model (model);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (treeview), TRUE);
gtk_container_add (GTK_CONTAINER (scrolled), treeview);
g_signal_connect (treeview, "button-press-event",
G_CALLBACK (midori_location_action_treeview_button_press_cb), action);
/* a nasty hack to get the completions treeview to size nicely */
gtk_widget_set_size_request (gtk_scrolled_window_get_vscrollbar (
GTK_SCROLLED_WINDOW (scrolled)), -1, 0);
action->treeview = treeview;
column = gtk_tree_view_column_new ();
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, FALSE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer,
"pixbuf", FAVICON_COL, "yalign", YALIGN_COL,
"cell-background-gdk", BACKGROUND_COL,
NULL);
renderer = gtk_cell_renderer_text_new ();
g_object_set_data (G_OBJECT (renderer), "location-action", action);
gtk_cell_renderer_set_fixed_size (renderer, 1, -1);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer,
"cell-background-gdk", BACKGROUND_COL,
NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
midori_location_entry_render_text_cb,
action, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
action->popup = popup;
g_signal_connect (popup, "destroy",
G_CALLBACK (gtk_widget_destroyed), &action->popup);
}
store = GTK_LIST_STORE (action->completion_model);
gtk_list_store_clear (store);
matches = searches = 0;
style = gtk_widget_get_style (action->treeview);
while (result == SQLITE_ROW)
{
sqlite3_int64 type = sqlite3_column_int64 (stmt, 0);
const unsigned char* uri = sqlite3_column_text (stmt, 1);
const unsigned char* title = sqlite3_column_text (stmt, 2);
GdkPixbuf* icon = katze_load_cached_icon ((gchar*)uri, NULL);
if (!icon)
icon = action->default_icon;
if (type == 1 /* history_view */)
{
gtk_list_store_insert_with_values (store, NULL, matches,
URI_COL, uri, TITLE_COL, title, YALIGN_COL, 0.25,
FAVICON_COL, icon, -1);
}
else if (type == 2 /* search_view */)
{
gchar* search_title = g_strdup_printf (_("Search for %s"), title);
gtk_list_store_insert_with_values (store, NULL, matches,
URI_COL, uri, TITLE_COL, search_title, YALIGN_COL, 0.25,
STYLE_COL, 1, FAVICON_COL, icon, -1);
g_free (search_title);
}
matches++;
result = sqlite3_step (stmt);
}
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
if (action->search_engines)
{
KatzeItem* item;
i = 0;
KATZE_ARRAY_FOREACH_ITEM (item, action->search_engines)
{
gchar* uri;
gchar* title;
uri = sokoke_search_uri (katze_item_get_uri (item), action->key);
title = g_strdup_printf (_("Search with %s"), katze_item_get_name (item));
gtk_list_store_insert_with_values (store, NULL, matches + i,
URI_COL, uri, TITLE_COL, title, YALIGN_COL, 0.25,
BACKGROUND_COL, style ? &style->bg[GTK_STATE_NORMAL] : NULL,
STYLE_COL, 1, FAVICON_COL, NULL, -1);
g_free (uri);
g_free (title);
i++;
}
searches += i;
}
if (!gtk_widget_get_visible (action->popup))
{
GtkWidget* toplevel = gtk_widget_get_toplevel (action->entry);
gtk_window_set_screen (GTK_WINDOW (action->popup),
gtk_widget_get_screen (action->entry));
gtk_window_set_transient_for (GTK_WINDOW (action->popup), GTK_WINDOW (toplevel));
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (action->treeview));
}
browser = midori_browser_get_for_widget (action->entry);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (action->treeview), 0);
gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, NULL, &height);
screen_height = gdk_screen_get_height (gtk_widget_get_screen (action->popup));
gtk_window_get_size (GTK_WINDOW (browser), NULL, &browser_height);
screen_height = MIN (MIN (browser_height, screen_height / 1.5), screen_height / 1.5);
gtk_widget_style_get (action->treeview, "vertical-separator", &sep, NULL);
/* FIXME: Instead of 1.5 we should relate to the height of one line */
height = MIN (matches * height + (matches + searches) * sep
+ searches * height / 1.5, screen_height);
gtk_widget_set_size_request (action->treeview, -1, height);
midori_location_action_popup_position (action->popup, action->entry);
gtk_widget_show_all (action->popup);
return FALSE;
}
static void
midori_location_action_popup_completion (MidoriLocationAction* action,
GtkWidget* entry,
gchar* key)
{
if (action->completion_timeout)
g_source_remove (action->completion_timeout);
katze_assign (action->key, key);
action->entry = entry;
g_signal_connect (entry, "destroy",
G_CALLBACK (gtk_widget_destroyed), &action->entry);
action->completion_timeout = g_timeout_add (COMPLETION_DELAY,
midori_location_action_popup_timeout_cb, action);
}
static void
midori_location_action_popdown_completion (MidoriLocationAction* location_action)
{
if (G_LIKELY (location_action->popup))
{
gtk_widget_hide (location_action->popup);
katze_assign (location_action->key, NULL);
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (
GTK_TREE_VIEW (location_action->treeview)));
}
if (location_action->completion_timeout)
{
g_source_remove (location_action->completion_timeout);
location_action->completion_timeout = 0;
}
location_action->completion_index = -1;
}
/* Allow this to be used in tests, it's otherwise private */
/*static*/ GtkWidget*
midori_location_action_entry_for_proxy (GtkWidget* proxy)
{
GtkWidget* alignment = gtk_bin_get_child (GTK_BIN (proxy));
GtkWidget* entry = gtk_bin_get_child (GTK_BIN (alignment));
return entry;
}
static void
midori_location_action_init (MidoriLocationAction* location_action)
{
location_action->text = location_action->uri = NULL;
location_action->search_engines = NULL;
location_action->progress = 0.0;
location_action->secondary_icon = NULL;
location_action->default_icon = NULL;
location_action->completion_timeout = 0;
location_action->completion_index = -1;
location_action->key = NULL;
location_action->popup = NULL;
location_action->entry = NULL;
location_action->history = NULL;
}
static void
midori_location_action_finalize (GObject* object)
{
MidoriLocationAction* location_action = MIDORI_LOCATION_ACTION (object);
katze_assign (location_action->text, NULL);
katze_assign (location_action->uri, NULL);
katze_assign (location_action->search_engines, NULL);
katze_assign (location_action->key, NULL);
if (location_action->popup)
{
gtk_widget_destroy (location_action->popup);
location_action->popup = NULL;
}
katze_object_assign (location_action->default_icon, NULL);
katze_object_assign (location_action->history, NULL);
G_OBJECT_CLASS (midori_location_action_parent_class)->finalize (object);
}
static void
midori_location_action_toggle_arrow_cb (GtkWidget* widget,
MidoriLocationAction* location_action)
{
gboolean show = FALSE;
gint result;
if (!GTK_IS_BUTTON (widget))
return;
if (location_action->history != NULL)
{
sqlite3* db = g_object_get_data (G_OBJECT (location_action->history), "db");
const char* sqlcmd = "SELECT uri FROM history LIMIT 1";
sqlite3_stmt* statement;
sqlite3_prepare_v2 (db, sqlcmd, -1, &statement, NULL);
result = sqlite3_step (statement);
if (result == SQLITE_ROW)
show = TRUE;
sqlite3_finalize (statement);
}
sokoke_widget_set_visible (widget, show);
gtk_widget_set_size_request (widget, show ? -1 : 1, show ? -1 : 1);
}
static void
midori_location_action_toggle_arrow (MidoriLocationAction* location_action)
{
GSList* proxies;
proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
GtkWidget* entry = midori_location_action_entry_for_proxy (proxies->data);
gtk_container_forall (GTK_CONTAINER (entry),
(GtkCallback)midori_location_action_toggle_arrow_cb, location_action);
}
}
static void
midori_location_action_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriLocationAction* location_action = MIDORI_LOCATION_ACTION (object);
switch (prop_id)
{
case PROP_PROGRESS:
midori_location_action_set_progress (location_action,
g_value_get_double (value));
break;
case PROP_SECONDARY_ICON:
midori_location_action_set_secondary_icon (location_action,
g_value_get_string (value));
break;
case PROP_HISTORY:
{
katze_assign (location_action->history, g_value_dup_object (value));
midori_location_action_toggle_arrow (location_action);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_location_action_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriLocationAction* location_action = MIDORI_LOCATION_ACTION (object);
switch (prop_id)
{
case PROP_PROGRESS:
g_value_set_double (value, location_action->progress);
break;
case PROP_SECONDARY_ICON:
g_value_set_string (value, location_action->secondary_icon);
break;
case PROP_HISTORY:
g_value_set_object (value, location_action->history);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_location_action_activate (GtkAction* action)
{
GSList* proxies;
GtkWidget* entry;
proxies = gtk_action_get_proxies (action);
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
entry = midori_location_action_entry_for_proxy (proxies->data);
/* Obviously only one widget can end up with the focus.
Yet we can't predict which one that is, can we? */
gtk_widget_grab_focus (entry);
}
if (GTK_ACTION_CLASS (midori_location_action_parent_class)->activate)
GTK_ACTION_CLASS (midori_location_action_parent_class)->activate (action);
}
static GtkWidget*
midori_location_action_create_tool_item (GtkAction* action)
{
GtkWidget* toolitem;
GtkWidget* alignment;
GtkWidget* location_entry;
GtkWidget* entry;
#if HAVE_HILDON
HildonGtkInputMode mode;
#endif
toolitem = GTK_WIDGET (gtk_tool_item_new ());
gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE);
alignment = gtk_alignment_new (0.0f, 0.5f, 1.0f, 0.1f);
gtk_widget_show (alignment);
gtk_container_add (GTK_CONTAINER (toolitem), alignment);
location_entry = gtk_combo_box_entry_new ();
gtk_widget_set_name (location_entry, "MidoriLocationEntry");
gtk_widget_show (location_entry);
gtk_container_add (GTK_CONTAINER (alignment), location_entry);
#if HAVE_HILDON
entry = gtk_entry_new ();
mode = hildon_gtk_entry_get_input_mode (GTK_ENTRY (entry));
mode &= ~HILDON_GTK_INPUT_MODE_AUTOCAP;
hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry), mode);
#else
entry = gtk_icon_entry_new ();
gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, GTK_STOCK_FILE);
gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_SECONDARY, TRUE);
#endif
gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (location_entry), entry);
return toolitem;
}
static void
midori_location_action_changed_cb (GtkEntry* entry,
MidoriLocationAction* location_action)
{
katze_assign (location_action->text, g_strdup (gtk_entry_get_text (entry)));
}
static void
midori_location_action_move_cursor_cb (GtkEntry* entry,
GtkMovementStep step,
gint count,
gboolean extend_selection,
MidoriLocationAction* action)
{
gchar* text = g_strdup (pango_layout_get_text (gtk_entry_get_layout (entry)));
/* Update entry with the completed text */
gtk_entry_set_text (entry, text);
g_free (text);
midori_location_action_popdown_completion (action);
}
static void
midori_location_action_backspace_cb (GtkWidget* entry,
MidoriLocationAction* action)
{
gchar* key = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
midori_location_action_popup_completion (action, entry, key);
action->completion_index = -1;
}
static void
midori_location_action_paste_clipboard_cb (GtkWidget* entry,
MidoriLocationAction* action)
{
gchar* key = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
midori_location_action_popup_completion (action, entry, key);
action->completion_index = -1;
}
static gboolean
midori_location_action_button_press_event_cb (GtkEntry* entry,
GdkEventKey* event,
MidoriLocationAction* action)
{
if (action->popup && gtk_widget_get_visible (action->popup))
{
midori_location_action_popdown_completion (action);
/* Allow button handling, for context menu and selection */
return FALSE;
}
return FALSE;
}
static gboolean
midori_location_action_key_press_event_cb (GtkEntry* entry,
GdkEventKey* event,
GtkAction* action)
{
GtkWidget* widget = GTK_WIDGET (entry);
MidoriLocationAction* location_action = MIDORI_LOCATION_ACTION (action);
const gchar* text;
gboolean is_enter = FALSE;
switch (event->keyval)
{
case GDK_ISO_Enter:
case GDK_KP_Enter:
case GDK_Return:
is_enter = TRUE;
case GDK_Left:
case GDK_KP_Left:
case GDK_Right:
case GDK_KP_Right:
if (location_action->popup && gtk_widget_get_visible (location_action->popup))
{
GtkTreeModel* model = location_action->completion_model;
GtkTreeIter iter;
gint selected = location_action->completion_index;
midori_location_action_popdown_completion (location_action);
if (selected > -1 &&
gtk_tree_model_iter_nth_child (model, &iter, NULL, selected))
{
gchar* uri;
gtk_tree_model_get (model, &iter, URI_COL, &uri, -1);
gtk_entry_set_text (entry, uri);
if (is_enter)
g_signal_emit (action, signals[SUBMIT_URI], 0, uri,
MIDORI_MOD_NEW_TAB (event->state));
g_free (uri);
return TRUE;
}
}
if (is_enter)
if ((text = gtk_entry_get_text (entry)) && *text)
g_signal_emit (action, signals[SUBMIT_URI], 0, text,
MIDORI_MOD_NEW_TAB (event->state));
break;
case GDK_Escape:
{
if (location_action->popup && gtk_widget_get_visible (location_action->popup))
{
midori_location_action_popdown_completion (location_action);
text = gtk_entry_get_text (entry);
pango_layout_set_text (gtk_entry_get_layout (entry), text, -1);
return TRUE;
}
g_signal_emit (action, signals[RESET_URI], 0);
/* Return FALSE to allow Escape to stop loading */
return FALSE;
}
case GDK_Page_Up:
case GDK_Page_Down:
if (!(location_action->popup && gtk_widget_get_visible (location_action->popup)))
return TRUE;
case GDK_Delete:
case GDK_KP_Delete:
{
gint selected = location_action->completion_index;
GtkTreeModel* model = location_action->completion_model;
GtkTreeIter iter;
if (selected > -1 &&
gtk_tree_model_iter_nth_child (model, &iter, NULL, selected))
{
gchar* uri;
gchar* sqlcmd;
sqlite3* db;
gchar* errmsg;
gint result;
gtk_tree_model_get (model, &iter, URI_COL, &uri, -1);
sqlcmd = sqlite3_mprintf ("DELETE FROM history "
"WHERE uri = '%q'", uri);
g_free (uri);
db = g_object_get_data (G_OBJECT (location_action->history), "db");
result = sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg);
sqlite3_free (sqlcmd);
if (result == SQLITE_ERROR)
{
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
URI_COL, errmsg, -1);
sqlite3_free (errmsg);
break;
}
if (result != SQLITE_OK || sqlite3_changes (db) == 0)
break;
if (!gtk_list_store_remove (GTK_LIST_STORE (model), &iter))
{
midori_location_action_popdown_completion (location_action);
break;
}
/* Fall through to advance the selection */
}
else
break;
}
case GDK_Down:
case GDK_KP_Down:
case GDK_Up:
case GDK_KP_Up:
{
GtkWidget* parent;
if (location_action->popup && gtk_widget_get_visible (location_action->popup))
{
GtkTreeModel* model = location_action->completion_model;
gint matches = gtk_tree_model_iter_n_children (model, NULL);
GtkTreePath* path;
GtkTreeIter iter;
gint selected = location_action->completion_index;
if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
selected = MIN (selected + 1, matches -1);
else if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
{
if (selected == -1)
selected = matches - 1;
else
selected = MAX (selected - 1, 0);
}
else if (event->keyval == GDK_Page_Down)
selected = MIN (selected + 14, matches -1);
else if (event->keyval == GDK_Page_Up)
selected = MAX (selected - 14, 0);
path = gtk_tree_path_new_from_indices (selected, -1);
gtk_tree_view_set_cursor (GTK_TREE_VIEW (location_action->treeview),
path, NULL, FALSE);
gtk_tree_path_free (path);
if (gtk_tree_model_iter_nth_child (model, &iter, NULL, selected))
{
gchar* uri;
gtk_tree_model_get (model, &iter, URI_COL, &uri, -1);
/* Update the layout without actually changing the text */
pango_layout_set_text (gtk_entry_get_layout (entry), uri, -1);
g_free (uri);
}
location_action->completion_index = selected;
return TRUE;
}
parent = gtk_widget_get_parent (widget);
if (location_action->history != NULL
&& !katze_object_get_boolean (parent, "popup-shown"))
gtk_combo_box_popup (GTK_COMBO_BOX (parent));
return TRUE;
}
default:
{
gunichar character;
gchar buffer[7];
gint length;
gchar* key;
character = gdk_keyval_to_unicode (event->keyval);
/* Don't trigger completion on control characters */
if (!character || event->is_modifier)
return FALSE;
length = g_unichar_to_utf8 (character, buffer);
buffer[length] = '\0';
key = g_strconcat (gtk_entry_get_text (entry), buffer, NULL);
midori_location_action_popup_completion (location_action, widget, key);
location_action->completion_index = -1;
return FALSE;
}
}
return FALSE;
}
#if GTK_CHECK_VERSION (2, 19, 3)
static void
midori_location_action_preedit_changed_cb (GtkWidget* entry,
const gchar* preedit,
GtkAction* action)
{
MidoriLocationAction* location_action = MIDORI_LOCATION_ACTION (action);
gchar* key = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
midori_location_action_popup_completion (location_action, entry, key);
}
#endif
static gboolean
midori_location_action_focus_in_event_cb (GtkWidget* widget,
GdkEventKey* event,
GtkAction* action)
{
g_signal_emit (action, signals[FOCUS_IN], 0);
return FALSE;
}
static gboolean
midori_location_action_focus_out_event_cb (GtkWidget* widget,
GdkEventKey* event,
GtkAction* action)
{
midori_location_action_popdown_completion (MIDORI_LOCATION_ACTION (action));
g_signal_emit (action, signals[FOCUS_OUT], 0);
return FALSE;
}
static void
midori_location_action_icon_released_cb (GtkWidget* widget,
GtkIconEntryPosition icon_pos,
gint button,
GtkAction* action)
{
if (icon_pos == GTK_ICON_ENTRY_SECONDARY)
{
gboolean result;
g_signal_emit (action, signals[SECONDARY_ICON_RELEASED], 0,
widget, &result);
}
}
static void
midori_location_entry_render_text_cb (GtkCellLayout* layout,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
gpointer data)
{
MidoriLocationAction* action = data;
gchar* uri_escaped;
gchar* uri;
gchar* title;
gboolean style;
gchar* desc;
gchar* desc_uri;
gchar* desc_iter;
gchar* temp_iter;
gchar* desc_title;
const gchar* str;
gchar* key;
gchar** keys;
gint key_idx;
gchar* start;
gchar* skey;
gchar* temp;
gchar* temp_concat;
gchar* temp_markup;
gchar** parts;
size_t offset;
gtk_tree_model_get (model, iter, URI_COL, &uri_escaped, TITLE_COL, &title,
STYLE_COL, &style, -1);
if (style) /* A search engine action */
{
g_object_set (renderer, "text", title,
"ellipsize-set", TRUE, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
g_free (uri_escaped);
g_free (title);
return;
}
desc = desc_uri = desc_title = key = NULL;
if (action->key)
str = action->key;
else
str = "";
key = g_utf8_strdown (str, -1);
keys = g_strsplit_set (key, " %", -1);
g_free (key);
uri = sokoke_uri_unescape_string (uri_escaped);
g_free (uri_escaped);
if (G_LIKELY (uri))
{
temp_iter = temp = g_utf8_strdown (uri, -1);
desc_iter = uri;
key_idx = 0;
key = keys[key_idx];
offset = 0;
while (key && (start = strstr (temp_iter, key)) && start)
{
gsize len = strlen (key);
if (len)
{
offset = (start - temp_iter);
skey = g_strndup (desc_iter + offset, len);
parts = g_strsplit (desc_iter, skey, 2);
if (parts[0] && parts[1])
{
if (desc_uri)
{
temp_markup = g_markup_printf_escaped ("%s<b>%s</b>",
parts[0], skey);
temp_concat = g_strconcat (desc_uri, temp_markup, NULL);
g_free (temp_markup);
katze_assign (desc_uri, temp_concat);
}
else
{
desc_uri = g_markup_printf_escaped ("%s<b>%s</b>",
parts[0], skey);
}
}
g_strfreev (parts);
g_free (skey);
offset += len;
temp_iter += offset;
desc_iter += offset;
}
key_idx++;
key = keys[key_idx];
if (key == NULL)
break;
}
if (key)
katze_assign (desc_uri, NULL);
if (desc_uri)
{
temp_markup = g_markup_escape_text (desc_iter, -1);
temp_concat = g_strconcat (desc_uri, temp_markup, NULL);
g_free (temp_markup);
katze_assign (desc_uri, temp_concat);
}
else
desc_uri = g_markup_escape_text (uri, -1);
g_free (temp);
}
if (G_LIKELY (title))
{
temp_iter = temp = g_utf8_strdown (title, -1);
desc_iter = title;
key_idx = 0;
key = keys[key_idx];
offset = 0;
while (key && (start = strstr (temp_iter, key)) && start)
{
gsize len = strlen (key);
if (len)
{
offset = (start - temp_iter);
skey = g_strndup (desc_iter + offset, len);
parts = g_strsplit (desc_iter, skey, 2);
if (parts[0] && parts[1])
{
if (desc_title)
{
temp_markup = g_markup_printf_escaped ("%s<b>%s</b>",
parts[0], skey);
temp_concat = g_strconcat (desc_title, temp_markup, NULL);
g_free (temp_markup);
katze_assign (desc_title, temp_concat);
}
else
{
desc_title = g_markup_printf_escaped ("%s<b>%s</b>",
parts[0], skey);
}
}
g_strfreev (parts);
g_free (skey);
offset += len;
temp_iter += offset;
desc_iter += offset;
}
key_idx++;
key = keys[key_idx];
if (key == NULL)
break;
}
if (key)
katze_assign (desc_title, NULL);
if (desc_title)
{
temp_markup = g_markup_escape_text (desc_iter, -1);
temp_concat = g_strconcat (desc_title, temp_markup, NULL);
g_free (temp_markup);
katze_assign (desc_title, temp_concat);
}
else
desc_title = g_markup_escape_text (title, -1);
g_free (temp);
}
if (desc_title)
{
desc = g_strdup_printf ("%s\n<span color='gray45'>%s</span>",
desc_title, desc_uri);
g_free (desc_uri);
g_free (desc_title);
}
else
desc = desc_uri;
g_object_set (renderer, "markup", desc,
"ellipsize-set", TRUE, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
g_free (uri);
g_free (title);
g_strfreev (keys);
g_free (desc);
}
static void
midori_location_action_entry_changed_cb (GtkComboBox* combo_box,
MidoriLocationAction* location_action)
{
GtkTreeIter iter;
if (gtk_combo_box_get_active_iter (combo_box, &iter))
{
GtkIconEntry* entry;
if ((entry = GTK_ICON_ENTRY (gtk_bin_get_child (GTK_BIN (combo_box)))))
{
GtkTreeModel* model;
gchar* uri;
#if !HAVE_HILDON
GdkPixbuf* pixbuf;
#endif
model = gtk_combo_box_get_model (combo_box);
gtk_tree_model_get (model, &iter, URI_COL, &uri, -1);
#if !HAVE_HILDON
gtk_tree_model_get (model, &iter, FAVICON_COL, &pixbuf, -1);
gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, pixbuf);
g_object_unref (pixbuf);
#endif
katze_assign (location_action->text, uri);
katze_assign (location_action->uri, g_strdup (uri));
g_signal_emit (location_action, signals[ACTIVE_CHANGED], 0,
gtk_combo_box_get_active (combo_box));
}
}
}
static void
midori_location_action_entry_popup_cb (GtkComboBox* combo_box,
MidoriLocationAction* location_action)
{
GtkListStore* store;
gint result;
const gchar* sqlcmd;
static sqlite3_stmt* stmt = NULL;
gint matches;
store = GTK_LIST_STORE (gtk_combo_box_get_model (combo_box));
gtk_list_store_clear (store);
if (!stmt)
{
sqlite3* db;
g_return_if_fail (location_action->history != NULL);
db = g_object_get_data (G_OBJECT (location_action->history), "db");
g_return_if_fail (db != NULL);
sqlcmd = "SELECT uri, title FROM history"
" GROUP BY uri ORDER BY count() DESC LIMIT ?";
sqlite3_prepare_v2 (db, sqlcmd, -1, &stmt, NULL);
}
sqlite3_bind_int64 (stmt, 1, MAX_ITEMS);
result = sqlite3_step (stmt);
if (result != SQLITE_ROW)
{
g_print (_("Failed to execute database statement\n"));
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
return;
}
matches = 0;
do
{
const unsigned char* uri = sqlite3_column_text (stmt, 0);
const unsigned char* title = sqlite3_column_text (stmt, 1);
GdkPixbuf* icon = katze_load_cached_icon ((gchar*)uri, NULL);
if (!icon)
icon = location_action->default_icon;
gtk_list_store_insert_with_values (store, NULL, matches,
URI_COL, uri, TITLE_COL, title, YALIGN_COL, 0.25,
FAVICON_COL, icon, -1);
matches++;
result = sqlite3_step (stmt);
}
while (result == SQLITE_ROW);
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
}
static void
midori_location_action_paste_proceed_cb (GtkWidget* menuitem,
GtkWidget* location_action)
{
GtkClipboard* clipboard = gtk_clipboard_get_for_display (
gtk_widget_get_display (GTK_WIDGET (menuitem)),GDK_SELECTION_CLIPBOARD);
gchar* uri;
if ((uri = gtk_clipboard_wait_for_text (clipboard)))
{
g_signal_emit (location_action, signals[SUBMIT_URI], 0, uri, FALSE);
g_free (uri);
}
}
static void
midori_location_action_populate_popup_cb (GtkWidget* entry,
GtkMenuShell* menu,
MidoriLocationAction* location_action)
{
MidoriBrowser* browser = midori_browser_get_for_widget (entry);
GtkActionGroup* actions = midori_browser_get_action_group (browser);
GtkWidget* menuitem;
menuitem = gtk_separator_menu_item_new ();
gtk_widget_show (menuitem);
gtk_menu_shell_append (menu, menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "ManageSearchEngines"));
gtk_menu_shell_append (menu, menuitem);
/* i18n: Right-click on Location, Open an URL from the clipboard */
menuitem = gtk_menu_item_new_with_mnemonic (_("Paste and p_roceed"));
gtk_widget_show (menuitem);
gtk_menu_shell_append (menu, menuitem);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_location_action_paste_proceed_cb), location_action);
}
static void
midori_location_action_connect_proxy (GtkAction* action,
GtkWidget* proxy)
{
MidoriLocationAction* location_action;
GtkCellRenderer* renderer;
GTK_ACTION_CLASS (midori_location_action_parent_class)->connect_proxy (
action, proxy);
location_action = MIDORI_LOCATION_ACTION (action);
katze_object_assign (location_action->default_icon,
gtk_widget_render_icon (proxy, GTK_STOCK_FILE,
GTK_ICON_SIZE_MENU, NULL));
if (GTK_IS_TOOL_ITEM (proxy))
{
GtkWidget* entry = midori_location_action_entry_for_proxy (proxy);
GtkWidget* child = gtk_bin_get_child (GTK_BIN (entry));
GtkTreeModel* model = midori_location_action_create_model ();
gtk_icon_entry_set_progress_fraction (GTK_ICON_ENTRY (child),
MIDORI_LOCATION_ACTION (action)->progress);
gtk_combo_box_set_model (GTK_COMBO_BOX (entry), model);
#if GTK_CHECK_VERSION (2, 14, 0)
gtk_combo_box_set_button_sensitivity (GTK_COMBO_BOX (entry),
GTK_SENSITIVITY_ON);
#endif
gtk_combo_box_entry_set_text_column (
GTK_COMBO_BOX_ENTRY (entry), URI_COL);
gtk_cell_layout_clear (GTK_CELL_LAYOUT (entry));
/* Setup the renderer for the favicon */
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, FALSE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (entry), renderer,
"pixbuf", FAVICON_COL, "yalign", YALIGN_COL, NULL);
renderer = gtk_cell_renderer_text_new ();
g_object_set_data (G_OBJECT (renderer), "location-action", action);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, TRUE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
renderer, midori_location_entry_render_text_cb, action, NULL);
gtk_combo_box_set_active (GTK_COMBO_BOX (entry), -1);
gtk_container_forall (GTK_CONTAINER (entry),
(GtkCallback)midori_location_action_toggle_arrow_cb, action);
g_signal_connect (entry, "changed",
G_CALLBACK (midori_location_action_entry_changed_cb), action);
g_signal_connect (entry, "popup",
G_CALLBACK (midori_location_action_entry_popup_cb), action);
g_object_connect (child,
"signal::changed",
midori_location_action_changed_cb, action,
"signal::move-cursor",
midori_location_action_move_cursor_cb, action,
"signal-after::backspace",
midori_location_action_backspace_cb, action,
"signal-after::paste-clipboard",
midori_location_action_paste_clipboard_cb, action,
"signal::button-press-event",
midori_location_action_button_press_event_cb, action,
"signal::key-press-event",
midori_location_action_key_press_event_cb, action,
#if GTK_CHECK_VERSION (2, 19, 3)
"signal-after::preedit-changed",
midori_location_action_preedit_changed_cb, action,
#endif
"signal::focus-in-event",
midori_location_action_focus_in_event_cb, action,
"signal::focus-out-event",
midori_location_action_focus_out_event_cb, action,
"signal::icon-release",
midori_location_action_icon_released_cb, action,
"signal::populate-popup",
midori_location_action_populate_popup_cb, action,
NULL);
}
}
static void
midori_location_action_disconnect_proxy (GtkAction* action,
GtkWidget* proxy)
{
/* FIXME: This is wrong */
g_signal_handlers_disconnect_by_func (proxy,
G_CALLBACK (gtk_action_activate), action);
GTK_ACTION_CLASS (midori_location_action_parent_class)->disconnect_proxy
(action, proxy);
}
/**
* midori_location_action_get_uri:
* @location_action: a #MidoriLocationAction
*
* Retrieves the current URI. See also midori_location_action_get_text().
*
* Return value: the current URI
**/
const gchar*
midori_location_action_get_uri (MidoriLocationAction* location_action)
{
g_return_val_if_fail (MIDORI_IS_LOCATION_ACTION (location_action), NULL);
return location_action->uri;
}
/**
* midori_location_action_get_text:
* @location_action: a #MidoriLocationAction
*
* Retrieves the current text, which may be the current URI or
* anything typed in the entry.
*
* Return value: the current text
*
* Since: 0.2.0
**/
const gchar*
midori_location_action_get_text (MidoriLocationAction* location_action)
{
g_return_val_if_fail (MIDORI_IS_LOCATION_ACTION (location_action), NULL);
return location_action->text;
}
/**
* midori_location_action_set_text:
* @location_action: a #MidoriLocationAction
* @text: a string
*
* Sets the entry text to @text and, if applicable, updates the icon.
*
* Since: 0.2.0
**/
void
midori_location_action_set_text (MidoriLocationAction* location_action,
const gchar* text)
{
GSList* proxies;
GtkWidget* location_entry;
GtkWidget* entry;
GdkPixbuf* icon;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (text != NULL);
midori_location_action_popdown_completion (location_action);
katze_assign (location_action->text, g_strdup (text));
katze_assign (location_action->uri, g_strdup (text));
if (!(proxies = gtk_action_get_proxies (GTK_ACTION (location_action))))
return;
if (!(icon = katze_load_cached_icon (location_action->uri, NULL)))
icon = g_object_ref (location_action->default_icon);
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
location_entry = midori_location_action_entry_for_proxy (proxies->data);
entry = gtk_bin_get_child (GTK_BIN (location_entry));
gtk_entry_set_text (GTK_ENTRY (entry), text);
#if !HAVE_HILDON
gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, icon);
#endif
}
g_object_unref (icon);
}
/**
* midori_location_action_set_icon:
* @location_action: a #MidoriLocationAction
* @icon: a #GdkPixbuf or %NULL
*
* Sets the icon shown on the left hand side.
*
* Note: Since 0.1.8 %NULL can be passed to indicate that the
* visible URI refers to a target, not the current location.
**/
void
midori_location_action_set_icon (MidoriLocationAction* location_action,
GdkPixbuf* icon)
{
#if !HAVE_HILDON
GSList* proxies;
GtkWidget* location_entry;
GtkWidget* entry;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (!icon || GDK_IS_PIXBUF (icon));
proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
location_entry = midori_location_action_entry_for_proxy (proxies->data);
entry = gtk_bin_get_child (GTK_BIN (location_entry));
if (icon)
gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, icon);
else
gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, GTK_STOCK_JUMP_TO);
}
#endif
}
void
midori_location_action_add_uri (MidoriLocationAction* location_action,
const gchar* uri)
{
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (uri != NULL);
katze_assign (location_action->uri, g_strdup (uri));
midori_location_action_toggle_arrow (location_action);
}
void
midori_location_action_add_item (MidoriLocationAction* location_action,
const gchar* uri,
GdkPixbuf* icon,
const gchar* title)
{
#if !HAVE_HILDON
GSList* proxies;
GtkWidget* location_entry;
GtkWidget* entry;
#endif
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (uri != NULL);
g_return_if_fail (title != NULL);
g_return_if_fail (!icon || GDK_IS_PIXBUF (icon));
#if !HAVE_HILDON
proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
location_entry = midori_location_action_entry_for_proxy (proxies->data);
entry = gtk_bin_get_child (GTK_BIN (location_entry));
gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, icon);
}
#endif
}
void
midori_location_action_set_icon_for_uri (MidoriLocationAction* location_action,
GdkPixbuf* icon,
const gchar* uri)
{
#if !HAVE_HILDON
GSList* proxies;
GtkWidget* location_entry;
GtkWidget* entry;
#endif
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (!icon || GDK_IS_PIXBUF (icon));
g_return_if_fail (uri != NULL);
#if !HAVE_HILDON
proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
location_entry = midori_location_action_entry_for_proxy (proxies->data);
entry = gtk_bin_get_child (GTK_BIN (location_entry));
gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, icon);
}
#endif
}
void
midori_location_action_set_title_for_uri (MidoriLocationAction* location_action,
const gchar* title,
const gchar* uri)
{
/* Nothing to do */
}
/**
* midori_location_action_set_search_engines:
* @location_action: a #MidoriLocationAction
* @search_engines: a #KatzeArray
*
* Assigns the specified search engines to the location action.
* Search engines will appear as actions in the completion.
*
* Since: 0.1.6
**/
void
midori_location_action_set_search_engines (MidoriLocationAction* location_action,
KatzeArray* search_engines)
{
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
if (search_engines)
g_object_ref (search_engines);
katze_object_assign (location_action->search_engines, search_engines);
}
gdouble
midori_location_action_get_progress (MidoriLocationAction* location_action)
{
g_return_val_if_fail (MIDORI_IS_LOCATION_ACTION (location_action), 0.0);
return location_action->progress;
}
void
midori_location_action_set_progress (MidoriLocationAction* location_action,
gdouble progress)
{
GSList* proxies;
GtkWidget* entry;
GtkWidget* child;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
location_action->progress = CLAMP (progress, 0.0, 1.0);
proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
entry = midori_location_action_entry_for_proxy (proxies->data);
child = gtk_bin_get_child (GTK_BIN (entry));
gtk_icon_entry_set_progress_fraction (GTK_ICON_ENTRY (child),
location_action->progress);
}
}
void
midori_location_action_set_secondary_icon (MidoriLocationAction* location_action,
const gchar* stock_id)
{
#if !HAVE_HILDON
GSList* proxies;
GtkWidget* entry;
GtkWidget* child;
#endif
GtkStockItem stock_item;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (!stock_id || gtk_stock_lookup (stock_id, &stock_item));
katze_assign (location_action->secondary_icon, g_strdup (stock_id));
#if !HAVE_HILDON
proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
entry = midori_location_action_entry_for_proxy (proxies->data);
child = gtk_bin_get_child (GTK_BIN (entry));
gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (child),
GTK_ICON_ENTRY_SECONDARY, stock_id);
}
#endif
}
/**
* midori_location_action_delete_item_from_uri:
* @location_action: a #MidoriLocationAction
* @uri: a string
*
* Finds the item from the list matching @uri
* and removes it if it is the last instance.
**/
void
midori_location_action_delete_item_from_uri (MidoriLocationAction* location_action,
const gchar* uri)
{
/* Nothing to do */
}
void
midori_location_action_clear (MidoriLocationAction* location_action)
{
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
midori_location_action_toggle_arrow (location_action);
}
/**
* midori_location_action_set_security_hint:
* @location_action: a #MidoriLocationAction
* @hint: a security hint
*
* Sets a security hint on the action, so that the security status
* can be reflected visually.
*
* Since: 0.2.5
**/
void
midori_location_action_set_security_hint (MidoriLocationAction* location_action,
MidoriSecurity hint)
{
GSList* proxies;
GtkWidget* entry;
GtkWidget* child;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
for (; proxies != NULL; proxies = g_slist_next (proxies))
if (GTK_IS_TOOL_ITEM (proxies->data))
{
GdkColor bg_color = { 0, 1 };
GdkColor fg_color = { 0, 1 };
entry = midori_location_action_entry_for_proxy (proxies->data);
child = gtk_bin_get_child (GTK_BIN (entry));
if (hint == MIDORI_SECURITY_UNKNOWN)
{
gdk_color_parse ("#ef7070", &bg_color);
gdk_color_parse ("#000", &fg_color);
#if !HAVE_HILDON
gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (child),
GTK_ICON_ENTRY_SECONDARY, GTK_STOCK_INFO);
#endif
}
else if (hint == MIDORI_SECURITY_TRUSTED)
{
gdk_color_parse ("#fcf19a", &bg_color);
gdk_color_parse ("#000", &fg_color);
#if !HAVE_HILDON
gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (child),
GTK_ICON_ENTRY_SECONDARY, GTK_STOCK_DIALOG_AUTHENTICATION);
#endif
}
gtk_widget_modify_base (child, GTK_STATE_NORMAL,
bg_color.red == 1 ? NULL : &bg_color);
gtk_widget_modify_text (child, GTK_STATE_NORMAL,
bg_color.red == 1 ? NULL : &fg_color);
}
}