midori/midori/midori-view.c
Christian Dywan 95111a054c Reimplement missing preferences
Implement font properties, web features,
Middle click opens selection,
Open tabs in the background and proxy.

While we are at it, remove Tab label size.
2008-10-03 00:49:16 +02:00

2860 lines
89 KiB
C

/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
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.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "midori-view.h"
#include "midori-source.h"
#include "midori-stock.h"
#include "compat.h"
#include "sokoke.h"
#include "gjs.h"
#include <string.h>
#include <stdlib.h>
#if HAVE_GIO
#include <gio/gio.h>
#endif
#include <glib/gi18n.h>
#include <webkit/webkit.h>
/* This is unstable API, so we need to declare it */
gchar*
webkit_web_view_get_selected_text (WebKitWebView* web_view);
struct _MidoriView
{
GtkScrolledWindow parent_instance;
gint socket_id;
GIOChannel* input;
FILE* output;
gchar* command_cache;
gchar* premature_uri;
gchar* uri;
gchar* title;
GdkPixbuf* icon;
gdouble progress;
MidoriLoadStatus load_status;
gchar* statusbar_text;
gchar* link_uri;
gboolean has_selection;
gchar* selected_text;
gboolean can_cut_clipboard;
gboolean can_copy_clipboard;
gboolean can_paste_clipboard;
gfloat zoom_level;
gboolean can_go_back;
gboolean can_go_forward;
MidoriWebSettings* settings;
GtkWidget* web_view;
gboolean window_object_cleared;
gchar* download_manager;
gchar* default_font_family;
gint default_font_size;
gint minimum_font_size;
gchar* default_encoding;
gboolean auto_load_images;
gboolean auto_shrink_images;
gboolean print_backgrounds;
gboolean resizable_text_areas;
gboolean enable_scripts;
gboolean enable_plugins;
gboolean middle_click_opens_selection;
gboolean open_tabs_in_the_background;
gboolean close_buttons_on_tabs;
gchar* http_proxy;
GtkWidget* menu_item;
GtkWidget* tab_label;
GtkWidget* tab_icon;
GtkWidget* tab_title;
GtkWidget* tab_close;
KatzeItem* item;
};
struct _MidoriViewClass
{
GtkScrolledWindowClass parent_class;
};
G_DEFINE_TYPE (MidoriView, midori_view, GTK_TYPE_SCROLLED_WINDOW)
GType
midori_load_status_get_type (void)
{
static GType type = 0;
if (type)
return type;
static const GEnumValue values[] = {
{ MIDORI_LOAD_PROVISIONAL, "MIDORI_LOAD_PROVISIONAL", N_("Load Provisional") },
{ MIDORI_LOAD_COMMITTED, "MIDORI_LOAD_COMMITTED", N_("Load Committed") },
{ MIDORI_LOAD_FINISHED, "MIDORI_LOAD_FINISHED", N_("Load Finished") },
{ 0, NULL, NULL }
};
type = g_enum_register_static ("MidoriLoadStatus", values);
return type;
}
enum
{
PROP_0,
PROP_SOCKET_ID,
PROP_URI,
PROP_TITLE,
PROP_ICON,
PROP_LOAD_STATUS,
PROP_PROGRESS,
PROP_ZOOM_LEVEL,
PROP_STATUSBAR_TEXT,
PROP_SETTINGS
};
enum {
ACTIVATE_ACTION,
CONSOLE_MESSAGE,
NEW_TAB,
NEW_WINDOW,
SEARCH_TEXT,
ADD_BOOKMARK,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void
midori_view_finalize (GObject* object);
static void
midori_view_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_view_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static void
midori_cclosure_marshal_VOID__STRING_BOOLEAN (GClosure* closure,
GValue* return_value,
guint n_param_values,
const GValue* param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
typedef void(*GMarshalFunc_VOID__STRING_BOOLEAN) (gpointer data1,
gpointer arg_1,
gboolean arg_2,
gpointer data2);
register GMarshalFunc_VOID__STRING_BOOLEAN callback;
register GCClosure* cc = (GCClosure*) closure;
register gpointer data1, data2;
g_return_if_fail (n_param_values == 3);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_VOID__STRING_BOOLEAN) (marshal_data
? marshal_data : cc->callback);
callback (data1,
(gchar*)g_value_get_string (param_values + 1),
g_value_get_boolean (param_values + 2),
data2);
}
static void
midori_cclosure_marshal_VOID__STRING_INT_STRING (GClosure* closure,
GValue* return_value,
guint n_param_values,
const GValue* param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
typedef void(*GMarshalFunc_VOID__STRING_INT_STRING) (gpointer data1,
gpointer arg_1,
gint arg_2,
gpointer arg_3,
gpointer data2);
register GMarshalFunc_VOID__STRING_INT_STRING callback;
register GCClosure* cc = (GCClosure*) closure;
register gpointer data1, data2;
g_return_if_fail (n_param_values == 4);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_VOID__STRING_INT_STRING) (marshal_data
? marshal_data : cc->callback);
callback (data1,
(gchar*)g_value_get_string (param_values + 1),
g_value_get_int (param_values + 2),
(gchar*)g_value_get_string (param_values + 3),
data2);
}
static void
midori_view_class_init (MidoriViewClass* class)
{
GObjectClass* gobject_class;
GParamFlags flags;
signals[ACTIVATE_ACTION] = g_signal_new (
"activate-action",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
0,
0,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
signals[CONSOLE_MESSAGE] = g_signal_new (
"console-message",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
0,
0,
NULL,
midori_cclosure_marshal_VOID__STRING_INT_STRING,
G_TYPE_NONE, 3,
G_TYPE_STRING,
G_TYPE_INT,
G_TYPE_STRING);
signals[NEW_TAB] = g_signal_new (
"new-tab",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
0,
0,
NULL,
midori_cclosure_marshal_VOID__STRING_BOOLEAN,
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_BOOLEAN);
signals[NEW_WINDOW] = g_signal_new (
"new-window",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
0,
0,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
signals[SEARCH_TEXT] = g_signal_new (
"search-text",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__BOOLEAN,
G_TYPE_NONE, 1,
G_TYPE_BOOLEAN);
signals[ADD_BOOKMARK] = g_signal_new (
"add-bookmark",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
0,
0,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_view_finalize;
gobject_class->set_property = midori_view_set_property;
gobject_class->get_property = midori_view_get_property;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
g_object_class_install_property (gobject_class,
PROP_SOCKET_ID,
g_param_spec_uint (
"socket-id",
_("Socket ID"),
_("The ID of a socket"),
0,
G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_URI,
g_param_spec_string (
"uri",
_("Uri"),
_("The URI of the currently loaded page"),
"about:blank",
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_TITLE,
g_param_spec_string (
"title",
_("Title"),
_("The title of the currently loaded page"),
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ICON,
g_param_spec_object (
"icon",
_("Icon"),
_("The icon of the view"),
GDK_TYPE_PIXBUF,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_LOAD_STATUS,
g_param_spec_enum (
"load-status",
_("Load Status"),
_("The current loading status"),
MIDORI_TYPE_LOAD_STATUS,
MIDORI_LOAD_FINISHED,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_PROGRESS,
g_param_spec_double (
"progress",
_("Progress"),
_("The current loading progress"),
0.0, 1.0, 0.0,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_ZOOM_LEVEL,
g_param_spec_float (
"zoom-level",
_("Zoom Level"),
_("The current zoom level"),
G_MINFLOAT,
G_MAXFLOAT,
1.0f,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_STATUSBAR_TEXT,
g_param_spec_string (
"statusbar-text",
_("Statusbar Text"),
_("The text displayed in the statusbar"),
"",
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_SETTINGS,
g_param_spec_object (
"settings",
_("Settings"),
_("The associated settings"),
MIDORI_TYPE_WEB_SETTINGS,
G_PARAM_READWRITE));
}
#define midori_view_is_socket(view) !view->socket_id
#define midori_view_is_plug(view) view->socket_id > 0
#if 0
#define midori_debug g_debug
#else
#define midori_debug(...) ;
#endif
/**
* int_to_str
* @in: an integer
*
* Converts an integer to a string.
*
* The returned string is valid until
* the next call to this function.
*
* Return value: a string
**/
static const gchar*
int_to_str (gint in)
{
static gchar* out = NULL;
g_free (out);
out = g_strdup_printf ("%d", in);
return out;
}
/**
* float_to_str
* @in: a float
*
* Converts a float to a string.
*
* The returned string is valid until
* the next call to this function.
*
* Return value: a string
**/
static const gchar*
float_to_str (gfloat in)
{
static gchar* out = NULL;
g_free (out);
out = g_strdup_printf ("%f", in);
return out;
}
static void
send_command (MidoriView* view,
const gchar* command,
const gchar* argument)
{
gchar* data;
gchar* cache;
if (argument)
data = g_strdup_printf ("%s %s", command, argument);
else
data = g_strdup (command);
if (!view->output)
{
/* The output is not ready, so we cache for now */
cache = g_strdup_printf ("%s\n%s",
view->command_cache ? view->command_cache : "", data);
katze_assign (view->command_cache, cache);
midori_debug ("!view->output, caching command: %s", command);
return;
}
fwrite (data, strlen (data) + 1, 1, view->output);
fflush (view->output);
g_free (data);
}
static void
midori_view_notify_uri_cb (MidoriView* view,
GParamSpec pspec)
{
if (midori_view_is_socket (view) && view->item)
katze_item_set_uri (view->item, view->uri);
if (midori_view_is_plug (view))
/* We must not send a NULL string here */
send_command (view, "uri", view->uri ? view->uri : "");
}
static void
midori_view_notify_icon_cb (MidoriView* view,
GParamSpec pspec)
{
if (view->tab_icon)
katze_throbber_set_static_pixbuf (KATZE_THROBBER (view->tab_icon),
view->icon);
if (view->menu_item)
gtk_image_menu_item_set_image (
GTK_IMAGE_MENU_ITEM (view->menu_item),
gtk_image_new_from_pixbuf (view->icon));
}
#if HAVE_GIO
void
loadable_icon_finish_cb (GdkPixbuf* icon,
GAsyncResult* res,
MidoriView* view)
{
GdkPixbuf* pixbuf;
GInputStream* stream;
GError* error;
GdkPixbuf* pixbuf_scaled;
gint icon_width, icon_height;
pixbuf = NULL;
stream = g_loadable_icon_load_finish (G_LOADABLE_ICON (icon),
res, NULL, NULL);
if (stream)
{
error = NULL;
pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &error);
if (error)
midori_debug ("Icon couldn't be loaded: %s", error->message);
g_object_unref (stream);
}
if (!pixbuf)
pixbuf = gtk_widget_render_icon (GTK_WIDGET (view),
GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
GDK_INTERP_BILINEAR);
g_object_unref (pixbuf);
katze_object_assign (view->icon, pixbuf_scaled);
g_object_notify (G_OBJECT (view), "icon");
}
void
file_info_finish_cb (GFile* icon_file,
GAsyncResult* res,
MidoriView* view)
{
GFileInfo* info;
const gchar* content_type;
GIcon* icon;
GFile* parent;
GFile* file;
GdkPixbuf* pixbuf;
gint icon_width, icon_height;
GdkPixbuf* pixbuf_scaled;
info = g_file_query_info_finish (G_FILE (icon_file), res, NULL);
if (info)
{
content_type = g_file_info_get_content_type (info);
if (g_str_has_prefix (content_type, "image/"))
{
icon = g_file_icon_new (icon_file);
g_loadable_icon_load_async (G_LOADABLE_ICON (icon),
0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, view);
return;
}
}
file = g_file_get_parent (icon_file);
parent = g_file_get_parent (file);
/* We need to check if file equals the parent due to a GIO bug */
if (parent && !g_file_equal (file, parent))
{
icon_file = g_file_get_child (parent, "favicon.ico");
g_file_query_info_async (icon_file,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
G_FILE_QUERY_INFO_NONE, 0, NULL,
(GAsyncReadyCallback)file_info_finish_cb, view);
return;
}
pixbuf = gtk_widget_render_icon (GTK_WIDGET (view),
GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
GDK_INTERP_BILINEAR);
g_object_unref (pixbuf);
view->icon = pixbuf_scaled;
g_object_notify (G_OBJECT (view), "icon");
}
#endif
static void
_midori_web_view_load_icon (MidoriView* view)
{
#if HAVE_GIO
GFile* file;
GFile* icon_file;
#endif
GdkPixbuf* pixbuf;
gint icon_width, icon_height;
GdkPixbuf* pixbuf_scaled;
#if HAVE_GIO
if (view->uri)
{
file = g_file_new_for_uri (view->uri);
icon_file = g_file_get_child (file, "favicon.ico");
g_file_query_info_async (icon_file,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
G_FILE_QUERY_INFO_NONE, 0, NULL,
(GAsyncReadyCallback)file_info_finish_cb, view);
return;
}
#endif
pixbuf = gtk_widget_render_icon (GTK_WIDGET (view),
GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
GDK_INTERP_BILINEAR);
g_object_unref (pixbuf);
view->icon = pixbuf_scaled;
g_object_notify (G_OBJECT (view), "icon");
}
static void
midori_view_notify_load_status_cb (MidoriView* view,
GParamSpec pspec)
{
view->can_go_back = midori_view_can_go_back (view);
view->can_go_forward = midori_view_can_go_forward (view);
if (midori_view_is_socket (view))
{
if (view->tab_icon)
katze_throbber_set_animated (KATZE_THROBBER (view->tab_icon),
view->load_status != MIDORI_LOAD_FINISHED);
}
if (midori_view_is_plug (view))
{
send_command (view, "load-status", int_to_str (view->load_status));
send_command (view, "can-go-back", int_to_str (view->can_go_back));
send_command (view, "can-go-forward", int_to_str (view->can_go_forward));
}
if (!midori_view_is_plug (view))
if (view->load_status == MIDORI_LOAD_COMMITTED)
_midori_web_view_load_icon (view);
}
static void
midori_view_notify_progress_cb (MidoriView* view,
GParamSpec pspec)
{
if (midori_view_is_plug (view))
send_command (view, "progress", float_to_str (view->progress));
}
static void
midori_view_action_cb (MidoriView* view,
const gchar* action)
{
if (midori_view_is_socket (view))
return;
send_command (view, "activate-action", action);
}
static void
midori_view_console_message_cb (MidoriView* view,
const gchar* message,
gint line,
const gchar* source_id)
{
gchar* argument;
if (midori_view_is_socket (view))
return;
argument = g_strdup_printf ("%s %d %s", message, line, source_id);
send_command (view, "console-message", argument);
g_free (argument);
}
static void
midori_view_new_tab_cb (MidoriView* view,
const gchar* uri,
gboolean background)
{
gchar* argument;
if (midori_view_is_socket (view))
return;
/* (uri, background) => (background, uri) */
argument = g_strdup_printf ("%d %s", background, uri);
send_command (view, "new-tab", argument);
g_free (argument);
}
static void
midori_view_new_window_cb (MidoriView* view,
const gchar* uri)
{
if (midori_view_is_socket (view))
return;
send_command (view, "new-window", uri);
}
static void
midori_view_search_text_cb (MidoriView* view,
gboolean found)
{
if (!midori_view_is_plug (view))
return;
send_command (view, "search-text", int_to_str (found));
}
static void
midori_view_add_bookmark_cb (MidoriView* view,
const gchar* uri)
{
if (midori_view_is_socket (view))
return;
send_command (view, "add-bookmark", uri);
}
static void
receive_status (MidoriView* view,
const gchar* command)
{
if (!strncmp (command, "uri ", 4))
{
katze_assign (view->uri, g_strdup (&command[4]));
g_object_notify (G_OBJECT (view), "uri");
}
else if (!strncmp (command, "title ", 6))
{
g_object_set (view, "title", &command[6], NULL);
}
else if (!strncmp (command, "load-status ", 12))
{
view->load_status = (MidoriLoadStatus)atoi (&command[12]);
g_object_notify (G_OBJECT (view), "load-status");
}
else if (!strncmp (command, "progress ", 9))
{
view->progress = atof (&command[9]);
g_object_notify (G_OBJECT (view), "progress");
}
else if (!strncmp (command, "zoom-level ", 11))
{
view->zoom_level = atof (&command[11]);
g_object_notify (G_OBJECT (view), "zoom-level");
}
else if (!strncmp (command, "can-go-back ", 12))
{
view->can_go_back = atoi (&command[12]);
}
else if (!strncmp (command, "can-go-forward ", 15))
{
view->can_go_forward = atoi (&command[15]);
}
else if (!strncmp (command, "statusbar-text ", 15))
{
g_object_set (view, "statusbar-text", &command[15], NULL);
}
else if (!strncmp (command, "activate-action ", 16))
{
g_signal_emit (view, signals[ACTIVATE_ACTION], 0, &command[16]);
}
else if (!strncmp (command, "console-message ", 16))
{
/* FIXME: Implement */
}
else if (!strncmp (command, "new-tab ", 8))
{
/* (background, uri) => (uri, background) */
g_signal_emit (view, signals[NEW_TAB], 0, &command[10], atoi (&command[8]));
}
else if (!strncmp (command, "new-window ", 11))
{
g_signal_emit (view, signals[NEW_WINDOW], 0, &command[11]);
}
else if (!strncmp (command, "search-text ", 12))
{
g_signal_emit (view, signals[SEARCH_TEXT], 0, atoi (&command[12]));
}
else if (!strncmp (command, "add-bookmark ", 13))
{
g_signal_emit (view, signals[ADD_BOOKMARK], 0, &command[13]);
}
else if (!strncmp (command, "clipboard ", 10))
{
view->can_cut_clipboard = atof (&command[10]);
view->can_copy_clipboard = atof (&command[12]);
view->can_paste_clipboard = atof (&command[14]);
midori_debug ("clipboards: %s => %d, %d, %d",
&command[10],
atoi (&command[10]), atoi (&command[12]), atoi (&command[14]));
}
else if (g_str_has_prefix (command, "**"))
{
g_print ("%s\n", command);
}
else
{
midori_debug ("receive_status: unknown command '%s'", command);
}
}
#define UPDATE_SETTING(name, value) \
g_object_set (webkit_web_view_get_settings ( \
WEBKIT_WEB_VIEW (view->web_view)), \
name, value, NULL)
static void
receive_command (MidoriView* view,
const gchar* command)
{
if (!strncmp (command, "set-uri ", 8))
midori_view_set_uri (view, &command[8]);
else if (!strncmp (command, "set-zoom-level ", 15))
midori_view_set_zoom_level (view, atof (&command[15]) / 10);
else if (!strncmp (command, "reload ", 7))
midori_view_reload (view, atoi (&command[7]));
else if (!strncmp (command, "stop-loading", 12))
midori_view_stop_loading (view);
else if (!strncmp (command, "go-back", 7))
midori_view_go_back (view);
else if (!strncmp (command, "go-forward", 10))
midori_view_go_forward (view);
else if (!strncmp (command, "print", 5))
midori_view_print (view);
else if (!strncmp (command, "unmark-matches", 14))
midori_view_unmark_text_matches (view);
else if (!strncmp (command, "search-text ", 12))
/* (forward, case_sensitive, text) => (text, case_sensitive, forward) */
midori_view_search_text (view, &command[16],
atoi (&command[14]), atoi (&command[12]));
else if (!strncmp (command, "mark-matches ", 13))
/* (case_sensitive, text) => (text, case_sensitive) */
midori_view_mark_text_matches (view, &command[17],
atoi (&command[15]));
else if (!strncmp (command, "hl-matches ", 11))
midori_view_set_highlight_text_matches (view, atoi (&command[11]));
else if (!strncmp (command, "dlmgr ", 6))
{
katze_assign (view->download_manager, g_strdup (&command[6]));
}
else if (!strncmp (command, "dffamily ", 9))
{
katze_assign (view->default_font_family, g_strdup (&command[9]));
UPDATE_SETTING ("default-font-family", view->default_font_family);
}
else if (!strncmp (command, "dfsize ", 7))
{
view->default_font_size = atoi (&command[7]);
UPDATE_SETTING ("default-font-size", view->default_font_size);
}
else if (!strncmp (command, "mfsize ", 7))
{
view->minimum_font_size = atoi (&command[7]);
UPDATE_SETTING ("minimum-font-size", view->minimum_font_size);
}
else if (!strncmp (command, "denc ", 5))
{
katze_assign (view->default_encoding, g_strdup (&command[5]));
UPDATE_SETTING ("default-encoding", view->default_encoding);
}
else if (!strncmp (command, "alimg ", 6))
{
view->auto_load_images = atoi (&command[6]);
UPDATE_SETTING ("auto-load-images", view->auto_load_images);
}
else if (!strncmp (command, "asimg ", 6))
{
view->auto_shrink_images = atoi (&command[6]);
UPDATE_SETTING ("auto-shrink-images", view->auto_shrink_images);
}
else if (!strncmp (command, "pbkg ", 5))
{
view->print_backgrounds = atoi (&command[5]);
UPDATE_SETTING ("print-backgrounds", view->print_backgrounds);
}
else if (!strncmp (command, "rta ", 4))
{
view->print_backgrounds = atoi (&command[4]);
UPDATE_SETTING ("resizable-text-areas", view->resizable_text_areas);
}
else if (!strncmp (command, "escripts ", 9))
{
view->enable_scripts = atoi (&command[9]);
UPDATE_SETTING ("enable-scripts", view->enable_scripts);
}
else if (!strncmp (command, "eplugins ", 9))
{
view->enable_plugins = atoi (&command[9]);
UPDATE_SETTING ("enable-plugins", view->enable_plugins);
}
else if (!strncmp (command, "mclksel ", 8))
{
view->middle_click_opens_selection = atoi (&command[8]);
}
else if (!strncmp (command, "tabsbkg ", 8))
{
view->open_tabs_in_the_background = atoi (&command[8]);
}
else if (!strncmp (command, "proxy ", 6))
{
katze_assign (view->http_proxy, g_strdup (&command[6]));
g_setenv ("http_proxy", view->http_proxy ? view->http_proxy : "", TRUE);
}
else if (g_str_has_prefix (command, "**"))
g_print ("%s\n", command);
else
midori_debug ("receive_command: unknown command '%s'", command);
}
static gboolean
io_input_watch_cb (GIOChannel* source,
GIOCondition condition,
MidoriView* view)
{
gchar* buffer;
GError* error;
error = NULL;
switch (condition)
{
case G_IO_PRI:
case G_IO_IN:
if (g_io_channel_read_line (source,
&buffer, NULL, NULL, &error) == G_IO_STATUS_NORMAL)
{
if (view->socket_id)
receive_command (view, buffer);
else
receive_status (view, buffer);
g_free (buffer);
}
else
{
g_warning ("Communication error: %s", error->message);
g_error_free (error);
}
break;
case G_IO_ERR:
case G_IO_NVAL:
g_warning ("Invalid operation");
return FALSE;
case G_IO_HUP:
midori_debug ("Tab closed");
return FALSE;
default:
g_warning ("Unexpected condition");
return FALSE;
}
return TRUE;
}
static void
webkit_web_view_load_started_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
MidoriView* view)
{
view->window_object_cleared = FALSE;
view->load_status = MIDORI_LOAD_PROVISIONAL;
g_object_notify (G_OBJECT (view), "load-status");
view->progress = 0.0;
g_object_notify (G_OBJECT (view), "progress");
}
static void
webkit_web_view_window_object_cleared_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
JSGlobalContextRef js_context,
JSObjectRef js_window,
MidoriView* view)
{
view->window_object_cleared = TRUE;
}
static void
webkit_web_view_load_committed_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
MidoriView* view)
{
const gchar* uri;
GdkPixbuf* icon;
uri = webkit_web_frame_get_uri (web_frame);
katze_assign (view->uri, g_strdup (uri));
g_object_notify (G_OBJECT (view), "uri");
g_object_set (view, "title", NULL, NULL);
icon = gtk_widget_render_icon (GTK_WIDGET (view),
GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
katze_object_assign (view->icon, icon);
g_object_notify (G_OBJECT (view), "icon");
view->load_status = MIDORI_LOAD_COMMITTED;
g_object_notify (G_OBJECT (view), "load-status");
}
static void
webkit_web_view_progress_changed_cb (WebKitWebView* web_view,
gint progress,
MidoriView* view)
{
view->progress = progress ? progress / 100.0 : 0.0;
g_object_notify (G_OBJECT (view), "progress");
}
/*
static void
gjs_value_links_foreach_cb (GjsValue* link,
MidoriView* view)
{
const gchar* type;
#if HAVE_GIO
const gchar* rel;
GFile* icon_file;
GIcon* icon;
#endif
if (gjs_value_is_object (link) && gjs_value_has_attribute (link, "href"))
{
if (gjs_value_has_attribute (link, "type"))
{
type = gjs_value_get_attribute_string (link, "type");
if (!strcmp (type, "application/rss+xml")
|| !strcmp (type, "application/x.atom+xml")
|| !strcmp (type, "application/atom+xml"))
{
katze_array_add_item (view->news_feeds, link);
g_signal_emit_by_name (view, "news-feed-ready",
gjs_value_get_attribute_string (link, "href"), type,
gjs_value_has_attribute (link, "title")
? gjs_value_get_attribute_string (link, "title") : NULL);
}
}
#if HAVE_GIO
if (gjs_value_has_attribute (link, "rel"))
{
rel = gjs_value_get_attribute_string (link, "rel");
if (!strcmp (rel, "icon") || !strcmp (rel, "shortcut icon"))
{
icon_file = g_file_new_for_uri (
gjs_value_get_attribute_string (link, "href"));
icon = g_file_icon_new (icon_file);
g_loadable_icon_load_async (G_LOADABLE_ICON (icon),
0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, view);
}
}
#endif
}
}
*/
static void
webkit_web_frame_load_done_cb (WebKitWebFrame* web_frame,
gboolean success,
MidoriView* view)
{
gchar* data;
JSContextRef js_context;
JSValueRef js_window;
/* GjsValue* value;
GjsValue* document;
GjsValue* links; */
if (!success)
{
midori_debug ("'%s' not found.", view->uri);
data = g_strdup_printf ("error:404 %s ", view->uri ? view->uri : "");
midori_view_set_uri (view, data);
g_free (data);
return;
}
/* If WebKit didn't emit the signal due to a bug, we will */
if (!view->window_object_cleared)
{
js_context = webkit_web_frame_get_global_context (web_frame);
js_window = JSContextGetGlobalObject (js_context);
g_signal_emit_by_name (view->web_view, "window-object-cleared",
web_frame, js_context, js_window);
}
/* js_context = webkit_web_frame_get_global_context (web_frame);
value = gjs_value_new (js_context, NULL);
document = gjs_value_get_by_name (value, "document");
links = gjs_value_get_elements_by_tag_name (document, "link");
katze_array_clear (web_view->news_feeds);
gjs_value_foreach (links, (GjsCallback)gjs_value_links_foreach_cb, web_view);
g_object_unref (links);
g_object_unref (document);
g_object_unref (value); */
view->load_status = MIDORI_LOAD_FINISHED;
g_object_notify (G_OBJECT (view), "load-status");
}
static void
webkit_web_view_load_finished_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
MidoriView* view)
{
view->progress = 1.0;
g_object_notify (G_OBJECT (view), "progress");
}
static void
webkit_web_view_title_changed_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
const gchar* title,
MidoriView* view)
{
g_object_set (view, "title", title, NULL);
}
static void
webkit_web_view_statusbar_text_changed_cb (WebKitWebView* web_view,
const gchar* text,
MidoriView* view)
{
g_object_set (G_OBJECT (view), "statusbar-text", text, NULL);
}
static void
webkit_web_view_hovering_over_link_cb (WebKitWebView* web_view,
const gchar* tooltip,
const gchar* link_uri,
MidoriView* view)
{
katze_assign (view->link_uri, g_strdup (link_uri));
g_object_set (G_OBJECT (view), "statusbar-text", link_uri, NULL);
}
static gboolean
gtk_widget_button_press_event_cb (WebKitWebView* web_view,
GdkEventButton* event,
MidoriView* view)
{
GdkModifierType state;
gint x, y;
GtkClipboard* clipboard;
gchar* uri;
gchar* new_uri;
const gchar* link_uri;
gboolean background;
gdk_window_get_pointer (NULL, &x, &y, &state);
link_uri = midori_view_get_link_uri (MIDORI_VIEW (view));
switch (event->button)
{
case 1:
if (!link_uri)
return FALSE;
if (state & GDK_SHIFT_MASK)
{
/* Open link in new window */
g_signal_emit_by_name (view, "new-window", link_uri);
return TRUE;
}
else if (state & GDK_MOD1_MASK)
{
/* Open link in new tab */
background = view->open_tabs_in_the_background;
if (state & GDK_CONTROL_MASK)
background = !background;
g_signal_emit_by_name (view, "new-tab", link_uri, background);
return TRUE;
}
break;
case 2:
if (link_uri)
{
/* Open link in new tab */
background = view->open_tabs_in_the_background;
if (state & GDK_CONTROL_MASK)
background = !background;
g_signal_emit_by_name (view, "new-tab", link_uri, background);
return TRUE;
}
else if (state & GDK_CONTROL_MASK)
{
midori_view_set_zoom_level (MIDORI_VIEW (view), 1.0);
return FALSE; /* Allow Ctrl + Middle click */
}
else if (view->middle_click_opens_selection)
{
state = (GdkModifierType) event->state;
clipboard = gtk_clipboard_get_for_display (
gtk_widget_get_display (GTK_WIDGET (view)),
GDK_SELECTION_PRIMARY);
uri = gtk_clipboard_wait_for_text (clipboard);
if (uri && strchr (uri, '.') && !strchr (uri, ' '))
{
new_uri = sokoke_magic_uri (uri, NULL);
if (state & GDK_CONTROL_MASK)
{
background = view->open_tabs_in_the_background;
if (state & GDK_CONTROL_MASK)
background = !background;
g_signal_emit_by_name (view, "new-tab", new_uri, background);
}
else
{
midori_view_set_uri (MIDORI_VIEW (view), new_uri);
gtk_widget_grab_focus (GTK_WIDGET (view));
}
g_free (new_uri);
g_free (uri);
return TRUE;
}
}
break;
}
return FALSE;
}
static gboolean
gtk_widget_button_release_event_cb (WebKitWebView* web_view,
GdkEventButton* event,
MidoriView* view)
{
GtkClipboard* clipboard;
gchar* text;
/* Emulate the primary clipboard, which WebKit doesn't support */
text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view));
clipboard = gtk_clipboard_get_for_display (
gtk_widget_get_display (GTK_WIDGET (web_view)), GDK_SELECTION_PRIMARY);
gtk_clipboard_set_text (clipboard, text, -1);
g_free (text);
return FALSE;
}
static gboolean
gtk_widget_scroll_event_cb (WebKitWebView* web_view,
GdkEventScroll* event,
MidoriView* view)
{
GdkModifierType state = (GdkModifierType)0;
gint x, y;
gdk_window_get_pointer (NULL, &x, &y, &state);
if (state & GDK_CONTROL_MASK)
{
if (event->direction == GDK_SCROLL_DOWN)
webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
else if(event->direction == GDK_SCROLL_UP)
webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
return TRUE;
}
else
return FALSE;
}
static void
midori_web_view_menu_new_tab_activate_cb (GtkWidget* widget,
MidoriView* view)
{
g_signal_emit (view, signals[NEW_TAB], 0, view->link_uri,
view->open_tabs_in_the_background);
}
static void
midori_web_view_menu_new_window_activate_cb (GtkWidget* widget,
MidoriView* view)
{
g_signal_emit (view, signals[NEW_WINDOW], 0, view->link_uri);
}
static void
midori_web_view_menu_download_activate_cb (GtkWidget* widget,
MidoriView* view)
{
sokoke_spawn_program (view->download_manager, view->link_uri);
}
static void
midori_web_view_menu_add_bookmark_activate_cb (GtkWidget* widget,
MidoriView* view)
{
g_signal_emit (view, signals[ADD_BOOKMARK], 0, view->link_uri);
}
static void
midori_web_view_menu_action_activate_cb (GtkWidget* widget,
MidoriView* view)
{
const gchar* action = g_object_get_data (G_OBJECT (widget), "action");
g_signal_emit_by_name (view, "activate-action", action);
}
static void
webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
GtkWidget* menu,
MidoriView* view)
{
GtkWidget* menuitem;
GtkWidget* icon;
gchar* stock_id;
GdkScreen* screen;
GtkIconTheme* icon_theme;
GList* items;
/* We do not want to modify the Edit menu.
The only reliable indicator is inspecting the first item. */
items = gtk_container_get_children (GTK_CONTAINER (menu));
menuitem = (GtkWidget*)g_list_nth_data (items, 0);
if (GTK_IS_IMAGE_MENU_ITEM (menuitem))
{
icon = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (menuitem));
gtk_image_get_stock (GTK_IMAGE (icon), &stock_id, NULL);
if (!strcmp (stock_id, GTK_STOCK_CUT))
return;
}
if (view->link_uri)
{
menuitem = gtk_image_menu_item_new_with_mnemonic (
_("Open Link in New _Tab"));
screen = gtk_widget_get_screen (GTK_WIDGET (view));
icon_theme = gtk_icon_theme_get_for_screen (screen);
if (gtk_icon_theme_has_icon (icon_theme, STOCK_TAB_NEW))
{
icon = gtk_image_new_from_stock (STOCK_TAB_NEW, GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
}
gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 1);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), view);
gtk_widget_show (menuitem);
/* hack to implement New Window */
items = gtk_container_get_children (GTK_CONTAINER (menu));
menuitem = (GtkWidget*)g_list_nth_data (items, 2);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_new_window_activate_cb), view);
menuitem = (GtkWidget*)g_list_nth_data (items, 3);
/* hack to disable non-functional Download File */
gtk_widget_set_sensitive (menuitem, FALSE);
g_list_free (items);
if (view->download_manager && *view->download_manager)
{
menuitem = gtk_image_menu_item_new_with_mnemonic (
_("Download Link with Download _Manager"));
icon = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS,
GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 4);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_download_activate_cb), view);
gtk_widget_show (menuitem);
}
menuitem = gtk_image_menu_item_new_from_stock (STOCK_BOOKMARK_ADD, NULL);
gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 5);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_add_bookmark_activate_cb), view);
gtk_widget_show (menuitem);
}
if (!view->link_uri && midori_view_has_selection (view))
{
if (strchr (view->selected_text, '.')
&& !strchr (view->selected_text, ' '))
{
menuitem = gtk_image_menu_item_new_with_mnemonic (
_("Open URL in New _Tab"));
icon = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO,
GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, -1);
g_object_set_data (G_OBJECT (menuitem), "uri", view->selected_text);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), view);
gtk_widget_show (menuitem);
}
/* FIXME: view selection source */
}
if (!view->link_uri && !midori_view_has_selection (view))
{
/* FIXME: Make this sensitive only when there is a tab to undo */
menuitem = gtk_image_menu_item_new_with_mnemonic (_("Undo Close Tab"));
icon = gtk_image_new_from_stock (GTK_STOCK_UNDELETE, GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_object_set_data (G_OBJECT (menuitem), "action", "UndoTabClose");
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
gtk_widget_show (menuitem);
menuitem = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
menuitem = gtk_image_menu_item_new_from_stock (STOCK_BOOKMARK_ADD, NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_object_set_data (G_OBJECT (menuitem), "action", "BookmarkAdd");
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
gtk_widget_show (menuitem);
menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS, NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_object_set_data (G_OBJECT (menuitem), "action", "SaveAs");
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
gtk_widget_show (menuitem);
/* FIXME: Make this sensitive once it's implemented */
gtk_widget_set_sensitive (menuitem, FALSE);
menuitem = gtk_image_menu_item_new_with_mnemonic (_("View _Source"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_object_set_data (G_OBJECT (menuitem), "action", "SourceView");
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
gtk_widget_show (menuitem);
#if !HAVE_GIO
gtk_widget_set_sensitive (menuitem, FALSE);
#endif
menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PRINT, NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_object_set_data (G_OBJECT (menuitem), "action", "Print");
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
gtk_widget_show (menuitem);
}
}
static void
webkit_web_view_console_message_cb (GtkWidget* web_view,
const gchar* message,
guint line,
const gchar* source_id,
MidoriView* view)
{
g_signal_emit_by_name (view, "console-message", message, line, source_id);
}
static gboolean
gtk_widget_focus_out_event_cb (GtkWidget* web_view,
GdkEventFocus* event,
MidoriView* view)
{
gchar* data;
data = g_strdup_printf ("%d %d %d",
midori_view_can_cut_clipboard (view),
midori_view_can_copy_clipboard (view),
midori_view_can_paste_clipboard (view));
send_command (view, "clipboard", data);
g_free (data);
return FALSE;
}
static void
midori_view_realize (MidoriView* view)
{
WebKitWebFrame* web_frame;
view->web_view = webkit_web_view_new ();
/* Adjustments are not created automatically */
g_object_set (view, "hadjustment", NULL, "vadjustment", NULL, NULL);
/* FIXME: Strictly we should send a command to query
the policy or send it as an argument */
/* The socket view is not supposed to scroll at all */
if (midori_view_is_socket (view))
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
GTK_POLICY_NEVER, GTK_POLICY_NEVER);
/* The plug view should use the policy of the socket */
if (midori_view_is_plug (view))
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_widget_show (view->web_view);
web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view->web_view));
g_object_connect (view->web_view,
"signal::load-started",
webkit_web_view_load_started_cb, view,
"signal::window-object-cleared",
webkit_web_view_window_object_cleared_cb, view,
"signal::load-committed",
webkit_web_view_load_committed_cb, view,
"signal::load-progress-changed",
webkit_web_view_progress_changed_cb, view,
"signal::load-finished",
webkit_web_view_load_finished_cb, view,
"signal::title-changed",
webkit_web_view_title_changed_cb, view,
"signal::status-bar-text-changed",
webkit_web_view_statusbar_text_changed_cb, view,
"signal::hovering-over-link",
webkit_web_view_hovering_over_link_cb, view,
"signal::button-press-event",
gtk_widget_button_press_event_cb, view,
"signal::button-release-event",
gtk_widget_button_release_event_cb, view,
"signal::scroll-event",
gtk_widget_scroll_event_cb, view,
"signal::populate-popup",
webkit_web_view_populate_popup_cb, view,
"signal::console-message",
webkit_web_view_console_message_cb, view,
"signal::focus-out-event",
gtk_widget_focus_out_event_cb, view,
NULL);
g_object_connect (web_frame,
"signal::load-done",
webkit_web_frame_load_done_cb, view,
NULL);
gtk_container_add (GTK_CONTAINER (view), view->web_view);
if (view->premature_uri)
{
midori_debug ("Loading premature uri '%s' now", view->premature_uri);
midori_view_set_uri (view, view->premature_uri);
}
katze_assign (view->premature_uri, NULL);
}
static void
gtk_socket_realize_cb (GtkWidget* socket,
MidoriView* view)
{
gchar* socket_id;
GError* error;
gboolean success;
gint stdin;
gint stdout;
gchar* argv[] = { NULL, "--id", NULL, NULL };
/* Sockets are not supported on all platforms,
so fallback to working without any socket or plug. */
if (!gtk_socket_get_id (GTK_SOCKET (socket)))
{
gtk_widget_destroy (socket);
midori_view_realize (view);
return;
}
socket_id = g_strdup_printf ("%d", gtk_socket_get_id (GTK_SOCKET (socket)));
argv[0] = (gchar*)sokoke_remember_argv0 (NULL);
argv[2] = socket_id;
error = NULL;
success = g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, NULL,
&stdin, &stdout, NULL, &error);
g_free (socket_id);
if (!success)
{
/* Fallback to operating without a socket */
view->socket_id = 0;
midori_view_realize (view);
g_error_free (error);
return;
}
view->output = fdopen (stdin, "w");
view->input = g_io_channel_unix_new (stdout);
g_io_channel_set_close_on_unref (view->input, TRUE);
g_io_add_watch (view->input,
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_NVAL | G_IO_HUP,
(GIOFunc)io_input_watch_cb, view);
if (view->command_cache)
{
/* Send cached commands if any */
fwrite (view->command_cache,
strlen (view->command_cache) + 1, 1, view->output);
katze_assign (view->command_cache, NULL);
fflush (view->output);
}
}
static gboolean
gtk_socket_plug_removed_cb (GtkWidget* socket,
MidoriView* view)
{
if (view->output)
{
fclose (view->output);
view->output = NULL;
}
if (view->input)
{
g_io_channel_unref (view->input);
view->input = NULL;
}
midori_debug ("'%s' died.", view->uri);
send_command (view, "set-uri error:died", view->uri ? view->uri : "");
if (GTK_WIDGET_REALIZED (view))
gtk_socket_realize_cb (socket, view);
return TRUE;
}
static void
midori_view_realize_cb (MidoriView* view)
{
GtkWidget* plug;
GtkWidget* socket;
if (midori_view_is_plug (view))
{
plug = gtk_plug_new (view->socket_id);
midori_view_realize (view);
gtk_widget_show (plug);
view->input = g_io_channel_unix_new (0); /* 0 is stdin */
g_io_channel_set_close_on_unref (view->input, TRUE);
g_io_add_watch (view->input,
G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP,
(GIOFunc)io_input_watch_cb, view);
view->output = fdopen (1, "w"); /* 1 is stdout */
}
else if (midori_view_is_socket (view))
{
socket = gtk_socket_new ();
g_signal_connect (socket, "realize",
G_CALLBACK (gtk_socket_realize_cb), view);
g_signal_connect (socket, "plug-removed",
G_CALLBACK (gtk_socket_plug_removed_cb), view);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (view),
GTK_WIDGET (socket));
gtk_widget_show (socket);
}
}
static void
midori_view_init (MidoriView* view)
{
view->command_cache = NULL;
view->premature_uri = NULL;
view->uri = NULL;
view->title = NULL;
view->icon = gtk_widget_render_icon (GTK_WIDGET (view), GTK_STOCK_FILE,
GTK_ICON_SIZE_MENU, NULL);
view->progress = 0.0;
view->load_status = MIDORI_LOAD_FINISHED;
view->statusbar_text = NULL;
view->link_uri = NULL;
view->selected_text = NULL;
view->settings = NULL;
view->item = NULL;
view->download_manager = NULL;
view->default_font_family = NULL;
view->default_encoding = NULL;
view->http_proxy = NULL;
g_object_connect (view,
"signal::notify::uri",
midori_view_notify_uri_cb, NULL,
"signal::notify::icon",
midori_view_notify_icon_cb, NULL,
"signal::notify::load-status",
midori_view_notify_load_status_cb, NULL,
"signal::notify::progress",
midori_view_notify_progress_cb, NULL,
"signal::realize",
midori_view_realize_cb, NULL,
"signal::activate-action",
midori_view_action_cb, NULL,
"signal::console-message",
midori_view_console_message_cb, NULL,
"signal::new-tab",
midori_view_new_tab_cb, NULL,
"signal::new-window",
midori_view_new_window_cb, NULL,
"signal::search-text",
midori_view_search_text_cb, NULL,
"signal::add-bookmark",
midori_view_add_bookmark_cb, NULL,
NULL);
}
static void
midori_view_finalize (GObject* object)
{
MidoriView* view;
/* WebKitWebFrame* web_frame; */
view = MIDORI_VIEW (object);
g_free (view->command_cache);
g_free (view->premature_uri);
g_free (view->uri);
g_free (view->title);
if (view->icon)
g_object_unref (view->icon);
g_free (view->statusbar_text);
g_free (view->link_uri);
g_free (view->selected_text);
if (view->settings)
g_object_unref (view->settings);
if (view->item)
g_object_unref (view->item);
g_free (view->download_manager);
/* web_frame = webkit_web_view_get_main_frame
(WEBKIT_WEB_VIEW (view->web_view));
g_signal_handlers_disconnect_by_func (web_frame,
webkit_web_frame_load_done, view); */
G_OBJECT_CLASS (midori_view_parent_class)->finalize (object);
}
static void
midori_view_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriView* view;
view = MIDORI_VIEW (object);
switch (prop_id)
{
case PROP_SOCKET_ID:
view->socket_id = g_value_get_uint (value);
break;
case PROP_TITLE:
katze_assign (view->title, g_value_dup_string (value));
if (!midori_view_is_plug (view))
{
#define title midori_view_get_display_title (view)
if (view->tab_label)
{
gtk_label_set_text (GTK_LABEL (view->tab_title), title);
gtk_widget_set_tooltip_text (view->tab_title, title);
}
if (view->menu_item)
gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN (
view->menu_item))), title);
if (view->item)
katze_item_set_name (view->item, title);
#undef title
}
if (midori_view_is_plug (view))
/* We must not send a NULL string here */
send_command (view, "title", view->title ? view->title : "");
break;
case PROP_ZOOM_LEVEL:
midori_view_set_zoom_level (view, g_value_get_float (value));
if (midori_view_is_plug (view))
send_command (view, "zoom-level", float_to_str (view->zoom_level));
break;
case PROP_STATUSBAR_TEXT:
katze_assign (view->statusbar_text, g_value_dup_string (value));
if (midori_view_is_plug (view))
/* We must not send a NULL string here */
send_command (view, "statusbar-text",
view->statusbar_text ? view->statusbar_text : "");
break;
case PROP_SETTINGS:
midori_view_set_settings (view, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_view_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriView* view = MIDORI_VIEW (object);
switch (prop_id)
{
case PROP_SOCKET_ID:
g_value_set_uint (value, view->socket_id);
break;
case PROP_URI:
g_value_set_string (value, view->uri);
break;
case PROP_TITLE:
g_value_set_string (value, view->title);
break;
case PROP_PROGRESS:
g_value_set_double (value, midori_view_get_progress (view));
break;
case PROP_LOAD_STATUS:
g_value_set_enum (value, midori_view_get_load_status (view));
break;
case PROP_ZOOM_LEVEL:
g_value_set_float (value, midori_view_get_zoom_level (view));
break;
case PROP_STATUSBAR_TEXT:
g_value_set_string (value, view->statusbar_text);
break;
case PROP_SETTINGS:
g_value_set_object (value, view->settings);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* midori_view_new:
* @view: a #MidoriView
*
* Creates a new view.
*
* Return value: a new #MidoriView
**/
GtkWidget*
midori_view_new (void)
{
return g_object_new (MIDORI_TYPE_VIEW, NULL);
}
/**
* midori_view_new_with_uri:
* @view: a #MidoriView
* @uri: an URI
*
* Creates a new view with a particular URI.
*
* This constructor supports opaque views and is
* in fact currently the only way to create them.
*
* The only currently supported opaque view is
* the source view, implementing a #MidoriSource.
* Pass an URI prefixed with "view-source:" in
* order to create a source view.
*
* Return value: a new #MidoriView
**/
GtkWidget*
midori_view_new_with_uri (const gchar* uri)
{
MidoriView* view;
gchar* title;
GtkWidget* widget;
view = g_object_new (MIDORI_TYPE_VIEW, NULL);
if (uri && g_str_has_prefix (uri, "view-source:"))
{
view->socket_id = -1;
katze_assign (view->uri, g_strdup (uri));
g_object_notify (G_OBJECT (view), "uri");
title = g_strdup_printf ("%s - %s", _("Source"), &uri[12]);
g_object_set (view, "title", title, NULL);
g_free (title);
katze_object_assign (view->icon,
gtk_widget_render_icon (GTK_WIDGET (view),
GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU, NULL));
widget = midori_source_new (&uri[12]);
/* Adjustments are not created automatically */
g_object_set (view, "hadjustment", NULL, "vadjustment", NULL, NULL);
gtk_container_add (GTK_CONTAINER (view), widget);
gtk_widget_show (widget);
}
else
midori_view_set_uri (view, uri);
return (GtkWidget*)view;
}
static void
_update_label_size (GtkWidget* label,
gint size)
{
gint width, height;
if (size < 1)
size = 10;
sokoke_widget_get_text_size (label, "M", &width, &height);
gtk_widget_set_size_request (label, width * size, -1);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
}
static void
_midori_view_update_settings (MidoriView* view)
{
g_object_get (view->settings,
"download-manager", &view->download_manager,
"default-font-family", &view->default_font_family,
"default-font-size", &view->default_font_size,
"minimum-font-size", &view->minimum_font_size,
"default-encoding", &view->default_encoding,
"auto-load-images", &view->auto_load_images,
"auto-shrink-images", &view->auto_shrink_images,
"print-backgrounds", &view->print_backgrounds,
"resizable-text-areas", &view->resizable_text_areas,
"enable-scripts", &view->enable_scripts,
"enable-plugins", &view->enable_plugins,
"close-buttons-on-tabs", &view->close_buttons_on_tabs,
"middle-click-opens-selection", &view->middle_click_opens_selection,
"open-tabs-in-the-background", &view->open_tabs_in_the_background,
"http-proxy", &view->http_proxy,
NULL);
if (midori_view_is_socket (view))
{
send_command (view, "dlmgr", view->download_manager);
send_command (view, "dffamily", view->default_font_family);
send_command (view, "dfsize", int_to_str (view->default_font_size));
send_command (view, "mfsize", int_to_str (view->minimum_font_size));
send_command (view, "denc", view->default_encoding);
send_command (view, "alimg", int_to_str (view->auto_load_images));
send_command (view, "asimg", int_to_str (view->auto_shrink_images));
send_command (view, "pbkg", int_to_str (view->print_backgrounds));
send_command (view, "rta", int_to_str (view->resizable_text_areas));
send_command (view, "escripts", int_to_str (view->enable_scripts));
send_command (view, "eplugins", int_to_str (view->enable_plugins));
send_command (view, "mclksel",
int_to_str (view->middle_click_opens_selection));
send_command (view, "tabsbkg",
int_to_str (view->open_tabs_in_the_background));
send_command (view, "proxy", view->http_proxy);
}
}
static void
midori_view_settings_notify_cb (MidoriWebSettings* settings,
GParamSpec* pspec,
MidoriView* view)
{
const gchar* name;
GValue value = { 0, };
name = g_intern_string (g_param_spec_get_name (pspec));
g_value_init (&value, pspec->value_type);
g_object_get_property (G_OBJECT (view->settings), name, &value);
if (name == g_intern_string ("download-manager"))
{
katze_assign (view->download_manager, g_value_dup_string (&value));
if (midori_view_is_socket (view))
send_command (view, "dlmgr", view->download_manager);
}
else if (name == g_intern_string ("default-font-family"))
{
katze_assign (view->default_font_family, g_value_dup_string (&value));
if (midori_view_is_socket (view))
send_command (view, "dffamily", view->default_font_family);
}
else if (name == g_intern_string ("default-font-size"))
{
view->default_font_size = g_value_get_int (&value);
if (midori_view_is_socket (view))
send_command (view, "dfsize", int_to_str (view->default_font_size));
}
else if (name == g_intern_string ("minimum-font-size"))
{
view->minimum_font_size = g_value_get_int (&value);
if (midori_view_is_socket (view))
send_command (view, "mfsize", int_to_str (view->minimum_font_size));
}
else if (name == g_intern_string ("default-encoding"))
{
katze_assign (view->default_encoding, g_value_dup_string (&value));
if (midori_view_is_socket (view))
send_command (view, "denc", view->default_encoding);
}
else if (name == g_intern_string ("auto-load-images"))
{
view->auto_load_images = g_value_get_boolean (&value);
if (midori_view_is_socket (view))
send_command (view, "alimg", int_to_str (view->auto_load_images));
}
else if (name == g_intern_string ("auto-shrink-images"))
{
view->auto_shrink_images = g_value_get_boolean (&value);
if (midori_view_is_socket (view))
send_command (view, "asimg", int_to_str (view->auto_shrink_images));
}
else if (name == g_intern_string ("print-backgrounds"))
{
view->print_backgrounds = g_value_get_boolean (&value);
if (midori_view_is_socket (view))
send_command (view, "pbkg", int_to_str (view->print_backgrounds));
}
else if (name == g_intern_string ("resizable-text-areas"))
{
view->resizable_text_areas = g_value_get_boolean (&value);
if (midori_view_is_socket (view))
send_command (view, "rta", int_to_str (view->resizable_text_areas));
}
else if (name == g_intern_string ("enable-scripts"))
{
view->enable_scripts = g_value_get_boolean (&value);
if (midori_view_is_socket (view))
send_command (view, "escripts", int_to_str (view->enable_scripts));
}
else if (name == g_intern_string ("enable-plugins"))
{
view->enable_plugins = g_value_get_boolean (&value);
if (midori_view_is_socket (view))
send_command (view, "eplugins", int_to_str (view->enable_plugins));
}
else if (name == g_intern_string ("close-buttons-on-tabs"))
{
view->close_buttons_on_tabs = g_value_get_boolean (&value);
sokoke_widget_set_visible (view->tab_close,
view->close_buttons_on_tabs);
}
else if (name == g_intern_string ("middle-click-opens-selection"))
{
view->middle_click_opens_selection = g_value_get_boolean (&value);
if (midori_view_is_socket (view))
send_command (view, "mclksel",
int_to_str (view->middle_click_opens_selection));
}
else if (name == g_intern_string ("open-tabs-in-the-background"))
{
view->open_tabs_in_the_background = g_value_get_boolean (&value);
if (midori_view_is_socket (view))
send_command (view, "tabsbkg",
int_to_str (view->open_tabs_in_the_background));
}
else if (name == g_intern_string ("http-proxy"))
{
katze_assign (view->http_proxy, g_value_dup_string (&value));
if (midori_view_is_socket (view))
send_command (view, "proxy", view->http_proxy);
}
g_value_unset (&value);
}
/**
* midori_view_set_settings:
* @view: a #MidoriView
* @settings: a #MidoriWebSettings
*
* Assigns a settings instance to the view.
**/
void
midori_view_set_settings (MidoriView* view,
MidoriWebSettings* settings)
{
if (view->settings)
g_signal_handlers_disconnect_by_func (view->settings,
midori_view_settings_notify_cb, view);
katze_object_assign (view->settings, g_object_ref (settings));
_midori_view_update_settings (view);
g_signal_connect (settings, "notify",
G_CALLBACK (midori_view_settings_notify_cb), view);
g_object_notify (G_OBJECT (view), "settings");
}
/**
* midori_view_load_status:
* @web_view: a #MidoriView
*
* Determines the current loading status of a view.
*
* Return value: the current #MidoriLoadStatus
**/
MidoriLoadStatus
midori_view_get_load_status (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), MIDORI_LOAD_FINISHED);
return view->load_status;
}
/**
* midori_view_get_progress:
* @view: a #MidoriView
*
* Retrieves the current loading progress as
* a fraction between 0.0 and 1.0.
*
* Return value: the current loading progress
**/
gdouble
midori_view_get_progress (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), 0.0);
return view->progress;
}
/**
* midori_view_set_uri:
* @view: a #MidoriView
*
* Opens the specified URI in the view.
*
* FIXME:
* If the view doesn't allow changing the URI it
* will automatically request a new tab.
**/
void
midori_view_set_uri (MidoriView* view,
const gchar* uri)
{
gchar* data;
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
/* We must not send a NULL string here */
send_command (view, "set-uri", uri ? uri : "");
else
{
if (!view->web_view)
{
/* An URI is requested before the view was realized.
We special case this to load it when we are ready. */
midori_debug ("Deferring premature uri '%s'", uri);
katze_assign (view->premature_uri, g_strdup (uri));
return;
}
midori_debug ("Opening URI: %s", uri);
/* This is not prefectly elegant, but creating an
error page inline is the simplest solution. */
if (g_str_has_prefix (uri, "error:"))
{
data = NULL;
if (!strncmp (uri, "error:died ", 11))
{
katze_assign (view->uri, g_strdup (&uri[11]));
data = g_strdup_printf (
"<html><head><title>Page died - %s</title></head>"
"<body><h1>Page died - %s</h1>"
"<p />The page you were navigating on died."
"<p />Try to <a href=\"%s\">load the page again</a>, "
"or move on to another page."
"</body></html>",
view->uri, view->uri, view->uri);
}
else if (!strncmp (uri, "error:404 ", 10))
{
katze_assign (view->uri, g_strdup (&uri[10]));
data = g_strdup_printf (
"<html><head><title>Not found - %s</title></head>"
"<body><h1>Not found - %s</h1>"
"<p />The page you were opening doesn't exist."
"<p />Try to <a href=\"%s\">load the page again</a>, "
"or move on to another page."
"</body></html>",
view->uri, view->uri, view->uri);
}
if (data)
{
webkit_web_view_load_html_string (
WEBKIT_WEB_VIEW (view->web_view), data, view->uri);
g_free (data);
g_object_notify (G_OBJECT (view), "uri");
return;
}
}
else
{
katze_assign (view->uri, g_strdup (uri));
webkit_web_view_open (WEBKIT_WEB_VIEW (view->web_view), uri);
}
}
}
/**
* midori_view_is_blank:
* @view: a #MidoriView
*
* Determines whether the view is currently empty.
**/
gboolean
midori_view_is_blank (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), TRUE);
return !(view->uri && *view->uri);
}
/**
* midori_view_get_icon:
* @view: a #MidoriView
*
* Retrieves the icon of the view.
*
* Return value: a #GdkPixbuf
**/
GdkPixbuf*
midori_view_get_icon (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
return view->icon;
}
/**
* midori_view_get_display_uri:
* @view: a #MidoriView
*
* Retrieves a string that is suitable for displaying,
* particularly an empty URI is represented as "about:blank".
*
* You can assume that the string is not %NULL.
*
* Return value: an URI string
**/
const gchar*
midori_view_get_display_uri (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), "about:blank");
if (view->uri && *view->uri)
return view->uri;
return "about:blank";
}
/**
* midori_view_get_display_title:
* @view: a #MidoriView
*
* Retrieves a string that is suitable for displaying
* as a title. Most of the time this will be the title
* or the current URI.
*
* You can assume that the string is not %NULL.
*
* Return value: a title string
**/
const gchar*
midori_view_get_display_title (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), "about:blank");
if (view->title && *view->title)
return view->title;
return midori_view_get_display_uri (view);
}
/**
* midori_view_get_link_uri:
* @view: a #MidoriView
*
* Retrieves the uri of the currently focused link,
* particularly while the mouse hovers a link or a
* context menu is being opened.
*
* Return value: an URI string, or %NULL if there is no link focussed
**/
const gchar*
midori_view_get_link_uri (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
return view->link_uri;
}
/**
* midori_view_has_selection:
* @view: a #MidoriView
*
* Determines whether something in the view is selected.
*
* This function returns %FALSE if there is a selection
* that effectively only consists of whitespace.
*
* Return value: %TRUE if effectively there is a selection
**/
gboolean
midori_view_has_selection (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
if (midori_view_is_socket (view))
return view->has_selection;
else
{
view->selected_text = webkit_web_view_get_selected_text (
WEBKIT_WEB_VIEW (view->web_view));
if (view->selected_text && *view->selected_text)
return TRUE;
return FALSE;
}
}
/**
* midori_view_get_selected_text:
* @view: a #MidoriView
*
* Retrieves the currently selected text.
*
* Return value: the selected text, or %NULL
**/
const gchar*
midori_view_get_selected_text (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
if (midori_view_is_socket (view))
return view->selected_text;
else if (midori_view_has_selection (view))
return midori_view_get_selected_text (view);
else
return NULL;
}
/**
* midori_view_can_cut_clipboard:
* @view: a #MidoriView
*
* Determines whether a selection can be cut.
*
* Return value: %TRUE if a selection can be cut
**/
gboolean
midori_view_can_cut_clipboard (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
if (midori_view_is_socket (view))
return view->can_cut_clipboard;
else if (view->web_view)
{
view->can_cut_clipboard = webkit_web_view_can_cut_clipboard (
WEBKIT_WEB_VIEW (view->web_view));
return view->can_cut_clipboard;
}
return FALSE;
}
/**
* midori_view_can_copy_clipboard:
* @view: a #MidoriView
*
* Determines whether a selection can be copied.
*
* Return value: %TRUE if a selection can be copied
**/
gboolean
midori_view_can_copy_clipboard (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
if (midori_view_is_socket (view))
return view->can_copy_clipboard;
else if (view->web_view)
{
view->can_copy_clipboard = webkit_web_view_can_copy_clipboard (
WEBKIT_WEB_VIEW (view->web_view));
return view->can_copy_clipboard;
}
return FALSE;
}
/**
* midori_view_can_paste_clipboard:
* @view: a #MidoriView
*
* Determines whether a selection can be pasted.
*
* Return value: %TRUE if a selection can be pasted
**/
gboolean
midori_view_can_paste_clipboard (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
if (midori_view_is_socket (view))
return view->can_paste_clipboard;
else if (view->web_view)
{
view->can_paste_clipboard = webkit_web_view_can_paste_clipboard (
WEBKIT_WEB_VIEW (view->web_view));
return view->can_paste_clipboard;
}
return FALSE;
}
/**
* midori_view_get_proxy_menu_item:
* @view: a #MidoriView
*
* Retrieves a proxy menu item that is typically added to a Window menu
* and which on activation switches to the right window/ tab.
*
* The item is created on the first call and will be updated to reflect
* changes to the icon and title automatically.
*
* The menu item is valid until it is removed from its container.
*
* Return value: the proxy #GtkMenuItem
**/
GtkWidget*
midori_view_get_proxy_menu_item (MidoriView* view)
{
const gchar* title;
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
if (!view->menu_item)
{
title = midori_view_get_display_title (view);
view->menu_item = sokoke_image_menu_item_new_ellipsized (title);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (view->menu_item),
gtk_image_new_from_pixbuf (view->icon));
g_signal_connect (view->menu_item, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&view->menu_item);
}
return view->menu_item;
}
static gboolean
midori_view_tab_label_button_release_event (GtkWidget* tab_label,
GdkEventButton* event,
GtkWidget* widget)
{
if (event->button == 2)
{
/* Close the widget on middle click */
gtk_widget_destroy (widget);
return TRUE;
}
return FALSE;
}
static void
midori_view_tab_icon_style_set (GtkWidget* tab_icon,
GtkStyle* previous_style)
{
GtkSettings* gtk_settings;
gint width, height;
gtk_settings = gtk_widget_get_settings (tab_icon);
gtk_icon_size_lookup_for_settings (gtk_settings, GTK_ICON_SIZE_MENU,
&width, &height);
gtk_widget_set_size_request (tab_icon, width + 2, height + 2);
}
static void
midori_view_tab_close_clicked (GtkWidget* tab_close,
GtkWidget* widget)
{
gtk_widget_destroy (widget);
}
/**
* midori_view_get_proxy_tab_label:
* @view: a #MidoriView
*
* Retrieves a proxy tab label that is typically used when
* adding the view to a notebook.
*
* The label is created on the first call and will be updated to reflect
* changes of the loading progress and title.
*
* The label is valid until it is removed from its container.
*
* Return value: the proxy #GtkEventBox
**/
GtkWidget*
midori_view_get_proxy_tab_label (MidoriView* view)
{
GtkWidget* event_box;
GtkWidget* hbox;
GtkRcStyle* rcstyle;
GtkWidget* image;
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
if (!view->tab_label)
{
view->tab_icon = katze_throbber_new ();
katze_throbber_set_static_pixbuf (KATZE_THROBBER (view->tab_icon),
midori_view_get_icon (view));
view->tab_title = gtk_label_new (midori_view_get_display_title (view));
event_box = gtk_event_box_new ();
gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
hbox = gtk_hbox_new (FALSE, 1);
gtk_container_border_width (GTK_CONTAINER (hbox), 2);
gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (hbox));
gtk_misc_set_alignment (GTK_MISC (view->tab_icon), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (hbox), view->tab_icon, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (view->tab_title), 0.0, 0.5);
/* TODO: make the tab initially look "unvisited" until it's focused */
gtk_box_pack_start (GTK_BOX (hbox), view->tab_title, FALSE, TRUE, 0);
_update_label_size (view->tab_title, 10);
view->tab_close = gtk_button_new ();
gtk_button_set_relief (GTK_BUTTON (view->tab_close), GTK_RELIEF_NONE);
gtk_button_set_focus_on_click (GTK_BUTTON (view->tab_close), FALSE);
rcstyle = gtk_rc_style_new ();
rcstyle->xthickness = rcstyle->ythickness = 0;
gtk_widget_modify_style (view->tab_close, rcstyle);
g_object_unref (rcstyle);
image = katze_throbber_new ();
katze_throbber_set_static_stock_id (KATZE_THROBBER (image),
GTK_STOCK_CLOSE);
gtk_button_set_image (GTK_BUTTON (view->tab_close), image);
gtk_misc_set_alignment (GTK_MISC (image), 0.0, 0.0);
gtk_box_pack_end (GTK_BOX (hbox), view->tab_close, FALSE, FALSE, 0);
gtk_widget_show_all (GTK_WIDGET (event_box));
if (view->settings &&
!sokoke_object_get_boolean (view->settings, "close-buttons-on-tabs"))
gtk_widget_hide (view->tab_close);
g_signal_connect (event_box, "button-release-event",
G_CALLBACK (midori_view_tab_label_button_release_event), view);
g_signal_connect (view->tab_close, "style-set",
G_CALLBACK (midori_view_tab_icon_style_set), NULL);
g_signal_connect (view->tab_close, "clicked",
G_CALLBACK (midori_view_tab_close_clicked), view);
view->tab_label = event_box;
g_signal_connect (view->tab_label, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&view->tab_label);
}
return view->tab_label;
}
/**
* midori_view_get_proxy_item:
* @view: a #MidoriView
*
* Retrieves a proxy item that can be used for bookmark storage as
* well as session management.
*
* The item is created on the first call and will be updated to reflect
* changes to the title and uri automatically.
*
* Return value: the proxy #KatzeItem
**/
KatzeItem*
midori_view_get_proxy_item (MidoriView* view)
{
const gchar* uri;
const gchar* title;
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
if (!view->item)
{
view->item = katze_item_new ();
uri = midori_view_get_display_uri (view);
katze_item_set_uri (view->item, uri);
title = midori_view_get_display_title (view);
katze_item_set_name (view->item, title);
}
return view->item;
}
/**
* midori_view_get_zoom_level:
* @view: a #MidoriView
*
* Determines the current zoom level of the view.
*
* Return value: the current zoom level
**/
gfloat
midori_view_get_zoom_level (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), 1.0);
if (midori_view_is_socket (view))
return view->zoom_level;
else if (view->web_view)
return webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (view->web_view));
return FALSE;
}
/**
* midori_view_set_zoom_level:
* @view: a #MidoriView
* @zoom_level: the new zoom level
*
* Sets the current zoom level of the view.
**/
void
midori_view_set_zoom_level (MidoriView* view,
gfloat zoom_level)
{
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
send_command (view, "set-zoom-level", float_to_str (zoom_level));
else
webkit_web_view_set_zoom_level (
WEBKIT_WEB_VIEW (view->web_view), zoom_level);
}
#define can_do(what) \
gboolean \
midori_view_can_##what (MidoriView* view) \
{ \
g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE); \
\
return view->socket_id > -1; \
}
can_do (zoom_in)
can_do (zoom_out)
can_do (reload)
can_do (print)
#if HAVE_GIO
can_do (view_source)
#else
gboolean midori_view_can_view_source (MidoriView* view)
{
return FALSE;
}
#endif
can_do (find)
/**
* midori_view_reload:
* @view: a #MidoriView
* @from_cache: whether to allow caching
*
* Reloads the view.
*
* Note: The @from_cache value is currently ignored.
**/
void
midori_view_reload (MidoriView* view,
gboolean from_cache)
{
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
send_command (view, "reload", int_to_str (from_cache));
else
webkit_web_view_reload (WEBKIT_WEB_VIEW (view->web_view));
}
/**
* midori_view_stop_loading
* @view: a #MidoriView
*
* Stops loading the view if it is currently loading.
**/
void
midori_view_stop_loading (MidoriView* view)
{
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
send_command (view, "stop-loading", NULL);
else
webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (view->web_view));
}
/**
* midori_view_can_go_back
* @view: a #MidoriView
*
* Determines whether the view can go back.
**/
gboolean
midori_view_can_go_back (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
if (midori_view_is_socket (view))
return view->can_go_back;
else if (view->web_view)
return webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (view->web_view));
else
return FALSE;
}
/**
* midori_view_go_back
* @view: a #MidoriView
*
* Goes back one page in the view.
**/
void
midori_view_go_back (MidoriView* view)
{
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
send_command (view, "go-back", NULL);
else
webkit_web_view_go_back (WEBKIT_WEB_VIEW (view->web_view));
}
/**
* midori_view_can_go_forward
* @view: a #MidoriView
*
* Determines whether the view can go forward.
**/
gboolean
midori_view_can_go_forward (MidoriView* view)
{
g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
if (midori_view_is_socket (view))
return view->can_go_forward;
else if (view->web_view)
return webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (view->web_view));
else
return FALSE;
}
/**
* midori_view_go_forward
* @view: a #MidoriView
*
* Goes forward one page in the view.
**/
void
midori_view_go_forward (MidoriView* view)
{
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
send_command (view, "go-forward", NULL);
else
webkit_web_view_go_forward (WEBKIT_WEB_VIEW (view->web_view));
}
/**
* midori_view_print
* @view: a #MidoriView
*
* Prints the contents of the view.
**/
void
midori_view_print (MidoriView* view)
{
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
send_command (view, "print", NULL);
else
webkit_web_view_execute_script (
WEBKIT_WEB_VIEW (view->web_view), "print();");
}
/**
* midori_view_unmark_text_matches
* @view: a #MidoriView
*
* Unmarks the text matches in the view.
**/
void
midori_view_unmark_text_matches (MidoriView* view)
{
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
send_command (view, "unmark-matches", NULL);
else
webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (view->web_view));
}
/**
* midori_view_search_text
* @view: a #MidoriView
* @text: a string
* @case_sensitive: case sensitivity
* @forward: whether to search forward
*
* Searches a text within the view.
**/
void
midori_view_search_text (MidoriView* view,
const gchar* text,
gboolean case_sensitive,
gboolean forward)
{
gchar* data;
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
{
/* (text, case_sensitive, forward) => (forward, case_sensitive, text) */
data = g_strdup_printf ("%d %d %s", forward, case_sensitive, text);
send_command (view, "search-text", data);
g_free (data);
}
else
g_signal_emit (view, signals[SEARCH_TEXT], 0,
webkit_web_view_search_text (WEBKIT_WEB_VIEW (view->web_view),
text, case_sensitive, forward, TRUE));
}
/**
* midori_view_mark_text_matches
* @view: a #MidoriView
* @text: a string
* @case_sensitive: case sensitivity
*
* Marks all text matches within the view.
**/
void
midori_view_mark_text_matches (MidoriView* view,
const gchar* text,
gboolean case_sensitive)
{
gchar* data;
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
{
/* (text, case_sensitive) => (case_sensitive, text) */
data = g_strdup_printf ("%d %s", case_sensitive, text);
send_command (view, "mark-matches", data);
g_free (data);
}
else
webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW (view->web_view),
text, case_sensitive, 0);
}
/**
* midori_view_set_highlight_text_matches
* @view: a #MidoriView
* @highlight: whether to highlight matches
*
* Whether to highlight all matches within the view.
**/
void
midori_view_set_highlight_text_matches (MidoriView* view,
gboolean highlight)
{
g_return_if_fail (MIDORI_IS_VIEW (view));
if (midori_view_is_socket (view))
send_command (view, "hl-matches", int_to_str (highlight));
else
webkit_web_view_set_highlight_text_matches (
WEBKIT_WEB_VIEW (view->web_view), highlight);
}