Imported Upstream version 0.1.8

This commit is contained in:
Ryan Niebur 2009-07-30 14:00:35 -07:00
parent add65b5191
commit 646f964fae
81 changed files with 21257 additions and 8570 deletions

View file

@ -48,6 +48,7 @@ Translations:
hu: SZERVÁC Attila <sas@321.hu> hu: SZERVÁC Attila <sas@321.hu>
id: Andhika Padmawan <andhika.padmawan@gmail.com> id: Andhika Padmawan <andhika.padmawan@gmail.com>
it: Sergio Durzu <sergio.durzu@ildeposito.org> it: Sergio Durzu <sergio.durzu@ildeposito.org>
it: Luca Perri <kurama_luka@yahoo.it>
ja: Masato Hashimoto <cabezon.hashimoto@gmail.com> ja: Masato Hashimoto <cabezon.hashimoto@gmail.com>
nl: Vincent Tunru <projects@vinnl.nl> nl: Vincent Tunru <projects@vinnl.nl>
pl: Przemysław Sitek <el.pescado@gazeta.pl> pl: Przemysław Sitek <el.pescado@gazeta.pl>
@ -58,8 +59,10 @@ Translations:
ru: Troitskiy Nikita <niktr@mail.ru> ru: Troitskiy Nikita <niktr@mail.ru>
ru: Anton Shestakov <engored@ya.ru> ru: Anton Shestakov <engored@ya.ru>
sk: Robert Hartl <hartl.robert@gmail.com> sk: Robert Hartl <hartl.robert@gmail.com>
sr: Miloš Popović <gpopac@gmail.com>
sv: Mikael Magnusson <mikachu@comhem.se> sv: Mikael Magnusson <mikachu@comhem.se>
tr: Mirat Can Bayrak <MiratCanBayrak@gmail.com> tr: Mirat Can Bayrak <MiratCanBayrak@gmail.com>
tr: Gökmen Görgen <gkmngrgn@gmail.com>
uk: Dmitry Nikitin <luckas_fb@mail.ru> uk: Dmitry Nikitin <luckas_fb@mail.ru>
zh_CN: Stanley Zhang <yatzhang@gmail.com> zh_CN: Stanley Zhang <yatzhang@gmail.com>
zh_TW: Wei-Lun Chao <william.chao@ossii.com.tw> zh_TW: Wei-Lun Chao <william.chao@ossii.com.tw>
@ -67,5 +70,7 @@ Translations:
Code from other projects: Code from other projects:
GTK+/ GdkPixbuf, Matthias Clasen <mclasen@redhat.com> GTK+/ GdkPixbuf, Matthias Clasen <mclasen@redhat.com>
GTK+/ GtkEntry, Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald GTK+/ GtkEntry, Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
GTK+/ GtkToolbar, Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GTK+ Team and others 1997-2000 Modified by the GTK+ Team and others 1997-2000
libSoup/ CookieJarText, Copyright (C) 2008 Xan Lopez <xan@gnome.org>, Dan Winship <danw@gnome.org> libSoup/ CookieJarText, Copyright (C) 2008 Xan Lopez <xan@gnome.org>, Dan Winship <danw@gnome.org>
libSylph, Copyright 1999-2008 Hiroyuki Yamamoto, Copyright 2006-2009 Enrico Tröger <enrico.troeger@uvena.de>

View file

@ -1,5 +1,33 @@
This file is licensed under the terms of the expat license, see the file EXPAT. This file is licensed under the terms of the expat license, see the file EXPAT.
v0.1.8:
+ Initial support for extension unit tests
+ Set a "browser" role on browser windows
+ Support typing search tokens to open websites
+ Fix focus loss when switching search engines
+ Rewrite Netscape Plugins panel backed by javascript
+ Implement a compact menu if menubar is hidden
+ Provide a context menu for tab labels
+ Implement Tab Panel as a tabbar replacement
+ Remember the last active tab
+ Read and write XBEL metadata internally
+ Implement -e, --execute to perform commands
+ Support socket based single instance
+ Move Go button inside the location entry
+ Fix the ident string after Midori updates
+ Bind Alt + n to switching to the n-th tab
+ Revisit conflicting mnemonics
+ Add a Toolbar Editor extension
+ Add a Shortcut Editor extension
+ Implement context menu in the Transfers panel
+ Simplified Extensions and Addons panels with tick marks
+ Fix Mouse Gestures often ignoreing gestures
+ Use one cookie manager model in all windows
+ Support building Midori for Win32
+ Add an entry to specify Fixed-Width font size
+ Implement Save As in the download dialog
+ Use one history model in all windows
v0.1.7: v0.1.7:
+ Save the activation status of extensions + Save the activation status of extensions
+ Catch and ignore mouse buttons meant for horizontal scrolling + Catch and ignore mouse buttons meant for horizontal scrolling

4
TODO
View file

@ -18,17 +18,13 @@ TODO:
. Have an internal uri scheme, eg. 'res:', to reference eg. themed icons . Have an internal uri scheme, eg. 'res:', to reference eg. themed icons
. 'about:' uris: about, blank, cache, config, plugins . 'about:' uris: about, blank, cache, config, plugins
. Panel of open tabs (with tree-structure), optional thumbnail-view . Panel of open tabs (with tree-structure), optional thumbnail-view
. Spell check support
. Check specific bookmarks for updates automatically (extension) . Check specific bookmarks for updates automatically (extension)
. Mark "new" as well as "actually modified" tabs specially (even over sessions) . Mark "new" as well as "actually modified" tabs specially (even over sessions)
. SearchEngine: "Show in context menu" . SearchEngine: "Show in context menu"
. Use libnotify for events, e.g. download finished
. Save screenshot of a document? . Save screenshot of a document?
. Right-click a textbox in a search form and choose 'add to websearch' . Right-click a textbox in a search form and choose 'add to websearch'
. Honor design principle "no warnings but undo of backups"? . Honor design principle "no warnings but undo of backups"?
. Support widgets 1.0 spec in tool windows and standalone? . Support widgets 1.0 spec in tool windows and standalone?
. Blank page: several custom links, displayed as thumbnails, like Opera?
. Handle downloads, optionally in a downloadbar
. Protected tabs prompt when attempting to close them . Protected tabs prompt when attempting to close them
. Provide a 'sleep mode' after a crash where open documents are loaded manually . Provide a 'sleep mode' after a crash where open documents are loaded manually
. Option to run plugins or scripts only on demand, like NoScript, per-site . Option to run plugins or scripts only on demand, like NoScript, per-site

2
data/midori.rc Normal file
View file

@ -0,0 +1,2 @@
IDR_MAINFRAME ICON DISCARDABLE "../_build_/default/data/midori.ico"

View file

@ -235,10 +235,6 @@
var a = cross.getNext (); var a = cross.getNext ();
var p = a.getNext (); var p = a.getNext ();
cross.dispose ();
div.removeClass ('activated');
a.empty ();
cross.dispose (); cross.dispose ();
div.removeClass ('activated'); div.removeClass ('activated');
a.empty ().set ('html', '<h1>' + num + '</h1><h4><span/></h4>'); a.empty ().set ('html', '<h1>' + num + '</h1><h4><span/></h4>');

View file

@ -3,6 +3,7 @@
# This file is licensed under the terms of the expat license, see the file EXPAT. # This file is licensed under the terms of the expat license, see the file EXPAT.
import pproc as subprocess import pproc as subprocess
import os
for module in ('midori', 'katze'): for module in ('midori', 'katze'):
try: try:

View file

@ -15,6 +15,9 @@
#include "config.h" #include "config.h"
#include <glib/gstdio.h> #include <glib/gstdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
static void static void
adblock_app_add_browser_cb (MidoriApp* app, adblock_app_add_browser_cb (MidoriApp* app,
@ -36,17 +39,64 @@ adblock_deactivate_cb (MidoriExtension* extension,
} }
static void static void
adblock_preferences_render_text (GtkTreeViewColumn* column, adblock_preferences_renderer_text_edited_cb (GtkCellRenderer* renderer,
GtkCellRenderer* renderer, const gchar* tree_path,
GtkTreeModel* model, const gchar* new_text,
GtkTreeIter* iter, GtkTreeModel* model)
MidoriExtension* extension)
{ {
gchar* uri; GtkTreeIter iter;
gtk_tree_model_get (model, iter, 0, &uri, -1); if (gtk_tree_model_get_iter_from_string (model, &iter, tree_path))
g_object_set (renderer, "text", uri, NULL); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, new_text, -1);
g_free (uri); }
static void
adblock_preferences_model_row_changed_cb (GtkTreeModel* model,
GtkTreePath* path,
GtkTreeIter* iter,
MidoriExtension* extension)
{
gsize length = gtk_tree_model_iter_n_children (model, NULL);
gchar** filters = g_new (gchar*, length + 1);
guint i = 0;
if (gtk_tree_model_iter_children (model, iter, NULL))
do
{
gchar* filter;
gtk_tree_model_get (model, iter, 0, &filter, -1);
filters[i++] = filter;
}
while (gtk_tree_model_iter_next (model, iter));
filters[length] = NULL;
midori_extension_set_string_list (extension, "filters", filters, length);
}
static void
adblock_preferences_model_row_deleted_cb (GtkTreeModel* model,
GtkTreePath* path,
MidoriExtension* extension)
{
GtkTreeIter iter;
adblock_preferences_model_row_changed_cb (model, path, &iter, extension);
}
static void
adblock_preferences_add_clicked_cb (GtkWidget* button,
GtkTreeModel* model)
{
gtk_list_store_insert_with_values (GTK_LIST_STORE (model),
NULL, 0, 0, "", -1);
}
static void
adblock_preferences_remove_clicked_cb (GtkWidget* button,
GtkTreeView* treeview)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
} }
static GtkWidget* static GtkWidget*
@ -102,19 +152,26 @@ adblock_get_preferences_dialog (MidoriExtension* extension)
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
TRUE, TRUE, 12); TRUE, TRUE, 12);
liststore = gtk_list_store_new (1, G_TYPE_STRING); liststore = gtk_list_store_new (1, G_TYPE_STRING);
g_object_connect (liststore,
"signal::row-inserted",
adblock_preferences_model_row_changed_cb, extension,
"signal::row-changed",
adblock_preferences_model_row_changed_cb, extension,
"signal::row-deleted",
adblock_preferences_model_row_deleted_cb, extension,
NULL);
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore)); treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
column = gtk_tree_view_column_new (); column = gtk_tree_view_column_new ();
renderer_pixbuf = gtk_cell_renderer_pixbuf_new (); renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE); gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
/* gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf,
(GtkTreeCellDataFunc)adblock_preferences_render_icon_cb,
treeview, NULL); */
renderer_text = gtk_cell_renderer_text_new (); renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, TRUE); gtk_tree_view_column_pack_start (column, renderer_text, TRUE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text, gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer_text,
(GtkTreeCellDataFunc)adblock_preferences_render_text, "text", 0, NULL);
extension, NULL); g_object_set (renderer_text, "editable", TRUE, NULL);
g_signal_connect (renderer_text, "edited",
G_CALLBACK (adblock_preferences_renderer_text_edited_cb), liststore);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
scrolled = gtk_scrolled_window_new (NULL, NULL); scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
@ -138,18 +195,16 @@ adblock_get_preferences_dialog (MidoriExtension* extension)
vbox = gtk_vbox_new (FALSE, 4); vbox = gtk_vbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 4); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 4);
button = gtk_button_new_from_stock (GTK_STOCK_ADD); button = gtk_button_new_from_stock (GTK_STOCK_ADD);
/* g_signal_connect (button, "clicked", g_signal_connect (button, "clicked",
G_CALLBACK (adblock_preferences_add_cb), extension); */ G_CALLBACK (adblock_preferences_add_clicked_cb), liststore);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_set_sensitive (button, FALSE);
button = gtk_button_new_from_stock (GTK_STOCK_EDIT); button = gtk_button_new_from_stock (GTK_STOCK_EDIT);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_set_sensitive (button, FALSE); gtk_widget_set_sensitive (button, FALSE);
button = gtk_button_new_from_stock (GTK_STOCK_REMOVE); button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
/* g_signal_connect (button, "clicked", g_signal_connect (button, "clicked",
G_CALLBACK (adblock_preferences_remove_cb), extension); */ G_CALLBACK (adblock_preferences_remove_clicked_cb), treeview);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_set_sensitive (button, FALSE);
button = gtk_label_new (""); /* This is an invisible separator */ button = gtk_label_new (""); /* This is an invisible separator */
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 8); gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 8);
gtk_widget_set_sensitive (button, FALSE); gtk_widget_set_sensitive (button, FALSE);
@ -223,14 +278,22 @@ adblock_app_add_browser_cb (MidoriApp* app,
G_CALLBACK (adblock_deactivate_cb), menuitem); G_CALLBACK (adblock_deactivate_cb), menuitem);
} }
static gboolean
adblock_is_matched (const gchar* pattern,
const GRegex* regex,
const gchar* uri)
{
return g_regex_match_full (regex, uri, -1, 0, 0, NULL, NULL);
}
static void static void
adblock_session_request_queued_cb (SoupSession* session, adblock_session_request_queued_cb (SoupSession* session,
SoupMessage* msg, SoupMessage* msg,
GRegex* regex) GHashTable* pattern)
{ {
SoupURI* soup_uri = soup_message_get_uri (msg); SoupURI* soup_uri = soup_message_get_uri (msg);
gchar* uri = soup_uri ? soup_uri_to_string (soup_uri, FALSE) : g_strdup (""); gchar* uri = soup_uri ? soup_uri_to_string (soup_uri, FALSE) : g_strdup ("");
if (g_regex_match_full (regex, uri, -1, 0, 0, NULL, NULL)) if (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched, uri))
{ {
/* g_debug ("match! '%s'", uri); */ /* g_debug ("match! '%s'", uri); */
/* FIXME: This leads to funny error pages if frames are blocked */ /* FIXME: This leads to funny error pages if frames are blocked */
@ -239,60 +302,77 @@ adblock_session_request_queued_cb (SoupSession* session,
g_free (uri); g_free (uri);
} }
static void static gchar*
adblock_session_add_filter (SoupSession* session, adblock_parse_line (gchar* line)
gchar* path) {
if (!line)
return NULL;
/* Ignore comments and new lines */
if (line[0] == '!')
return NULL;
/* FIXME: No support for whitelisting */
if (line[0] == '@' && line[1] == '@')
return NULL;
/* FIXME: Differentiate # comments from element hiding */
/* FIXME: No support for element hiding */
if (line[0] == '#' && line[1] == '#')
return NULL;
/* FIXME: No support for [include] and [exclude] tags */
if (line[0] == '[')
return NULL;
g_strchomp (line);
/* TODO: Replace trailing '*' with '.*' */
if (line[0] == '*')
return g_strconcat (".", line, NULL);
else if (line[0] == '?')
return g_strconcat ("\\", line, NULL);
return g_strdup (line);
}
static GHashTable*
adblock_parse_file (gchar* path)
{ {
FILE* file; FILE* file;
if ((file = g_fopen (path, "r"))) if ((file = g_fopen (path, "r")))
{ {
/* We assume filter lists found on the web are commonly very long */ GHashTable* pattern = g_hash_table_new_full (g_str_hash, g_str_equal,
GString* pattern = g_string_sized_new (1000 * 200); (GDestroyNotify)g_free,
(GDestroyNotify)g_regex_unref);
gboolean have_pattern = FALSE;
gchar line[255]; gchar line[255];
GRegex* regex; GRegex* regex;
GError* error;
while (fgets (line, 255, file)) while (fgets (line, 255, file))
{ {
/* Ignore comments and new lines */ GError* error = NULL;
if (line[0] == '!') gchar* parsed;
continue;
/* FIXME: No support for whitelisting */
if (line[0] == '@' && line[1] == '@')
continue;
/* FIXME: Differentiate # comments from element hiding */
/* FIXME: No support for element hiding */
if (line[0] == '#' && line[1] == '#')
continue;
/* FIXME: No support for [include] and [exclude] tags */
if (line[0] == '[')
continue;
g_strchomp (line);
g_string_append (pattern, line);
g_string_append_c (pattern, '|');
}
error = NULL; parsed = adblock_parse_line (line);
if (pattern->len > 2 && regex = g_regex_new (parsed, G_REGEX_OPTIMIZE,
(regex = g_regex_new (pattern->str, G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, &error);
G_REGEX_MATCH_NOTEMPTY, &error))) if (error)
{ {
/* g_debug ("%s: '%s'", G_STRFUNC, pattern->str); */ g_warning ("%s: %s", G_STRFUNC, error->message);
g_signal_connect_data (session, "request-queued", g_error_free (error);
G_CALLBACK (adblock_session_request_queued_cb), g_free (parsed);
regex, (GClosureNotify)g_regex_unref, 0); }
else
{
have_pattern = TRUE;
g_hash_table_insert (pattern, parsed, regex);
}
} }
else if (error)
{
/* g_warning ("%s: %s", G_STRFUNC, error->message); */
g_error_free (error);
}
g_string_free (pattern, TRUE);
fclose (file); fclose (file);
if (have_pattern)
return pattern;
} }
/* FIXME: This should presumably be freed, but there's a possible crash /* FIXME: This should presumably be freed, but there's a possible crash
g_free (path); */ g_free (path); */
return NULL;
} }
#if WEBKIT_CHECK_VERSION (1, 1, 3) #if WEBKIT_CHECK_VERSION (1, 1, 3)
@ -302,7 +382,11 @@ adblock_download_notify_status_cb (WebKitDownload* download,
gchar* path) gchar* path)
{ {
SoupSession* session = webkit_get_default_session (); SoupSession* session = webkit_get_default_session ();
adblock_session_add_filter (session, path); GHashTable* pattern = adblock_parse_file (path);
if (pattern)
g_signal_connect_data (session, "request-queued",
G_CALLBACK (adblock_session_request_queued_cb),
pattern, (GClosureNotify)g_hash_table_destroy, 0);
/* g_object_unref (download); */ /* g_object_unref (download); */
} }
#endif #endif
@ -359,7 +443,13 @@ adblock_activate_cb (MidoriExtension* extension,
#endif #endif
} }
else else
adblock_session_add_filter (session, path); {
GHashTable* pattern = adblock_parse_file (path);
if (pattern)
g_signal_connect_data (session, "request-queued",
G_CALLBACK (adblock_session_request_queued_cb),
pattern, (GClosureNotify)g_hash_table_destroy, 0);
}
g_free (filename); g_free (filename);
} }
} }
@ -367,6 +457,68 @@ adblock_activate_cb (MidoriExtension* extension,
g_free (folder); g_free (folder);
} }
#if G_ENABLE_DEBUG
static void
test_adblock_parse (void)
{
g_assert (!adblock_parse_line (NULL));
g_assert (!adblock_parse_line ("!"));
g_assert (!adblock_parse_line ("@@"));
g_assert (!adblock_parse_line ("##"));
g_assert (!adblock_parse_line ("["));
g_assert_cmpstr (adblock_parse_line ("*foo"), ==, ".*foo");
g_assert_cmpstr (adblock_parse_line ("?foo"), ==, "\\?foo");
/* g_assert_cmpstr (adblock_parse_line ("foo*"), ==, "foo.*");
g_assert_cmpstr (adblock_parse_line ("foo?"), ==, "foo\\?"); */
g_assert_cmpstr (adblock_parse_line (".*foo/bar"), ==, ".*foo/bar");
g_assert_cmpstr (adblock_parse_line ("http://bla.blub/.*"), ==, "http://bla.blub/.*");
}
static void
test_adblock_pattern (void)
{
gint temp;
gchar* filename;
GHashTable* pattern;
temp = g_file_open_tmp ("midori_adblock_match_test_XXXXXX", &filename, NULL);
g_file_set_contents (filename,
"*ads.foo.bar.*\n"
".*ads.bogus.name.*\n"
"http://ads.bla.blub/.*\n"
"http://ads.blub.boing/*.",
-1, NULL);
pattern = adblock_parse_file (filename);
g_assert (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched,
"http://ads.foo.bar/teddy"));
g_assert (!g_hash_table_find (pattern, (GHRFunc) adblock_is_matched,
"http://ads.fuu.bar/teddy"));
g_assert (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched,
"https://ads.bogus.name/blub"));
g_assert (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched,
"http://ads.bla.blub/kitty"));
g_assert (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched,
"http://ads.blub.boing/soda"));
g_assert (!g_hash_table_find (pattern, (GHRFunc) adblock_is_matched,
"http://ads.foo.boing/beer"));
g_hash_table_destroy (pattern);
close (temp);
g_unlink (filename);
}
void
extension_test (void)
{
g_test_add_func ("/extensions/adblock/parse", test_adblock_parse);
g_test_add_func ("/extensions/adblock/pattern", test_adblock_pattern);
}
#endif
MidoriExtension* MidoriExtension*
extension_init (void) extension_init (void)
{ {

View file

@ -72,7 +72,7 @@ static void
colorful_tabs_button_toggled_cb (GtkWidget* button, colorful_tabs_button_toggled_cb (GtkWidget* button,
MidoriExtension* extension) MidoriExtension* extension)
{ {
MidoriBrowser* browser = MIDORI_BROWSER (gtk_widget_get_toplevel (button)); MidoriBrowser* browser = midori_browser_get_for_widget (button);
midori_extension_set_boolean (extension, "tint", midori_extension_set_boolean (extension, "tint",
!midori_extension_get_boolean (extension, "tint")); !midori_extension_get_boolean (extension, "tint"));
@ -96,7 +96,7 @@ colorful_tabs_deactivate_cb (MidoriExtension* extension,
g_signal_handlers_disconnect_by_func ( g_signal_handlers_disconnect_by_func (
extension, colorful_tabs_deactivate_cb, bbox); extension, colorful_tabs_deactivate_cb, bbox);
/* FIXME: Disconnect signals */ /* FIXME: Disconnect signals */
midori_browser_foreach (MIDORI_BROWSER (gtk_widget_get_toplevel (bbox)), midori_browser_foreach (midori_browser_get_for_widget (bbox),
(GtkCallback)colorful_tabs_browser_foreach_cb, extension); (GtkCallback)colorful_tabs_browser_foreach_cb, extension);
gtk_widget_destroy (bbox); gtk_widget_destroy (bbox);
} }

View file

@ -28,22 +28,17 @@ typedef struct _CookieManagerPagePrivate CookieManagerPagePrivate;
#define CM_EMPTY_LABEL_TEXT "\n\n\n\n\n\n" #define CM_EMPTY_LABEL_TEXT "\n\n\n\n\n\n"
enum
{
COOKIE_MANAGER_COL_NAME,
COOKIE_MANAGER_COL_COOKIE,
COOKIE_MANAGER_COL_VISIBLE,
COOKIE_MANAGER_N_COLUMNS
};
struct _CookieManagerPagePrivate struct _CookieManagerPagePrivate
{ {
CookieManager *parent;
GtkWidget *treeview; GtkWidget *treeview;
GtkTreeStore *store; GtkTreeStore *store;
GtkTreeModel *filter; GtkTreeModel *filter;
GtkWidget *filter_entry; GtkWidget *filter_entry;
gboolean ignore_changed_filter;
GtkWidget *desc_label; GtkWidget *desc_label;
GtkWidget *delete_button; GtkWidget *delete_button;
@ -53,11 +48,13 @@ struct _CookieManagerPagePrivate
GtkWidget *toolbar; GtkWidget *toolbar;
GtkWidget *popup_menu; GtkWidget *popup_menu;
};
GSList *cookies; enum
SoupCookieJar *jar; {
guint timer_id; PROP_0,
gint ignore_changed_count; PROP_STORE,
PROP_PARENT
}; };
@ -69,7 +66,6 @@ static void cm_button_delete_all_clicked_cb(GtkToolButton *button, CookieManager
static void cm_tree_popup_collapse_activate_cb(GtkMenuItem *item, CookieManagerPage *cmp); static void cm_tree_popup_collapse_activate_cb(GtkMenuItem *item, CookieManagerPage *cmp);
static void cm_tree_popup_expand_activate_cb(GtkMenuItem *item, CookieManagerPage *cmp); static void cm_tree_popup_expand_activate_cb(GtkMenuItem *item, CookieManagerPage *cmp);
static void cm_filter_tree(CookieManagerPage *cmp, const gchar *filter_text); static void cm_filter_tree(CookieManagerPage *cmp, const gchar *filter_text);
static void cm_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new, CookieManagerPage *cmp);
G_DEFINE_TYPE_WITH_CODE(CookieManagerPage, cookie_manager_page, GTK_TYPE_VBOX, G_DEFINE_TYPE_WITH_CODE(CookieManagerPage, cookie_manager_page, GTK_TYPE_VBOX,
@ -90,22 +86,6 @@ static const gchar *cookie_manager_page_get_stock_id(MidoriViewable *viewable)
} }
static void cm_free_cookie_list(CookieManagerPage *cmp)
{
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
if (priv->cookies != NULL)
{
GSList *l;
for (l = priv->cookies; l != NULL; l = g_slist_next(l))
soup_cookie_free(l->data);
g_slist_free(priv->cookies);
priv->cookies = NULL;
}
}
static void cm_create_toolbar(CookieManagerPage *cmp) static void cm_create_toolbar(CookieManagerPage *cmp)
{ {
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp); CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
@ -174,73 +154,19 @@ static void cookie_manager_page_viewable_iface_init(MidoriViewableIface* iface)
} }
static void cookie_manager_page_finalize(GObject *object) static void cookie_manager_page_pre_cookies_change_cb(CookieManager *cm, CookieManagerPage *cmp)
{ {
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(object);
g_signal_handlers_disconnect_by_func(priv->jar, cm_jar_changed_cb, object);
if (priv->timer_id > 0)
g_source_remove(priv->timer_id);
cm_free_cookie_list(COOKIE_MANAGER_PAGE(object));
gtk_widget_destroy(priv->popup_menu);
G_OBJECT_CLASS(cookie_manager_page_parent_class)->finalize(object);
}
static void cm_refresh_store(CookieManagerPage *cmp)
{
GSList *l;
GHashTable *parents;
GtkTreeIter iter;
GtkTreeIter *parent_iter;
SoupCookie *cookie;
const gchar *filter_text;
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp); CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
g_object_ref(priv->filter); g_object_ref(priv->filter);
gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), NULL); gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), NULL);
}
gtk_tree_store_clear(priv->store);
/* free the old list */ static void cookie_manager_page_cookies_changed_cb(CookieManager *cm, CookieManagerPage *cmp)
cm_free_cookie_list(cmp); {
const gchar *filter_text;
priv->cookies = soup_cookie_jar_all_cookies(priv->jar); CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
/* Hashtable holds domain names as keys, the corresponding tree iters as values */
parents = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
for (l = priv->cookies; l != NULL; l = g_slist_next(l))
{
cookie = l->data;
/* look for the parent item for the current domain name and create it if it doesn't exist */
if ((parent_iter = (GtkTreeIter*) g_hash_table_lookup(parents, cookie->domain)) == NULL)
{
parent_iter = g_new0(GtkTreeIter, 1);
gtk_tree_store_append(priv->store, parent_iter, NULL);
gtk_tree_store_set(priv->store, parent_iter,
COOKIE_MANAGER_COL_NAME, cookie->domain,
COOKIE_MANAGER_COL_COOKIE, NULL,
COOKIE_MANAGER_COL_VISIBLE, TRUE,
-1);
g_hash_table_insert(parents, g_strdup(cookie->domain), parent_iter);
}
gtk_tree_store_append(priv->store, &iter, parent_iter);
gtk_tree_store_set(priv->store, &iter,
COOKIE_MANAGER_COL_NAME, cookie->name,
COOKIE_MANAGER_COL_COOKIE, cookie,
COOKIE_MANAGER_COL_VISIBLE, TRUE,
-1);
}
g_hash_table_destroy(parents);
gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter)); gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter));
g_object_unref(priv->filter); g_object_unref(priv->filter);
@ -255,32 +181,78 @@ static void cm_refresh_store(CookieManagerPage *cmp)
} }
static gboolean cm_delayed_refresh(CookieManagerPage *cmp) static void cookie_manager_page_filter_changed_cb(CookieManager *cm, const gchar *text,
CookieManagerPage *cmp)
{ {
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp); CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
cm_refresh_store(cmp); priv->ignore_changed_filter = TRUE;
priv->timer_id = 0; gtk_entry_set_text(GTK_ENTRY(priv->filter_entry), text);
priv->ignore_changed_filter = FALSE;
return FALSE;
} }
static void cm_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new, static void cookie_manager_page_finalize(GObject *object)
CookieManagerPage *cmp)
{ {
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp); CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(object);
if (priv->ignore_changed_count > 0) gtk_widget_destroy(priv->popup_menu);
g_signal_handlers_disconnect_by_func(priv->parent,
cookie_manager_page_pre_cookies_change_cb, object);
g_signal_handlers_disconnect_by_func(priv->parent,
cookie_manager_page_cookies_changed_cb, object);
g_signal_handlers_disconnect_by_func(priv->parent,
cookie_manager_page_filter_changed_cb, object);
G_OBJECT_CLASS(cookie_manager_page_parent_class)->finalize(object);
}
static void cookie_manager_page_set_property(GObject *object, guint prop_id, const GValue *value,
GParamSpec *pspec)
{
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(object);
switch (prop_id)
{ {
priv->ignore_changed_count--; case PROP_STORE:
return; {
} priv->store = g_value_get_object(value);
/* We delay these events a little bit to avoid too many rebuilds of the tree. /* setting filter and model */
* Some websites (like Flyspray bugtrackers sent a whole bunch of cookies at once. */ priv->filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(priv->store), NULL);
if (priv->timer_id == 0) gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(priv->filter),
priv->timer_id = g_timeout_add_seconds(1, (GSourceFunc) cm_delayed_refresh, cmp); COOKIE_MANAGER_COL_VISIBLE);
gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter));
g_object_unref(priv->filter);
break;
}
case PROP_PARENT:
{
if (priv->parent != NULL)
{
g_signal_handlers_disconnect_by_func(priv->parent,
cookie_manager_page_pre_cookies_change_cb, object);
g_signal_handlers_disconnect_by_func(priv->parent,
cookie_manager_page_cookies_changed_cb, object);
g_signal_handlers_disconnect_by_func(priv->parent,
cookie_manager_page_filter_changed_cb, object);
}
priv->parent = g_value_get_object(value);
g_signal_connect(priv->parent, "pre-cookies-change",
G_CALLBACK(cookie_manager_page_pre_cookies_change_cb), object);
g_signal_connect(priv->parent, "cookies-changed",
G_CALLBACK(cookie_manager_page_cookies_changed_cb), object);
g_signal_connect(priv->parent, "filter-changed",
G_CALLBACK(cookie_manager_page_filter_changed_cb), object);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
} }
@ -288,7 +260,27 @@ static void cookie_manager_page_class_init(CookieManagerPageClass *klass)
{ {
GObjectClass *g_object_class; GObjectClass *g_object_class;
g_object_class = G_OBJECT_CLASS(klass); g_object_class = G_OBJECT_CLASS(klass);
g_object_class->finalize = cookie_manager_page_finalize; g_object_class->finalize = cookie_manager_page_finalize;
g_object_class->set_property = cookie_manager_page_set_property;
g_object_class_install_property(g_object_class,
PROP_STORE,
g_param_spec_object(
"store",
"Treestore",
"The tree store",
GTK_TYPE_TREE_STORE,
G_PARAM_WRITABLE));
g_object_class_install_property(g_object_class,
PROP_PARENT,
g_param_spec_object(
"parent",
"Parent",
"The CookieManager parent instance",
COOKIE_MANAGER_TYPE,
G_PARAM_WRITABLE));
g_type_class_add_private(klass, sizeof(CookieManagerPagePrivate)); g_type_class_add_private(klass, sizeof(CookieManagerPagePrivate));
} }
@ -346,13 +338,7 @@ static void cm_delete_cookie(CookieManagerPage *cmp, GtkTreeModel *model, GtkTre
gtk_tree_model_get(model, child, COOKIE_MANAGER_COL_COOKIE, &cookie, -1); gtk_tree_model_get(model, child, COOKIE_MANAGER_COL_COOKIE, &cookie, -1);
if (cookie != NULL) cookie_manager_delete_cookie(priv->parent, cookie);
{
priv->ignore_changed_count++;
soup_cookie_jar_delete_cookie(priv->jar, cookie);
/* the SoupCookie object is freed when the whole list gets updated */
}
} }
@ -670,11 +656,17 @@ static void cm_filter_tree(CookieManagerPage *cmp, const gchar *filter_text)
static void cm_filter_entry_changed_cb(GtkEditable *editable, CookieManagerPage *cmp) static void cm_filter_entry_changed_cb(GtkEditable *editable, CookieManagerPage *cmp)
{ {
const gchar *text = gtk_entry_get_text(GTK_ENTRY(editable)); const gchar *text;
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp); CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
if (priv->ignore_changed_filter)
return;
text = gtk_entry_get_text(GTK_ENTRY(editable));
cm_filter_tree(cmp, text); cm_filter_tree(cmp, text);
cookie_manager_update_filter(priv->parent, text);
if (*text != '\0') if (*text != '\0')
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview)); gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
else else
@ -830,20 +822,6 @@ static GtkWidget *cm_tree_prepare(CookieManagerPage *cmp)
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
/* create the main store */
priv->store = gtk_tree_store_new(COOKIE_MANAGER_N_COLUMNS,
G_TYPE_STRING, SOUP_TYPE_COOKIE, G_TYPE_BOOLEAN);
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(priv->store),
COOKIE_MANAGER_COL_NAME, GTK_SORT_ASCENDING);
/* setting filter and model */
priv->filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(priv->store), NULL);
gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(priv->filter),
COOKIE_MANAGER_COL_VISIBLE);
gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter));
g_object_unref(priv->store);
g_object_unref(priv->filter);
/* signals */ /* signals */
g_signal_connect(sel, "changed", G_CALLBACK(cm_tree_selection_changed_cb), cmp); g_signal_connect(sel, "changed", G_CALLBACK(cm_tree_selection_changed_cb), cmp);
g_signal_connect(treeview, "button-press-event", G_CALLBACK(cm_tree_button_press_event_cb), cmp); g_signal_connect(treeview, "button-press-event", G_CALLBACK(cm_tree_button_press_event_cb), cmp);
@ -909,9 +887,12 @@ static void cookie_manager_page_init(CookieManagerPage *self)
GtkWidget *filter_hbox; GtkWidget *filter_hbox;
GtkWidget *filter_label; GtkWidget *filter_label;
GtkWidget *treeview; GtkWidget *treeview;
SoupSession *session;
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(self); CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(self);
priv->parent = NULL;
priv->store = NULL;
priv->ignore_changed_filter = FALSE;
cm_create_toolbar(self); cm_create_toolbar(self);
priv->desc_label = gtk_label_new(CM_EMPTY_LABEL_TEXT); priv->desc_label = gtk_label_new(CM_EMPTY_LABEL_TEXT);
@ -968,18 +949,19 @@ static void cookie_manager_page_init(CookieManagerPage *self)
gtk_box_pack_start(GTK_BOX(self), filter_hbox, FALSE, FALSE, 5); gtk_box_pack_start(GTK_BOX(self), filter_hbox, FALSE, FALSE, 5);
gtk_box_pack_start(GTK_BOX(self), paned, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self), paned, TRUE, TRUE, 0);
/* setup soup */
session = webkit_get_default_session();
priv->jar = SOUP_COOKIE_JAR(soup_session_get_feature(session, soup_cookie_jar_get_type()));
g_signal_connect(priv->jar, "changed", G_CALLBACK(cm_jar_changed_cb), self);
cm_refresh_store(self);
} }
GtkWidget *cookie_manager_page_new(void) GtkWidget *cookie_manager_page_new(CookieManager *parent, GtkTreeStore *store,
const gchar *filter_text)
{ {
return g_object_new(COOKIE_MANAGER_PAGE_TYPE, NULL); GtkWidget *cmp;
cmp = g_object_new(COOKIE_MANAGER_PAGE_TYPE, "parent", parent, "store", store, NULL);
if (filter_text != NULL)
cookie_manager_page_filter_changed_cb(parent, filter_text, COOKIE_MANAGER_PAGE(cmp));
return cmp;
} }

View file

@ -38,7 +38,9 @@ struct _CookieManagerPageClass
}; };
GType cookie_manager_page_get_type (void); GType cookie_manager_page_get_type (void);
GtkWidget* cookie_manager_page_new (void); GtkWidget* cookie_manager_page_new (CookieManager *parent,
GtkTreeStore *store,
const gchar *filter_text);
G_END_DECLS G_END_DECLS

View file

@ -16,115 +16,324 @@
#include "cookie-manager.h" #include "cookie-manager.h"
#include "cookie-manager-page.h" #include "cookie-manager-page.h"
typedef struct _CookieManagerPrivate CookieManagerPrivate;
#define COOKIE_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj),\
COOKIE_MANAGER_TYPE, CookieManagerPrivate))
typedef struct struct _CookieManager
{
GObject parent;
};
struct _CookieManagerClass
{
GObjectClass parent_class;
};
struct _CookieManagerPrivate
{ {
MidoriApp *app; MidoriApp *app;
MidoriBrowser *browser;
MidoriExtension *extension; MidoriExtension *extension;
GtkWidget *panel_page;
} CMData;
static void cm_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext); GSList *panel_pages;
static void cm_deactivate_cb(MidoriExtension *extension, CMData *cmdata);
GtkTreeStore *store;
GSList *cookies;
SoupCookieJar *jar;
guint timer_id;
gint ignore_changed_count;
gchar *filter_text;
};
static void cm_browser_close_cb(GtkObject *browser, CMData *cmdata) static void cookie_manager_finalize(GObject *object);
static void cookie_manager_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser,
CookieManager *cm);
enum
{ {
g_signal_handlers_disconnect_by_func(cmdata->extension, cm_deactivate_cb, cmdata); COOKIES_CHANGED,
g_signal_handlers_disconnect_by_func(cmdata->browser, cm_browser_close_cb, cmdata); PRE_COOKIES_CHANGE,
FILTER_CHANGED,
/* the panel_page widget gets destroyed automatically when a browser is closed but not LAST_SIGNAL
* when the extension is deactivated */ };
if (cmdata->panel_page != NULL && IS_COOKIE_MANAGER_PAGE(cmdata->panel_page)) static guint signals[LAST_SIGNAL];
gtk_widget_destroy(cmdata->panel_page);
g_free(cmdata);
G_DEFINE_TYPE(CookieManager, cookie_manager, G_TYPE_OBJECT);
static void cookie_manager_class_init(CookieManagerClass *klass)
{
GObjectClass *g_object_class;
g_object_class = G_OBJECT_CLASS(klass);
g_object_class->finalize = cookie_manager_finalize;
signals[COOKIES_CHANGED] = g_signal_new(
"cookies-changed",
G_TYPE_FROM_CLASS(klass),
(GSignalFlags) 0,
0,
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[PRE_COOKIES_CHANGE] = g_signal_new(
"pre-cookies-change",
G_TYPE_FROM_CLASS(klass),
(GSignalFlags) 0,
0,
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[FILTER_CHANGED] = g_signal_new(
"filter-changed",
G_TYPE_FROM_CLASS(klass),
(GSignalFlags) 0,
0,
0,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
g_type_class_add_private(klass, sizeof(CookieManagerPrivate));
} }
static void cm_deactivate_cb(MidoriExtension *extension, CMData *cmdata) static void cookie_manager_panel_pages_foreach(gpointer ptr, gpointer data)
{ {
g_signal_handlers_disconnect_by_func(cmdata->app, cm_app_add_browser_cb, extension); if (ptr != NULL && GTK_IS_WIDGET(ptr))
cm_browser_close_cb(NULL, cmdata); gtk_widget_destroy(GTK_WIDGET(ptr));
} }
static void cm_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext) static void cookie_manager_page_destroy_cb(GtkObject *page, CookieManager *cm)
{ {
GtkWidget *panel; CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
priv->panel_pages = g_slist_remove(priv->panel_pages, page);
}
static void cookie_manager_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser,
CookieManager *cm)
{
MidoriPanel *panel;
GtkWidget *page; GtkWidget *page;
CMData *cmdata; CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
panel = katze_object_get_object(browser, "panel"); panel = katze_object_get_object(browser, "panel");
page = cookie_manager_page_new(); page = cookie_manager_page_new(cm, priv->store, priv->filter_text);
gtk_widget_show(page); gtk_widget_show(page);
midori_panel_append_page(MIDORI_PANEL(panel), MIDORI_VIEWABLE(page)); midori_panel_append_page(panel, MIDORI_VIEWABLE(page));
g_signal_connect(page, "destroy", G_CALLBACK(cookie_manager_page_destroy_cb), cm);
cmdata = g_new0(CMData, 1); priv->panel_pages = g_slist_append(priv->panel_pages, page);
cmdata->app = app;
cmdata->browser = browser;
cmdata->extension = ext;
cmdata->panel_page = page;
g_signal_connect(browser, "destroy", G_CALLBACK(cm_browser_close_cb), cmdata);
g_signal_connect(ext, "deactivate", G_CALLBACK(cm_deactivate_cb), cmdata);
g_object_unref(panel); g_object_unref(panel);
} }
static void cm_activate_cb(MidoriExtension *extension, MidoriApp *app, gpointer data) static void cookie_manager_free_cookie_list(CookieManager *cm)
{ {
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
if (priv->cookies != NULL)
{
GSList *l;
for (l = priv->cookies; l != NULL; l = g_slist_next(l))
soup_cookie_free(l->data);
g_slist_free(priv->cookies);
priv->cookies = NULL;
}
}
static void cookie_manager_refresh_store(CookieManager *cm)
{
GSList *l;
GHashTable *parents;
GtkTreeIter iter;
GtkTreeIter *parent_iter;
SoupCookie *cookie;
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
g_signal_emit(cm, signals[PRE_COOKIES_CHANGE], 0);
gtk_tree_store_clear(priv->store);
/* free the old list */
cookie_manager_free_cookie_list(cm);
priv->cookies = soup_cookie_jar_all_cookies(priv->jar);
/* Hashtable holds domain names as keys, the corresponding tree iters as values */
parents = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
for (l = priv->cookies; l != NULL; l = g_slist_next(l))
{
cookie = l->data;
/* look for the parent item for the current domain name and create it if it doesn't exist */
if ((parent_iter = (GtkTreeIter*) g_hash_table_lookup(parents, cookie->domain)) == NULL)
{
parent_iter = g_new0(GtkTreeIter, 1);
gtk_tree_store_append(priv->store, parent_iter, NULL);
gtk_tree_store_set(priv->store, parent_iter,
COOKIE_MANAGER_COL_NAME, cookie->domain,
COOKIE_MANAGER_COL_COOKIE, NULL,
COOKIE_MANAGER_COL_VISIBLE, TRUE,
-1);
g_hash_table_insert(parents, g_strdup(cookie->domain), parent_iter);
}
gtk_tree_store_append(priv->store, &iter, parent_iter);
gtk_tree_store_set(priv->store, &iter,
COOKIE_MANAGER_COL_NAME, cookie->name,
COOKIE_MANAGER_COL_COOKIE, cookie,
COOKIE_MANAGER_COL_VISIBLE, TRUE,
-1);
}
g_hash_table_destroy(parents);
g_signal_emit(cm, signals[COOKIES_CHANGED], 0);
}
static gboolean cookie_manager_delayed_refresh(CookieManager *cm)
{
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
cookie_manager_refresh_store(cm);
priv->timer_id = 0;
return FALSE;
}
static void cookie_manager_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new,
CookieManager *cm)
{
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
if (priv->ignore_changed_count > 0)
{
priv->ignore_changed_count--;
return;
}
/* We delay these events a little bit to avoid too many rebuilds of the tree.
* Some websites (like Flyspray bugtrackers sent a whole bunch of cookies at once. */
if (priv->timer_id == 0)
priv->timer_id = g_timeout_add_seconds(1, (GSourceFunc) cookie_manager_delayed_refresh, cm);
}
static void cookie_manager_finalize(GObject *object)
{
CookieManager *cm = COOKIE_MANAGER(object);
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
g_signal_handlers_disconnect_by_func(priv->app, cookie_manager_app_add_browser_cb, cm);
g_signal_handlers_disconnect_by_func(priv->jar, cookie_manager_jar_changed_cb, cm);
/* remove all panel pages from open windows */
g_slist_foreach(priv->panel_pages, cookie_manager_panel_pages_foreach, NULL);
g_slist_free(priv->panel_pages);
/* clean cookies */
if (priv->timer_id > 0)
g_source_remove(priv->timer_id);
cookie_manager_free_cookie_list(cm);
g_object_unref(priv->store);
g_free(priv->filter_text);
G_OBJECT_CLASS(cookie_manager_parent_class)->finalize(object);
}
static void cookie_manager_init(CookieManager *self)
{
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(self);
SoupSession *session;
priv->filter_text = NULL;
priv->panel_pages = NULL;
/* create the main store */
priv->store = gtk_tree_store_new(COOKIE_MANAGER_N_COLUMNS,
G_TYPE_STRING, SOUP_TYPE_COOKIE, G_TYPE_BOOLEAN);
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(priv->store),
COOKIE_MANAGER_COL_NAME, GTK_SORT_ASCENDING);
/* setup soup */
session = webkit_get_default_session();
priv->jar = SOUP_COOKIE_JAR(soup_session_get_feature(session, soup_cookie_jar_get_type()));
g_signal_connect(priv->jar, "changed", G_CALLBACK(cookie_manager_jar_changed_cb), self);
cookie_manager_refresh_store(self);
}
void cookie_manager_update_filter(CookieManager *cm, const gchar *text)
{
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
katze_assign(priv->filter_text, g_strdup(text));
g_signal_emit(cm, signals[FILTER_CHANGED], 0, text);
}
void cookie_manager_delete_cookie(CookieManager *cm, SoupCookie *cookie)
{
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
if (cookie != NULL)
{
priv->ignore_changed_count++;
soup_cookie_jar_delete_cookie(priv->jar, cookie);
/* the SoupCookie object is freed when the whole list gets updated */
}
}
CookieManager *cookie_manager_new(MidoriExtension *extension, MidoriApp *app)
{
CookieManager *cm;
CookieManagerPrivate *priv;
guint i; guint i;
KatzeArray *browsers; KatzeArray *browsers;
MidoriBrowser *browser; MidoriBrowser *browser;
cm = g_object_new(COOKIE_MANAGER_TYPE, NULL);
priv = COOKIE_MANAGER_GET_PRIVATE(cm);
priv->app = app;
priv->extension = extension;
/* add the cookie manager panel page to existing browsers */ /* add the cookie manager panel page to existing browsers */
browsers = katze_object_get_object(app, "browsers"); browsers = katze_object_get_object(app, "browsers");
i = 0; i = 0;
while ((browser = katze_array_get_nth_item(browsers, i++))) while ((browser = katze_array_get_nth_item(browsers, i++)))
cm_app_add_browser_cb(app, browser, extension); cookie_manager_app_add_browser_cb(app, browser, cm);
g_object_unref(browsers); g_object_unref(browsers);
g_signal_connect(app, "add-browser", G_CALLBACK(cm_app_add_browser_cb), extension); g_signal_connect(app, "add-browser", G_CALLBACK(cookie_manager_app_add_browser_cb), cm);
return cm;
} }
MidoriExtension *extension_init(void)
{
MidoriExtension *extension;
GtkIconFactory *factory;
GtkIconSource *icon_source;
GtkIconSet *icon_set;
static GtkStockItem items[] =
{
{ STOCK_COOKIE_MANAGER, N_("_Cookie Manager"), 0, 0, NULL }
};
factory = gtk_icon_factory_new();
gtk_stock_add(items, G_N_ELEMENTS(items));
icon_set = gtk_icon_set_new();
icon_source = gtk_icon_source_new();
gtk_icon_source_set_icon_name(icon_source, GTK_STOCK_DIALOG_AUTHENTICATION);
gtk_icon_set_add_source(icon_set, icon_source);
gtk_icon_source_free(icon_source);
gtk_icon_factory_add(factory, STOCK_COOKIE_MANAGER, icon_set);
gtk_icon_set_unref(icon_set);
gtk_icon_factory_add_default(factory);
g_object_unref(factory);
extension = g_object_new(MIDORI_TYPE_EXTENSION,
"name", _("Cookie Manager"),
"description", _("List, view and delete cookies"),
"version", "0.2",
"authors", "Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>",
NULL);
g_signal_connect(extension, "activate", G_CALLBACK(cm_activate_cb), NULL);
return extension;
}

View file

@ -13,8 +13,38 @@
#ifndef __COOKIE_MANAGER_H__ #ifndef __COOKIE_MANAGER_H__
#define __COOKIE_MANAGER_H__ #define __COOKIE_MANAGER_H__
G_BEGIN_DECLS
#define STOCK_COOKIE_MANAGER "cookie-manager" #define STOCK_COOKIE_MANAGER "cookie-manager"
enum
{
COOKIE_MANAGER_COL_NAME,
COOKIE_MANAGER_COL_COOKIE,
COOKIE_MANAGER_COL_VISIBLE,
COOKIE_MANAGER_N_COLUMNS
};
#endif /* __COOKIE_MANAGER_H__ */
#define COOKIE_MANAGER_TYPE (cookie_manager_get_type())
#define COOKIE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
COOKIE_MANAGER_TYPE, CookieManager))
#define COOKIE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
COOKIE_MANAGER_TYPE, CookieManagerClass))
#define IS_COOKIE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
COOKIE_MANAGER_TYPE))
#define IS_COOKIE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
COOKIE_MANAGER_TYPE))
typedef struct _CookieManager CookieManager;
typedef struct _CookieManagerClass CookieManagerClass;
GType cookie_manager_get_type (void);
CookieManager* cookie_manager_new (MidoriExtension *extension, MidoriApp *app);
void cookie_manager_delete_cookie(CookieManager *cm, SoupCookie *cookie);
void cookie_manager_update_filter(CookieManager *cm, const gchar *text);
G_END_DECLS
#endif /* __COOKIE-MANAGER_H__ */

View file

@ -0,0 +1,66 @@
/*
Copyright (C) 2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)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.
*/
#include "config.h"
#include <midori/midori.h>
#include "cookie-manager.h"
CookieManager *cm = NULL;
static void cm_deactivate_cb(MidoriExtension *extension, gpointer data)
{
g_object_unref(cm);
}
static void cm_activate_cb(MidoriExtension *extension, MidoriApp *app, gpointer data)
{
cm = cookie_manager_new(extension, app);
}
MidoriExtension *extension_init(void)
{
MidoriExtension *extension;
GtkIconFactory *factory;
GtkIconSource *icon_source;
GtkIconSet *icon_set;
static GtkStockItem items[] =
{
{ STOCK_COOKIE_MANAGER, N_("_Cookie Manager"), 0, 0, NULL }
};
factory = gtk_icon_factory_new();
gtk_stock_add(items, G_N_ELEMENTS(items));
icon_set = gtk_icon_set_new();
icon_source = gtk_icon_source_new();
gtk_icon_source_set_icon_name(icon_source, GTK_STOCK_DIALOG_AUTHENTICATION);
gtk_icon_set_add_source(icon_set, icon_source);
gtk_icon_source_free(icon_source);
gtk_icon_factory_add(factory, STOCK_COOKIE_MANAGER, icon_set);
gtk_icon_set_unref(icon_set);
gtk_icon_factory_add_default(factory);
g_object_unref(factory);
extension = g_object_new(MIDORI_TYPE_EXTENSION,
"name", _("Cookie Manager"),
"description", _("List, view and delete cookies"),
"version", "0.2",
"authors", "Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>",
NULL);
g_signal_connect(extension, "activate", G_CALLBACK(cm_activate_cb), NULL);
g_signal_connect(extension, "deactivate", G_CALLBACK(cm_deactivate_cb), NULL);
return extension;
}

View file

@ -44,7 +44,7 @@ static gboolean mouse_gestures_handle_events (GtkWidget *widget,
MidoriBrowser *browser) MidoriBrowser *browser)
{ {
/* A button was pressed */ /* A button was pressed */
if (event->type == GDK_BUTTON_PRESS) if (event->type == GDK_BUTTON_PRESS && event->button.button == 2)
{ {
/* If the gesture was previously cleaned, start a new gesture and coordinates */ /* If the gesture was previously cleaned, start a new gesture and coordinates */
if (gesture->last == MOUSE_BUTTON_UNSET) if (gesture->last == MOUSE_BUTTON_UNSET)
@ -75,7 +75,7 @@ static gboolean mouse_gestures_handle_events (GtkWidget *widget,
(gesture->middle.y - y < DEVIANCE && gesture->middle.y - y > -DEVIANCE)) (gesture->middle.y - y < DEVIANCE && gesture->middle.y - y > -DEVIANCE))
{ {
gesture->end.x = x; gesture->end.x = x;
gesture->end.y = y; gesture->end.y = y;
} }
} }
@ -91,9 +91,9 @@ static gboolean mouse_gestures_handle_events (GtkWidget *widget,
(gesture->middle.x - gesture->start.x > -DEVIANCE)) (gesture->middle.x - gesture->start.x > -DEVIANCE))
{ {
/* We initially moved down more than MINLENGTH pixels */ /* We initially moved down more than MINLENGTH pixels */
if (gesture->middle.y > gesture->start.y + MINLENGTH) if (gesture->middle.y > gesture->start.y + MINLENGTH)
{ {
/* Then we the final vertical move is between the bounds and /* Then we the final vertical move is between the bounds and
we moved right more than MINLENGTH pixels */ we moved right more than MINLENGTH pixels */
if ((gesture->middle.y - gesture->end.y < DEVIANCE) && if ((gesture->middle.y - gesture->end.y < DEVIANCE) &&
(gesture->middle.y - gesture->end.y > -DEVIANCE) && (gesture->middle.y - gesture->end.y > -DEVIANCE) &&
@ -119,8 +119,8 @@ static gboolean mouse_gestures_handle_events (GtkWidget *widget,
} }
} }
/* We initially moved up more than MINLENGTH pixels */ /* We initially moved up more than MINLENGTH pixels */
else if (gesture->middle.y + MINLENGTH < gesture->start.y) else if (gesture->middle.y + MINLENGTH < gesture->start.y)
{ {
/* The end node was never updated, we only did a vertical move */ /* The end node was never updated, we only did a vertical move */
if (gesture->end.y == 0 && gesture->end.x == 0) if (gesture->end.y == 0 && gesture->end.x == 0)
{ {
@ -145,7 +145,7 @@ static gboolean mouse_gestures_handle_events (GtkWidget *widget,
} }
/* We initially moved left more than MINLENGTH pixels */ /* We initially moved left more than MINLENGTH pixels */
else if (gesture->middle.x + MINLENGTH < gesture->start.x) else if (gesture->middle.x + MINLENGTH < gesture->start.x)
{ {
/* The end node was never updated, we only did an horizontal move */ /* The end node was never updated, we only did an horizontal move */
if (gesture->end.x == 0 && gesture->end.y == 0) if (gesture->end.x == 0 && gesture->end.y == 0)
{ {
@ -156,7 +156,7 @@ static gboolean mouse_gestures_handle_events (GtkWidget *widget,
} }
} }
mouse_gesture_clear (gesture); mouse_gesture_clear (gesture);
return TRUE; return TRUE;
} }
@ -177,32 +177,25 @@ static void mouse_gestures_browser_cb (MidoriApp *app, MidoriBrowser *browser)
static void mouse_gestures_deactivate (MidoriExtension *extension, MidoriApp *app) static void mouse_gestures_deactivate (MidoriExtension *extension, MidoriApp *app)
{ {
gulong signal_id; gulong signal_id;
KatzeArray *browsers; KatzeArray* browsers;
MidoriBrowser* browser;
guint i; guint i;
gint j;
GtkWidget *notebook;
signal_id = signal_id = g_signal_handler_find (app, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
g_signal_handler_find (app, G_SIGNAL_MATCH_FUNC, mouse_gestures_browser_cb, NULL);
0, 0, NULL,
mouse_gestures_browser_cb, NULL);
if(signal_id != 0) if (signal_id != 0)
g_signal_handler_disconnect (app, signal_id); g_signal_handler_disconnect (app, signal_id);
browsers = katze_object_get_object (app, "browsers"); browsers = katze_object_get_object (app, "browsers");
i = 0;
for (i = 0; i < katze_array_get_length (browsers); i++) while ((browser = katze_array_get_nth_item (browsers, i++)))
{ {
MidoriBrowser *browser; gint j;
GtkWidget* notebook;
browser = katze_array_get_nth_item (browsers, i);
signal_id =
g_signal_handler_find (browser, G_SIGNAL_MATCH_FUNC,
0, 0, NULL,
mouse_gestures_tab_cb, NULL);
signal_id = g_signal_handler_find (browser, G_SIGNAL_MATCH_FUNC,
0, 0, NULL, mouse_gestures_tab_cb, NULL);
if (signal_id != 0) if (signal_id != 0)
g_signal_handler_disconnect (browser, signal_id); g_signal_handler_disconnect (browser, signal_id);
@ -212,15 +205,14 @@ static void mouse_gestures_deactivate (MidoriExtension *extension, MidoriApp *ap
{ {
GtkWidget *page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), j); GtkWidget *page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), j);
signal_id = signal_id = g_signal_handler_find (page, G_SIGNAL_MATCH_FUNC,
g_signal_handler_find (page, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, mouse_gestures_handle_events, NULL);
0, 0, NULL,
mouse_gestures_handle_events, NULL);
if (signal_id != 0) if (signal_id != 0)
g_signal_handler_disconnect (page, signal_id); g_signal_handler_disconnect (page, signal_id);
} }
} }
g_object_unref (browsers);
g_signal_handlers_disconnect_by_func (extension, mouse_gestures_deactivate, app); g_signal_handlers_disconnect_by_func (extension, mouse_gestures_deactivate, app);
g_free (gesture); g_free (gesture);

305
extensions/shortcuts.c Normal file
View file

@ -0,0 +1,305 @@
/*
Copyright (C) 2009 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.
*/
#include <midori/midori.h>
#include <midori/sokoke.h>
#include "config.h"
static void
shortcuts_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension);
static void
shortcuts_deactivate_cb (MidoriExtension* extension,
GtkWidget* menuitem)
{
MidoriApp* app = midori_extension_get_app (extension);
gtk_widget_destroy (menuitem);
g_signal_handlers_disconnect_by_func (
extension, shortcuts_deactivate_cb, menuitem);
g_signal_handlers_disconnect_by_func (
app, shortcuts_app_add_browser_cb, extension);
}
static void
shortcuts_preferences_render_text (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
MidoriExtension* extension)
{
GtkAction* action;
gchar* label;
gchar* stripped;
gtk_tree_model_get (model, iter, 0, &action, -1);
if ((label = katze_object_get_string (action, "label")))
stripped = katze_strip_mnemonics (label);
else
{
GtkStockItem item;
g_object_get (action, "stock-id", &label, NULL);
if (gtk_stock_lookup (label, &item))
stripped = katze_strip_mnemonics (item.label);
else
stripped = g_strdup ("");
}
g_free (label);
g_object_set (renderer, "text", stripped, NULL);
g_free (stripped);
g_object_unref (action);
}
static void
shortcuts_preferences_render_accel (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
MidoriExtension* extension)
{
GtkAction* action;
const gchar* accel_path;
GtkAccelKey key;
gtk_tree_model_get (model, iter, 0, &action, -1);
accel_path = gtk_action_get_accel_path (action);
if (accel_path)
{
if (gtk_accel_map_lookup_entry (accel_path, &key))
{
if (key.accel_key)
g_object_set (renderer,
"accel-key", key.accel_key,
"accel-mods", key.accel_mods,
NULL);
else
g_object_set (renderer, "text", _("None"), NULL);
}
g_object_set (renderer, "sensitive", TRUE, "editable", TRUE, NULL);
}
else
g_object_set (renderer, "text", "", "sensitive", FALSE, NULL);
g_object_unref (action);
}
static void
shortcuts_accel_edited_cb (GtkCellRenderer* renderer,
const gchar* tree_path,
guint accel_key,
GdkModifierType accel_mods,
guint keycode,
GtkTreeModel* model)
{
GtkTreeIter iter;
if (gtk_tree_model_get_iter_from_string (model, &iter, tree_path))
{
GtkAction* action;
const gchar* accel_path;
gtk_tree_model_get (model, &iter, 0, &action, -1);
accel_path = gtk_action_get_accel_path (action);
gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, TRUE);
g_object_unref (action);
}
}
static void
shortcuts_accel_cleared_cb (GtkCellRenderer* renderer,
const gchar* tree_path,
GtkTreeModel* model)
{
GtkTreeIter iter;
if (gtk_tree_model_get_iter_from_string (model, &iter, tree_path))
{
GtkAction* action;
const gchar* accel_path;
gtk_tree_model_get (model, &iter, 0, &action, -1);
accel_path = gtk_action_get_accel_path (action);
gtk_accel_map_change_entry (accel_path, 0, 0, FALSE);
g_object_unref (action);
}
}
static GtkWidget*
shortcuts_get_preferences_dialog (MidoriExtension* extension)
{
MidoriApp* app;
GtkWidget* browser;
const gchar* dialog_title;
GtkWidget* dialog;
gint width, height;
GtkWidget* xfce_heading;
GtkWidget* hbox;
GtkListStore* liststore;
GtkWidget* treeview;
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_accel;
GtkWidget* scrolled;
GtkActionGroup* action_group;
GList* actions;
guint i;
GtkAction* action;
#if HAVE_OSX
GtkWidget* icon;
#endif
app = midori_extension_get_app (extension);
browser = katze_object_get_object (app, "browser");
dialog_title = _("Configure Keyboard shortcuts");
dialog = gtk_dialog_new_with_buttons (dialog_title, GTK_WINDOW (browser),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
#if !HAVE_OSX
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
#endif
NULL);
g_signal_connect (dialog, "destroy",
G_CALLBACK (gtk_widget_destroyed), &dialog);
gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_PROPERTIES);
sokoke_widget_get_text_size (dialog, "M", &width, &height);
gtk_window_set_default_size (GTK_WINDOW (dialog), width * 52, height * 24);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), dialog);
if ((xfce_heading = sokoke_xfce_header_new (
gtk_window_get_icon_name (GTK_WINDOW (dialog)), dialog_title)))
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
xfce_heading, FALSE, FALSE, 0);
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
TRUE, TRUE, 12);
liststore = gtk_list_store_new (1, GTK_TYPE_ACTION);
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
column = gtk_tree_view_column_new ();
renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
(GtkTreeCellDataFunc)shortcuts_preferences_render_text,
extension, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
column = gtk_tree_view_column_new ();
renderer_accel = gtk_cell_renderer_accel_new ();
gtk_tree_view_column_pack_start (column, renderer_accel, TRUE);
gtk_tree_view_column_set_cell_data_func (column, renderer_accel,
(GtkTreeCellDataFunc)shortcuts_preferences_render_accel,
extension, NULL);
g_signal_connect (renderer_accel, "accel-edited",
G_CALLBACK (shortcuts_accel_edited_cb), liststore);
g_signal_connect (renderer_accel, "accel-cleared",
G_CALLBACK (shortcuts_accel_cleared_cb), liststore);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolled), treeview);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 5);
action_group = midori_browser_get_action_group (MIDORI_BROWSER (browser));
actions = gtk_action_group_list_actions (action_group);
i = 0;
/* FIXME: Catch added and removed actions */
while ((action = g_list_nth_data (actions, i++)))
gtk_list_store_insert_with_values (GTK_LIST_STORE (liststore),
NULL, G_MAXINT, 0, action, -1);
g_list_free (actions);
g_object_unref (liststore);
gtk_widget_show_all (GTK_DIALOG (dialog)->vbox);
g_object_unref (browser);
return dialog;
}
static void
shortcuts_menu_configure_shortcuts_activate_cb (GtkWidget* menuitem,
MidoriExtension* extension)
{
static GtkWidget* dialog = NULL;
if (!dialog)
{
dialog = shortcuts_get_preferences_dialog (extension);
g_signal_connect (dialog, "destroy",
G_CALLBACK (gtk_widget_destroyed), &dialog);
gtk_widget_show (dialog);
}
else
gtk_window_present (GTK_WINDOW (dialog));
}
static void
shortcuts_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
GtkWidget* panel;
GtkWidget* menu;
GtkWidget* menuitem;
panel = katze_object_get_object (browser, "panel");
menu = katze_object_get_object (panel, "menu");
g_object_unref (panel);
menuitem = gtk_menu_item_new_with_mnemonic (_("Configure Sh_ortcuts..."));
g_signal_connect (menuitem, "activate",
G_CALLBACK (shortcuts_menu_configure_shortcuts_activate_cb), extension);
gtk_widget_show (menuitem);
gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 3);
g_object_unref (menu);
g_signal_connect (extension, "deactivate",
G_CALLBACK (shortcuts_deactivate_cb), menuitem);
}
static void
shortcuts_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
shortcuts_app_add_browser_cb (app, browser, extension);
g_signal_connect (app, "add-browser",
G_CALLBACK (shortcuts_app_add_browser_cb), extension);
g_object_unref (browsers);
}
MidoriExtension*
extension_init (void)
{
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Shortcuts"),
"description", _("View and edit keyboard shortcuts"),
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
g_signal_connect (extension, "activate",
G_CALLBACK (shortcuts_activate_cb), NULL);
return extension;
}

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de> Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -16,13 +16,45 @@ statusbar_features_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser, MidoriBrowser* browser,
MidoriExtension* extension); MidoriExtension* extension);
static void
statusbar_features_toolbar_notify_toolbar_style_cb (GtkWidget* toolbar,
GParamSpec* pspec,
GtkWidget* button)
{
GtkToolbarStyle style = katze_object_get_enum (toolbar, "toolbar-style");
const gchar* text = g_object_get_data (G_OBJECT (button), "feature-label");
switch (style)
{
case GTK_TOOLBAR_BOTH:
case GTK_TOOLBAR_BOTH_HORIZ:
gtk_button_set_label (GTK_BUTTON (button), text);
gtk_widget_show (gtk_button_get_image (GTK_BUTTON (button)));
break;
case GTK_TOOLBAR_TEXT:
gtk_button_set_label (GTK_BUTTON (button), text);
gtk_widget_hide (gtk_button_get_image (GTK_BUTTON (button)));
break;
case GTK_TOOLBAR_ICONS:
gtk_button_set_label (GTK_BUTTON (button), "");
gtk_widget_show (gtk_button_get_image (GTK_BUTTON (button)));
break;
default:
g_assert_not_reached ();
}
}
static void static void
statusbar_features_deactivate_cb (MidoriExtension* extension, statusbar_features_deactivate_cb (MidoriExtension* extension,
GtkWidget* bbox) GtkWidget* bbox)
{ {
MidoriApp* app = midori_extension_get_app (extension); MidoriApp* app = midori_extension_get_app (extension);
MidoriBrowser* browser = midori_browser_get_for_widget (bbox);
GtkWidget* toolbar = katze_object_get_object (browser, "navigationbar");
gtk_widget_destroy (bbox); gtk_widget_destroy (bbox);
g_signal_handlers_disconnect_matched (toolbar, G_SIGNAL_MATCH_FUNC,
0, -1, NULL, statusbar_features_toolbar_notify_toolbar_style_cb, NULL);
g_object_unref (toolbar);
g_signal_handlers_disconnect_by_func ( g_signal_handlers_disconnect_by_func (
extension, statusbar_features_deactivate_cb, bbox); extension, statusbar_features_deactivate_cb, bbox);
g_signal_handlers_disconnect_by_func ( g_signal_handlers_disconnect_by_func (
@ -37,6 +69,7 @@ statusbar_features_app_add_browser_cb (MidoriApp* app,
GtkWidget* statusbar; GtkWidget* statusbar;
GtkWidget* bbox; GtkWidget* bbox;
MidoriWebSettings* settings; MidoriWebSettings* settings;
GtkWidget* toolbar;
GtkWidget* button; GtkWidget* button;
GtkWidget* image; GtkWidget* image;
@ -46,36 +79,47 @@ statusbar_features_app_add_browser_cb (MidoriApp* app,
statusbar = katze_object_get_object (browser, "statusbar"); statusbar = katze_object_get_object (browser, "statusbar");
bbox = gtk_hbox_new (FALSE, 0); bbox = gtk_hbox_new (FALSE, 0);
settings = katze_object_get_object (browser, "settings"); settings = katze_object_get_object (browser, "settings");
toolbar = katze_object_get_object (browser, "navigationbar");
button = katze_property_proxy (settings, "auto-load-images", "toggle"); button = katze_property_proxy (settings, "auto-load-images", "toggle");
g_object_set_data (G_OBJECT (button), "feature-label", _("Images"));
image = gtk_image_new_from_stock (STOCK_IMAGE, GTK_ICON_SIZE_MENU); image = gtk_image_new_from_stock (STOCK_IMAGE, GTK_ICON_SIZE_MENU);
gtk_widget_show (image); gtk_button_set_image (GTK_BUTTON (button), image);
gtk_container_add (GTK_CONTAINER (button), image);
#if GTK_CHECK_VERSION(2, 12, 0) #if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Load images automatically")); gtk_widget_set_tooltip_text (button, _("Load images automatically"));
#endif #endif
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
g_signal_connect (toolbar, "notify::toolbar-style",
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
gtk_widget_show (button); gtk_widget_show (button);
button = katze_property_proxy (settings, "enable-scripts", "toggle"); button = katze_property_proxy (settings, "enable-scripts", "toggle");
g_object_set_data (G_OBJECT (button), "feature-label", _("Scripts"));
image = gtk_image_new_from_stock (STOCK_SCRIPTS, GTK_ICON_SIZE_MENU); image = gtk_image_new_from_stock (STOCK_SCRIPTS, GTK_ICON_SIZE_MENU);
gtk_widget_show (image); gtk_button_set_image (GTK_BUTTON (button), image);
gtk_container_add (GTK_CONTAINER (button), image);
#if GTK_CHECK_VERSION(2, 12, 0) #if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Enable scripts")); gtk_widget_set_tooltip_text (button, _("Enable scripts"));
#endif #endif
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
g_signal_connect (toolbar, "notify::toolbar-style",
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
gtk_widget_show (button); gtk_widget_show (button);
button = katze_property_proxy (settings, "enable-plugins", "toggle"); button = katze_property_proxy (settings, "enable-plugins", "toggle");
g_object_set_data (G_OBJECT (button), "feature-label", _("Netscape plugins"));
image = gtk_image_new_from_stock (STOCK_PLUGINS, GTK_ICON_SIZE_MENU); image = gtk_image_new_from_stock (STOCK_PLUGINS, GTK_ICON_SIZE_MENU);
gtk_widget_show (image); gtk_button_set_image (GTK_BUTTON (button), image);
gtk_container_add (GTK_CONTAINER (button), image);
#if GTK_CHECK_VERSION(2, 12, 0) #if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Enable Netscape plugins")); gtk_widget_set_tooltip_text (button, _("Enable Netscape plugins"));
#endif #endif
statusbar_features_toolbar_notify_toolbar_style_cb (toolbar, NULL, button);
g_signal_connect (toolbar, "notify::toolbar-style",
G_CALLBACK (statusbar_features_toolbar_notify_toolbar_style_cb), button);
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 2);
gtk_widget_show (button); gtk_widget_show (button);
gtk_widget_show (bbox); gtk_widget_show (bbox);
gtk_box_pack_start (GTK_BOX (statusbar), bbox, FALSE, FALSE, 3); gtk_box_pack_start (GTK_BOX (statusbar), bbox, FALSE, FALSE, 3);
g_object_unref (settings); g_object_unref (settings);
g_object_unref (statusbar);
g_signal_connect (extension, "deactivate", g_signal_connect (extension, "deactivate",
G_CALLBACK (statusbar_features_deactivate_cb), bbox); G_CALLBACK (statusbar_features_deactivate_cb), bbox);
@ -95,6 +139,7 @@ statusbar_features_activate_cb (MidoriExtension* extension,
statusbar_features_app_add_browser_cb (app, browser, extension); statusbar_features_app_add_browser_cb (app, browser, extension);
g_signal_connect (app, "add-browser", g_signal_connect (app, "add-browser",
G_CALLBACK (statusbar_features_app_add_browser_cb), extension); G_CALLBACK (statusbar_features_app_add_browser_cb), extension);
g_object_unref (browsers);
} }
MidoriExtension* MidoriExtension*

362
extensions/tab-panel.c Normal file
View file

@ -0,0 +1,362 @@
/*
Copyright (C) 2008-2009 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.
*/
#include <midori/midori.h>
#include <midori/sokoke.h>
#define STOCK_TAB_PANEL "tab-panel"
static void
tab_panel_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension);
static void
tab_panel_deactivate_cb (MidoriExtension* extension,
GtkWidget* panel)
{
MidoriApp* app = midori_extension_get_app (extension);
GtkTreeModel* model;
MidoriBrowser* browser;
model = g_object_get_data (G_OBJECT (extension), "treemodel");
g_object_unref (model);
browser = midori_browser_get_for_widget (panel);
g_object_set (browser, "show-tabs", TRUE, NULL);
gtk_widget_destroy (panel);
g_signal_handlers_disconnect_by_func (
extension, tab_panel_deactivate_cb, panel);
g_signal_handlers_disconnect_by_func (
app, tab_panel_app_add_browser_cb, extension);
}
static void
midori_extension_cursor_or_row_changed_cb (GtkTreeView* treeview,
MidoriExtension* extension)
{
/* Nothing to do */
}
static void
midori_extension_treeview_render_icon_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
{
MidoriView* view;
GdkPixbuf* pixbuf;
gtk_tree_model_get (model, iter, 0, &view, -1);
if ((pixbuf = midori_view_get_icon (view)))
g_object_set (renderer, "pixbuf", pixbuf, NULL);
g_object_unref (view);
}
static void
midori_extension_treeview_render_text_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
{
MidoriView* view;
gtk_tree_model_get (model, iter, 0, &view, -1);
g_object_set (renderer, "text", midori_view_get_display_title (view), NULL);
g_object_unref (view);
}
static void
midori_extension_row_activated_cb (GtkTreeView* treeview,
GtkTreePath* path,
GtkTreeViewColumn* column,
MidoriExtension* extension)
{
GtkTreeModel* model;
GtkTreeIter iter;
model = gtk_tree_view_get_model (treeview);
if (gtk_tree_model_get_iter (model, &iter, path))
{
GtkWidget* view;
MidoriBrowser* browser;
gtk_tree_model_get (model, &iter, 0, &view, -1);
browser = midori_browser_get_for_widget (GTK_WIDGET (treeview));
midori_browser_set_current_tab (browser, view);
g_object_unref (view);
}
}
static void
midori_extension_popup (GtkWidget* widget,
GdkEventButton* event,
GtkWidget* view,
MidoriExtension* extension)
{
GtkWidget* menu = midori_view_get_tab_menu (MIDORI_VIEW (view));
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
}
static gboolean
midori_extension_button_release_event_cb (GtkWidget* widget,
GdkEventButton* event,
MidoriExtension* extension)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (event->button < 1 || event->button > 3)
return FALSE;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
GtkWidget* view;
gtk_tree_model_get (model, &iter, 0, &view, -1);
if (event->button == 1)
{
MidoriBrowser* browser = midori_browser_get_for_widget (widget);
midori_browser_set_current_tab (browser, view);
}
else if (event->button == 2)
gtk_widget_destroy (view);
else
midori_extension_popup (widget, event, view, extension);
g_object_unref (view);
return TRUE;
}
return FALSE;
}
static gboolean
midori_extension_key_release_event_cb (GtkWidget* widget,
GdkEventKey* event,
MidoriExtension* extension)
{
/* Nothing to do */
return FALSE;
}
static void
midori_extension_popup_menu_cb (GtkWidget* widget,
MidoriExtension* extension)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
GtkWidget* view;
gtk_tree_model_get (model, &iter, 0, &view, -1);
midori_extension_popup (widget, NULL, view, extension);
g_object_unref (view);
}
}
static void
tab_panel_browser_add_tab_cb (MidoriBrowser* browser,
GtkWidget* view,
MidoriExtension* extension)
{
GtkTreeModel* model = g_object_get_data (G_OBJECT (extension), "treemodel");
GtkTreeIter iter;
GtkWidget* notebook = katze_object_get_object (browser, "notebook");
gint page = gtk_notebook_page_num (GTK_NOTEBOOK (notebook), view);
g_object_unref (notebook);
gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
&iter, NULL, page, 0, view, -1);
}
static void
tab_panel_browser_foreach_cb (GtkWidget* view,
MidoriExtension* extension)
{
tab_panel_browser_add_tab_cb (midori_browser_get_for_widget (view),
view, extension);
}
static void
tab_panel_browser_remove_tab_cb (MidoriBrowser* browser,
MidoriView* view,
MidoriExtension* extension)
{
GtkTreeModel* model = g_object_get_data (G_OBJECT (extension), "treemodel");
guint i;
GtkTreeIter iter;
i = 0;
while (gtk_tree_model_iter_nth_child (model, &iter, NULL, i))
{
MidoriView* view_;
gtk_tree_model_get (model, &iter, 0, &view_, -1);
if (view == view_)
{
gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
g_object_unref (view_);
break;
}
g_object_unref (view_);
i++;
}
}
static void
tab_panel_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
GtkTreeStore* model;
GtkWidget* treeview;
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_pixbuf;
GtkCellRenderer* renderer_text;
GtkWidget* panel;
GtkWidget* toolbar;
/* GtkToolItem* toolitem; */
g_object_set (browser, "show-tabs", FALSE, NULL);
panel = katze_object_get_object (browser, "panel");
model = g_object_get_data (G_OBJECT (extension), "treemodel");
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
column = gtk_tree_view_column_new ();
renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf,
(GtkTreeCellDataFunc)midori_extension_treeview_render_icon_cb,
treeview, NULL);
renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
(GtkTreeCellDataFunc)midori_extension_treeview_render_text_cb,
treeview, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
g_object_connect (treeview,
"signal::row-activated",
midori_extension_row_activated_cb, extension,
"signal::cursor-changed",
midori_extension_cursor_or_row_changed_cb, extension,
"signal::columns-changed",
midori_extension_cursor_or_row_changed_cb, extension,
"signal::button-release-event",
midori_extension_button_release_event_cb, extension,
"signal::key-release-event",
midori_extension_key_release_event_cb, extension,
"signal::popup-menu",
midori_extension_popup_menu_cb, extension,
NULL);
gtk_widget_show (treeview);
toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ);
gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON);
gtk_widget_show (toolbar);
/*
TODO: Implement optional thumbnail images
toolitem = gtk_toggle_tool_button_new_from_stock (STOCK_IMAGE);
gtk_tool_item_set_is_important (toolitem, TRUE);
g_signal_connect (toolitem, "toggled",
G_CALLBACK (tab_panel_button_thumbnail_toggled_cb), notebook);
gtk_widget_show (GTK_WIDGET (toolitem));
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); */
midori_panel_append_widget (MIDORI_PANEL (panel), treeview,
STOCK_TAB_PANEL, _("Tab Panel"), toolbar);
g_object_unref (panel);
midori_browser_foreach (browser,
(GtkCallback)tab_panel_browser_foreach_cb, treeview);
g_signal_connect_after (browser, "add-tab",
G_CALLBACK (tab_panel_browser_add_tab_cb), extension);
g_signal_connect (browser, "remove-tab",
G_CALLBACK (tab_panel_browser_remove_tab_cb), extension);
g_signal_connect (extension, "deactivate",
G_CALLBACK (tab_panel_deactivate_cb), treeview);
}
static void
tab_panel_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
GtkTreeStore* model;
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
model = gtk_tree_store_new (1, MIDORI_TYPE_VIEW);
g_object_set_data (G_OBJECT (extension), "treemodel", model);
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
tab_panel_app_add_browser_cb (app, browser, extension);
g_object_unref (browsers);
g_signal_connect (app, "add-browser",
G_CALLBACK (tab_panel_app_add_browser_cb), extension);
}
MidoriExtension*
extension_init (void)
{
GtkIconFactory* factory;
GtkIconSource* icon_source;
GtkIconSet* icon_set;
static GtkStockItem items[] =
{
{ STOCK_TAB_PANEL, N_("T_ab Panel"), 0, 0, NULL },
};
factory = gtk_icon_factory_new ();
gtk_stock_add (items, G_N_ELEMENTS (items));
icon_set = gtk_icon_set_new ();
icon_source = gtk_icon_source_new ();
gtk_icon_source_set_icon_name (icon_source, GTK_STOCK_INDEX);
gtk_icon_set_add_source (icon_set, icon_source);
gtk_icon_source_free (icon_source);
gtk_icon_factory_add (factory, STOCK_TAB_PANEL, icon_set);
gtk_icon_set_unref (icon_set);
gtk_icon_factory_add_default (factory);
g_object_unref (factory);
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Tab Panel"),
"description", _("Show tabs in a vertical panel"),
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
g_signal_connect (extension, "activate",
G_CALLBACK (tab_panel_activate_cb), NULL);
return extension;
}

View file

@ -1,77 +0,0 @@
/*
Copyright (C) 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.
*/
#include "tab-panel-extension.h"
#include <midori/midori.h>
#define STOCK_TAB_PANEL "tab-panel"
static void
tab_panel_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser)
{
GtkWidget* panel;
GtkWidget* child;
/* FIXME: Actually provide a tree view listing all views. */
panel = katze_object_get_object (browser, "panel");
child = midori_view_new (NULL);
gtk_widget_show (child);
midori_panel_append_widget (MIDORI_PANEL (panel), child,
STOCK_TAB_PANEL, _("Tab Panel"), NULL);
}
static void
tab_panel_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
g_signal_connect (app, "add-browser",
G_CALLBACK (tab_panel_app_add_browser_cb), NULL);
}
MidoriExtension*
extension_init (void)
{
MidoriExtension* extension;
GtkIconFactory* factory;
GtkIconSource* icon_source;
GtkIconSet* icon_set;
static GtkStockItem items[] =
{
{ STOCK_TAB_PANEL, N_("T_ab Panel"), 0, 0, NULL },
};
factory = gtk_icon_factory_new ();
gtk_stock_add (items, G_N_ELEMENTS (items));
icon_set = gtk_icon_set_new ();
icon_source = gtk_icon_source_new ();
gtk_icon_source_set_icon_name (icon_source, GTK_STOCK_INDEX);
gtk_icon_set_add_source (icon_set, icon_source);
gtk_icon_source_free (icon_source);
gtk_icon_factory_add (factory, STOCK_TAB_PANEL, icon_set);
gtk_icon_set_unref (icon_set);
gtk_icon_factory_add_default (factory);
g_object_unref (factory);
extension = g_object_new (TAB_PANEL_TYPE_EXTENSION,
"name", _("Tab Panel"),
"description", "",
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
g_signal_connect (extension, "activate",
G_CALLBACK (tab_panel_activate_cb), NULL);
return extension;
}

View file

@ -1,38 +0,0 @@
/*
Copyright (C) 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.
*/
#include "tab-panel-extension.h"
#include <midori/midori.h>
struct _TabPanelExtension
{
MidoriExtension parent_instance;
};
struct _TabPanelExtensionClass
{
MidoriExtensionClass parent_class;
};
G_DEFINE_TYPE (TabPanelExtension, tab_panel_extension, MIDORI_TYPE_EXTENSION);
static void
tab_panel_extension_class_init (TabPanelExtensionClass* class)
{
/* Nothing to do. */
}
static void
tab_panel_extension_init (TabPanelExtension* extension)
{
/* Nothing to do. */
}

View file

@ -1,43 +0,0 @@
/*
Copyright (C) 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.
*/
#ifndef __TAB_PANEL_EXTENSION_H__
#define __TAB_PANEL_EXTENSION_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define TAB_PANEL_TYPE_EXTENSION \
(midori_extension_get_type ())
#define TAB_PANEL_EXTENSION(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), TAB_PANEL_TYPE_EXTENSION, TabPanelExtension))
#define TAB_PANEL_EXTENSION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), TAB_PANEL_TYPE_EXTENSION, TabPanelExtensionClass))
#define TAB_PANEL_IS_EXTENSION(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), TAB_PANEL_TYPE_EXTENSION))
#define TAB_PANEL_IS_EXTENSION_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), TAB_PANEL_TYPE_EXTENSION))
#define TAB_PANEL_EXTENSION_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), TAB_PANEL_TYPE_EXTENSION, TabPanelExtensionClass))
typedef struct _TabPanelExtension TabPanelExtension;
typedef struct _TabPanelExtensionClass TabPanelExtensionClass;
GType
tab_panel_extension_get_type (void);
/* There is no API for TabPanelExtension. Please use the
available properties and signals. */
G_END_DECLS
#endif /* __TAB_PANEL_EXTENSION_H__ */

625
extensions/toolbar-editor.c Normal file
View file

@ -0,0 +1,625 @@
/*
Copyright (C) 2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)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.
*/
#include <midori/midori.h>
#include "config.h"
#if !HAVE_HILDON
typedef struct
{
GtkWidget *dialog;
GtkTreeView *tree_available;
GtkTreeView *tree_used;
GtkListStore *store_available;
GtkListStore *store_used;
GtkTreePath *last_drag_path;
GtkTreeViewDropPosition last_drag_pos;
GtkWidget *drag_source;
GtkActionGroup *action_group;
MidoriBrowser *browser;
} TBEditorWidget;
enum
{
TB_EDITOR_COL_ACTION,
TB_EDITOR_COL_LABEL,
TB_EDITOR_COL_ICON,
TB_EDITOR_COLS_MAX
};
static const GtkTargetEntry tb_editor_dnd_targets[] =
{
{ "MIDORI_TB_EDITOR_ROW", 0, 0 }
};
static const gint tb_editor_dnd_targets_len = G_N_ELEMENTS(tb_editor_dnd_targets);
static void tb_editor_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext);
static void tb_editor_deactivate_cb(MidoriExtension *extension, GtkWidget *menuitem)
{
MidoriApp *app = midori_extension_get_app(extension);
gtk_widget_destroy(menuitem);
g_signal_handlers_disconnect_by_func(extension, tb_editor_deactivate_cb, menuitem);
g_signal_handlers_disconnect_by_func(app, tb_editor_app_add_browser_cb, extension);
}
static void tb_editor_set_item_values(TBEditorWidget *tbw, const gchar *action_name,
GtkListStore *store, GtkTreeIter *iter)
{
gchar *icon = NULL;
gchar *label = NULL;
gchar *label_clean = NULL;
GtkAction *action;
action = gtk_action_group_get_action(tbw->action_group, action_name);
if (action != NULL)
{
icon = katze_object_get_string(action, "icon-name");
if (icon == NULL)
{
icon = katze_object_get_string(action, "stock-id");
}
label = katze_object_get_string(action, "label");
if (label != NULL)
label_clean = katze_strip_mnemonics(label);
}
gtk_list_store_set(store, iter,
TB_EDITOR_COL_ACTION, action_name,
TB_EDITOR_COL_LABEL, label_clean,
TB_EDITOR_COL_ICON, icon,
-1);
g_free(icon);
g_free(label);
g_free(label_clean);
}
static GSList *tb_editor_array_to_list(const gchar **items)
{
const gchar **name;
GSList *list = NULL;
name = items;
while (*name != NULL)
{
if (*name[0] != '\0')
list = g_slist_append(list, g_strdup(*name));
name++;
}
return list;
}
static GSList *tb_editor_parse_active_items(MidoriBrowser *browser)
{
gchar *items;
gchar **names;
GSList *list = NULL;
MidoriWebSettings *settings;
settings = katze_object_get_object(browser, "settings");
g_object_get(settings, "toolbar-items", &items, NULL);
g_object_unref(settings);
names = g_strsplit(items ? items : "", ",", 0);
list = tb_editor_array_to_list((const gchar **) names);
g_strfreev(names);
g_free(items);
return list;
}
static GSList *tb_editor_get_available_actions(MidoriBrowser *browser)
{
GSList *list = NULL;
list = tb_editor_array_to_list(midori_browser_get_toolbar_actions(browser));
return list;
}
static void tb_editor_scroll_to_iter(GtkTreeView *treeview, GtkTreeIter *iter)
{
GtkTreePath *path = gtk_tree_model_get_path(gtk_tree_view_get_model(treeview), iter);
gtk_tree_view_scroll_to_cell(treeview, path, NULL, TRUE, 0.5, 0.0);
gtk_tree_path_free(path);
}
static void tb_editor_free_path(TBEditorWidget *tbw)
{
if (tbw->last_drag_path != NULL)
{
gtk_tree_path_free(tbw->last_drag_path);
tbw->last_drag_path = NULL;
}
}
static void tb_editor_btn_remove_clicked_cb(GtkWidget *button, TBEditorWidget *tbw)
{
GtkTreeModel *model_used;
GtkTreeSelection *selection_used;
GtkTreeIter iter_used, iter_new;
gchar *action_name;
selection_used = gtk_tree_view_get_selection(tbw->tree_used);
if (gtk_tree_selection_get_selected(selection_used, &model_used, &iter_used))
{
gtk_tree_model_get(model_used, &iter_used, TB_EDITOR_COL_ACTION, &action_name, -1);
if (g_strcmp0(action_name, "Location") != 0)
{
if (gtk_list_store_remove(tbw->store_used, &iter_used))
gtk_tree_selection_select_iter(selection_used, &iter_used);
if (g_strcmp0(action_name, "Separator") != 0)
{
gtk_list_store_append(tbw->store_available, &iter_new);
tb_editor_set_item_values(tbw, action_name, tbw->store_available, &iter_new);
tb_editor_scroll_to_iter(tbw->tree_available, &iter_new);
}
}
g_free(action_name);
}
}
static void tb_editor_btn_add_clicked_cb(GtkWidget *button, TBEditorWidget *tbw)
{
GtkTreeModel *model_available;
GtkTreeSelection *selection_available, *selection_used;
GtkTreeIter iter_available, iter_new, iter_selected;
gchar *action_name;
selection_available = gtk_tree_view_get_selection(tbw->tree_available);
if (gtk_tree_selection_get_selected(selection_available, &model_available, &iter_available))
{
gtk_tree_model_get(model_available, &iter_available, TB_EDITOR_COL_ACTION, &action_name, -1);
if (g_strcmp0(action_name, "Separator") != 0)
{
if (gtk_list_store_remove(tbw->store_available, &iter_available))
gtk_tree_selection_select_iter(selection_available, &iter_available);
}
selection_used = gtk_tree_view_get_selection(tbw->tree_used);
if (gtk_tree_selection_get_selected(selection_used, NULL, &iter_selected))
{
gtk_list_store_insert_before(tbw->store_used, &iter_new, &iter_selected);
tb_editor_set_item_values(tbw, action_name, tbw->store_used, &iter_new);
}
else
{
gtk_list_store_append(tbw->store_used, &iter_new);
tb_editor_set_item_values(tbw, action_name, tbw->store_used, &iter_new);
}
tb_editor_scroll_to_iter(tbw->tree_used, &iter_new);
g_free(action_name);
}
}
static gboolean tb_editor_drag_motion_cb(GtkWidget *widget, GdkDragContext *drag_context,
gint x, gint y, guint ltime, TBEditorWidget *tbw)
{
if (tbw->last_drag_path != NULL)
gtk_tree_path_free(tbw->last_drag_path);
gtk_tree_view_get_drag_dest_row(GTK_TREE_VIEW(widget),
&(tbw->last_drag_path), &(tbw->last_drag_pos));
return FALSE;
}
static void tb_editor_drag_data_get_cb(GtkWidget *widget, GdkDragContext *context,
GtkSelectionData *data, guint info, guint ltime,
TBEditorWidget *tbw)
{
GtkTreeIter iter;
GtkTreeSelection *selection;
GtkTreeModel *model;
GdkAtom atom;
gchar *name;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
if (! gtk_tree_selection_get_selected(selection, &model, &iter))
return;
gtk_tree_model_get(model, &iter, TB_EDITOR_COL_ACTION, &name, -1);
if (name == NULL || *name == '\0')
{
g_free(name);
return;
}
atom = gdk_atom_intern(tb_editor_dnd_targets[0].target, FALSE);
gtk_selection_data_set(data, atom, 8, (guchar*) name, strlen(name));
g_free(name);
tbw->drag_source = widget;
}
static void tb_editor_drag_data_rcvd_cb(GtkWidget *widget, GdkDragContext *context,
gint x, gint y, GtkSelectionData *data, guint info,
guint ltime, TBEditorWidget *tbw)
{
GtkTreeView *tree = GTK_TREE_VIEW(widget);
gboolean del = FALSE;
if (data->length >= 0 && data->format == 8)
{
gboolean is_sep;
gchar *text = NULL;
text = (gchar*) data->data;
/* We allow re-ordering the Location item but not removing it from the list. */
if (g_strcmp0(text, "Location") == 0 && widget != tbw->drag_source)
return;
is_sep = (g_strcmp0(text, "Separator") == 0);
/* If the source of the action is equal to the target, we do just re-order and so need
* to delete the separator to get it moved, not just copied. */
if (is_sep && widget == tbw->drag_source)
is_sep = FALSE;
if (tree != tbw->tree_available || ! is_sep)
{
GtkTreeIter iter, iter_before, *iter_before_ptr;
GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(tree));
if (tbw->last_drag_path != NULL)
{
gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter_before, tbw->last_drag_path);
if (gtk_list_store_iter_is_valid(store, &iter_before))
iter_before_ptr = &iter_before;
else
iter_before_ptr = NULL;
if (tbw->last_drag_pos == GTK_TREE_VIEW_DROP_BEFORE ||
tbw->last_drag_pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
gtk_list_store_insert_before(store, &iter, iter_before_ptr);
else
gtk_list_store_insert_after(store, &iter, iter_before_ptr);
tb_editor_set_item_values(tbw, text, store, &iter);
}
else
{
gtk_list_store_append(store, &iter);
tb_editor_set_item_values(tbw, text, store, &iter);
}
tb_editor_scroll_to_iter(tree, &iter);
}
if (tree != tbw->tree_used || ! is_sep)
del = TRUE;
}
tbw->drag_source = NULL; /* reset the value just to be sure */
tb_editor_free_path(tbw);
gtk_drag_finish(context, TRUE, del, ltime);
}
static gboolean tb_editor_foreach_used(GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
{
gchar *action_name;
gtk_tree_model_get(model, iter, TB_EDITOR_COL_ACTION, &action_name, -1);
if (action_name != NULL && *action_name != '\0')
{
g_string_append(data, action_name);
g_string_append_c(data, ',');
}
g_free(action_name);
return FALSE;
}
static void tb_editor_update_toolbar(TBEditorWidget *tbw)
{
MidoriWebSettings *settings;
GString *str = g_string_new(NULL);
gtk_tree_model_foreach(GTK_TREE_MODEL(tbw->store_used), tb_editor_foreach_used, str);
settings = katze_object_get_object(tbw->browser, "settings");
g_object_set(settings, "toolbar-items", str->str, NULL);
g_object_unref(settings);
g_string_free(str, TRUE);
}
static void tb_editor_available_items_changed_cb(GtkTreeModel *model, GtkTreePath *arg1,
GtkTreeIter *arg2, TBEditorWidget *tbw)
{
tb_editor_update_toolbar(tbw);
}
static void tb_editor_available_items_deleted_cb(GtkTreeModel *model, GtkTreePath *arg1,
TBEditorWidget *tbw)
{
tb_editor_update_toolbar(tbw);
}
static TBEditorWidget *tb_editor_create_dialog(MidoriBrowser *parent)
{
GtkWidget *dialog, *vbox, *hbox, *vbox_buttons, *button_add, *button_remove;
GtkWidget *swin_available, *swin_used, *tree_available, *tree_used, *label;
GtkCellRenderer *text_renderer, *icon_renderer;
GtkTreeViewColumn *column;
TBEditorWidget *tbw = g_new(TBEditorWidget, 1);
dialog = gtk_dialog_new_with_buttons(_("Customize Toolbar"),
GTK_WINDOW(parent),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
vbox = (GTK_DIALOG(dialog))->vbox;
gtk_box_set_spacing(GTK_BOX(vbox), 6);
gtk_widget_set_name(dialog, "GeanyDialog");
gtk_window_set_default_size(GTK_WINDOW(dialog), -1, 400);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
tbw->store_available = gtk_list_store_new(TB_EDITOR_COLS_MAX,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
tbw->store_used = gtk_list_store_new(TB_EDITOR_COLS_MAX,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
label = gtk_label_new(
_("Select items to be displayed on the toolbar. Items can be reodered by drag and drop."));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
tree_available = gtk_tree_view_new();
gtk_tree_view_set_model(GTK_TREE_VIEW(tree_available), GTK_TREE_MODEL(tbw->store_available));
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_available), TRUE);
gtk_tree_sortable_set_sort_column_id(
GTK_TREE_SORTABLE(tbw->store_available), TB_EDITOR_COL_LABEL, GTK_SORT_ASCENDING);
icon_renderer = gtk_cell_renderer_pixbuf_new();
column = gtk_tree_view_column_new_with_attributes(
NULL, icon_renderer, "stock-id", TB_EDITOR_COL_ICON, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_available), column);
text_renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
_("Available Items"), text_renderer, "text", TB_EDITOR_COL_LABEL, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_available), column);
swin_available = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin_available),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swin_available), GTK_SHADOW_ETCHED_IN);
gtk_container_add(GTK_CONTAINER(swin_available), tree_available);
tree_used = gtk_tree_view_new();
gtk_tree_view_set_model(GTK_TREE_VIEW(tree_used), GTK_TREE_MODEL(tbw->store_used));
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_used), TRUE);
gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tree_used), TRUE);
icon_renderer = gtk_cell_renderer_pixbuf_new();
column = gtk_tree_view_column_new_with_attributes(
NULL, icon_renderer, "stock-id", TB_EDITOR_COL_ICON, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_used), column);
text_renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
_("Displayed Items"), text_renderer, "text", TB_EDITOR_COL_LABEL, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_used), column);
swin_used = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin_used),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swin_used), GTK_SHADOW_ETCHED_IN);
gtk_container_add(GTK_CONTAINER(swin_used), tree_used);
/* drag'n'drop */
gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(tree_available), GDK_BUTTON1_MASK,
tb_editor_dnd_targets, tb_editor_dnd_targets_len, GDK_ACTION_MOVE);
gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(tree_available),
tb_editor_dnd_targets, tb_editor_dnd_targets_len, GDK_ACTION_MOVE);
g_signal_connect(tree_available, "drag-data-get",
G_CALLBACK(tb_editor_drag_data_get_cb), tbw);
g_signal_connect(tree_available, "drag-data-received",
G_CALLBACK(tb_editor_drag_data_rcvd_cb), tbw);
g_signal_connect(tree_available, "drag-motion",
G_CALLBACK(tb_editor_drag_motion_cb), tbw);
gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(tree_used), GDK_BUTTON1_MASK,
tb_editor_dnd_targets, tb_editor_dnd_targets_len, GDK_ACTION_MOVE);
gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(tree_used),
tb_editor_dnd_targets, tb_editor_dnd_targets_len, GDK_ACTION_MOVE);
g_signal_connect(tree_used, "drag-data-get",
G_CALLBACK(tb_editor_drag_data_get_cb), tbw);
g_signal_connect(tree_used, "drag-data-received",
G_CALLBACK(tb_editor_drag_data_rcvd_cb), tbw);
g_signal_connect(tree_used, "drag-motion",
G_CALLBACK(tb_editor_drag_motion_cb), tbw);
button_add = gtk_button_new();
gtk_button_set_image(GTK_BUTTON(button_add),
gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON));
button_remove = gtk_button_new();
g_signal_connect(button_add, "clicked", G_CALLBACK(tb_editor_btn_add_clicked_cb), tbw);
gtk_button_set_image(GTK_BUTTON(button_remove),
gtk_image_new_from_stock(GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON));
g_signal_connect(button_remove, "clicked", G_CALLBACK(tb_editor_btn_remove_clicked_cb), tbw);
vbox_buttons = gtk_vbox_new(FALSE, 6);
/* FIXME this is a little hack'ish, any better ideas? */
gtk_box_pack_start(GTK_BOX(vbox_buttons), gtk_label_new(""), TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox_buttons), button_add, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox_buttons), button_remove, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox_buttons), gtk_label_new(""), TRUE, TRUE, 0);
hbox = gtk_hbox_new(FALSE, 6);
gtk_box_pack_start(GTK_BOX(hbox), swin_available, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox_buttons, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), swin_used, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 6);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show_all(vbox);
g_object_unref(tbw->store_available);
g_object_unref(tbw->store_used);
tbw->dialog = dialog;
tbw->tree_available = GTK_TREE_VIEW(tree_available);
tbw->tree_used = GTK_TREE_VIEW(tree_used);
tbw->last_drag_path = NULL;
return tbw;
}
static void tb_editor_menu_configure_toolbar_activate_cb(GtkWidget *menuitem, MidoriBrowser *browser)
{
GSList *node, *used_items, *all_items;
GtkTreeIter iter;
GtkTreePath *path;
TBEditorWidget *tbw;
/* read the current active toolbar items */
used_items = tb_editor_parse_active_items(browser);
/* get all available actions */
all_items = tb_editor_get_available_actions(browser);
/* create the GUI */
tbw = tb_editor_create_dialog(browser);
/* cache some pointers, this is safe enough since the dialog is run modally */
tbw->action_group = midori_browser_get_action_group(browser);
tbw->browser = browser;
/* fill the stores */
for (node = all_items; node != NULL; node = node->next)
{
if (strcmp(node->data, "Separator") == 0 ||
g_slist_find_custom(used_items, node->data, (GCompareFunc) strcmp) == NULL)
{
gtk_list_store_append(tbw->store_available, &iter);
tb_editor_set_item_values(tbw, node->data, tbw->store_available, &iter);
}
}
for (node = used_items; node != NULL; node = node->next)
{
gtk_list_store_append(tbw->store_used, &iter);
tb_editor_set_item_values(tbw, node->data, tbw->store_used, &iter);
}
/* select first item */
path = gtk_tree_path_new_from_string("0");
gtk_tree_selection_select_path(gtk_tree_view_get_selection(tbw->tree_used), path);
gtk_tree_path_free(path);
/* connect the changed signals after populating the store */
g_signal_connect(tbw->store_used, "row-changed",
G_CALLBACK(tb_editor_available_items_changed_cb), tbw);
g_signal_connect(tbw->store_used, "row-deleted",
G_CALLBACK(tb_editor_available_items_deleted_cb), tbw);
/* run it */
gtk_dialog_run(GTK_DIALOG(tbw->dialog));
gtk_widget_destroy(tbw->dialog);
g_slist_foreach(used_items, (GFunc) g_free, NULL);
g_slist_foreach(all_items, (GFunc) g_free, NULL);
g_slist_free(used_items);
g_slist_free(all_items);
tb_editor_free_path(tbw);
g_free(tbw);
}
static void tb_editor_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext)
{
GtkWidget *panel;
GtkWidget *menu;
GtkWidget *menuitem;
panel = katze_object_get_object(browser, "panel");
menu = katze_object_get_object(panel, "menu");
g_object_unref(panel);
menuitem = gtk_menu_item_new_with_mnemonic(_("Configure _Toolbar..."));
g_signal_connect(menuitem, "activate",
G_CALLBACK(tb_editor_menu_configure_toolbar_activate_cb), browser);
gtk_widget_show(menuitem);
gtk_menu_shell_insert(GTK_MENU_SHELL (menu), menuitem, 3);
g_object_unref(menu);
g_signal_connect(ext, "deactivate", G_CALLBACK(tb_editor_deactivate_cb), menuitem);
}
static void tb_editor_activate_cb(MidoriExtension *extension, MidoriApp *app)
{
KatzeArray *browsers;
MidoriBrowser *browser;
guint i;
browsers = katze_object_get_object(app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item(browsers, i++)))
tb_editor_app_add_browser_cb(app, browser, extension);
g_signal_connect(app, "add-browser", G_CALLBACK(tb_editor_app_add_browser_cb), extension);
g_object_unref(browsers);
}
MidoriExtension *extension_init(void)
{
MidoriExtension* extension = g_object_new(MIDORI_TYPE_EXTENSION,
"name", _("Toolbar Editor"),
"description", _("Easily edit the toolbar layout"),
"version", "0.1",
"authors", "Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>",
NULL);
g_signal_connect(extension, "activate", G_CALLBACK(tb_editor_activate_cb), NULL);
return extension;
}
#endif

View file

@ -2,11 +2,10 @@
# WAF build script for midori # WAF build script for midori
# This file is licensed under the terms of the expat license, see the file EXPAT. # This file is licensed under the terms of the expat license, see the file EXPAT.
import os
extensions = os.listdir ('extensions') extensions = os.listdir ('extensions')
for extension in extensions: for extension in extensions:
# Tab Panel isn't useful at this point
if extension == 'tab-panel':
continue
# Adblock is incomplete and not ready for release # Adblock is incomplete and not ready for release
if extension == 'adblock.c': if extension == 'adblock.c':
continue continue

View file

@ -3,6 +3,7 @@
# This file is licensed under the terms of the expat license, see the file EXPAT. # This file is licensed under the terms of the expat license, see the file EXPAT.
import Utils import Utils
import os
def add_image (bld, category, name): def add_image (bld, category, name):
@ -14,10 +15,10 @@ def add_image (bld, category, name):
if rsvg_convert: if rsvg_convert:
Utils.check_dir (blddir + '/icons') Utils.check_dir (blddir + '/icons')
for size in [16, 22, 32, 48]: for size in [16, 22, 24, 32, 48]:
format = str (size) + 'x' + str (size) format = str (size) + 'x' + str (size)
if os.access (srcdir + '/icons/' + format + '/' + name + '.png', os.F_OK): if os.access (srcdir + '/icons/' + format + '/' + name + '.png', os.F_OK):
bld.install_files ('${DATADIR}/icons/hicolor/' + format + '/' + category, bld.install_files ('${MDATADIR}/icons/hicolor/' + format + '/' + category,
srcdir + '/icons/' + format + '/' + name + '.png') srcdir + '/icons/' + format + '/' + name + '.png')
elif not rsvg_convert: elif not rsvg_convert:
pass pass
@ -28,7 +29,7 @@ def add_image (bld, category, name):
' -o ' + blddir + '/icons/' + format + '/' + name + '.png' + \ ' -o ' + blddir + '/icons/' + format + '/' + name + '.png' + \
' ' + srcdir + '/icons/scalable/' + name + '.svg' ' ' + srcdir + '/icons/scalable/' + name + '.svg'
if not Utils.exec_command (command): if not Utils.exec_command (command):
bld.install_files ('${DATADIR}/icons/hicolor/' + format + '/' + category, bld.install_files ('${MDATADIR}/icons/hicolor/' + format + '/' + category,
blddir + '/icons/' + format + '/' + name + '.png') blddir + '/icons/' + format + '/' + name + '.png')
else: else:
Utils.pprint ('BLUE', "Optimized icons could not be created.") Utils.pprint ('BLUE', "Optimized icons could not be created.")

View file

@ -559,7 +559,7 @@ katze_array_action_create_tool_item_for (KatzeArrayAction* array_action,
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image); gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
label = gtk_label_new (NULL); label = gtk_label_new (NULL);
/* FIXME: Should text direction be respected here? */ /* FIXME: Should text direction be respected here? */
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_label_set_max_width_chars (GTK_LABEL (label), 25); gtk_label_set_max_width_chars (GTK_LABEL (label), 25);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE); gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
gtk_widget_show (label); gtk_widget_show (label);

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de> Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -147,7 +147,8 @@ katze_item_class_init (KatzeItemClass* class)
static void static void
katze_item_init (KatzeItem* item) katze_item_init (KatzeItem* item)
{ {
/* Nothing to do here */ item->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
} }
static void static void
@ -161,6 +162,8 @@ katze_item_finalize (GObject* object)
g_free (item->icon); g_free (item->icon);
g_free (item->token); g_free (item->token);
g_hash_table_unref (item->metadata);
G_OBJECT_CLASS (katze_item_parent_class)->finalize (object); G_OBJECT_CLASS (katze_item_parent_class)->finalize (object);
} }
@ -451,6 +454,151 @@ katze_item_set_added (KatzeItem* item,
g_object_notify (G_OBJECT (item), "added"); g_object_notify (G_OBJECT (item), "added");
} }
/**
* katze_item_get_meta_keys:
* @item: a #KatzeItem
*
* Retrieves a list of all meta keys.
*
* Return value: a newly allocated #GList of constant strings
*
* Since: 0.1.8
**/
GList*
katze_item_get_meta_keys (KatzeItem* item)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
return g_hash_table_get_keys (item->metadata);
}
static void
katze_item_set_meta_data_value (KatzeItem* item,
const gchar* key,
gchar* value)
{
/* FIXME: Make the default namespace configurable */
if (g_str_has_prefix (key, "midori:"))
g_hash_table_insert (item->metadata, g_strdup (&key[7]), value);
else
g_hash_table_insert (item->metadata, g_strdup (key), value);
/* TODO: Emit meta-key-changed */
}
/**
* katze_item_get_meta_string:
* @item: a #KatzeItem
* @key: the name of an integer value
*
* Retrieves a string value by the specified key from the
* meta data of the item.
*
* Specify "namespace:key" or "key" to use the default namespace.
*
* Return value: a string, or %NULL
*
* Since: 0.1.8
**/
const gchar*
katze_item_get_meta_string (KatzeItem* item,
const gchar* key)
{
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
g_return_val_if_fail (key != NULL, NULL);
if (g_str_has_prefix (key, "midori:"))
key = &key[7];
return g_hash_table_lookup (item->metadata, key);
}
/**
* katze_item_set_meta_string:
* @item: a #KatzeItem
* @key: the name of a string value
* @value: the value as a string
*
* Saves the specified string value in the meta data of
* the item under the specified key.
*
* Specify "namespace:key" or "key" to use the default namespace.
*
* Since: 0.1.8
**/
void
katze_item_set_meta_string (KatzeItem* item,
const gchar* key,
const gchar* value)
{
g_return_if_fail (KATZE_IS_ITEM (item));
g_return_if_fail (key != NULL);
katze_item_set_meta_data_value (item, key, g_strdup (value));
}
/**
* katze_item_get_meta_integer:
* @item: a #KatzeItem
* @key: the name of an integer value
*
* Retrieves an integer value by the specified key from the
* meta data of the item.
*
* If the key is present but not representable as an
* integer, -1 is returned.
*
* Return value: an integer value, or -1
*
* Since: 0.1.8
**/
gint64
katze_item_get_meta_integer (KatzeItem* item,
const gchar* key)
{
gpointer value;
g_return_val_if_fail (KATZE_IS_ITEM (item), -1);
g_return_val_if_fail (key != NULL, -1);
if (g_str_has_prefix (key, "midori:"))
key = &key[7];
if (g_hash_table_lookup_extended (item->metadata, key, NULL, &value))
return g_ascii_strtoll (value, NULL, 0);
return -1;
}
/**
* katze_item_set_meta_integer:
* @item: a #KatzeItem
* @key: the name of an integer value
*
* Saves the specified integer value in the meta data of
* the item under the specified key.
*
* A value of -1 is intepreted as unset.
*
* Since: 0.1.8
**/
void
katze_item_set_meta_integer (KatzeItem* item,
const gchar* key,
gint64 value)
{
g_return_if_fail (KATZE_IS_ITEM (item));
g_return_if_fail (key != NULL);
if (value == -1)
katze_item_set_meta_data_value (item, key, NULL);
else
{
katze_item_set_meta_data_value (item, key,
#ifdef G_GINT64_FORMAT
g_strdup_printf ("%" G_GINT64_FORMAT, value));
#else
g_strdup_printf ("%li", value));
#endif
}
}
/** /**
* katze_item_get_parent: * katze_item_get_parent:
* @item: a #KatzeItem * @item: a #KatzeItem

View file

@ -42,6 +42,7 @@ struct _KatzeItem
gchar* icon; gchar* icon;
gchar* token; gchar* token;
gint64 added; gint64 added;
GHashTable* metadata;
KatzeItem* parent; KatzeItem* parent;
}; };
@ -102,6 +103,27 @@ void
katze_item_set_added (KatzeItem* item, katze_item_set_added (KatzeItem* item,
gint64 added); gint64 added);
GList*
katze_item_get_meta_keys (KatzeItem* item);
const gchar*
katze_item_get_meta_string (KatzeItem* item,
const gchar* key);
void
katze_item_set_meta_string (KatzeItem* item,
const gchar* key,
const gchar* value);
gint64
katze_item_get_meta_integer (KatzeItem* item,
const gchar* key);
void
katze_item_set_meta_integer (KatzeItem* item,
const gchar* key,
gint64 value);
gpointer gpointer
katze_item_get_parent (KatzeItem* item); katze_item_get_parent (KatzeItem* item);

View file

@ -129,6 +129,22 @@ proxy_object_notify_string_cb (GObject* object,
g_free (value); g_free (value);
} }
static void
proxy_widget_boolean_destroy_cb (GtkWidget* proxy,
GObject* object)
{
g_signal_handlers_disconnect_by_func (object,
proxy_object_notify_boolean_cb, proxy);
}
static void
proxy_widget_string_destroy_cb (GtkWidget* proxy,
GObject* object)
{
g_signal_handlers_disconnect_by_func (object,
proxy_object_notify_string_cb, proxy);
}
/** /**
* katze_property_proxy: * katze_property_proxy:
* @object: a #GObject * @object: a #GObject
@ -153,6 +169,7 @@ proxy_object_notify_string_cb (GObject* object,
* Since 0.1.6 the following hints are also supported: * Since 0.1.6 the following hints are also supported:
* "toggle": the widget created will be an empty toggle button. This * "toggle": the widget created will be an empty toggle button. This
* is only supported with boolean properties. * is only supported with boolean properties.
* Since 0.1.8 "toggle" creates GtkCheckButton widgets without checkmarks.
* *
* Any other values for @hint are silently ignored. * Any other values for @hint are silently ignored.
* *
@ -196,16 +213,19 @@ katze_property_proxy (gpointer object,
gchar* notify_property; gchar* notify_property;
gboolean toggled = katze_object_get_boolean (object, property); gboolean toggled = katze_object_get_boolean (object, property);
widget = gtk_check_button_new ();
if (_hint == g_intern_string ("toggle")) if (_hint == g_intern_string ("toggle"))
widget = gtk_toggle_button_new (); gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (widget), FALSE);
else else
widget = gtk_check_button_new_with_label (gettext (nick)); gtk_button_set_label (GTK_BUTTON (widget), gettext (nick));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), toggled); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), toggled);
g_signal_connect (widget, "toggled", g_signal_connect (widget, "toggled",
G_CALLBACK (proxy_toggle_button_toggled_cb), object); G_CALLBACK (proxy_toggle_button_toggled_cb), object);
notify_property = g_strdup_printf ("notify::%s", property); notify_property = g_strdup_printf ("notify::%s", property);
g_signal_connect (object, notify_property, g_signal_connect (object, notify_property,
G_CALLBACK (proxy_object_notify_boolean_cb), widget); G_CALLBACK (proxy_object_notify_boolean_cb), widget);
g_signal_connect (widget, "destroy",
G_CALLBACK (proxy_widget_boolean_destroy_cb), object);
g_free (notify_property); g_free (notify_property);
} }
else if (type == G_TYPE_PARAM_STRING && _hint == g_intern_string ("file")) else if (type == G_TYPE_PARAM_STRING && _hint == g_intern_string ("file"))
@ -298,6 +318,8 @@ katze_property_proxy (gpointer object,
notify_property = g_strdup_printf ("notify::%s", property); notify_property = g_strdup_printf ("notify::%s", property);
g_signal_connect (object, notify_property, g_signal_connect (object, notify_property,
G_CALLBACK (proxy_object_notify_string_cb), widget); G_CALLBACK (proxy_object_notify_string_cb), widget);
g_signal_connect (widget, "destroy",
G_CALLBACK (proxy_widget_string_destroy_cb), object);
g_free (notify_property); g_free (notify_property);
} }
else if (type == G_TYPE_PARAM_FLOAT) else if (type == G_TYPE_PARAM_FLOAT)
@ -602,6 +624,64 @@ katze_tree_view_get_selected_iter (GtkTreeView* treeview,
return FALSE; return FALSE;
} }
/**
* katze_strip_mnemonics:
* @original: a string with mnemonics
*
* Parses the given string for mnemonics in the form
* "B_utton" or "Button (_U)" and returns a string
* without any mnemonics.
*
* Return value: a newly allocated string without mnemonics
*
* Since: 0.1.8
**/
gchar*
katze_strip_mnemonics (const gchar* original)
{
/* A copy of _gtk_toolbar_elide_underscores
Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Copied from GTK+ 2.17.1 */
gchar *q, *result;
const gchar *p, *end;
gsize len;
gboolean last_underscore;
if (!original)
return NULL;
len = strlen (original);
q = result = g_malloc (len + 1);
last_underscore = FALSE;
end = original + len;
for (p = original; p < end; p++)
{
if (!last_underscore && *p == '_')
last_underscore = TRUE;
else
{
last_underscore = FALSE;
if (original + 2 <= p && p + 1 <= end &&
p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')')
{
q--;
*q = '\0';
p++;
}
else
*q++ = *p;
}
}
if (last_underscore)
*q++ = '_';
*q = '\0';
return result;
}
/** /**
* katze_object_has_property: * katze_object_has_property:
* @object: a #GObject * @object: a #GObject

View file

@ -106,6 +106,9 @@ katze_tree_view_get_selected_iter (GtkTreeView* treeview,
GtkTreeModel** model, GtkTreeModel** model,
GtkTreeIter* iter); GtkTreeIter* iter);
gchar*
katze_strip_mnemonics (const gchar* original);
gboolean gboolean
katze_object_has_property (gpointer object, katze_object_has_property (gpointer object,
const gchar* property); const gchar* property);

View file

@ -27,10 +27,13 @@ gtk_icon_entry_set_icon_from_pixbuf (GtkEntry* entry,
GtkEntryIconPosition position, GtkEntryIconPosition position,
GdkPixbuf* pixbuf) GdkPixbuf* pixbuf)
{ {
gboolean activatable;
/* Without this ugly hack pixbuf icons don't work */ /* Without this ugly hack pixbuf icons don't work */
gtk_widget_hide (GTK_WIDGET (entry)); activatable = gtk_entry_get_icon_activatable (entry, position);
gtk_entry_set_icon_from_pixbuf (entry, position, pixbuf); gtk_entry_set_icon_from_pixbuf (entry, position, pixbuf);
gtk_widget_show (GTK_WIDGET (entry)); gtk_entry_set_icon_activatable (entry, position, !activatable);
gtk_entry_set_icon_activatable (entry, position, activatable);
} }
#else #else

View file

@ -220,9 +220,9 @@ settings_save_to_file (MidoriWebSettings* settings,
} }
else if (type == G_TYPE_PARAM_BOOLEAN) else if (type == G_TYPE_PARAM_BOOLEAN)
{ {
gboolean boolean; gboolean truth;
g_object_get (settings, property, &boolean, NULL); g_object_get (settings, property, &truth, NULL);
g_key_file_set_boolean (key_file, "settings", property, boolean); g_key_file_set_boolean (key_file, "settings", property, truth);
} }
else if (type == G_TYPE_PARAM_ENUM) else if (type == G_TYPE_PARAM_ENUM)
{ {
@ -744,6 +744,15 @@ settings_notify_cb (MidoriWebSettings* settings,
g_free (config_file); g_free (config_file);
} }
static void
extension_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
MidoriWebSettings* settings = katze_object_get_object (app, "settings");
settings_notify_cb (settings, NULL, app);
g_object_unref (settings);
}
static void static void
accel_map_changed_cb (GtkAccelMap* accel_map, accel_map_changed_cb (GtkAccelMap* accel_map,
gchar* accel_path, gchar* accel_path,
@ -1185,6 +1194,8 @@ midori_load_extensions (gpointer data)
if (extension_dir != NULL) if (extension_dir != NULL)
{ {
const gchar* filename; const gchar* filename;
gchar* config_file = build_config_filename ("config");
gboolean is_writable = is_writable (config_file);
while ((filename = g_dir_read_name (extension_dir))) while ((filename = g_dir_read_name (extension_dir)))
{ {
@ -1228,9 +1239,17 @@ midori_load_extensions (gpointer data)
if (!g_strcmp0 (filename, name)) if (!g_strcmp0 (filename, name))
g_signal_emit_by_name (extension, "activate", app); g_signal_emit_by_name (extension, "activate", app);
} }
if (is_writable)
{
g_signal_connect_after (extension, "activate",
G_CALLBACK (extension_activate_cb), app);
g_signal_connect_after (extension, "deactivate",
G_CALLBACK (extension_activate_cb), app);
}
g_object_unref (extension); g_object_unref (extension);
} }
g_dir_close (extension_dir); g_dir_close (extension_dir);
g_free (config_file);
} }
g_free (extension_path); g_free (extension_path);
} }
@ -1250,6 +1269,8 @@ midori_load_session (gpointer data)
KatzeArray* session; KatzeArray* session;
KatzeItem* item; KatzeItem* item;
guint i; guint i;
gint64 current;
gchar** command = g_object_get_data (G_OBJECT (app), "execute-command");
browser = midori_app_create_browser (app); browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser); midori_app_add_browser (app, browser);
@ -1285,8 +1306,12 @@ midori_load_session (gpointer data)
i = 0; i = 0;
while ((item = katze_array_get_nth_item (_session, i++))) while ((item = katze_array_get_nth_item (_session, i++)))
midori_browser_add_item (browser, item); midori_browser_add_item (browser, item);
/* FIXME: Switch to the last active page */ current = katze_item_get_meta_integer (KATZE_ITEM (_session), "current");
item = katze_array_get_nth_item (_session, 0); if (current < 0)
current = 0;
midori_browser_set_current_page (browser, current);
if (!(item = katze_array_get_nth_item (_session, current)))
item = katze_array_get_nth_item (_session, 0);
if (!strcmp (katze_item_get_uri (item), "")) if (!strcmp (katze_item_get_uri (item), ""))
midori_browser_activate_action (browser, "Location"); midori_browser_activate_action (browser, "Location");
g_object_unref (_session); g_object_unref (_session);
@ -1304,9 +1329,13 @@ midori_load_session (gpointer data)
(GWeakNotify)(midori_browser_weak_notify_cb), browser); (GWeakNotify)(midori_browser_weak_notify_cb), browser);
} }
if (command)
midori_app_send_command (app, command);
return FALSE; return FALSE;
} }
#ifdef HAVE_JSCORE
static gint static gint
midori_run_script (const gchar* filename) midori_run_script (const gchar* filename)
{ {
@ -1344,6 +1373,7 @@ midori_run_script (const gchar* filename)
g_print ("%s - Exception: %s\n", filename, exception); g_print ("%s - Exception: %s\n", filename, exception);
return 1; return 1;
} }
#endif
#if WEBKIT_CHECK_VERSION (1, 1, 6) #if WEBKIT_CHECK_VERSION (1, 1, 6)
static void static void
@ -1372,6 +1402,19 @@ snapshot_load_finished_cb (GtkWidget* web_view,
} }
#endif #endif
static void
midori_web_app_browser_notify_load_status_cb (MidoriBrowser* browser,
GParamSpec* pspec,
gpointer data)
{
if (katze_object_get_enum (browser, "load-status") != MIDORI_LOAD_PROVISIONAL)
{
GtkWidget* view = midori_browser_get_current_tab (browser);
GdkPixbuf* icon = midori_view_get_icon (MIDORI_VIEW (view));
gtk_window_set_icon (GTK_WINDOW (browser), icon);
}
}
int int
main (int argc, main (int argc,
char** argv) char** argv)
@ -1380,6 +1423,7 @@ main (int argc,
gchar* config; gchar* config;
gboolean run; gboolean run;
gchar* snapshot; gchar* snapshot;
gboolean execute;
gboolean version; gboolean version;
gchar** uris; gchar** uris;
MidoriApp* app; MidoriApp* app;
@ -1391,12 +1435,16 @@ main (int argc,
N_("Run ADDRESS as a web application"), N_("ADDRESS") }, N_("Run ADDRESS as a web application"), N_("ADDRESS") },
{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &config, { "config", 'c', 0, G_OPTION_ARG_FILENAME, &config,
N_("Use FOLDER as configuration folder"), N_("FOLDER") }, N_("Use FOLDER as configuration folder"), N_("FOLDER") },
#ifdef HAVE_JSCORE
{ "run", 'r', 0, G_OPTION_ARG_NONE, &run, { "run", 'r', 0, G_OPTION_ARG_NONE, &run,
N_("Run the specified filename as javascript"), NULL }, N_("Run the specified filename as javascript"), NULL },
#endif
#if WEBKIT_CHECK_VERSION (1, 1, 6) #if WEBKIT_CHECK_VERSION (1, 1, 6)
{ "snapshot", 's', 0, G_OPTION_ARG_STRING, &snapshot, { "snapshot", 's', 0, G_OPTION_ARG_STRING, &snapshot,
N_("Take a snapshot of the specified URI"), NULL }, N_("Take a snapshot of the specified URI"), NULL },
#endif #endif
{ "execute", 'e', 0, G_OPTION_ARG_NONE, &execute,
N_("Execute the specified command"), NULL },
{ "version", 'V', 0, G_OPTION_ARG_NONE, &version, { "version", 'V', 0, G_OPTION_ARG_NONE, &version,
N_("Display program version"), NULL }, N_("Display program version"), NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &uris, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &uris,
@ -1430,7 +1478,15 @@ main (int argc,
if (g_getenv ("NLSPATH")) if (g_getenv ("NLSPATH"))
bindtextdomain (GETTEXT_PACKAGE, g_getenv ("NLSPATH")); bindtextdomain (GETTEXT_PACKAGE, g_getenv ("NLSPATH"));
else else
#ifdef G_OS_WIN32
{
gchar* path = sokoke_find_data_filename ("locale");
bindtextdomain (GETTEXT_PACKAGE, path);
g_free (path);
}
#else
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
#endif
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE); textdomain (GETTEXT_PACKAGE);
#endif #endif
@ -1440,6 +1496,7 @@ main (int argc,
config = NULL; config = NULL;
run = FALSE; run = FALSE;
snapshot = NULL; snapshot = NULL;
execute = FALSE;
version = FALSE; version = FALSE;
uris = NULL; uris = NULL;
error = NULL; error = NULL;
@ -1515,10 +1572,13 @@ main (int argc,
"show-menubar", FALSE, "show-menubar", FALSE,
"show-navigationbar", TRUE, "show-navigationbar", TRUE,
"toolbar-items", "Back,Forward,ReloadStop,Location", "toolbar-items", "Back,Forward,ReloadStop,Location",
"homepage", NULL,
"show-statusbar", TRUE, "show-statusbar", TRUE,
NULL); NULL);
g_object_unref (settings); g_object_unref (settings);
g_object_set (browser, "settings", settings, NULL); g_object_set (browser, "settings", settings, NULL);
g_signal_connect (browser, "notify::load-status",
G_CALLBACK (midori_web_app_browser_notify_load_status_cb), NULL);
midori_browser_add_uri (browser, webapp); midori_browser_add_uri (browser, webapp);
g_object_set_data (G_OBJECT (browser), "locked", (void*)1); g_object_set_data (G_OBJECT (browser), "locked", (void*)1);
g_signal_connect (browser, "destroy", g_signal_connect (browser, "destroy",
@ -1529,9 +1589,11 @@ main (int argc,
return 0; return 0;
} }
#ifdef HAVE_JSCORE
/* Standalone javascript support */ /* Standalone javascript support */
if (run) if (run)
return midori_run_script (uris ? *uris : NULL); return midori_run_script (uris ? *uris : NULL);
#endif
#if HAVE_HILDON #if HAVE_HILDON
osso_context = osso_initialize (PACKAGE_NAME, PACKAGE_VERSION, FALSE, NULL); osso_context = osso_initialize (PACKAGE_NAME, PACKAGE_VERSION, FALSE, NULL);
@ -1569,8 +1631,9 @@ main (int argc,
{ {
GtkWidget* dialog; GtkWidget* dialog;
/* TODO: Open as many tabs as we have uris, seperated by pipes */ if (execute)
if (uris) result = midori_app_send_command (app, uris);
else if (uris) /* TODO: Open a tab per URI, seperated by pipes */
result = midori_app_instance_send_uris (app, uris); result = midori_app_instance_send_uris (app, uris);
else else
result = midori_app_instance_send_new_browser (app); result = midori_app_instance_send_new_browser (app);
@ -1606,6 +1669,15 @@ main (int argc,
} }
if (!error && katze_array_is_empty (search_engines)) if (!error && katze_array_is_empty (search_engines))
{ {
#ifdef G_OS_WIN32
gchar* dir;
dir = g_win32_get_package_installation_directory_of_module (NULL);
katze_assign (config_file,
g_build_filename (dir, "etc", "xdg", PACKAGE_NAME, "search", NULL));
g_free (dir);
search_engines = search_engines_new_from_file (config_file, NULL);
#else
const gchar* const * config_dirs = g_get_system_config_dirs (); const gchar* const * config_dirs = g_get_system_config_dirs ();
i = 0; i = 0;
while (config_dirs[i]) while (config_dirs[i])
@ -1625,6 +1697,7 @@ main (int argc,
g_build_filename (SYSCONFDIR, "xdg", PACKAGE_NAME, "search", NULL)); g_build_filename (SYSCONFDIR, "xdg", PACKAGE_NAME, "search", NULL));
search_engines = search_engines_new_from_file (config_file, NULL); search_engines = search_engines_new_from_file (config_file, NULL);
} }
#endif
} }
else if (error) else if (error)
{ {
@ -1730,6 +1803,9 @@ main (int argc,
} }
g_string_free (error_messages, TRUE); g_string_free (error_messages, TRUE);
/* If -e or --execute was specified, "uris" refers to the command. */
if (!execute)
{
/* Open as many tabs as we have uris, seperated by pipes */ /* Open as many tabs as we have uris, seperated by pipes */
i = 0; i = 0;
while (uris && uris[i]) while (uris && uris[i])
@ -1747,6 +1823,7 @@ main (int argc,
g_free (uri); g_free (uri);
i++; i++;
} }
}
katze_assign (config_file, build_config_filename ("config")); katze_assign (config_file, build_config_filename ("config"));
if (is_writable (config_file)) if (is_writable (config_file))
@ -1845,6 +1922,9 @@ main (int argc,
katze_item_set_parent (KATZE_ITEM (_session), app); katze_item_set_parent (KATZE_ITEM (_session), app);
g_idle_add (midori_load_session, _session); g_idle_add (midori_load_session, _session);
if (execute)
g_object_set_data (G_OBJECT (app), "execute-command", uris);
gtk_main (); gtk_main ();
#if HAVE_HILDON #if HAVE_HILDON

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de> Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -21,7 +21,14 @@
#include <glib/gi18n.h> #include <glib/gi18n.h>
#if HAVE_UNIQUE #if HAVE_UNIQUE
typedef gpointer MidoriAppInstance;
#define MidoriAppInstanceNull NULL
#include <unique/unique.h> #include <unique/unique.h>
#define MIDORI_UNIQUE_COMMAND 1
#else
typedef gint MidoriAppInstance;
#define MidoriAppInstanceNull -1
#include "socket.h"
#endif #endif
typedef struct _NotifyNotification NotifyNotification; typedef struct _NotifyNotification NotifyNotification;
@ -54,7 +61,7 @@ struct _MidoriApp
KatzeArray* extensions; KatzeArray* extensions;
KatzeArray* browsers; KatzeArray* browsers;
gpointer instance; MidoriAppInstance instance;
/* libnotify handling */ /* libnotify handling */
gchar* program_notify_send; gchar* program_notify_send;
@ -197,6 +204,7 @@ _midori_app_add_browser (MidoriApp* app,
katze_array_add_item (app->browsers, browser); katze_array_add_item (app->browsers, browser);
app->browser = browser;
#if HAVE_UNIQUE #if HAVE_UNIQUE
if (app->instance) if (app->instance)
unique_app_watch_window (app->instance, GTK_WINDOW (browser)); unique_app_watch_window (app->instance, GTK_WINDOW (browser));
@ -383,6 +391,89 @@ midori_app_class_init (MidoriAppClass* class)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
} }
static gboolean
midori_app_command_received (MidoriApp* app,
const gchar* command,
gchar** uris,
GdkScreen* screen)
{
if (!screen)
{
if (app->browser && gtk_widget_has_screen (GTK_WIDGET (app->browser)))
screen = gtk_widget_get_screen (GTK_WIDGET (app->browser));
else
screen = gdk_screen_get_default ();
}
if (g_str_equal (command, "activate"))
{
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_window_present (GTK_WINDOW (app->browser));
return TRUE;
}
else if (g_str_equal (command, "new"))
{
MidoriBrowser* browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
/* FIXME: Should open the homepage according to settings */
midori_browser_add_uri (browser, "");
midori_browser_activate_action (browser, "Location");
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_widget_show (GTK_WIDGET (browser));
return TRUE;
}
else if (g_str_equal (command, "open"))
{
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_window_present (GTK_WINDOW (app->browser));
if (!uris)
return FALSE;
else
{
MidoriBrowser* browser;
MidoriNewPage open_external_pages_in;
gboolean first;
g_object_get (app->settings, "open-external-pages-in",
&open_external_pages_in, NULL);
if (open_external_pages_in == MIDORI_NEW_PAGE_WINDOW)
{
browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_widget_show (GTK_WIDGET (browser));
}
else
browser = app->browser;
first = (open_external_pages_in == MIDORI_NEW_PAGE_CURRENT);
while (*uris)
{
gchar* fixed_uri = sokoke_magic_uri (*uris, NULL);
if (first)
{
midori_browser_set_current_uri (browser, fixed_uri);
first = FALSE;
}
else
midori_browser_set_current_page (browser,
midori_browser_add_uri (browser, fixed_uri));
g_free (fixed_uri);
uris++;
}
return TRUE;
}
}
else if (g_str_equal (command, "command"))
{
if (!uris || !app->browser)
return FALSE;
midori_browser_activate_action (app->browser, *uris);
return TRUE;
}
return FALSE;
}
#if HAVE_UNIQUE #if HAVE_UNIQUE
static UniqueResponse static UniqueResponse
midori_browser_message_received_cb (UniqueApp* instance, midori_browser_message_received_cb (UniqueApp* instance,
@ -391,98 +482,115 @@ midori_browser_message_received_cb (UniqueApp* instance,
guint timestamp, guint timestamp,
MidoriApp* app) MidoriApp* app)
{ {
UniqueResponse response; gboolean success;
MidoriBrowser* browser; GdkScreen* screen = unique_message_data_get_screen (message);
gchar** uris;
MidoriNewPage open_external_pages_in;
gboolean first;
switch (command) switch (command)
{ {
case UNIQUE_ACTIVATE: case UNIQUE_ACTIVATE:
gtk_window_set_screen (GTK_WINDOW (app->browser), success = midori_app_command_received (app, "activate", NULL, screen);
unique_message_data_get_screen (message));
gtk_window_present (GTK_WINDOW (app->browser));
response = UNIQUE_RESPONSE_OK;
break; break;
case UNIQUE_NEW: case UNIQUE_NEW:
browser = midori_app_create_browser (app); success = midori_app_command_received (app, "new", NULL, screen);
midori_app_add_browser (app, browser);
/* FIXME: Should open the homepage according to settings */
midori_browser_add_uri (browser, "");
midori_browser_activate_action (browser, "Location");
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
gtk_widget_show (GTK_WIDGET (browser));
response = UNIQUE_RESPONSE_OK;
break; break;
case UNIQUE_OPEN: case UNIQUE_OPEN:
gtk_window_set_screen (GTK_WINDOW (app->browser), {
unique_message_data_get_screen (message)); gchar** uris = unique_message_data_get_uris (message);
gtk_window_present (GTK_WINDOW (app->browser)); success = midori_app_command_received (app, "open", uris, screen);
uris = unique_message_data_get_uris (message); /* g_strfreev (uris); */
if (!uris)
response = UNIQUE_RESPONSE_FAIL;
else
{
g_object_get (app->settings, "open-external-pages-in",
&open_external_pages_in, NULL);
if (open_external_pages_in == MIDORI_NEW_PAGE_WINDOW)
{
browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
gtk_widget_show (GTK_WIDGET (browser));
}
else
browser = app->browser;
first = (open_external_pages_in == MIDORI_NEW_PAGE_CURRENT);
while (*uris)
{
gchar* fixed_uri = sokoke_magic_uri (*uris, NULL);
if (first)
{
midori_browser_set_current_uri (browser, fixed_uri);
first = FALSE;
}
else
midori_browser_set_current_page (browser,
midori_browser_add_uri (browser, fixed_uri));
g_free (fixed_uri);
uris++;
}
/* g_strfreev (uris); */
response = UNIQUE_RESPONSE_OK;
}
break; break;
}
case MIDORI_UNIQUE_COMMAND:
{
gchar** uris = unique_message_data_get_uris (message);
success = midori_app_command_received (app, "command", uris, screen);
/* g_strfreev (uris); */
break;
}
default: default:
response = UNIQUE_RESPONSE_FAIL; success = FALSE;
break; break;
} }
return response; return success ? UNIQUE_RESPONSE_OK : UNIQUE_RESPONSE_FAIL;
}
#else
static gboolean
midori_app_io_channel_watch_cb (GIOChannel* channel,
GIOCondition condition,
MidoriApp* app)
{
GdkScreen* screen = gtk_widget_get_screen (GTK_WIDGET (app->browser));
gint fd, sock;
gchar buf[4096];
struct sockaddr_in caddr;
guint caddr_len = sizeof(caddr);
fd = app->instance;
sock = accept (fd, (struct sockaddr *)&caddr, &caddr_len);
while (fd_gets (sock, buf, sizeof (buf)) != -1)
{
if (strncmp (buf, "activate", 8) == 0)
{
midori_app_command_received (app, "open", NULL, screen);
}
else if (strncmp (buf, "new", 3) == 0)
{
midori_app_command_received (app, "new", NULL, screen);
}
else if (strncmp (buf, "open", 4) == 0)
{
while (fd_gets (sock, buf, sizeof (buf)) != -1 && *buf != '.')
{
gchar** uris = g_strsplit (g_strstrip (buf), "\n", 2);
midori_app_command_received (app, "open", uris, screen);
g_strfreev (uris);
}
}
else if (strncmp (buf, "command", 7) == 0)
{
guint i = 0;
gchar** uris = g_new (gchar*, 100);
while (fd_gets (sock, buf, sizeof (buf)) != -1 && *buf != '.')
{
uris[i++] = g_strdup (g_strstrip (buf));
if (i == 99)
break;
}
uris[i] = NULL;
midori_app_command_received (app, "command", uris, screen);
g_strfreev (uris);
}
}
gtk_window_present (GTK_WINDOW (app->browser));
fd_close (sock);
return TRUE;
} }
#endif #endif
static gpointer static MidoriAppInstance
midori_app_create_instance (MidoriApp* app, midori_app_create_instance (MidoriApp* app,
const gchar* name) const gchar* name)
{ {
#if HAVE_UNIQUE MidoriAppInstance instance;
gpointer instance;
GdkDisplay* display; GdkDisplay* display;
gchar* display_name; gchar* display_name;
gchar* instance_name; gchar* instance_name;
guint i, n; guint i, n;
#if !HAVE_UNIQUE
gboolean exists;
GIOChannel* channel;
#endif #endif
if (!name) if (!name)
name = "midori"; name = "midori";
#if HAVE_UNIQUE
if (!(display = gdk_display_get_default ())) if (!(display = gdk_display_get_default ()))
return NULL; return MidoriAppInstanceNull;
display_name = g_strdup (gdk_display_get_name (display)); display_name = g_strdup (gdk_display_get_name (display));
n = strlen (display_name); n = strlen (display_name);
@ -490,15 +598,25 @@ midori_app_create_instance (MidoriApp* app,
if (display_name[i] == ':' || display_name[i] == '.') if (display_name[i] == ':' || display_name[i] == '.')
display_name[i] = '_'; display_name[i] = '_';
instance_name = g_strdup_printf ("de.twotoasts.%s_%s", name, display_name); instance_name = g_strdup_printf ("de.twotoasts.%s_%s", name, display_name);
#if HAVE_UNIQUE
instance = unique_app_new (instance_name, NULL); instance = unique_app_new (instance_name, NULL);
g_free (instance_name); unique_app_add_command (instance, "midori-command", MIDORI_UNIQUE_COMMAND);
g_free (display_name);
g_signal_connect (instance, "message-received", g_signal_connect (instance, "message-received",
G_CALLBACK (midori_browser_message_received_cb), app); G_CALLBACK (midori_browser_message_received_cb), app);
return instance;
#else #else
return NULL; instance = socket_init (instance_name, sokoke_set_config_dir (NULL), &exists);
g_object_set_data (G_OBJECT (app), "sock-exists",
exists ? (gpointer)0xdeadbeef : NULL);
channel = g_io_channel_unix_new (instance);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR,
(GIOFunc)midori_app_io_channel_watch_cb, app);
#endif #endif
g_free (instance_name);
g_free (display_name);
return instance;
} }
static void static void
@ -514,7 +632,7 @@ midori_app_init (MidoriApp* app)
app->extensions = NULL; app->extensions = NULL;
app->browsers = katze_array_new (MIDORI_TYPE_BROWSER); app->browsers = katze_array_new (MIDORI_TYPE_BROWSER);
app->instance = NULL; app->instance = MidoriAppInstanceNull;
midori_app_init_libnotify (app); midori_app_init_libnotify (app);
} }
@ -535,7 +653,11 @@ midori_app_finalize (GObject* object)
katze_object_assign (app->extensions, NULL); katze_object_assign (app->extensions, NULL);
katze_object_assign (app->browsers, NULL); katze_object_assign (app->browsers, NULL);
#if HAVE_UNIQUE
katze_object_assign (app->instance, NULL); katze_object_assign (app->instance, NULL);
#else
sock_cleanup ();
#endif
if (app->libnotify_module) if (app->libnotify_module)
{ {
@ -663,9 +785,6 @@ midori_app_new (void)
* Use the "name" property if you want to run more * Use the "name" property if you want to run more
* than one instance. * than one instance.
* *
* If Midori was built without single instance support
* this function will always return %FALSE.
*
* Return value: %TRUE if an instance is already running * Return value: %TRUE if an instance is already running
**/ **/
gboolean gboolean
@ -673,11 +792,13 @@ midori_app_instance_is_running (MidoriApp* app)
{ {
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
#if HAVE_UNIQUE if (app->instance == MidoriAppInstanceNull)
if (!app->instance)
app->instance = midori_app_create_instance (app, app->name); app->instance = midori_app_create_instance (app, app->name);
#if HAVE_UNIQUE
if (app->instance) if (app->instance)
return unique_app_is_running (app->instance); return unique_app_is_running (app->instance);
#else
return g_object_get_data (G_OBJECT (app), "sock-exists") != NULL;
#endif #endif
return FALSE; return FALSE;
} }
@ -710,6 +831,12 @@ midori_app_instance_send_activate (MidoriApp* app)
if (response == UNIQUE_RESPONSE_OK) if (response == UNIQUE_RESPONSE_OK)
return TRUE; return TRUE;
} }
#else
if (app->instance > -1)
{
send_open_command (app->instance, "activate", NULL);
return TRUE;
}
#endif #endif
return FALSE; return FALSE;
} }
@ -740,6 +867,12 @@ midori_app_instance_send_new_browser (MidoriApp* app)
if (response == UNIQUE_RESPONSE_OK) if (response == UNIQUE_RESPONSE_OK)
return TRUE; return TRUE;
} }
#else
if (app->instance > -1)
{
send_open_command (app->instance, "new", NULL);
return TRUE;
}
#endif #endif
return FALSE; return FALSE;
} }
@ -779,6 +912,63 @@ midori_app_instance_send_uris (MidoriApp* app,
if (response == UNIQUE_RESPONSE_OK) if (response == UNIQUE_RESPONSE_OK)
return TRUE; return TRUE;
} }
#else
if (app->instance > -1)
{
send_open_command (app->instance, "open", uris);
return TRUE;
}
#endif
return FALSE;
}
/**
* midori_app_send_command:
* @app: a #MidoriApp
* @command: a string vector of a command to execute
*
* Sends a command to an instance of Midori, which
* is either the current process or an already running
* instance with the same name on the default display.
*
* Names of GtkAction objects of MidoriBrowser are recognized as commands.
*
* Return value: %TRUE if the message was sent successfully
*
* Since: 0.1.8
**/
gboolean
midori_app_send_command (MidoriApp* app,
gchar** command)
{
#if HAVE_UNIQUE
UniqueMessageData* message;
UniqueResponse response;
#endif
/* g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); */
g_return_val_if_fail (command != NULL, FALSE);
if (!midori_app_instance_is_running (app))
return midori_app_command_received (app, "command", command, NULL);
#if HAVE_UNIQUE
if (app->instance)
{
message = unique_message_data_new ();
unique_message_data_set_uris (message, command);
response = unique_app_send_message (app->instance,
MIDORI_UNIQUE_COMMAND, message);
unique_message_data_free (message);
if (response == UNIQUE_RESPONSE_OK)
return TRUE;
}
#else
if (app->instance > -1)
{
send_open_command (app->instance, "command", command);
return TRUE;
}
#endif #endif
return FALSE; return FALSE;
} }

View file

@ -54,6 +54,10 @@ gboolean
midori_app_instance_send_uris (MidoriApp* app, midori_app_instance_send_uris (MidoriApp* app,
gchar** uris); gchar** uris);
gboolean
midori_app_send_command (MidoriApp* app,
gchar** command);
void void
midori_app_add_browser (MidoriApp* app, midori_app_add_browser (MidoriApp* app,
MidoriBrowser* browser); MidoriBrowser* browser);

View file

@ -22,6 +22,13 @@
#include <libxml/tree.h> #include <libxml/tree.h>
#endif #endif
static void
katze_xbel_parse_info (KatzeItem* item,
xmlNodePtr cur);
static gchar*
katze_item_metadata_to_xbel (KatzeItem* item);
#if HAVE_LIBXML #if HAVE_LIBXML
static KatzeItem* static KatzeItem*
katze_item_from_xmlNodePtr (xmlNodePtr cur) katze_item_from_xmlNodePtr (xmlNodePtr cur)
@ -49,6 +56,8 @@ katze_item_from_xmlNodePtr (xmlNodePtr cur)
katze_item_set_text (item, g_strstrip ((gchar*)key)); katze_item_set_text (item, g_strstrip ((gchar*)key));
g_free (key); g_free (key);
} }
else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
katze_xbel_parse_info (item, cur);
cur = cur->next; cur = cur->next;
} }
return item; return item;
@ -109,6 +118,52 @@ katze_array_from_xmlNodePtr (xmlNodePtr cur)
return array; return array;
} }
static void
katze_xbel_parse_info (KatzeItem* item,
xmlNodePtr cur)
{
cur = cur->xmlChildrenNode;
while (cur)
{
if (!xmlStrcmp (cur->name, (const xmlChar*)"metadata"))
{
xmlChar* owner = xmlGetProp (cur, (xmlChar*)"owner");
g_strstrip ((gchar*)owner);
/* FIXME: Save metadata from unknown owners */
if (!g_strcmp0 ((gchar*)owner, "http://www.twotoasts.de"))
{
xmlAttrPtr properties = cur->properties;
while (properties)
{
if (!xmlStrcmp (properties->name, (xmlChar*)"owner"))
{
properties = properties->next;
continue;
}
xmlChar* value = xmlGetProp (cur, properties->name);
if (properties->ns && properties->ns->prefix)
{
gchar* ns_value = g_strdup_printf ("%s:%s",
properties->ns->prefix, properties->name);
katze_item_set_meta_string (item,
(gchar*)ns_value, (gchar*)value);
g_free (ns_value);
}
else
katze_item_set_meta_string (item,
(gchar*)properties->name, (gchar*)value);
xmlFree (value);
properties = properties->next;
}
}
xmlFree (owner);
}
else if (g_strcmp0 ((gchar*)cur->name, "text"))
g_critical ("Unexpected element <%s> in <metadata>.", cur->name);
cur = cur->next;
}
}
/* Loads the contents from an xmlNodePtr into an array. */ /* Loads the contents from an xmlNodePtr into an array. */
static gboolean static gboolean
katze_array_from_xmlDocPtr (KatzeArray* array, katze_array_from_xmlDocPtr (KatzeArray* array,
@ -153,8 +208,8 @@ katze_array_from_xmlDocPtr (KatzeArray* array,
item = katze_item_from_xmlNodePtr (cur); item = katze_item_from_xmlNodePtr (cur);
else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator")) else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator"))
item = katze_item_new (); item = katze_item_new ();
/*else if (!xmlStrcmp (cur->name, (const xmlChar*)"info")) else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
item = katze_xbel_parse_info (xbel, cur);*/ katze_xbel_parse_info (KATZE_ITEM (array), cur);
if (item) if (item)
katze_array_add_item (array, item); katze_array_add_item (array, item);
cur = cur->next; cur = cur->next;
@ -236,10 +291,12 @@ static gchar*
katze_item_to_data (KatzeItem* item) katze_item_to_data (KatzeItem* item)
{ {
gchar* markup; gchar* markup;
gchar* metadata;
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL); g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
markup = NULL; markup = NULL;
metadata = katze_item_metadata_to_xbel (item);
if (KATZE_IS_ARRAY (item)) if (KATZE_IS_ARRAY (item))
{ {
GString* _markup = g_string_new (NULL); GString* _markup = g_string_new (NULL);
@ -254,10 +311,11 @@ katze_item_to_data (KatzeItem* item)
/* gchar* folded = item->folded ? NULL : g_strdup_printf (" folded=\"no\""); */ /* gchar* folded = item->folded ? NULL : g_strdup_printf (" folded=\"no\""); */
gchar* title = _simple_xml_element ("title", katze_item_get_name (item)); gchar* title = _simple_xml_element ("title", katze_item_get_name (item));
gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item)); gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item));
markup = g_strdup_printf ("<folder%s>\n%s%s%s</folder>\n", markup = g_strdup_printf ("<folder%s>\n%s%s%s%s</folder>\n",
"" /* folded ? folded : "" */, "" /* folded ? folded : "" */,
title, desc, title, desc,
_markup->str); _markup->str,
metadata);
g_string_free (_markup, TRUE); g_string_free (_markup, TRUE);
/* g_free (folded); */ /* g_free (folded); */
g_free (title); g_free (title);
@ -273,16 +331,42 @@ katze_item_to_data (KatzeItem* item)
markup = g_strdup_printf ("<bookmark%s>\n%s%s%s</bookmark>\n", markup = g_strdup_printf ("<bookmark%s>\n%s%s%s</bookmark>\n",
href, href,
title, desc, title, desc,
""); metadata);
g_free (href); g_free (href);
g_free (title); g_free (title);
g_free (desc); g_free (desc);
} }
else else
markup = g_strdup ("<separator/>\n"); markup = g_strdup ("<separator/>\n");
g_free (metadata);
return markup; return markup;
} }
static gchar*
katze_item_metadata_to_xbel (KatzeItem* item)
{
GList* keys = katze_item_get_meta_keys (item);
GString* markup;
/* FIXME: Allow specifying an alternative namespace/ URI */
const gchar* namespace_uri = "http://www.twotoasts.de";
const gchar* namespace = "midori";
gsize i;
const gchar* key;
if (!keys)
return g_strdup ("");
markup = g_string_new ("<info>\n<metadata owner=\"");
g_string_append_printf (markup, "%s\"", namespace_uri);
i = 0;
while ((key = g_list_nth_data (keys, i++)))
if (katze_item_get_meta_string (item, key))
g_string_append_printf (markup, " %s:%s=\"%s\"", namespace, key,
katze_item_get_meta_string (item, key));
g_string_append_printf (markup, "/>\n</info>\n");
return g_string_free (markup, FALSE);
}
static gchar* static gchar*
katze_array_to_xbel (KatzeArray* array, katze_array_to_xbel (KatzeArray* array,
GError** error) GError** error)
@ -291,8 +375,10 @@ katze_array_to_xbel (KatzeArray* array,
guint i; guint i;
KatzeItem* item; KatzeItem* item;
gchar* item_xml; gchar* item_xml;
const gchar* namespacing;
gchar* title; gchar* title;
gchar* desc; gchar* desc;
gchar* metadata;
gchar* outer_markup; gchar* outer_markup;
inner_markup = g_string_new (NULL); inner_markup = g_string_new (NULL);
@ -304,20 +390,25 @@ katze_array_to_xbel (KatzeArray* array,
g_free (item_xml); g_free (item_xml);
} }
namespacing = " xmlns:midori=\"http://www.twotoasts.de\"";
title = _simple_xml_element ("title", katze_item_get_name (KATZE_ITEM (array))); title = _simple_xml_element ("title", katze_item_get_name (KATZE_ITEM (array)));
desc = _simple_xml_element ("desc", katze_item_get_text (KATZE_ITEM (array))); desc = _simple_xml_element ("desc", katze_item_get_text (KATZE_ITEM (array)));
metadata = katze_item_metadata_to_xbel (KATZE_ITEM (array));
outer_markup = g_strdup_printf ( outer_markup = g_strdup_printf (
"%s%s<xbel version=\"1.0\">\n%s%s%s</xbel>\n", "%s%s<xbel version=\"1.0\"%s>\n%s%s%s%s</xbel>\n",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD " "<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD "
"XML Bookmark Exchange Language 1.0//EN//XML\" " "XML Bookmark Exchange Language 1.0//EN//XML\" "
"\"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n", "\"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n",
namespacing,
title, title,
desc, desc,
metadata,
inner_markup->str); inner_markup->str);
g_string_free (inner_markup, TRUE); g_string_free (inner_markup, TRUE);
g_free (title); g_free (title);
g_free (desc); g_free (desc);
g_free (metadata);
return outer_markup; return outer_markup;
} }

File diff suppressed because it is too large Load diff

View file

@ -138,6 +138,9 @@ midori_browser_get_for_widget (GtkWidget* widget);
void void
midori_browser_quit (MidoriBrowser* browser); midori_browser_quit (MidoriBrowser* browser);
const gchar**
midori_browser_get_toolbar_actions (MidoriBrowser* browser);
G_END_DECLS G_END_DECLS
#endif /* __MIDORI_BROWSER_H__ */ #endif /* __MIDORI_BROWSER_H__ */

View file

@ -28,6 +28,7 @@ struct _MidoriExtensionPrivate
gchar* description; gchar* description;
gchar* version; gchar* version;
gchar* authors; gchar* authors;
gchar* website;
MidoriApp* app; MidoriApp* app;
gint active; gint active;
@ -129,7 +130,8 @@ enum
PROP_NAME, PROP_NAME,
PROP_DESCRIPTION, PROP_DESCRIPTION,
PROP_VERSION, PROP_VERSION,
PROP_AUTHORS PROP_AUTHORS,
PROP_WEBSITE
}; };
enum { enum {
@ -227,6 +229,22 @@ midori_extension_class_init (MidoriExtensionClass* class)
NULL, NULL,
flags)); flags));
/**
* MidoriExtension:website:
*
* The website of the extension.
*
* Since: 0.1.8
*/
g_object_class_install_property (gobject_class,
PROP_WEBSITE,
g_param_spec_string (
"website",
"Website",
"The website of the extension",
NULL,
flags));
g_type_class_add_private (class, sizeof (MidoriExtensionPrivate)); g_type_class_add_private (class, sizeof (MidoriExtensionPrivate));
} }
@ -346,6 +364,7 @@ midori_extension_finalize (GObject* object)
katze_assign (extension->priv->description, NULL); katze_assign (extension->priv->description, NULL);
katze_assign (extension->priv->version, NULL); katze_assign (extension->priv->version, NULL);
katze_assign (extension->priv->authors, NULL); katze_assign (extension->priv->authors, NULL);
katze_assign (extension->priv->website, NULL);
katze_assign (extension->priv->config_dir, NULL); katze_assign (extension->priv->config_dir, NULL);
g_list_free (extension->priv->lsettings); g_list_free (extension->priv->lsettings);
@ -376,6 +395,9 @@ midori_extension_set_property (GObject* object,
case PROP_AUTHORS: case PROP_AUTHORS:
katze_assign (extension->priv->authors, g_value_dup_string (value)); katze_assign (extension->priv->authors, g_value_dup_string (value));
break; break;
case PROP_WEBSITE:
katze_assign (extension->priv->website, g_value_dup_string (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -404,6 +426,9 @@ midori_extension_get_property (GObject* object,
case PROP_AUTHORS: case PROP_AUTHORS:
g_value_set_string (value, extension->priv->authors); g_value_set_string (value, extension->priv->authors);
break; break;
case PROP_WEBSITE:
g_value_set_string (value, extension->priv->website);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -36,6 +36,8 @@ struct _MidoriLocationAction
GtkTreeModel* sort_model; GtkTreeModel* sort_model;
GdkPixbuf* default_icon; GdkPixbuf* default_icon;
GHashTable* items; GHashTable* items;
KatzeNet* net;
KatzeArray* history;
}; };
struct _MidoriLocationActionClass struct _MidoriLocationActionClass
@ -50,12 +52,14 @@ enum
PROP_0, PROP_0,
PROP_PROGRESS, PROP_PROGRESS,
PROP_SECONDARY_ICON PROP_SECONDARY_ICON,
PROP_HISTORY
}; };
enum enum
{ {
ACTIVE_CHANGED, ACTIVE_CHANGED,
FOCUS_IN,
FOCUS_OUT, FOCUS_OUT,
SECONDARY_ICON_RELEASED, SECONDARY_ICON_RELEASED,
RESET_URI, RESET_URI,
@ -72,6 +76,7 @@ enum
TITLE_COL, TITLE_COL,
VISITS_COL, VISITS_COL,
VISIBLE_COL, VISIBLE_COL,
YALIGN_COL,
N_COLS N_COLS
}; };
@ -104,6 +109,10 @@ static void
midori_location_action_disconnect_proxy (GtkAction* action, midori_location_action_disconnect_proxy (GtkAction* action,
GtkWidget* proxy); GtkWidget* proxy);
static void
midori_location_action_completion_init (MidoriLocationAction* location_action,
GtkEntry* entry);
static void static void
midori_location_action_class_init (MidoriLocationActionClass* class) midori_location_action_class_init (MidoriLocationActionClass* class)
{ {
@ -120,6 +129,22 @@ midori_location_action_class_init (MidoriLocationActionClass* class)
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
G_TYPE_INT); 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", signals[FOCUS_OUT] = g_signal_new ("focus-out",
G_TYPE_FROM_CLASS (class), G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST), (GSignalFlags) (G_SIGNAL_RUN_LAST),
@ -187,6 +212,24 @@ midori_location_action_class_init (MidoriLocationActionClass* class)
"The stock ID of the secondary icon", "The stock ID of the secondary icon",
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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));
} }
/* Allow this to be used in tests, it's otherwise private */ /* Allow this to be used in tests, it's otherwise private */
@ -194,10 +237,7 @@ midori_location_action_class_init (MidoriLocationActionClass* class)
midori_location_action_entry_for_proxy (GtkWidget* proxy) midori_location_action_entry_for_proxy (GtkWidget* proxy)
{ {
GtkWidget* alignment = gtk_bin_get_child (GTK_BIN (proxy)); GtkWidget* alignment = gtk_bin_get_child (GTK_BIN (proxy));
GtkWidget* hbox = gtk_bin_get_child (GTK_BIN (alignment)); GtkWidget* entry = gtk_bin_get_child (GTK_BIN (alignment));
GList* children = gtk_container_get_children (GTK_CONTAINER (hbox));
GtkWidget* entry = g_list_nth_data (children, 0);
g_list_free (children);
return entry; return entry;
} }
@ -218,9 +258,7 @@ midori_location_action_set_model (MidoriLocationAction* location_action,
entry = gtk_bin_get_child (GTK_BIN (location_entry)); entry = gtk_bin_get_child (GTK_BIN (location_entry));
g_object_set (location_entry, "model", model, NULL); g_object_set (location_entry, "model", model, NULL);
gtk_entry_completion_set_model ( midori_location_action_completion_init (location_action, GTK_ENTRY (entry));
gtk_entry_get_completion (GTK_ENTRY (entry)),
model ? location_action->filter_model : NULL);
} }
} }
@ -285,10 +323,10 @@ midori_location_action_thaw (MidoriLocationAction* location_action)
filter_model = gtk_tree_model_filter_new (sort_model, NULL); filter_model = gtk_tree_model_filter_new (sort_model, NULL);
gtk_tree_model_filter_set_visible_column ( gtk_tree_model_filter_set_visible_column (
GTK_TREE_MODEL_FILTER (filter_model), VISIBLE_COL); GTK_TREE_MODEL_FILTER (filter_model), VISIBLE_COL);
midori_location_action_set_model (location_action, location_action->model);
location_action->filter_model = filter_model; location_action->filter_model = filter_model;
location_action->sort_model = sort_model; location_action->sort_model = sort_model;
midori_location_action_set_model (location_action, location_action->model);
i = MAX_ITEMS; i = MAX_ITEMS;
while (gtk_tree_model_iter_nth_child (sort_model, &iter, NULL, i++)) while (gtk_tree_model_iter_nth_child (sort_model, &iter, NULL, i++))
@ -300,6 +338,15 @@ midori_location_action_thaw (MidoriLocationAction* location_action)
} }
} }
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);
return model;
}
static void static void
midori_location_action_init (MidoriLocationAction* location_action) midori_location_action_init (MidoriLocationAction* location_action)
{ {
@ -309,9 +356,7 @@ midori_location_action_init (MidoriLocationAction* location_action)
location_action->secondary_icon = NULL; location_action->secondary_icon = NULL;
location_action->default_icon = NULL; location_action->default_icon = NULL;
location_action->model = (GtkTreeModel*)gtk_list_store_new (N_COLS, location_action->model = midori_location_action_create_model ();
GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INT, G_TYPE_BOOLEAN);
location_action->filter_model = NULL; location_action->filter_model = NULL;
location_action->sort_model = NULL; location_action->sort_model = NULL;
@ -319,6 +364,8 @@ midori_location_action_init (MidoriLocationAction* location_action)
location_action->items = g_hash_table_new_full (g_str_hash, g_str_equal, location_action->items = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free); g_free, g_free);
location_action->net = katze_net_new ();
location_action->history = NULL;
} }
static void static void
@ -335,10 +382,55 @@ midori_location_action_finalize (GObject* object)
katze_object_assign (location_action->default_icon, NULL); katze_object_assign (location_action->default_icon, NULL);
g_hash_table_destroy (location_action->items); g_hash_table_destroy (location_action->items);
katze_object_assign (location_action->net, NULL);
katze_object_assign (location_action->history, NULL);
G_OBJECT_CLASS (midori_location_action_parent_class)->finalize (object); G_OBJECT_CLASS (midori_location_action_parent_class)->finalize (object);
} }
static void
midori_location_action_history_remove_item_cb (KatzeArray* folder,
KatzeItem* item,
MidoriLocationAction* action)
{
midori_location_action_delete_item_from_uri (action, katze_item_get_uri (item));
if (KATZE_IS_ARRAY (item))
g_signal_handlers_disconnect_by_func (item,
midori_location_action_history_remove_item_cb, action);
}
static void
midori_location_action_insert_history_item (MidoriLocationAction* action,
KatzeItem* item)
{
KatzeItem* child;
guint i;
const gchar* uri;
GdkPixbuf* pixbuf = NULL;
if (KATZE_IS_ARRAY (item))
{
for (i = katze_array_get_length (KATZE_ARRAY (item)); i > 0; i--)
{
child = katze_array_get_nth_item (KATZE_ARRAY (item), i - 1);
midori_location_action_insert_history_item (action, child);
}
}
else
{
uri = katze_item_get_uri (item);
pixbuf = katze_net_load_icon (action->net, katze_item_get_uri (item),
NULL, NULL, NULL);
if (!pixbuf)
pixbuf = action->default_icon;
midori_location_action_add_item (action, uri,
pixbuf, katze_item_get_name (item));
g_object_unref (pixbuf);
g_signal_connect (katze_item_get_parent (item), "remove-item",
G_CALLBACK (midori_location_action_history_remove_item_cb), action);
}
}
static void static void
midori_location_action_set_property (GObject* object, midori_location_action_set_property (GObject* object,
guint prop_id, guint prop_id,
@ -357,6 +449,35 @@ midori_location_action_set_property (GObject* object,
midori_location_action_set_secondary_icon (location_action, midori_location_action_set_secondary_icon (location_action,
g_value_get_string (value)); g_value_get_string (value));
break; break;
case PROP_HISTORY:
{
KatzeArray* history;
GtkTreeModel* model;
history = g_value_dup_object (value);
katze_assign (location_action->history, g_object_ref (history));
model = g_object_get_data (G_OBJECT (history), "midori-location-model");
if (model != NULL)
{
katze_object_assign (location_action->model, g_object_ref (model));
location_action->filter_model = NULL;
midori_location_action_thaw (location_action);
}
else
{
g_object_unref (location_action->model);
location_action->model = midori_location_action_create_model ();
midori_location_action_freeze (location_action);
/* FIXME: MidoriBrowser is essentially making up for the lack
of synchronicity of newly added items. */
midori_location_action_insert_history_item (location_action,
KATZE_ITEM (g_value_get_object (value)));
midori_location_action_thaw (location_action);
g_object_set_data (G_OBJECT (history),
"midori-location-model", location_action->model);
}
break;
}
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -379,6 +500,9 @@ midori_location_action_get_property (GObject* object,
case PROP_SECONDARY_ICON: case PROP_SECONDARY_ICON:
g_value_set_string (value, location_action->secondary_icon); g_value_set_string (value, location_action->secondary_icon);
break; break;
case PROP_HISTORY:
g_value_set_object (value, location_action->history);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -407,29 +531,12 @@ midori_location_action_activate (GtkAction* action)
GTK_ACTION_CLASS (midori_location_action_parent_class)->activate (action); GTK_ACTION_CLASS (midori_location_action_parent_class)->activate (action);
} }
static void
midori_location_action_go_clicked_cb (GtkWidget* button,
GtkAction* action)
{
GtkWidget* hbox = gtk_widget_get_parent (button);
GList* children = gtk_container_get_children (GTK_CONTAINER (hbox));
GtkWidget* location_entry = g_list_nth_data (children, 0);
g_list_free (children);
GtkWidget* entry = gtk_bin_get_child (GTK_BIN (location_entry));
const gchar* uri = gtk_entry_get_text (GTK_ENTRY (entry));
if (uri && *uri)
g_signal_emit (action, signals[SUBMIT_URI], 0, uri, FALSE);
}
static GtkWidget* static GtkWidget*
midori_location_action_create_tool_item (GtkAction* action) midori_location_action_create_tool_item (GtkAction* action)
{ {
GtkWidget* toolitem; GtkWidget* toolitem;
GtkWidget* alignment; GtkWidget* alignment;
GtkWidget* hbox;
GtkWidget* location_entry; GtkWidget* location_entry;
GtkWidget* go_button;
GtkWidget* go_icon;
toolitem = GTK_WIDGET (gtk_tool_item_new ()); toolitem = GTK_WIDGET (gtk_tool_item_new ());
gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE); gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE);
@ -437,21 +544,9 @@ midori_location_action_create_tool_item (GtkAction* action)
alignment = gtk_alignment_new (0.0f, 0.5f, 1.0f, 0.1f); alignment = gtk_alignment_new (0.0f, 0.5f, 1.0f, 0.1f);
gtk_widget_show (alignment); gtk_widget_show (alignment);
gtk_container_add (GTK_CONTAINER (toolitem), alignment); gtk_container_add (GTK_CONTAINER (toolitem), alignment);
hbox = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox);
gtk_container_add (GTK_CONTAINER (alignment), hbox);
location_entry = midori_location_entry_new (); location_entry = midori_location_entry_new ();
gtk_widget_show (location_entry); gtk_widget_show (location_entry);
gtk_box_pack_start (GTK_BOX (hbox), location_entry, TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (alignment), location_entry);
go_button = gtk_button_new ();
gtk_button_set_focus_on_click (GTK_BUTTON (go_button), FALSE);
gtk_button_set_relief (GTK_BUTTON (go_button), GTK_RELIEF_NONE);
go_icon = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
gtk_button_set_image (GTK_BUTTON (go_button), go_icon);
gtk_widget_show (go_button);
gtk_box_pack_start (GTK_BOX (hbox), go_button, FALSE, FALSE, 0);
g_signal_connect (go_button, "clicked",
G_CALLBACK (midori_location_action_go_clicked_cb), action);
return toolitem; return toolitem;
} }
@ -485,6 +580,15 @@ midori_location_action_key_press_event_cb (GtkWidget* widget,
return FALSE; return FALSE;
} }
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 static gboolean
midori_location_action_focus_out_event_cb (GtkWidget* widget, midori_location_action_focus_out_event_cb (GtkWidget* widget,
GdkEventKey* event, GdkEventKey* event,
@ -504,23 +608,6 @@ midori_location_action_icon_released_cb (GtkWidget* widget,
g_signal_emit (action, signals[SECONDARY_ICON_RELEASED], 0, widget); g_signal_emit (action, signals[SECONDARY_ICON_RELEASED], 0, widget);
} }
static void
midori_location_entry_render_pixbuf_cb (GtkCellLayout* layout,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
gpointer data)
{
GdkPixbuf* pixbuf;
gtk_tree_model_get (model, iter, FAVICON_COL, &pixbuf, -1);
if (pixbuf)
{
g_object_set (renderer, "pixbuf", pixbuf, "yalign", 0.25, NULL);
g_object_unref (pixbuf);
}
}
static void static void
midori_location_entry_render_text_cb (GtkCellLayout* layout, midori_location_entry_render_text_cb (GtkCellLayout* layout,
GtkCellRenderer* renderer, GtkCellRenderer* renderer,
@ -662,7 +749,7 @@ midori_location_action_set_item (MidoriLocationAction* location_action,
gtk_tree_model_get (location_action->model, iter, TITLE_COL, &item->title, -1); gtk_tree_model_get (location_action->model, iter, TITLE_COL, &item->title, -1);
gtk_list_store_set (GTK_LIST_STORE (location_action->model), iter, gtk_list_store_set (GTK_LIST_STORE (location_action->model), iter,
URI_COL, item->uri, TITLE_COL, item->title, -1); URI_COL, item->uri, TITLE_COL, item->title, YALIGN_COL, 0.25, -1);
gtk_tree_model_get (location_action->model, iter, FAVICON_COL, &icon, -1); gtk_tree_model_get (location_action->model, iter, FAVICON_COL, &icon, -1);
if (item->favicon) if (item->favicon)
@ -820,16 +907,26 @@ midori_location_action_add_actions (GtkEntryCompletion* completion,
static void static void
midori_location_action_completion_init (MidoriLocationAction* location_action, midori_location_action_completion_init (MidoriLocationAction* location_action,
GtkWidget* location_entry) GtkEntry* entry)
{ {
GtkWidget* entry;
GtkEntryCompletion* completion; GtkEntryCompletion* completion;
GtkCellRenderer* renderer; GtkCellRenderer* renderer;
entry = gtk_bin_get_child (GTK_BIN (location_entry)); if ((completion = gtk_entry_get_completion (entry)))
completion = gtk_entry_completion_new (); {
gtk_entry_completion_set_model (completion,
midori_location_action_is_frozen (location_action)
? NULL : location_action->filter_model);
return;
}
completion = gtk_entry_completion_new ();
gtk_entry_set_completion (entry, completion);
g_object_unref (completion);
gtk_entry_completion_set_model (completion,
midori_location_action_is_frozen (location_action)
? NULL : location_action->filter_model);
gtk_entry_completion_set_model (completion, location_action->sort_model);
gtk_entry_completion_set_text_column (completion, URI_COL); gtk_entry_completion_set_text_column (completion, URI_COL);
#if GTK_CHECK_VERSION (2, 12, 0) #if GTK_CHECK_VERSION (2, 12, 0)
gtk_entry_completion_set_inline_selection (completion, TRUE); gtk_entry_completion_set_inline_selection (completion, TRUE);
@ -838,10 +935,12 @@ midori_location_action_completion_init (MidoriLocationAction* location_action,
renderer = gtk_cell_renderer_pixbuf_new (); renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, FALSE); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, FALSE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer, gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer,
midori_location_entry_render_pixbuf_cb, "pixbuf", FAVICON_COL, "yalign", YALIGN_COL, NULL);
NULL, NULL);
renderer = gtk_cell_renderer_text_new (); renderer = gtk_cell_renderer_text_new ();
gtk_cell_renderer_set_fixed_size (renderer, 1, -1);
gtk_cell_renderer_text_set_fixed_height_from_font (
GTK_CELL_RENDERER_TEXT (renderer), 2);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer, gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer,
midori_location_entry_render_text_cb, midori_location_entry_render_text_cb,
@ -849,7 +948,7 @@ midori_location_action_completion_init (MidoriLocationAction* location_action,
gtk_entry_completion_set_match_func (completion, gtk_entry_completion_set_match_func (completion,
midori_location_entry_completion_match_cb, NULL, NULL); midori_location_entry_completion_match_cb, NULL, NULL);
gtk_entry_set_completion (GTK_ENTRY (entry), completion);
g_signal_connect (completion, "match-selected", g_signal_connect (completion, "match-selected",
G_CALLBACK (midori_location_entry_match_selected_cb), location_action); G_CALLBACK (midori_location_entry_match_selected_cb), location_action);
@ -857,8 +956,6 @@ midori_location_action_completion_init (MidoriLocationAction* location_action,
location_action->search_engines); location_action->search_engines);
g_signal_connect (completion, "action-activated", g_signal_connect (completion, "action-activated",
G_CALLBACK (midori_location_entry_action_activated_cb), location_action); G_CALLBACK (midori_location_entry_action_activated_cb), location_action);
g_object_unref (completion);
} }
static void static void
@ -923,21 +1020,24 @@ midori_location_action_connect_proxy (GtkAction* action,
/* Setup the renderer for the favicon */ /* Setup the renderer for the favicon */
renderer = gtk_cell_renderer_pixbuf_new (); renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, FALSE); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, FALSE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry), gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (entry), renderer,
renderer, midori_location_entry_render_pixbuf_cb, NULL, NULL); "pixbuf", FAVICON_COL, "yalign", YALIGN_COL, NULL);
renderer = gtk_cell_renderer_text_new (); renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, TRUE); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, TRUE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry), gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
renderer, midori_location_entry_render_text_cb, NULL, NULL); renderer, midori_location_entry_render_text_cb, NULL, NULL);
gtk_combo_box_set_active (GTK_COMBO_BOX (entry), -1); gtk_combo_box_set_active (GTK_COMBO_BOX (entry), -1);
midori_location_action_completion_init (location_action, entry); midori_location_action_completion_init (location_action,
GTK_ENTRY (gtk_bin_get_child (GTK_BIN (entry))));
g_signal_connect (entry, "changed", g_signal_connect (entry, "changed",
G_CALLBACK (midori_location_action_entry_changed_cb), action); G_CALLBACK (midori_location_action_entry_changed_cb), action);
g_object_connect (gtk_bin_get_child (GTK_BIN (entry)), g_object_connect (gtk_bin_get_child (GTK_BIN (entry)),
"signal::key-press-event", "signal::key-press-event",
midori_location_action_key_press_event_cb, action, midori_location_action_key_press_event_cb, action,
"signal::focus-in-event",
midori_location_action_focus_in_event_cb, action,
"signal::focus-out-event", "signal::focus-out-event",
midori_location_action_focus_out_event_cb, action, midori_location_action_focus_out_event_cb, action,
"signal::icon-release", "signal::icon-release",
@ -1271,6 +1371,7 @@ midori_location_action_set_search_engines (MidoriLocationAction* location_action
entry = midori_location_action_entry_for_proxy (proxies->data); entry = midori_location_action_entry_for_proxy (proxies->data);
child = gtk_bin_get_child (GTK_BIN (entry)); child = gtk_bin_get_child (GTK_BIN (entry));
midori_location_action_completion_init (location_action, GTK_ENTRY (child));
completion = gtk_entry_get_completion (GTK_ENTRY (child)); completion = gtk_entry_get_completion (GTK_ENTRY (child));
i = 0; i = 0;
if (location_action->search_engines) if (location_action->search_engines)
@ -1342,7 +1443,7 @@ midori_location_action_set_secondary_icon (MidoriLocationAction* location_action
} }
/** /**
* midori_location_action_set_item_from_uri: * midori_location_action_delete_item_from_uri:
* @location_action: a #MidoriLocationAction * @location_action: a #MidoriLocationAction
* @uri: a string * @uri: a string
* *

View file

@ -231,7 +231,6 @@ static void
midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton, midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton,
MidoriPanel* panel) MidoriPanel* panel)
{ {
/* FIXME: Use stock icon for window */
/* FIXME: What happens when the browser is destroyed? */ /* FIXME: What happens when the browser is destroyed? */
/* FIXME: What about multiple browsers? */ /* FIXME: What about multiple browsers? */
/* FIXME: Should we remember if the child was detached? */ /* FIXME: Should we remember if the child was detached? */
@ -248,6 +247,7 @@ midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton,
GtkWidget* vbox = gtk_vbox_new (FALSE, 0); GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
g_object_set_data (G_OBJECT (window), "scrolled", scrolled); g_object_set_data (G_OBJECT (window), "scrolled", scrolled);
gtk_window_set_title (GTK_WINDOW (window), title); gtk_window_set_title (GTK_WINDOW (window), title);
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
gtk_window_set_default_size (GTK_WINDOW (window), 250, 400); gtk_window_set_default_size (GTK_WINDOW (window), 250, 400);
gtk_window_set_transient_for (GTK_WINDOW (window), gtk_window_set_transient_for (GTK_WINDOW (window),
GTK_WINDOW (gtk_widget_get_toplevel (panel->notebook))); GTK_WINDOW (gtk_widget_get_toplevel (panel->notebook)));
@ -329,10 +329,8 @@ midori_panel_init (MidoriPanel* panel)
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_FULLSCREEN); toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_FULLSCREEN);
gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE);
panel->button_detach = toolitem; panel->button_detach = toolitem;
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem),
_("Detach chosen panel from the window"));
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem), gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem),
_("Whether to detach the chosen panel from the window")); _("Detach chosen panel from the window"));
g_signal_connect (toolitem, "clicked", g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_detach_clicked_cb), panel); G_CALLBACK (midori_panel_button_detach_clicked_cb), panel);
#if HAVE_OSX #if HAVE_OSX
@ -341,10 +339,8 @@ midori_panel_init (MidoriPanel* panel)
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1); gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
#endif #endif
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD); toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem),
_("Align sidepanel on the right"));
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem), gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem),
_("Whether to align the sidepanel on the right")); _("Align sidepanel to the right"));
g_signal_connect (toolitem, "clicked", g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_align_clicked_cb), panel); G_CALLBACK (midori_panel_button_align_clicked_cb), panel);
#if HAVE_OSX #if HAVE_OSX
@ -488,7 +484,7 @@ midori_panel_set_compact (MidoriPanel* panel,
/** /**
* midori_panel_set_right_aligned: * midori_panel_set_right_aligned:
* @compact: %TRUE if the panel should be aligned to the right * @right_aligned: %TRUE if the panel should be aligned to the right
* *
* Determines if the panel should be right aligned. * Determines if the panel should be right aligned.
* *
@ -508,6 +504,9 @@ midori_panel_set_right_aligned (MidoriPanel* panel,
gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (panel->button_align), gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (panel->button_align),
right_aligned ? GTK_STOCK_GO_BACK : GTK_STOCK_GO_FORWARD); right_aligned ? GTK_STOCK_GO_BACK : GTK_STOCK_GO_FORWARD);
panel->right_aligned = right_aligned; panel->right_aligned = right_aligned;
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (panel->button_align),
!panel->right_aligned ? _("Align sidepanel to the right")
: _("Align sidepanel to the left"));
g_object_notify (G_OBJECT (panel), "right-aligned"); g_object_notify (G_OBJECT (panel), "right-aligned");
} }
@ -662,7 +661,7 @@ midori_panel_append_page (MidoriPanel* panel,
g_signal_connect (menuitem, "activate", g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_panel_menu_item_activate_cb), G_CALLBACK (midori_panel_menu_item_activate_cb),
panel); panel);
gtk_menu_shell_append (GTK_MENU_SHELL (panel->menu), menuitem); gtk_menu_shell_insert (GTK_MENU_SHELL (panel->menu), menuitem, 4);
g_object_set_data (G_OBJECT (scrolled), "panel-menuitem", menuitem); g_object_set_data (G_OBJECT (scrolled), "panel-menuitem", menuitem);
g_signal_connect (viewable, "destroy", g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), menuitem); G_CALLBACK (midori_panel_widget_destroy_cb), menuitem);
@ -798,6 +797,8 @@ midori_panel_page_num (MidoriPanel* panel,
* *
* The child must be visible, otherwise the underlying GtkNotebook will * The child must be visible, otherwise the underlying GtkNotebook will
* silently ignore the attempt to switch the page. * silently ignore the attempt to switch the page.
*
* Since 0.1.8 the "page" property is notifying changes.
**/ **/
void void
midori_panel_set_current_page (MidoriPanel* panel, midori_panel_set_current_page (MidoriPanel* panel,
@ -807,15 +808,15 @@ midori_panel_set_current_page (MidoriPanel* panel,
g_return_if_fail (MIDORI_IS_PANEL (panel)); g_return_if_fail (MIDORI_IS_PANEL (panel));
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->toolbook), n);
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->notebook), n);
if ((viewable = midori_panel_get_nth_page (panel, n))) if ((viewable = midori_panel_get_nth_page (panel, n)))
{ {
const gchar* label; const gchar* label;
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->toolbook), n);
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->notebook), n);
label = midori_viewable_get_label (MIDORI_VIEWABLE (viewable)); label = midori_viewable_get_label (MIDORI_VIEWABLE (viewable));
g_object_set (panel->toolbar_label, "label", label, NULL); g_object_set (panel->toolbar_label, "label", label, NULL);
g_object_notify (G_OBJECT (panel), "page");
} }
} }

View file

@ -452,9 +452,14 @@ midori_preferences_set_settings (MidoriPreferences* preferences,
FILLED_ADD (hbox, 1, 2, 0, 1); FILLED_ADD (hbox, 1, 2, 0, 1);
label = gtk_label_new (_("Fixed-width Font Family")); label = gtk_label_new (_("Fixed-width Font Family"));
INDENTED_ADD (label, 0, 1, 1, 2); INDENTED_ADD (label, 0, 1, 1, 2);
hbox = gtk_hbox_new (FALSE, 4);
button = katze_property_proxy (settings, "monospace-font-family", "font"); button = katze_property_proxy (settings, "monospace-font-family", "font");
gtk_widget_set_tooltip_text (button, _("The font family used to display fixed-width text")); gtk_widget_set_tooltip_text (button, _("The font family used to display fixed-width text"));
INDENTED_ADD (button, 1, 2, 1, 2); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
entry = katze_property_proxy (settings, "default-monospace-font-size", NULL);
gtk_widget_set_tooltip_text (entry, _("The font size used to display fixed-width text"));
gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 4);
INDENTED_ADD (hbox, 1, 2, 1, 2);
label = gtk_label_new (_("Minimum Font Size")); label = gtk_label_new (_("Minimum Font Size"));
INDENTED_ADD (label, 0, 1, 2, 3); INDENTED_ADD (label, 0, 1, 2, 3);
entry = katze_property_proxy (settings, "minimum-font-size", NULL); entry = katze_property_proxy (settings, "minimum-font-size", NULL);
@ -546,12 +551,10 @@ midori_preferences_set_settings (MidoriPreferences* preferences,
INDENTED_ADD (label, 0, 1, 0, 1); INDENTED_ADD (label, 0, 1, 0, 1);
button = katze_property_proxy (settings, "open-new-pages-in", NULL); button = katze_property_proxy (settings, "open-new-pages-in", NULL);
FILLED_ADD (button, 1, 2, 0, 1); FILLED_ADD (button, 1, 2, 0, 1);
#if HAVE_UNIQUE
label = katze_property_label (settings, "open-external-pages-in"); label = katze_property_label (settings, "open-external-pages-in");
INDENTED_ADD (label, 0, 1, 1, 2); INDENTED_ADD (label, 0, 1, 1, 2);
button = katze_property_proxy (settings, "open-external-pages-in", NULL); button = katze_property_proxy (settings, "open-external-pages-in", NULL);
FILLED_ADD (button, 1, 2, 1, 2); FILLED_ADD (button, 1, 2, 1, 2);
#endif
button = katze_property_proxy (settings, "always-show-tabbar", NULL); button = katze_property_proxy (settings, "always-show-tabbar", NULL);
INDENTED_ADD (button, 0, 1, 2, 3); INDENTED_ADD (button, 0, 1, 2, 3);
button = katze_property_proxy (settings, "open-tabs-in-the-background", NULL); button = katze_property_proxy (settings, "open-tabs-in-the-background", NULL);

View file

@ -1016,6 +1016,20 @@ midori_search_action_get_editor (MidoriSearchAction* search_action,
gtk_widget_destroy (dialog); gtk_widget_destroy (dialog);
} }
static void
midori_search_action_activate_edit_cb (GtkTreeView *treeview,
GtkTreePath *path,
GtkTreeViewColumn *column,
MidoriSearchAction* search_action)
{
GtkTreeSelection* selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
if (gtk_tree_selection_get_selected (selection, NULL, NULL))
midori_search_action_get_editor (search_action, FALSE);
}
static void static void
midori_search_action_dialog_add_cb (GtkWidget* widget, midori_search_action_dialog_add_cb (GtkWidget* widget,
MidoriSearchAction* search_action) MidoriSearchAction* search_action)
@ -1228,6 +1242,8 @@ midori_search_action_get_dialog (MidoriSearchAction* search_action)
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
"changed", G_CALLBACK (midori_search_action_treeview_selection_cb), "changed", G_CALLBACK (midori_search_action_treeview_selection_cb),
search_action); search_action);
g_signal_connect (treeview, "row-activated",
G_CALLBACK (midori_search_action_activate_edit_cb), search_action);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
g_object_set_data (G_OBJECT (treeview), "search-action", search_action); g_object_set_data (G_OBJECT (treeview), "search-action", search_action);
column = gtk_tree_view_column_new (); column = gtk_tree_view_column_new ();

View file

@ -25,6 +25,7 @@
#define STOCK_EXTENSION "extension" #define STOCK_EXTENSION "extension"
#define STOCK_EXTENSIONS "extension" #define STOCK_EXTENSIONS "extension"
#define STOCK_HISTORY "document-open-recent" #define STOCK_HISTORY "document-open-recent"
#define STOCK_WEB_BROWSER "web-browser"
#define STOCK_NEWS_FEED "news-feed" #define STOCK_NEWS_FEED "news-feed"
#define STOCK_STYLE "gnome-settings-theme" #define STOCK_STYLE "gnome-settings-theme"
#define STOCK_STYLES "gnome-settings-theme" #define STOCK_STYLES "gnome-settings-theme"

View file

@ -16,6 +16,7 @@
#include "midori-view.h" #include "midori-view.h"
#include "midori-stock.h" #include "midori-stock.h"
#include "midori-browser.h"
#include "compat.h" #include "compat.h"
#include "marshal.h" #include "marshal.h"
@ -26,6 +27,7 @@
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <glib/gprintf.h> #include <glib/gprintf.h>
#include <glib/gstdio.h> #include <glib/gstdio.h>
#include <gdk/gdkkeysyms.h>
#include <webkit/webkit.h> #include <webkit/webkit.h>
/* This is unstable API, so we need to declare it */ /* This is unstable API, so we need to declare it */
@ -45,6 +47,11 @@ midori_search_action_get_icon (KatzeNet* net,
static void static void
midori_view_construct_web_view (MidoriView* view); midori_view_construct_web_view (MidoriView* view);
GdkPixbuf*
midori_view_get_snapshot (MidoriView* view,
gint width,
gint height);
struct _MidoriView struct _MidoriView
{ {
GtkScrolledWindow parent_instance; GtkScrolledWindow parent_instance;
@ -74,6 +81,7 @@ struct _MidoriView
GtkWidget* menu_item; GtkWidget* menu_item;
GtkWidget* tab_label; GtkWidget* tab_label;
/* GtkWidget* tooltip_image; */
GtkWidget* tab_icon; GtkWidget* tab_icon;
GtkWidget* tab_title; GtkWidget* tab_title;
GtkWidget* tab_close; GtkWidget* tab_close;
@ -514,6 +522,7 @@ midori_view_class_init (MidoriViewClass* class)
static void static void
midori_view_update_title (MidoriView* view) midori_view_update_title (MidoriView* view)
{ {
#ifndef G_OS_WIN32
/* If left-to-right text is combined with right-to-left text the default /* If left-to-right text is combined with right-to-left text the default
behaviour of Pango can result in awkwardly aligned text. For example behaviour of Pango can result in awkwardly aligned text. For example
"‪بستيان نوصر (hadess) | An era comes to an end - Midori" becomes "‪بستيان نوصر (hadess) | An era comes to an end - Midori" becomes
@ -525,6 +534,7 @@ midori_view_update_title (MidoriView* view)
gchar* new_title = g_strconcat ("", view->title, NULL); gchar* new_title = g_strconcat ("", view->title, NULL);
katze_assign (view->title, new_title); katze_assign (view->title, new_title);
} }
#endif
#define title midori_view_get_display_title (view) #define title midori_view_get_display_title (view)
if (view->tab_label) if (view->tab_label)
{ {
@ -547,7 +557,9 @@ midori_view_update_title (MidoriView* view)
soup_uri_free (uri); soup_uri_free (uri);
} }
gtk_label_set_text (GTK_LABEL (view->tab_title), title); gtk_label_set_text (GTK_LABEL (view->tab_title), title);
#if 1
gtk_widget_set_tooltip_text (view->tab_title, title); gtk_widget_set_tooltip_text (view->tab_title, title);
#endif
} }
if (view->menu_item) if (view->menu_item)
gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN ( gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN (
@ -720,10 +732,12 @@ webkit_web_view_load_error_cb (WebKitWebView* web_view,
GError* error, GError* error,
MidoriView* view) MidoriView* view)
{ {
const gchar* template_file = DATADIR "/midori/res/error.html"; gchar* template_file = g_build_filename ("midori", "res", "error.html", NULL);
gchar* path = sokoke_find_data_filename (template_file);
gchar* template; gchar* template;
if (g_file_get_contents (template_file, &template, NULL, NULL)) g_free (template_file);
if (g_file_get_contents (path, &template, NULL, NULL))
{ {
SoupServer* res_server; SoupServer* res_server;
guint port; guint port;
@ -754,9 +768,11 @@ webkit_web_view_load_error_cb (WebKitWebView* web_view,
g_free (res_root); g_free (res_root);
g_free (stock_root); g_free (stock_root);
g_free (result); g_free (result);
g_free (path);
return TRUE; return TRUE;
} }
g_free (path);
return FALSE; return FALSE;
} }
@ -777,7 +793,7 @@ webkit_web_frame_load_done_cb (WebKitWebFrame* web_frame,
data = g_strdup_printf ( data = g_strdup_printf (
"<html><head><title>%s</title></head>" "<html><head><title>%s</title></head>"
"<body><h1>%s</h1>" "<body><h1>%s</h1>"
"<img src=\"file://" DATADIR "/midori/logo-shade.png\" " "<img src=\"file://" MDATADIR "/midori/logo-shade.png\" "
"style=\"position: absolute; right: 15px; bottom: 15px;\">" "style=\"position: absolute; right: 15px; bottom: 15px;\">"
"<p />The page you were opening doesn't exist." "<p />The page you were opening doesn't exist."
"<p />Try to <a href=\"%s\">load the page again</a>, " "<p />Try to <a href=\"%s\">load the page again</a>, "
@ -817,12 +833,13 @@ webkit_web_view_load_finished_cb (WebKitWebView* web_view,
"f.push (l[i].href + '|' + l[i].title); } return f; }" "f.push (l[i].href + '|' + l[i].title); } return f; }"
"feeds (document.getElementsByTagName ('link'))", NULL); "feeds (document.getElementsByTagName ('link'))", NULL);
gchar** items = g_strsplit (value, ",", 0); gchar** items = g_strsplit (value, ",", 0);
gchar** iter; guint i = 0;
katze_array_clear (view->news_feeds); katze_array_clear (view->news_feeds);
for (iter = items; iter && *iter; iter++) if (items != NULL)
while (items[i] != NULL)
{ {
gchar** parts = g_strsplit (*iter, "|", 2); gchar** parts = g_strsplit (items[i], "|", 2);
KatzeItem* item = g_object_new (KATZE_TYPE_ITEM, KatzeItem* item = g_object_new (KATZE_TYPE_ITEM,
"uri", parts ? *parts : "", "uri", parts ? *parts : "",
"name", parts && *parts ? parts[1] : NULL, "name", parts && *parts ? parts[1] : NULL,
@ -830,6 +847,7 @@ webkit_web_view_load_finished_cb (WebKitWebView* web_view,
katze_array_add_item (view->news_feeds, item); katze_array_add_item (view->news_feeds, item);
g_object_unref (item); g_object_unref (item);
g_strfreev (parts); g_strfreev (parts);
i++;
} }
g_strfreev (items); g_strfreev (items);
g_object_set_data (G_OBJECT (view), "news-feeds", g_object_set_data (G_OBJECT (view), "news-feeds",
@ -1007,6 +1025,9 @@ gtk_widget_button_press_event_cb (WebKitWebView* web_view,
return TRUE; return TRUE;
} }
/* We propagate the event, since it may otherwise be stuck in WebKit */
g_signal_emit_by_name (view, "event", event, &background);
return FALSE; return FALSE;
} }
@ -1016,15 +1037,16 @@ gtk_widget_key_press_event_cb (WebKitWebView* web_view,
MidoriView* view) MidoriView* view)
{ {
guint character = gdk_unicode_to_keyval (event->keyval); guint character = gdk_unicode_to_keyval (event->keyval);
/* Skip control characters */
if (character == (event->keyval | 0x01000000))
return FALSE;
if (character == '.' || character == '/') if (event->keyval == '.' || event->keyval == '/' || event->keyval == GDK_KP_Divide)
character = '\0'; character = '\0';
else if (!view->find_while_typing) else if (!view->find_while_typing)
return FALSE; return FALSE;
/* Skip control characters */
if (character == (event->keyval | 0x01000000))
return FALSE;
if (!webkit_web_view_can_cut_clipboard (web_view) if (!webkit_web_view_can_cut_clipboard (web_view)
&& !webkit_web_view_can_paste_clipboard (web_view)) && !webkit_web_view_can_paste_clipboard (web_view))
{ {
@ -1070,13 +1092,6 @@ midori_web_view_menu_new_tab_activate_cb (GtkWidget* widget,
view->open_tabs_in_the_background); view->open_tabs_in_the_background);
} }
static void
midori_web_view_menu_action_add_speed_dial_cb (GtkWidget* widget,
MidoriView* view)
{
g_signal_emit (view, signals[ADD_SPEED_DIAL], 0, view->link_uri);
}
static void static void
midori_web_view_menu_search_web_activate_cb (GtkWidget* widget, midori_web_view_menu_search_web_activate_cb (GtkWidget* widget,
MidoriView* view) MidoriView* view)
@ -1121,19 +1136,13 @@ midori_web_view_menu_add_bookmark_activate_cb (GtkWidget* widget,
g_signal_emit (view, signals[ADD_BOOKMARK], 0, view->link_uri); 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 (view, signals[ACTIVATE_ACTION], 0, action);
}
static void static void
webkit_web_view_populate_popup_cb (WebKitWebView* web_view, webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
GtkWidget* menu, GtkWidget* menu,
MidoriView* view) MidoriView* view)
{ {
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (view));
GtkActionGroup* actions = midori_browser_get_action_group (browser);
GtkWidget* menuitem; GtkWidget* menuitem;
GtkWidget* icon; GtkWidget* icon;
gchar* stock_id; gchar* stock_id;
@ -1301,63 +1310,74 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
} }
} }
g_list_free (items); g_list_free (items);
menuitem = gtk_image_menu_item_new_with_mnemonic (_("Undo Close Tab")); menuitem = sokoke_action_create_popup_menu_item (
icon = gtk_image_new_from_stock (GTK_STOCK_UNDELETE, GTK_ICON_SIZE_MENU); gtk_action_group_get_action (actions, "UndoTabClose"));
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); 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);
/* FIXME: Make this sensitive only when there is a tab to undo */
gtk_widget_show (menuitem);
menuitem = gtk_separator_menu_item_new (); menuitem = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem); gtk_widget_show (menuitem);
menuitem = gtk_image_menu_item_new_from_stock (STOCK_BOOKMARK_ADD, NULL); menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "ZoomIn"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "ZoomOut"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "Encoding"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
if (GTK_WIDGET_IS_SENSITIVE (menuitem))
{
GtkWidget* sub_menu;
static const GtkActionEntry encodings[] = {
{ "EncodingAutomatic" },
{ "EncodingChinese" },
{ "EncodingJapanese" },
{ "EncodingRussian" },
{ "EncodingUnicode" },
{ "EncodingWestern" },
{ "EncodingCustom" },
};
guint i;
sub_menu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), sub_menu);
for (i = 0; i < G_N_ELEMENTS (encodings); i++)
{
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, encodings[i].name));
gtk_menu_shell_append (GTK_MENU_SHELL (sub_menu), menuitem);
}
}
menuitem = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); 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); gtk_widget_show (menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "BookmarkAdd"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
if (view->speed_dial_in_new_tabs && !midori_view_is_blank (view)) if (view->speed_dial_in_new_tabs && !midori_view_is_blank (view))
{ {
menuitem = gtk_image_menu_item_new_with_mnemonic (_("Add to Speed _dial")); menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "AddSpeedDial"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_object_set_data (G_OBJECT (menuitem), "action", "AddSpeedDial");
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_action_add_speed_dial_cb), view);
gtk_widget_show (menuitem);
} }
menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS, NULL); menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "SaveAs"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); 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);
/* Currently views that don't support source, don't support /* Currently views that don't support source, don't support
saving either. If that changes, we need to think of something. */ saving either. If that changes, we need to think of something. */
if (!midori_view_can_view_source (view)) if (!midori_view_can_view_source (view))
gtk_widget_set_sensitive (menuitem, FALSE); gtk_widget_set_sensitive (menuitem, FALSE);
menuitem = sokoke_action_create_popup_menu_item (
menuitem = gtk_image_menu_item_new_with_mnemonic (_("View _Source")); gtk_action_group_get_action (actions, "SourceView"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); 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 (!midori_view_can_view_source (view))
gtk_widget_set_sensitive (menuitem, FALSE);
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);
} }
} }
@ -1479,6 +1499,7 @@ webkit_web_view_mime_type_decision_cb (GtkWidget* web_view,
} }
gtk_dialog_add_buttons (GTK_DIALOG (dialog), gtk_dialog_add_buttons (GTK_DIALOG (dialog),
GTK_STOCK_SAVE, 1, GTK_STOCK_SAVE, 1,
GTK_STOCK_SAVE_AS, 4,
GTK_STOCK_CANCEL, 2, GTK_STOCK_CANCEL, 2,
GTK_STOCK_OPEN, 3, GTK_STOCK_OPEN, 3,
NULL); NULL);
@ -1487,6 +1508,11 @@ webkit_web_view_mime_type_decision_cb (GtkWidget* web_view,
g_object_set_data (G_OBJECT (view), "open-download", (gpointer)0); g_object_set_data (G_OBJECT (view), "open-download", (gpointer)0);
switch (response) switch (response)
{ {
case 4:
g_object_set_data (G_OBJECT (view), "save-as-download", (gpointer)1);
webkit_web_policy_decision_download (decision);
webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (view->web_view));
return TRUE;
case 3: case 3:
g_object_set_data (G_OBJECT (view), "open-download", (gpointer)1); g_object_set_data (G_OBJECT (view), "open-download", (gpointer)1);
case 1: case 1:
@ -1525,7 +1551,10 @@ webkit_web_view_download_requested_cb (GtkWidget* web_view,
gboolean handled; gboolean handled;
g_object_set_data (G_OBJECT (download), "open-download", g_object_set_data (G_OBJECT (download), "open-download",
g_object_get_data (G_OBJECT (view), "open-download")); g_object_get_data (G_OBJECT (view), "open-download"));
g_object_set_data (G_OBJECT (download), "save-as-download",
g_object_get_data (G_OBJECT (view), "save-as-download"));
g_object_set_data (G_OBJECT (view), "open-download", (gpointer)0); g_object_set_data (G_OBJECT (view), "open-download", (gpointer)0);
g_object_set_data (G_OBJECT (view), "save-as-download", (gpointer)0);
g_signal_emit (view, signals[DOWNLOAD_REQUESTED], 0, download, &handled); g_signal_emit (view, signals[DOWNLOAD_REQUESTED], 0, download, &handled);
return handled; return handled;
} }
@ -2038,7 +2067,7 @@ midori_view_set_uri (MidoriView* view,
katze_assign (view->uri, g_strdup ("")); katze_assign (view->uri, g_strdup (""));
g_file_get_contents (DATADIR "/midori/res/speeddial-head.html", g_file_get_contents (MDATADIR "/midori/res/speeddial-head.html",
&speed_dial_head, NULL, NULL); &speed_dial_head, NULL, NULL);
res_server = sokoke_get_res_server (); res_server = sokoke_get_res_server ();
@ -2050,7 +2079,7 @@ midori_view_set_uri (MidoriView* view,
if (!g_file_test (body_fname, G_FILE_TEST_EXISTS)) if (!g_file_test (body_fname, G_FILE_TEST_EXISTS))
{ {
if (g_file_get_contents (DATADIR "/midori/res/speeddial.json", if (g_file_get_contents (MDATADIR "/midori/res/speeddial.json",
&speed_dial_body, NULL, NULL)) &speed_dial_body, NULL, NULL))
g_file_set_contents (body_fname, speed_dial_body, -1, NULL); g_file_set_contents (body_fname, speed_dial_body, -1, NULL);
else else
@ -2101,7 +2130,7 @@ midori_view_set_uri (MidoriView* view,
data = g_strdup_printf ( data = g_strdup_printf (
"<html><head><title>%s</title></head>" "<html><head><title>%s</title></head>"
"<body><h1>%s</h1>" "<body><h1>%s</h1>"
"<img src=\"file://" DATADIR "/midori/logo-shade.png\" " "<img src=\"file://" MDATADIR "/midori/logo-shade.png\" "
"style=\"position: absolute; right: 15px; bottom: 15px;\">" "style=\"position: absolute; right: 15px; bottom: 15px;\">"
"<p />The document %s of type '%s' cannot be displayed." "<p />The document %s of type '%s' cannot be displayed."
"</body></html>", "</body></html>",
@ -2118,7 +2147,7 @@ midori_view_set_uri (MidoriView* view,
data = g_strdup_printf ( data = g_strdup_printf (
"<html><head><title>%s</title></head>" "<html><head><title>%s</title></head>"
"<body><h1>%s</h1>" "<body><h1>%s</h1>"
"<img src=\"file://" DATADIR "/midori/logo-shade.png\" " "<img src=\"file://" MDATADIR "/midori/logo-shade.png\" "
"style=\"position: absolute; right: 15px; bottom: 15px;\">" "style=\"position: absolute; right: 15px; bottom: 15px;\">"
"<p />There is no documentation installed at %s." "<p />There is no documentation installed at %s."
"You may want to ask your distribution or " "You may want to ask your distribution or "
@ -2178,6 +2207,8 @@ midori_view_is_blank (MidoriView* view)
* *
* Retrieves the icon of the view. * Retrieves the icon of the view.
* *
* The returned icon is owned by the @view and must not be modified.
*
* Return value: a #GdkPixbuf * Return value: a #GdkPixbuf
**/ **/
GdkPixbuf* GdkPixbuf*
@ -2396,6 +2427,84 @@ midori_view_get_proxy_menu_item (MidoriView* view)
return view->menu_item; return view->menu_item;
} }
static void
midori_view_tab_label_menu_open_cb (GtkWidget* menuitem,
GtkWidget* view)
{
MidoriBrowser* browser = midori_browser_get_for_widget (view);
midori_browser_set_current_tab (browser, view);
}
static void
midori_view_tab_label_menu_window_new_cb (GtkWidget* menuitem,
GtkWidget* view)
{
g_signal_emit (view, signals[NEW_WINDOW], 0,
midori_view_get_display_uri (MIDORI_VIEW (view)));
}
static void
midori_view_tab_label_menu_duplicate_tab_cb (GtkWidget* menuitem,
MidoriView* view)
{
MidoriNewView where = MIDORI_NEW_VIEW_TAB;
GtkWidget* new_view = g_object_new (MIDORI_TYPE_VIEW,
"net", view->net, "settings", view->settings, NULL);
midori_view_set_uri (MIDORI_VIEW (new_view),
midori_view_get_display_uri (view));
g_signal_emit (view, signals[NEW_VIEW], 0, new_view, where);
}
static void
midori_view_tab_label_menu_close_cb (GtkWidget* menuitem,
GtkWidget* view)
{
gtk_widget_destroy (view);
}
/**
* midori_view_get_tab_menu:
* @view: a #MidoriView
*
* Retrieves a menu that is typically shown when right-clicking
* a tab label or equivalent representation.
*
* Return value: a #GtkMenu
*
* Since: 0.1.8
**/
GtkWidget*
midori_view_get_tab_menu (MidoriView* view)
{
GtkWidget* menu;
GtkWidget* menuitem;
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
menu = gtk_menu_new ();
menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_OPEN, NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_view_tab_label_menu_open_cb), view);
menuitem = gtk_image_menu_item_new_from_stock (STOCK_WINDOW_NEW, NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_view_tab_label_menu_window_new_cb), view);
menuitem = gtk_menu_item_new_with_mnemonic (_("_Duplicate Tab"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_view_tab_label_menu_duplicate_tab_cb), view);
menuitem = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLOSE, NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_view_tab_label_menu_close_cb), view);
gtk_widget_show_all (menu);
return menu;
}
static gboolean static gboolean
midori_view_tab_label_button_release_event (GtkWidget* tab_label, midori_view_tab_label_button_release_event (GtkWidget* tab_label,
GdkEventButton* event, GdkEventButton* event,
@ -2407,6 +2516,15 @@ midori_view_tab_label_button_release_event (GtkWidget* tab_label,
gtk_widget_destroy (widget); gtk_widget_destroy (widget);
return TRUE; return TRUE;
} }
else if (event->button == 3)
{
/* Show a context menu on right click */
GtkWidget* menu = midori_view_get_tab_menu (MIDORI_VIEW (widget));
katze_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
return TRUE;
}
return FALSE; return FALSE;
} }
@ -2533,6 +2651,23 @@ midori_view_tab_label_parent_set (GtkWidget* tab_label,
} }
} }
#if 0
static gboolean
midori_view_tab_label_query_tooltip_cb (GtkWidget* tab_label,
gint x,
gint y,
gboolean keyboard,
GtkTooltip* tooltip,
MidoriView* view)
{
if (view->speed_dial_in_new_tabs)
gtk_tooltip_set_icon (tooltip, midori_view_get_snapshot (view, -160, -107));
else
gtk_tooltip_set_text (tooltip, midori_view_get_display_title (view));
return TRUE;
}
#endif
/** /**
* midori_view_get_proxy_tab_label: * midori_view_get_proxy_tab_label:
* @view: a #MidoriView * @view: a #MidoriView
@ -2609,6 +2744,11 @@ midori_view_get_proxy_tab_label (MidoriView* view)
G_CALLBACK (midori_view_tab_close_clicked), view); G_CALLBACK (midori_view_tab_close_clicked), view);
view->tab_label = event_box; view->tab_label = event_box;
#if 0
gtk_widget_set_has_tooltip (view->tab_label, TRUE);
g_signal_connect (view->tab_label, "query-tooltip",
G_CALLBACK (midori_view_tab_label_query_tooltip_cb), view);
#endif
g_signal_connect (view->tab_icon, "destroy", g_signal_connect (view->tab_icon, "destroy",
G_CALLBACK (gtk_widget_destroyed), G_CALLBACK (gtk_widget_destroyed),
&view->tab_icon); &view->tab_icon);
@ -2768,6 +2908,8 @@ midori_view_reload (MidoriView* view,
#endif #endif
if (view->title && strstr (title, view->title)) if (view->title && strstr (title, view->title))
webkit_web_view_open (WEBKIT_WEB_VIEW (view->web_view), view->uri); webkit_web_view_open (WEBKIT_WEB_VIEW (view->web_view), view->uri);
else if (midori_view_is_blank (view))
midori_view_set_uri (view, view->uri);
else if (from_cache) else if (from_cache)
webkit_web_view_reload (WEBKIT_WEB_VIEW (view->web_view)); webkit_web_view_reload (WEBKIT_WEB_VIEW (view->web_view));
else else
@ -2978,10 +3120,12 @@ midori_view_execute_script (MidoriView* view,
/* For now this is private API */ /* For now this is private API */
GdkPixbuf* GdkPixbuf*
midori_view_get_snapshot (MidoriView* view, midori_view_get_snapshot (MidoriView* view,
guint width, gint width,
guint height) gint height)
{ {
GtkWidget* web_view; GtkWidget* web_view;
gboolean fast;
gint x, y, w, h;
GdkRectangle rect; GdkRectangle rect;
GdkPixmap* pixmap; GdkPixmap* pixmap;
GdkEvent event; GdkEvent event;
@ -2993,13 +3137,30 @@ midori_view_get_snapshot (MidoriView* view,
web_view = gtk_bin_get_child (GTK_BIN (view)); web_view = gtk_bin_get_child (GTK_BIN (view));
g_return_val_if_fail (web_view->window, NULL); g_return_val_if_fail (web_view->window, NULL);
rect.x = web_view->allocation.x; x = web_view->allocation.x;
rect.y = web_view->allocation.y; y = web_view->allocation.y;
rect.width = web_view->allocation.width; w = web_view->allocation.width;
rect.height = web_view->allocation.height; h = web_view->allocation.height;
pixmap = gdk_pixmap_new (web_view->window, /* If width and height are both negative, we try to render faster at
web_view->allocation.width, web_view->allocation.height, the cost of correctness or beauty. Only a part of the page is
rendered which makes it a lot faster and scaling isn't as nice. */
fast = FALSE;
if (width < 0 && height < 0)
{
width *= -1;
height *= -1;
w = w > 320 ? 320 : w;
h = h > 240 ? 240 : h;
fast = TRUE;
}
rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;
pixmap = gdk_pixmap_new (web_view->window, w, h,
gdk_drawable_get_depth (web_view->window)); gdk_drawable_get_depth (web_view->window));
event.expose.type = GDK_EXPOSE; event.expose.type = GDK_EXPOSE;
event.expose.window = pixmap; event.expose.window = pixmap;
@ -3025,8 +3186,9 @@ midori_view_get_snapshot (MidoriView* view,
width = rect.width; width = rect.width;
if (!height) if (!height)
height = rect.height; height = rect.height;
scaled = gdk_pixbuf_scale_simple (pixbuf, width, height, scaled = gdk_pixbuf_scale_simple (pixbuf, width, height,
GDK_INTERP_TILES); fast ? GDK_INTERP_NEAREST : GDK_INTERP_TILES);
g_object_unref (pixbuf); g_object_unref (pixbuf);
return scaled; return scaled;
} }

View file

@ -113,6 +113,9 @@ midori_view_can_paste_clipboard (MidoriView* view);
GtkWidget* GtkWidget*
midori_view_get_proxy_menu_item (MidoriView* view); midori_view_get_proxy_menu_item (MidoriView* view);
GtkWidget*
midori_view_get_tab_menu (MidoriView* view);
GtkWidget* GtkWidget*
midori_view_get_proxy_tab_label (MidoriView* view); midori_view_get_proxy_tab_label (MidoriView* view);

View file

@ -20,6 +20,10 @@
#include <config.h> #include <config.h>
#endif #endif
#if defined (G_OS_UNIX)
#include <sys/utsname.h>
#endif
struct _MidoriWebSettings struct _MidoriWebSettings
{ {
WebKitWebSettings parent_instance; WebKitWebSettings parent_instance;
@ -513,7 +517,7 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
"toolbar-items", "toolbar-items",
_("Toolbar Items"), _("Toolbar Items"),
_("The items to show on the toolbar"), _("The items to show on the toolbar"),
"Back,Forward,ReloadStop,Location,Panel,Trash,Search", "Back,Forward,ReloadStop,Location,Panel,Search,Trash",
flags)); flags));
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
@ -592,11 +596,7 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
_("Show speed dial in new tabs"), _("Show speed dial in new tabs"),
_("Show speed dial in newly opened tabs"), _("Show speed dial in newly opened tabs"),
TRUE, TRUE,
#if GTK_CHECK_VERSION (2, 14, 0)
flags)); flags));
#else
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
#endif
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
PROP_DOWNLOAD_FOLDER, PROP_DOWNLOAD_FOLDER,
@ -741,11 +741,7 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
_("Where to open externally opened pages"), _("Where to open externally opened pages"),
MIDORI_TYPE_NEW_PAGE, MIDORI_TYPE_NEW_PAGE,
MIDORI_NEW_PAGE_TAB, MIDORI_NEW_PAGE_TAB,
#if HAVE_UNIQUE
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#else
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
#endif
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
PROP_MIDDLE_CLICK_OPENS_SELECTION, PROP_MIDDLE_CLICK_OPENS_SELECTION,
@ -1033,6 +1029,24 @@ midori_web_settings_finalize (GObject* object)
G_OBJECT_CLASS (midori_web_settings_parent_class)->finalize (object); G_OBJECT_CLASS (midori_web_settings_parent_class)->finalize (object);
} }
#if defined (G_OS_UNIX)
static gchar*
get_sys_name (void)
{
static gchar* sys_name = NULL;
if (!sys_name)
{
struct utsname name;
if (uname (&name) != -1)
sys_name = g_strdup_printf ("%s %s", name.sysname, name.machine);
else
sys_name = "Unix";
}
return sys_name;
}
#endif
static gchar* static gchar*
generate_ident_string (MidoriIdentity identify_as) generate_ident_string (MidoriIdentity identify_as)
{ {
@ -1057,12 +1071,7 @@ generate_ident_string (MidoriIdentity identify_as)
"PPC Mac OS X"; "PPC Mac OS X";
#endif */ #endif */
#elif defined (G_OS_UNIX) #elif defined (G_OS_UNIX)
/* struct utsname name; get_sys_name ();
if (uname (&name) != -1)
String::format ("%s %s", name.sysname, name.machine);
else
"Unknown";*/
"Linux";
#elif defined (G_OS_WIN32) #elif defined (G_OS_WIN32)
// FIXME: Windows NT version // FIXME: Windows NT version
"Windows"; "Windows";
@ -1296,7 +1305,8 @@ midori_web_settings_set_property (GObject* object,
} }
break; break;
case PROP_IDENT_STRING: case PROP_IDENT_STRING:
katze_assign (web_settings->ident_string, g_value_dup_string (value)); if (web_settings->identify_as == MIDORI_IDENT_CUSTOM)
katze_assign (web_settings->ident_string, g_value_dup_string (value));
break; break;
case PROP_CACHE_SIZE: case PROP_CACHE_SIZE:
web_settings->cache_size = g_value_get_int (value); web_settings->cache_size = g_value_get_int (value);

1766
midori/socket.c Normal file

File diff suppressed because it is too large Load diff

128
midori/socket.h Normal file
View file

@ -0,0 +1,128 @@
/*
Copyright 1999-2008 Hiroyuki Yamamoto
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.
*/
#ifndef __SYLPH_SOCKET_H__
#define __SYLPH_SOCKET_H__
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib.h>
#if HAVE_NETDB_H
# include <netdb.h>
#endif
typedef struct _SockInfo SockInfo;
#if USE_SSL
# include <openssl/ssl.h>
#endif
typedef enum
{
CONN_READY,
CONN_LOOKUPSUCCESS,
CONN_ESTABLISHED,
CONN_LOOKUPFAILED,
CONN_FAILED
} ConnectionState;
typedef gint (*SockConnectFunc) (SockInfo *sock,
gpointer data);
typedef gboolean (*SockFunc) (SockInfo *sock,
GIOCondition condition,
gpointer data);
struct _SockInfo
{
gint sock;
#if USE_SSL
SSL *ssl;
#else
gpointer ssl;
#endif
GIOChannel *sock_ch;
gchar *hostname;
gushort port;
ConnectionState state;
gboolean nonblock;
gpointer data;
SockFunc callback;
GIOCondition condition;
};
void send_open_command (gint sock, const gchar *command,
gchar **args);
gint socket_init (const gchar *instance_name,
const gchar *config_dir, gboolean *exists);
gint sock_cleanup (void);
gint sock_set_io_timeout (guint sec);
gint sock_set_nonblocking_mode (SockInfo *sock, gboolean nonblock);
gboolean sock_is_nonblocking_mode (SockInfo *sock);
gboolean sock_has_read_data (SockInfo *sock);
guint sock_add_watch (SockInfo *sock, GIOCondition condition,
SockFunc func, gpointer data);
struct hostent *my_gethostbyname (const gchar *hostname);
SockInfo *sock_connect (const gchar *hostname, gushort port);
#ifdef G_OS_UNIX
gint sock_connect_async (const gchar *hostname, gushort port,
SockConnectFunc func, gpointer data);
gint sock_connect_async_cancel (gint id);
#endif
/* Basic I/O functions */
gint sock_printf (SockInfo *sock, const gchar *format, ...)
G_GNUC_PRINTF(2, 3);
gint sock_read (SockInfo *sock, gchar *buf, gint len);
gint sock_write (SockInfo *sock, const gchar *buf, gint len);
gint sock_write_all (SockInfo *sock, const gchar *buf, gint len);
gint sock_gets (SockInfo *sock, gchar *buf, gint len);
gint sock_getline (SockInfo *sock, gchar **line);
gint sock_puts (SockInfo *sock, const gchar *buf);
gint sock_peek (SockInfo *sock, gchar *buf, gint len);
gint sock_close (SockInfo *sock);
/* Functions to directly work on FD. They are needed for pipes */
gint fd_connect_inet (gushort port);
gint fd_open_inet (gushort port);
gint fd_connect_unix (const gchar *path);
gint fd_open_unix (const gchar *path);
gint fd_accept (gint sock);
gint fd_read (gint sock, gchar *buf, gint len);
gint fd_write (gint sock, const gchar *buf, gint len);
gint fd_write_all (gint sock, const gchar *buf, gint len);
gint fd_gets (gint sock, gchar *buf, gint len);
gint fd_getline (gint sock, gchar **line);
gint fd_close (gint sock);
/* Functions for SSL */
#if USE_SSL
gint ssl_read (SSL *ssl, gchar *buf, gint len);
gint ssl_write (SSL *ssl, const gchar *buf, gint len);
gint ssl_write_all (SSL *ssl, const gchar *buf, gint len);
gint ssl_gets (SSL *ssl, gchar *buf, gint len);
gint ssl_getline (SSL *ssl, gchar **line);
gint ssl_peek (SSL *ssl, gchar *buf, gint len);
void ssl_done_socket (SockInfo *sockinfo);
#endif
#endif /* __SYLPH_SOCKET_H__ */

View file

@ -36,6 +36,7 @@
#include <idna.h> #include <idna.h>
#endif #endif
#ifdef HAVE_JSCORE
static gchar* static gchar*
sokoke_js_string_utf8 (JSStringRef js_string) sokoke_js_string_utf8 (JSStringRef js_string)
{ {
@ -49,18 +50,22 @@ sokoke_js_string_utf8 (JSStringRef js_string)
JSStringGetUTF8CString (js_string, string_utf8, size_utf8); JSStringGetUTF8CString (js_string, string_utf8, size_utf8);
return string_utf8; return string_utf8;
} }
#endif
gchar* gchar*
sokoke_js_script_eval (JSContextRef js_context, sokoke_js_script_eval (JSContextRef js_context,
const gchar* script, const gchar* script,
gchar** exception) gchar** exception)
{ {
#ifdef HAVE_JSCORE
gchar* value; gchar* value;
JSStringRef js_value_string; JSStringRef js_value_string;
#endif
g_return_val_if_fail (js_context, FALSE); g_return_val_if_fail (js_context, FALSE);
g_return_val_if_fail (script, FALSE); g_return_val_if_fail (script, FALSE);
#ifdef HAVE_JSCORE
JSStringRef js_script = JSStringCreateWithUTF8CString (script); JSStringRef js_script = JSStringCreateWithUTF8CString (script);
JSValueRef js_exception = NULL; JSValueRef js_exception = NULL;
JSValueRef js_value = JSEvaluateScript (js_context, js_script, JSValueRef js_value = JSEvaluateScript (js_context, js_script,
@ -79,6 +84,9 @@ sokoke_js_script_eval (JSContextRef js_context,
value = sokoke_js_string_utf8 (js_value_string); value = sokoke_js_string_utf8 (js_value_string);
JSStringRelease (js_value_string); JSStringRelease (js_value_string);
return value; return value;
#else
return g_strdup ("");
#endif
} }
static void static void
@ -92,8 +100,6 @@ error_dialog (const gchar* short_message,
gtk_widget_show (dialog); gtk_widget_show (dialog);
g_signal_connect_swapped (dialog, "response", g_signal_connect_swapped (dialog, "response",
G_CALLBACK (gtk_widget_destroy), dialog); G_CALLBACK (gtk_widget_destroy), dialog);
} }
/** /**
@ -355,11 +361,11 @@ sokoke_magic_uri (const gchar* uri,
search_uri = NULL; search_uri = NULL;
/* Do we have a keyword and a string? */ /* Do we have a keyword and a string? */
parts = g_strsplit (uri, " ", 2); parts = g_strsplit (uri, " ", 2);
if (parts[0] && parts[1]) if (parts[0])
if ((item = katze_array_find_token (search_engines, parts[0]))) if ((item = katze_array_find_token (search_engines, parts[0])))
{ {
search_uri = katze_item_get_uri (item); search_uri = katze_item_get_uri (item);
search = sokoke_search_uri (search_uri, parts[1]); search = sokoke_search_uri (search_uri, parts[1] ? parts[1] : "");
} }
g_strfreev (parts); g_strfreev (parts);
return search; return search;
@ -511,12 +517,16 @@ sokoke_hig_frame_new (const gchar* title)
{ {
/* Create a frame with no actual frame but a bold label and indentation */ /* Create a frame with no actual frame but a bold label and indentation */
GtkWidget* frame = gtk_frame_new (NULL); GtkWidget* frame = gtk_frame_new (NULL);
#ifdef G_OS_WIN32
gtk_frame_set_label (GTK_FRAME (frame), title);
#else
gchar* title_bold = g_strdup_printf ("<b>%s</b>", title); gchar* title_bold = g_strdup_printf ("<b>%s</b>", title);
GtkWidget* label = gtk_label_new (NULL); GtkWidget* label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), title_bold); gtk_label_set_markup (GTK_LABEL (label), title_bold);
g_free (title_bold); g_free (title_bold);
gtk_frame_set_label_widget (GTK_FRAME (frame), label); gtk_frame_set_label_widget (GTK_FRAME (frame), label);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
#endif
return frame; return frame;
} }
@ -735,6 +745,9 @@ sokoke_action_create_popup_menu_item (GtkAction* action)
g_return_val_if_fail (GTK_IS_ACTION (action), NULL); g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
if (KATZE_IS_ARRAY_ACTION (action))
return gtk_action_create_menu_item (action);
g_object_get (action, g_object_get (action,
"label", &label, "label", &label,
"stock-id", &stock_id, "stock-id", &stock_id,
@ -747,6 +760,9 @@ sokoke_action_create_popup_menu_item (GtkAction* action)
menuitem = gtk_check_menu_item_new_with_mnemonic (label); menuitem = gtk_check_menu_item_new_with_mnemonic (label);
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem),
gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
if (GTK_IS_RADIO_ACTION (action))
gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (menuitem),
TRUE);
} }
else if (stock_id) else if (stock_id)
{ {
@ -839,6 +855,7 @@ sokoke_register_stock_items (void)
{ {
{ STOCK_EXTENSION, NULL, 0, 0, GTK_STOCK_CONVERT }, { STOCK_EXTENSION, NULL, 0, 0, GTK_STOCK_CONVERT },
{ STOCK_IMAGE, NULL, 0, 0, GTK_STOCK_ORIENTATION_PORTRAIT }, { STOCK_IMAGE, NULL, 0, 0, GTK_STOCK_ORIENTATION_PORTRAIT },
{ STOCK_WEB_BROWSER, NULL, 0, 0, "gnome-web-browser" },
{ STOCK_NEWS_FEED, NULL, 0, 0, GTK_STOCK_INDEX }, { STOCK_NEWS_FEED, NULL, 0, 0, GTK_STOCK_INDEX },
{ STOCK_SCRIPT, NULL, 0, 0, GTK_STOCK_EXECUTE }, { STOCK_SCRIPT, NULL, 0, 0, GTK_STOCK_EXECUTE },
{ STOCK_STYLE, NULL, 0, 0, GTK_STOCK_SELECT_COLOR }, { STOCK_STYLE, NULL, 0, 0, GTK_STOCK_SELECT_COLOR },
@ -846,7 +863,7 @@ sokoke_register_stock_items (void)
{ STOCK_BOOKMARK, N_("_Bookmark"), 0, 0, GTK_STOCK_FILE }, { STOCK_BOOKMARK, N_("_Bookmark"), 0, 0, GTK_STOCK_FILE },
{ STOCK_BOOKMARKS, N_("_Bookmarks"), 0, 0, GTK_STOCK_DIRECTORY }, { STOCK_BOOKMARKS, N_("_Bookmarks"), 0, 0, GTK_STOCK_DIRECTORY },
{ STOCK_BOOKMARK_ADD, N_("_Add Bookmark"), 0, 0, GTK_STOCK_ADD }, { STOCK_BOOKMARK_ADD, N_("Add Boo_kmark"), 0, 0, GTK_STOCK_ADD },
{ STOCK_CONSOLE, N_("_Console"), 0, 0, GTK_STOCK_DIALOG_WARNING }, { STOCK_CONSOLE, N_("_Console"), 0, 0, GTK_STOCK_DIALOG_WARNING },
{ STOCK_EXTENSIONS, N_("_Extensions"), 0, 0, GTK_STOCK_CONVERT }, { STOCK_EXTENSIONS, N_("_Extensions"), 0, 0, GTK_STOCK_CONVERT },
{ STOCK_HISTORY, N_("_History"), 0, 0, GTK_STOCK_SORT_ASCENDING }, { STOCK_HISTORY, N_("_History"), 0, 0, GTK_STOCK_SORT_ASCENDING },
@ -948,6 +965,32 @@ sokoke_remove_path (const gchar* path,
return TRUE; return TRUE;
} }
/**
* sokoke_find_data_filename:
* @filename: a filename or relative path
*
* Looks for the specified filename in the system data
* directories, depending on the platform.
*
* Return value: a full path
**/
gchar*
sokoke_find_data_filename (const gchar* filename)
{
const gchar* const* data_dirs = g_get_system_data_dirs ();
guint i = 0;
const gchar* data_dir;
while ((data_dir = data_dirs[i++]))
{
gchar* path = g_build_filename (data_dir, filename, NULL);
if (g_file_test (path, G_FILE_TEST_EXISTS))
return path;
g_free (path);
}
return g_build_filename (MDATADIR, filename, NULL);
}
static void static void
res_server_handler_cb (SoupServer* res_server, res_server_handler_cb (SoupServer* res_server,
SoupMessage* msg, SoupMessage* msg,
@ -958,13 +1001,15 @@ res_server_handler_cb (SoupServer* res_server,
{ {
if (g_str_has_prefix (path, "/res")) if (g_str_has_prefix (path, "/res"))
{ {
gchar* filename = g_strconcat (DATADIR "/midori", path, NULL); gchar* filename = g_build_filename ("midori", path, NULL);
gchar* filepath = sokoke_find_data_filename (filename);
gchar* contents; gchar* contents;
gsize length; gsize length;
if (g_file_get_contents (filename, &contents, &length, NULL)) g_free (filename);
if (g_file_get_contents (filepath, &contents, &length, NULL))
{ {
gchar* content_type = g_content_type_guess (filename, (guchar*)contents, gchar* content_type = g_content_type_guess (filepath, (guchar*)contents,
length, NULL); length, NULL);
gchar* mime_type = g_content_type_get_mime_type (content_type); gchar* mime_type = g_content_type_get_mime_type (content_type);
g_free (content_type); g_free (content_type);
@ -975,7 +1020,7 @@ res_server_handler_cb (SoupServer* res_server,
} }
else else
soup_message_set_status (msg, 404); soup_message_set_status (msg, 404);
g_free (filename); g_free (filepath);
} }
else if (g_str_has_prefix (path, "/stock/")) else if (g_str_has_prefix (path, "/stock/"))
{ {

View file

@ -151,6 +151,9 @@ gboolean
sokoke_remove_path (const gchar* path, sokoke_remove_path (const gchar* path,
gboolean ignore_errors); gboolean ignore_errors);
gchar*
sokoke_find_data_filename (const gchar* filename);
SoupServer* SoupServer*
sokoke_get_res_server (void); sokoke_get_res_server (void);

View file

@ -5,12 +5,12 @@
import platform import platform
obj = bld.new_task_gen ('cc', 'staticlib') obj = bld.new_task_gen ('cc', 'staticlib')
obj.name = 'midori' obj.name = 'midori-core'
obj.target = 'midori' obj.target = 'midori'
obj.includes = '. ..' obj.includes = '. ..'
obj.find_sources_in_dirs ('.', excludes=['main.c']) obj.find_sources_in_dirs ('.', excludes=['main.c'])
obj.add_marshal_file ('marshal.list', 'midori_cclosure_marshal') obj.add_marshal_file ('marshal.list', 'midori_cclosure_marshal')
obj.uselib = 'UNIQUE LIBSOUP LIBIDN GIO GTK SQLITE WEBKIT LIBXML HILDON' obj.uselib = 'UNIQUE LIBSOUP LIBIDN GIO GTK SQLITE WEBKIT LIBXML WS2_32 OPENSSL HILDON'
obj.uselib_local = 'katze' obj.uselib_local = 'katze'
obj.install_path = None obj.install_path = None
@ -20,12 +20,14 @@ obj.target = 'panels'
obj.includes = '. ..' obj.includes = '. ..'
obj.find_sources_in_dirs ('../panels') obj.find_sources_in_dirs ('../panels')
obj.uselib = 'UNIQUE LIBSOUP GMODULE GTHREAD GIO GTK SQLITE WEBKIT LIBXML' obj.uselib = 'UNIQUE LIBSOUP GMODULE GTHREAD GIO GTK SQLITE WEBKIT LIBXML'
obj.uselib_local = 'midori' obj.uselib_local = 'midori-core'
obj.install_path = None obj.install_path = None
obj = bld.new_task_gen ('cc', 'program') obj = bld.new_task_gen ('cc', 'program')
obj.target = 'midori' obj.target = 'midori'
obj.includes = '. .. ../panels' obj.includes = '. .. ../panels'
obj.source = 'main.c' obj.source = 'main.c'
if bld.env['WINRC']:
obj.source += ' ../data/midori.rc'
obj.uselib = 'UNIQUE LIBSOUP GMODULE GTHREAD GIO GTK SQLITE WEBKIT LIBXML' obj.uselib = 'UNIQUE LIBSOUP GMODULE GTHREAD GIO GTK SQLITE WEBKIT LIBXML'
obj.uselib_local = 'panels' obj.uselib_local = 'panels'

View file

@ -306,49 +306,6 @@ _addons_get_files (MidoriAddons* addons)
return files; return files;
} }
static GtkTreePath*
_treeview_first_selected_path (GtkTreeView *treeview)
{
GtkTreeSelection* selection;
GList* tree_paths;
selection = gtk_tree_view_get_selection (treeview);
if (!selection)
return NULL;
if (gtk_tree_selection_get_selected (selection, NULL, NULL))
{
GtkTreePath* result;
tree_paths = gtk_tree_selection_get_selected_rows (selection, NULL);
result = gtk_tree_path_copy (g_list_nth_data (tree_paths, 0));
g_list_foreach (tree_paths, (GFunc)gtk_tree_path_free, NULL);
g_list_free (tree_paths);
return result;
}
else
return NULL;
}
static void
_addons_toggle_enable_button (MidoriAddons* addons,
gboolean sensitive)
{
GtkToolItem* button;
button = gtk_toolbar_get_nth_item (GTK_TOOLBAR (addons->toolbar), 1);
gtk_widget_set_sensitive (GTK_WIDGET (button), sensitive);
}
static void
_addons_toggle_disable_button (MidoriAddons* addons,
gboolean sensitive)
{
GtkToolItem* button;
button = gtk_toolbar_get_nth_item (GTK_TOOLBAR (addons->toolbar), 2);
gtk_widget_set_sensitive (GTK_WIDGET (button), sensitive);
}
static void static void
midori_addons_directory_monitor_changed (GFileMonitor* monitor, midori_addons_directory_monitor_changed (GFileMonitor* monitor,
GFile* child, GFile* child,
@ -359,67 +316,6 @@ midori_addons_directory_monitor_changed (GFileMonitor* monitor,
midori_addons_update_elements (addons); midori_addons_update_elements (addons);
} }
static void
midori_addons_treeview_cursor_changed (GtkTreeView* treeview,
MidoriAddons* addons)
{
struct AddonElement* element;
GtkTreeModel* model;
GtkTreeIter iter;
GtkTreePath *path;
path = _treeview_first_selected_path (treeview);
model = gtk_tree_view_get_model (treeview);
if (path && gtk_tree_model_get_iter (model, &iter, path))
{
gtk_tree_model_get (model, &iter, 0, &element, -1);
if (element->broken)
{
_addons_toggle_enable_button (addons, FALSE);
_addons_toggle_disable_button (addons, FALSE);
} else
{
_addons_toggle_enable_button (addons, !element->enabled);
_addons_toggle_disable_button (addons, element->enabled);
}
}
}
static void
midori_addons_button_status_clicked_cb (GtkToolItem* toolitem,
MidoriAddons* addons)
{
GtkTreeView* treeview;
struct AddonElement* element;
GtkTreeModel* model;
GtkTreeIter iter;
GtkTreePath* path;
treeview = GTK_TREE_VIEW (addons->treeview);
path = _treeview_first_selected_path (treeview);
model = gtk_tree_view_get_model (treeview);
if (gtk_tree_model_get_iter (model, &iter, path))
{
gtk_tree_model_get (model, &iter, 0, &element, -1);
if (toolitem == gtk_toolbar_get_nth_item (
GTK_TOOLBAR (addons->toolbar), 2)) /* disable button */
element->enabled = FALSE;
else if (toolitem == gtk_toolbar_get_nth_item (
GTK_TOOLBAR (addons->toolbar), 1)) /* enable button */
element->enabled = TRUE;
_addons_toggle_enable_button (addons, !element->enabled);
_addons_toggle_disable_button (addons, element->enabled);
/* After enabling or disabling an element, the tree view
is not updated automatically; we need to notify tree model
in order to take the modification into account */
gtk_tree_model_row_changed (model, path, &iter);
}
}
static void static void
midori_addons_button_add_clicked_cb (GtkToolItem* toolitem, midori_addons_button_add_clicked_cb (GtkToolItem* toolitem,
MidoriAddons* addons) MidoriAddons* addons)
@ -435,7 +331,7 @@ midori_addons_button_add_clicked_cb (GtkToolItem* toolitem,
} }
static void static void
midori_addons_treeview_render_icon_cb (GtkTreeViewColumn* column, midori_addons_treeview_render_tick_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer, GtkCellRenderer* renderer,
GtkTreeModel* model, GtkTreeModel* model,
GtkTreeIter* iter, GtkTreeIter* iter,
@ -445,10 +341,10 @@ midori_addons_treeview_render_icon_cb (GtkTreeViewColumn* column,
gtk_tree_model_get (model, iter, 0, &element, -1); gtk_tree_model_get (model, iter, 0, &element, -1);
if (element->broken) g_object_set (renderer,
g_object_set (renderer, "stock-id", GTK_STOCK_STOP, NULL); "active", element->enabled,
else "sensitive", !element->broken,
g_object_set (renderer, "stock-id", GTK_STOCK_FILE, NULL); NULL);
} }
static void static void
@ -475,14 +371,48 @@ midori_addons_treeview_row_activated_cb (GtkTreeView* treeview,
GtkTreeViewColumn* column, GtkTreeViewColumn* column,
MidoriAddons* addons) MidoriAddons* addons)
{ {
/*GtkTreeModel* model = gtk_tree_view_get_model (treeview); GtkTreeModel* model = gtk_tree_view_get_model (treeview);
GtkTreeIter iter; GtkTreeIter iter;
if (gtk_tree_model_get_iter (model, &iter, path)) if (gtk_tree_model_get_iter (model, &iter, path))
{ {
gchar* b; struct AddonElement *element;
gtk_tree_model_get (model, &iter, 2, &b, -1);
g_free (b); gtk_tree_model_get (model, &iter, 0, &element, -1);
}*/
element->enabled = !element->enabled;
/* After enabling or disabling an element, the tree view
is not updated automatically; we need to notify tree model
in order to take the modification into account */
gtk_tree_model_row_changed (model, path, &iter);
}
}
static void
midori_addons_cell_renderer_toggled_cb (GtkCellRendererToggle* renderer,
const gchar* path,
MidoriAddons* addons)
{
GtkTreeModel* model;
GtkTreeIter iter;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (addons->treeview));
if (gtk_tree_model_get_iter_from_string (model, &iter, path))
{
struct AddonElement *element;
GtkTreePath* tree_path;
gtk_tree_model_get (model, &iter, 0, &element, -1);
element->enabled = !element->enabled;
/* After enabling or disabling an element, the tree view
is not updated automatically; we need to notify tree model
in order to take the modification into account */
tree_path = gtk_tree_path_new_from_string (path);
gtk_tree_model_row_changed (model, tree_path, &iter);
gtk_tree_path_free (tree_path);
}
} }
static void static void
@ -490,7 +420,7 @@ midori_addons_init (MidoriAddons* addons)
{ {
GtkTreeViewColumn* column; GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_pixbuf; GtkCellRenderer* renderer_toggle;
addons->web_widget = NULL; addons->web_widget = NULL;
addons->elements = NULL; addons->elements = NULL;
@ -498,11 +428,15 @@ midori_addons_init (MidoriAddons* addons)
addons->treeview = gtk_tree_view_new (); addons->treeview = gtk_tree_view_new ();
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (addons->treeview), FALSE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (addons->treeview), FALSE);
column = gtk_tree_view_column_new (); column = gtk_tree_view_column_new ();
renderer_pixbuf = gtk_cell_renderer_pixbuf_new (); renderer_toggle = gtk_cell_renderer_toggle_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE); gtk_tree_view_column_pack_start (column, renderer_toggle, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf, gtk_tree_view_column_set_cell_data_func (column, renderer_toggle,
(GtkTreeCellDataFunc)midori_addons_treeview_render_icon_cb, (GtkTreeCellDataFunc)midori_addons_treeview_render_tick_cb,
addons->treeview, NULL); addons->treeview, NULL);
g_signal_connect (renderer_toggle, "toggled",
G_CALLBACK (midori_addons_cell_renderer_toggled_cb), addons);
gtk_tree_view_append_column (GTK_TREE_VIEW (addons->treeview), column);
column = gtk_tree_view_column_new ();
renderer_text = gtk_cell_renderer_text_new (); renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE); gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text, gtk_tree_view_column_set_cell_data_func (column, renderer_text,
@ -1026,26 +960,6 @@ midori_addons_get_toolbar (MidoriViewable* addons)
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem)); gtk_widget_show (GTK_WIDGET (toolitem));
/* enable button */
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_YES);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("_Enable"));
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), _("Enable"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_addons_button_status_clicked_cb), addons);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE);
gtk_widget_show (GTK_WIDGET (toolitem));
/* disable button */
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_NO);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("_Disable"));
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), _("Disable"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_addons_button_status_clicked_cb), addons);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE);
gtk_widget_show (GTK_WIDGET (toolitem));
/* separator */ /* separator */
toolitem = gtk_separator_tool_item_new (); toolitem = gtk_separator_tool_item_new ();
gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (toolitem), gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (toolitem),
@ -1063,10 +977,6 @@ midori_addons_get_toolbar (MidoriViewable* addons)
gtk_widget_show (GTK_WIDGET (toolitem)); gtk_widget_show (GTK_WIDGET (toolitem));
MIDORI_ADDONS (addons)->toolbar = toolbar; MIDORI_ADDONS (addons)->toolbar = toolbar;
g_signal_connect (MIDORI_ADDONS (addons)->treeview, "cursor-changed",
G_CALLBACK (midori_addons_treeview_cursor_changed),
addons);
g_signal_connect (toolbar, "destroy", g_signal_connect (toolbar, "destroy",
G_CALLBACK (gtk_widget_destroyed), G_CALLBACK (gtk_widget_destroyed),
&MIDORI_ADDONS (addons)->toolbar); &MIDORI_ADDONS (addons)->toolbar);
@ -1179,12 +1089,5 @@ midori_addons_update_elements (MidoriAddons* addons)
gtk_tree_view_set_model (GTK_TREE_VIEW (addons->treeview), gtk_tree_view_set_model (GTK_TREE_VIEW (addons->treeview),
GTK_TREE_MODEL (liststore)); GTK_TREE_MODEL (liststore));
/* In case a row was selected, that selection will be cancelled gtk_widget_queue_draw (GTK_WIDGET (addons->treeview));
when calling gtk_tree_view_set_model. So, we need to make sure
that the buttons are insensitive. */
if (addons->toolbar)
{
_addons_toggle_enable_button (addons, FALSE);
_addons_toggle_disable_button (addons, FALSE);
}
} }

View file

@ -0,0 +1,110 @@
/*
Copyright (C) 2009 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.
*/
#include "midori-bookmark-store.h"
struct _MidoriBookmarkStore
{
GtkTreeStore parent_instance;
};
struct _MidoriBookmarkStoreClass
{
GtkTreeStoreClass parent_class;
};
static void
midori_bookmark_store_drag_source_iface_init (GtkTreeDragSourceIface* iface);
static void
midori_bookmark_store_drag_dest_iface_init (GtkTreeDragDestIface* iface);
G_DEFINE_TYPE_WITH_CODE (MidoriBookmarkStore, midori_bookmark_store, GTK_TYPE_TREE_STORE,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
midori_bookmark_store_drag_source_iface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
midori_bookmark_store_drag_dest_iface_init));
static void
midori_bookmark_store_finalize (GObject* object);
static void
midori_bookmark_store_class_init (MidoriBookmarkStoreClass* class)
{
GObjectClass* gobject_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_bookmark_store_finalize;
}
static void
midori_bookmark_store_init (MidoriBookmarkStore* bookmark_store)
{
/* Nothing to do */
}
static void
midori_bookmark_store_finalize (GObject* object)
{
/* Nothing to do */
}
static void
midori_bookmark_store_drag_source_iface_init (GtkTreeDragSourceIface* iface)
{
/*iface->row_draggable = real_gtk_tree_store_row_draggable;
iface->drag_data_delete = gtk_tree_store_drag_data_delete;
iface->drag_data_get = gtk_tree_store_drag_data_get;*/
}
static void
midori_bookmark_store_drag_dest_iface_init (GtkTreeDragDestIface* iface)
{
/*iface->drag_data_received = gtk_tree_store_drag_data_received;
iface->row_drop_possible = gtk_tree_store_row_drop_possible;*/
}
/**
* midori_bookmark_store_new:
*
* Creates a new empty bookmark_store.
*
* Return value: a new #MidoriBookmarkStore
*
* Since: 0.1.8
**/
GtkTreeStore*
midori_bookmark_store_new (gint n_columns,
...)
{
GtkTreeStore* treestore;
va_list args;
gint i;
GType* types;
g_return_val_if_fail (n_columns > 0, NULL);
treestore = g_object_new (MIDORI_TYPE_BOOKMARK_STORE, NULL);
va_start (args, n_columns);
types = g_new (GType, n_columns);
for (i = 0; i < n_columns; i++)
{
GType type = va_arg (args, GType);
types[i] = type;
}
va_end (args);
gtk_tree_store_set_column_types (treestore, i, types);
return treestore;
}

View file

@ -0,0 +1,44 @@
/*
Copyright (C) 2009 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.
*/
#ifndef __MIDORI_BOOKMARK_STORE_H__
#define __MIDORI_BOOKMARK_STORE_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define MIDORI_TYPE_BOOKMARK_STORE \
(midori_bookmark_store_get_type ())
#define MIDORI_BOOKMARK_STORE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_BOOKMARK_STORE, MidoriBookmarkStore))
#define MIDORI_BOOKMARK_STORE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_BOOKMARK_STORE, MidoriBookmarkStoreClass))
#define MIDORI_IS_BOOKMARK_STORE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_BOOKMARK_STORE))
#define MIDORI_IS_BOOKMARK_STORE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_BOOKMARK_STORE))
#define MIDORI_BOOKMARK_STORE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_BOOKMARK_STORE, MidoriBookmarkStoreClass))
typedef struct _MidoriBookmarkStore MidoriBookmarkStore;
typedef struct _MidoriBookmarkStoreClass MidoriBookmarkStoreClass;
GType
midori_bookmark_store_get_type (void);
GtkTreeStore*
midori_bookmark_store_new (gint n_columns,
...);
G_END_DECLS
#endif /* __MIDORI_BOOKMARK_STORE_H__ */

View file

@ -16,6 +16,7 @@
#include "midori-stock.h" #include "midori-stock.h"
#include "midori-view.h" #include "midori-view.h"
#include "midori-viewable.h" #include "midori-viewable.h"
#include "midori-bookmark-store.h"
#include "sokoke.h" #include "sokoke.h"
@ -725,8 +726,10 @@ midori_bookmarks_open_in_window_activate_cb (GtkWidget* menuitem,
if (uri && *uri) if (uri && *uri)
{ {
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (bookmarks)); MidoriBrowser* new_browser = midori_app_create_browser (bookmarks->app);
g_signal_emit_by_name (browser, "new-window", uri); midori_app_add_browser (bookmarks->app, new_browser);
gtk_widget_show (GTK_WIDGET (new_browser));
midori_browser_add_uri (new_browser, uri);
} }
} }
@ -892,7 +895,7 @@ midori_bookmarks_init (MidoriBookmarks* bookmarks)
bookmarks->net = katze_net_new (); bookmarks->net = katze_net_new ();
/* Create the treeview */ /* Create the treeview */
model = gtk_tree_store_new (1, KATZE_TYPE_ITEM); model = midori_bookmark_store_new (1, KATZE_TYPE_ITEM);
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
column = gtk_tree_view_column_new (); column = gtk_tree_view_column_new ();

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de> Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -59,6 +59,9 @@ midori_extensions_get_property (GObject* object,
GValue* value, GValue* value,
GParamSpec* pspec); GParamSpec* pspec);
static void
midori_extensions_finalize (GObject* object);
static void static void
midori_extensions_class_init (MidoriExtensionsClass* class) midori_extensions_class_init (MidoriExtensionsClass* class)
{ {
@ -68,6 +71,7 @@ midori_extensions_class_init (MidoriExtensionsClass* class)
gobject_class = G_OBJECT_CLASS (class); gobject_class = G_OBJECT_CLASS (class);
gobject_class->set_property = midori_extensions_set_property; gobject_class->set_property = midori_extensions_set_property;
gobject_class->get_property = midori_extensions_get_property; gobject_class->get_property = midori_extensions_get_property;
gobject_class->finalize = midori_extensions_finalize;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT; flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
@ -93,37 +97,6 @@ midori_extensions_get_stock_id (MidoriViewable* viewable)
return STOCK_EXTENSIONS; return STOCK_EXTENSIONS;
} }
static void
midori_extensions_button_status_clicked_cb (GtkToolItem* toolitem,
MidoriExtensions* extensions)
{
GtkTreeView* treeview;
GtkTreeModel* model;
GtkTreeIter iter;
MidoriExtension* extension;
treeview = GTK_TREE_VIEW (extensions->treeview);
if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
{
GtkToolItem* button_enable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 1);
GtkToolItem* button_disable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 2);
gtk_tree_model_get (model, &iter, 0, &extension, -1);
if (toolitem == button_enable)
g_signal_emit_by_name (extension, "activate", extensions->app);
else if (toolitem == button_disable)
midori_extension_deactivate (extension);
gtk_widget_set_sensitive (GTK_WIDGET (button_enable),
!midori_extension_is_active (extension));
gtk_widget_set_sensitive (GTK_WIDGET (button_disable),
midori_extension_is_active (extension));
}
}
static GtkWidget* static GtkWidget*
midori_extensions_get_toolbar (MidoriViewable* extensions) midori_extensions_get_toolbar (MidoriViewable* extensions)
{ {
@ -139,26 +112,6 @@ midori_extensions_get_toolbar (MidoriViewable* extensions)
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem)); gtk_widget_show (GTK_WIDGET (toolitem));
/* enable button */
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_YES);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("_Enable"));
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), _("Enable"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_extensions_button_status_clicked_cb), extensions);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE);
gtk_widget_show (GTK_WIDGET (toolitem));
/* disable button */
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_NO);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("_Disable"));
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), _("Disable"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_extensions_button_status_clicked_cb), extensions);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE);
gtk_widget_show (GTK_WIDGET (toolitem));
MIDORI_EXTENSIONS (extensions)->toolbar = toolbar; MIDORI_EXTENSIONS (extensions)->toolbar = toolbar;
} }
@ -173,6 +126,21 @@ midori_extensions_viewable_iface_init (MidoriViewableIface* iface)
iface->get_toolbar = midori_extensions_get_toolbar; iface->get_toolbar = midori_extensions_get_toolbar;
} }
static void
midori_extensions_extension_activate_cb (MidoriExtension* extension,
MidoriApp* app,
MidoriExtensions* extensions)
{
gtk_widget_queue_draw (GTK_WIDGET (extensions->treeview));
}
static void
midori_extensions_extension_deactivate_cb (MidoriExtension* extension,
MidoriExtensions* extensions)
{
gtk_widget_queue_draw (GTK_WIDGET (extensions->treeview));
}
static void static void
midori_extensions_add_item_cb (KatzeArray* array, midori_extensions_add_item_cb (KatzeArray* array,
MidoriExtension* extension, MidoriExtension* extension,
@ -184,6 +152,10 @@ midori_extensions_add_item_cb (KatzeArray* array,
model = gtk_tree_view_get_model (GTK_TREE_VIEW (extensions->treeview)); model = gtk_tree_view_get_model (GTK_TREE_VIEW (extensions->treeview));
gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_append (GTK_LIST_STORE (model), &iter);
gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, extension, -1); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, extension, -1);
g_signal_connect (extension, "activate",
G_CALLBACK (midori_extensions_extension_activate_cb), extensions);
g_signal_connect (extension, "deactivate",
G_CALLBACK (midori_extensions_extension_deactivate_cb), extensions);
} }
static void static void
@ -239,13 +211,19 @@ midori_extensions_get_property (GObject* object,
} }
static void static void
midori_extensions_treeview_render_icon_cb (GtkTreeViewColumn* column, midori_extensions_treeview_render_tick_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer, GtkCellRenderer* renderer,
GtkTreeModel* model, GtkTreeModel* model,
GtkTreeIter* iter, GtkTreeIter* iter,
GtkWidget* treeview) GtkWidget* treeview)
{ {
g_object_set (renderer, "stock-id", GTK_STOCK_EXECUTE, NULL); MidoriExtension* extension;
gtk_tree_model_get (model, iter, 0, &extension, -1);
g_object_set (renderer, "active", midori_extension_is_active (extension), NULL);
g_object_unref (extension);
} }
static void static void
@ -266,13 +244,13 @@ midori_extensions_treeview_render_text_cb (GtkTreeViewColumn* column,
name = katze_object_get_string (extension, "name"); name = katze_object_get_string (extension, "name");
version = katze_object_get_string (extension, "version"); version = katze_object_get_string (extension, "version");
desc = katze_object_get_string (extension, "description"); desc = katze_object_get_string (extension, "description");
text = g_strdup_printf ("%s %s\n%s", name, version, desc); text = g_markup_printf_escaped ("<b>%s</b> %s\n%s", name, version, desc);
g_free (name); g_free (name);
g_free (version); g_free (version);
g_free (desc); g_free (desc);
g_object_set (renderer, "text", text,
"sensitive", midori_extension_is_active (extension), g_object_set (renderer, "markup", text, NULL);
NULL);
g_free (text); g_free (text);
g_object_unref (extension); g_object_unref (extension);
} }
@ -283,16 +261,10 @@ midori_extensions_treeview_row_activated_cb (GtkTreeView* treeview,
GtkTreeViewColumn* column, GtkTreeViewColumn* column,
MidoriExtensions* extensions) MidoriExtensions* extensions)
{ {
GtkToolItem* button_enable;
GtkToolItem* button_disable;
GtkTreeModel* model; GtkTreeModel* model;
GtkTreeIter iter; GtkTreeIter iter;
model = gtk_tree_view_get_model (treeview); model = gtk_tree_view_get_model (treeview);
button_enable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 1);
button_disable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 2);
if (gtk_tree_model_get_iter (model, &iter, path)) if (gtk_tree_model_get_iter (model, &iter, path))
{ {
MidoriExtension* extension; MidoriExtension* extension;
@ -302,45 +274,198 @@ midori_extensions_treeview_row_activated_cb (GtkTreeView* treeview,
midori_extension_deactivate (extension); midori_extension_deactivate (extension);
else else
g_signal_emit_by_name (extension, "activate", extensions->app); g_signal_emit_by_name (extension, "activate", extensions->app);
gtk_widget_set_sensitive (GTK_WIDGET (button_enable),
!midori_extension_is_active (extension)); g_object_unref (extension);
gtk_widget_set_sensitive (GTK_WIDGET (button_disable),
midori_extension_is_active (extension));
/* FIXME: Update only the appropriate row */
gtk_widget_queue_draw (GTK_WIDGET (treeview));
} }
} }
static void static void
midori_extensions_treeview_cursor_changed_cb (GtkTreeView* treeview, midori_extensions_preferences_activate_cb (GtkWidget* menuitem,
MidoriExtensions* extensions) MidoriExtensions* extensions)
{
MidoriExtension* extension;
extension = g_object_get_data (G_OBJECT (menuitem), "MidoriExtension");
g_return_if_fail (extension != NULL);
}
static void
midori_extensions_website_activate_cb (GtkWidget* menuitem,
MidoriExtensions* extensions)
{
gchar* uri;
gint n;
MidoriBrowser* browser;
MidoriExtension* extension;
extension = g_object_get_data (G_OBJECT (menuitem), "MidoriExtension");
g_return_if_fail (extension != NULL);
uri = katze_object_get_string (extension, "website");
browser = midori_browser_get_for_widget (GTK_WIDGET (extensions));
n = midori_browser_add_uri (browser, uri);
midori_browser_set_current_page (browser, n);
g_free (uri);
}
static void
midori_extensions_about_activate_cb (GtkWidget* menuitem,
MidoriExtensions* extensions)
{
MidoriExtension* extension;
extension = g_object_get_data (G_OBJECT (menuitem), "MidoriExtension");
g_return_if_fail (extension != NULL);
}
static GtkWidget*
midori_extensions_popup_menu_item (GtkMenu* menu,
const gchar* stock_id,
const gchar* label,
MidoriExtension* extension,
gpointer callback,
gboolean enabled,
MidoriExtensions* extensions)
{
GtkWidget* menuitem;
menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
if (label)
gtk_label_set_text_with_mnemonic (GTK_LABEL (gtk_bin_get_child (
GTK_BIN (menuitem))), label);
if (!enabled)
gtk_widget_set_sensitive (menuitem, FALSE);
g_object_set_data (G_OBJECT (menuitem), "MidoriExtension", extension);
if (callback)
g_signal_connect (menuitem, "activate", G_CALLBACK (callback), extensions);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
return menuitem;
}
static void
midori_extensions_popup (GtkWidget* widget,
GdkEventButton* event,
MidoriExtension* extension,
MidoriExtensions* extensions)
{
GtkWidget* menu;
gchar* website;
website = katze_object_get_string (extension, "website");
menu = gtk_menu_new ();
midori_extensions_popup_menu_item (GTK_MENU (menu), GTK_STOCK_PREFERENCES, NULL, extension,
midori_extensions_preferences_activate_cb, FALSE,
extensions);
midori_extensions_popup_menu_item (GTK_MENU (menu), GTK_STOCK_HOME, NULL, extension,
midori_extensions_website_activate_cb, website != NULL,
extensions);
midori_extensions_popup_menu_item (GTK_MENU (menu), GTK_STOCK_ABOUT, NULL, extension,
midori_extensions_about_activate_cb, FALSE,
extensions);
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
g_free (website);
}
static gboolean
midori_extensions_popup_menu_cb (GtkWidget* widget,
MidoriExtensions* extensions)
{ {
GtkTreeModel* model; GtkTreeModel* model;
GtkTreePath* path;
GtkTreeIter iter; GtkTreeIter iter;
GtkToolItem* button_enable;
GtkToolItem* button_disable;
gtk_tree_view_get_cursor (treeview, &path, NULL); if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
model = gtk_tree_view_get_model (treeview);
button_enable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 1);
button_disable = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (extensions->toolbar), 2);
if (gtk_tree_model_get_iter (model, &iter, path))
{ {
MidoriExtension* extension; MidoriExtension *extension;
if (katze_tree_view_get_selected_iter (treeview, &model, &iter)) gtk_tree_model_get (model, &iter, 0, &extension, -1);
{
gtk_tree_model_get (model, &iter, 0, &extension, -1); midori_extensions_popup (widget, NULL, extension, extensions);
gtk_widget_set_sensitive (GTK_WIDGET (button_enable), g_object_unref (extension);
!midori_extension_is_active (extension)); return TRUE;
gtk_widget_set_sensitive (GTK_WIDGET (button_disable),
midori_extension_is_active (extension));
}
} }
return; return FALSE;
}
static gboolean
midori_extensions_button_release_event_cb (GtkWidget* widget,
GdkEventButton* event,
MidoriExtensions* extensions)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (event->button != 3)
return FALSE;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
MidoriExtension *extension;
gtk_tree_model_get (model, &iter, 0, &extension, -1);
midori_extensions_popup (widget, event, extension, extensions);
g_object_unref (extension);
return TRUE;
}
return FALSE;
}
static void
midori_extensions_cell_renderer_toggled_cb (GtkCellRendererToggle* renderer,
const gchar* path,
MidoriExtensions* extensions)
{
GtkTreeModel* model;
GtkTreeIter iter;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (extensions->treeview));
if (gtk_tree_model_get_iter_from_string (model, &iter, path))
{
MidoriExtension *extension;
gtk_tree_model_get (model, &iter, 0, &extension, -1);
if (midori_extension_is_active (extension))
midori_extension_deactivate (extension);
else
g_signal_emit_by_name (extension, "activate", extensions->app);
g_object_unref (extension);
}
}
static gint
midori_extensions_tree_sort_func (GtkTreeModel* model,
GtkTreeIter* a,
GtkTreeIter* b,
gpointer data)
{
MidoriExtension* e1, *e2;
gchar* name1, *name2;
gint result = 0;
gtk_tree_model_get (model, a, 0, &e1, -1);
gtk_tree_model_get (model, b, 0, &e2, -1);
name1 = katze_object_get_string (e1, "name");
name2 = katze_object_get_string (e2, "name");
result = g_strcmp0 (name1, name2);
g_free (name1);
g_free (name2);
return result;
} }
static void static void
@ -349,16 +474,24 @@ midori_extensions_init (MidoriExtensions* extensions)
/* Create the treeview */ /* Create the treeview */
GtkTreeViewColumn* column; GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_pixbuf; GtkCellRenderer* renderer_toggle;
GtkListStore* liststore = gtk_list_store_new (1, G_TYPE_OBJECT); GtkListStore* liststore = gtk_list_store_new (1, G_TYPE_OBJECT);
extensions->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore)); extensions->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore));
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (liststore),
0, GTK_SORT_ASCENDING);
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (liststore),
0, midori_extensions_tree_sort_func, NULL, NULL);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (extensions->treeview), FALSE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (extensions->treeview), FALSE);
column = gtk_tree_view_column_new (); column = gtk_tree_view_column_new ();
renderer_pixbuf = gtk_cell_renderer_pixbuf_new (); renderer_toggle = gtk_cell_renderer_toggle_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE); gtk_tree_view_column_pack_start (column, renderer_toggle, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf, gtk_tree_view_column_set_cell_data_func (column, renderer_toggle,
(GtkTreeCellDataFunc)midori_extensions_treeview_render_icon_cb, (GtkTreeCellDataFunc)midori_extensions_treeview_render_tick_cb,
extensions->treeview, NULL); extensions->treeview, NULL);
g_signal_connect (renderer_toggle, "toggled",
G_CALLBACK (midori_extensions_cell_renderer_toggled_cb), extensions);
gtk_tree_view_append_column (GTK_TREE_VIEW (extensions->treeview), column);
column = gtk_tree_view_column_new ();
renderer_text = gtk_cell_renderer_text_new (); renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE); gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text, gtk_tree_view_column_set_cell_data_func (column, renderer_text,
@ -366,16 +499,39 @@ midori_extensions_init (MidoriExtensions* extensions)
extensions->treeview, NULL); extensions->treeview, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (extensions->treeview), column); gtk_tree_view_append_column (GTK_TREE_VIEW (extensions->treeview), column);
g_object_unref (liststore); g_object_unref (liststore);
g_signal_connect (extensions->treeview, "row-activated", g_object_connect (extensions->treeview,
G_CALLBACK (midori_extensions_treeview_row_activated_cb), "signal::row-activated",
extensions); midori_extensions_treeview_row_activated_cb, extensions,
g_signal_connect (extensions->treeview, "cursor-changed", "signal::button-release-event",
G_CALLBACK (midori_extensions_treeview_cursor_changed_cb), midori_extensions_button_release_event_cb, extensions,
extensions); "signal::popup-menu",
midori_extensions_popup_menu_cb, extensions,
NULL);
gtk_widget_show (extensions->treeview); gtk_widget_show (extensions->treeview);
gtk_box_pack_start (GTK_BOX (extensions), extensions->treeview, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (extensions), extensions->treeview, TRUE, TRUE, 0);
} }
static void
midori_extensions_finalize (GObject* object)
{
MidoriExtensions* extensions = MIDORI_EXTENSIONS (object);
KatzeArray* array = katze_object_get_object (extensions->app, "extensions");
guint i = 0;
MidoriExtension* extension;
while ((extension = katze_array_get_nth_item (array, i++)))
{
g_signal_handlers_disconnect_by_func (extension,
midori_extensions_extension_activate_cb, extensions);
g_signal_handlers_disconnect_by_func (extension,
midori_extensions_extension_deactivate_cb, extensions);
}
g_signal_handlers_disconnect_by_func (array,
midori_extensions_add_item_cb, extensions);
g_object_unref (array);
}
/** /**
* midori_extensions_new: * midori_extensions_new:
* *

View file

@ -757,8 +757,10 @@ midori_history_open_in_window_activate_cb (GtkWidget* menuitem,
if (uri && *uri) if (uri && *uri)
{ {
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (history)); MidoriBrowser* new_browser = midori_app_create_browser (history->app);
g_signal_emit_by_name (browser, "new-window", uri); midori_app_add_browser (history->app, new_browser);
gtk_widget_show (GTK_WIDGET (new_browser));
midori_browser_add_uri (new_browser, uri);
} }
} }

View file

@ -224,6 +224,7 @@ midori_plugins_init (MidoriPlugins* plugins)
GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_pixbuf; GtkCellRenderer* renderer_pixbuf;
GtkListStore* liststore = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); GtkListStore* liststore = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
plugins->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore)); plugins->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (plugins->treeview), FALSE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (plugins->treeview), FALSE);
column = gtk_tree_view_column_new (); column = gtk_tree_view_column_new ();
@ -242,76 +243,34 @@ midori_plugins_init (MidoriPlugins* plugins)
gtk_widget_show (plugins->treeview); gtk_widget_show (plugins->treeview);
gtk_box_pack_start (GTK_BOX (plugins), plugins->treeview, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (plugins), plugins->treeview, TRUE, TRUE, 0);
/* FIXME: Monitor folders for newly added and removes files */ if (1)
if (g_module_supported ())
{ {
/* FIXME: WebKit is also looking in legacy folders, /* FIXME: WebKit should have API to obtain the list of plugins. */
we should have API to obtain that same list. */ /* FIXME: Monitor folders for newly added and removes files */
gchar** plugin_dirs; GtkWidget* web_view = webkit_web_view_new ();
gsize i = 0; WebKitWebFrame* web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
JSContextRef js_context = webkit_web_frame_get_global_context (web_frame);
/* This snippet joins the available plugins into a string like this:
URI1|title1,URI2|title2
FIXME: Ensure separators contained in the string can't break it */
gchar* value = sokoke_js_script_eval (js_context,
"function plugins (l) { var f = new Array (); for (i in l) "
"{ var t = l[i].name; "
"f.push (l[i].name + '|' + l[i].filename); } return f; }"
"plugins (navigator.plugins)", NULL);
gchar** items = g_strsplit (value, ",", 0);
guint i = 0;
if (g_getenv ("MOZ_PLUGIN_PATH")) if (items != NULL)
plugin_dirs = g_strsplit (g_getenv ("MOZ_PLUGIN_PATH"), ":", 0); while (items[i] != NULL)
else
plugin_dirs = g_strsplit ("/usr/lib/mozilla/plugins", ":", 0);
while (plugin_dirs[i])
{ {
gchar* plugin_path; gchar** parts = g_strsplit (items[i], "|", 2);
GDir* plugin_dir; if (parts && *parts && !g_str_equal (parts[1], "undefined"))
midori_plugins_add_item (plugins, *parts, parts[1]);
plugin_path = g_build_filename (plugin_dirs[i], NULL); g_strfreev (parts);
plugin_dir = g_dir_open (plugin_path, 0, NULL);
if (plugin_dir != 0)
{
const gchar* filename;
while ((filename = g_dir_read_name (plugin_dir)))
{
gchar* fullname;
GModule* module;
typedef int (*NP_GetValue_func)(void* instance,
int variable,
void* value);
NP_GetValue_func NP_GetValue;
const gchar* plugin_name;
const gchar* plugin_description;
/* Ignore files which don't have the correct suffix */
if (!g_str_has_suffix (filename, G_MODULE_SUFFIX))
continue;
fullname = g_build_filename (plugin_path, filename, NULL);
module = g_module_open (fullname, G_MODULE_BIND_LOCAL);
g_free (fullname);
if (module && g_module_symbol (module, "NP_GetValue",
(gpointer) &NP_GetValue))
{
typedef const gchar* (*NP_GetMIMEDescription_func)(void);
NP_GetMIMEDescription_func NP_GetMIMEDescription;
NP_GetValue (NULL, 2, &plugin_name);
if (g_module_symbol (module, "NP_GetMIMEDescription",
(gpointer) &NP_GetMIMEDescription))
plugin_description = NP_GetMIMEDescription ();
else
plugin_description = g_module_error ();
}
else
{
plugin_name = filename;
plugin_description = g_module_error ();
}
midori_plugins_add_item (plugins, plugin_name, plugin_description);
}
g_dir_close (plugin_dir);
}
g_free (plugin_path);
i++; i++;
} }
g_strfreev (plugin_dirs); g_strfreev (items);
} }
} }

View file

@ -372,6 +372,169 @@ midori_transfers_hierarchy_changed_cb (MidoriTransfers* transfers,
#endif #endif
} }
#if WEBKIT_CHECK_VERSION (1, 1, 3)
static GtkWidget*
midori_transfers_popup_menu_item (GtkMenu* menu,
const gchar* stock_id,
const gchar* label,
WebKitDownload* download,
gpointer callback,
gboolean enabled,
MidoriTransfers* transfers)
{
GtkWidget* menuitem;
menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
if (label)
gtk_label_set_text_with_mnemonic (GTK_LABEL (gtk_bin_get_child (
GTK_BIN (menuitem))), label);
if (!enabled)
gtk_widget_set_sensitive (menuitem, FALSE);
g_object_set_data (G_OBJECT (menuitem), "WebKitDownload", download);
if (callback)
g_signal_connect (menuitem, "activate", G_CALLBACK (callback), transfers);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
return menuitem;
}
static void
midori_transfers_open_activate_cb (GtkWidget* menuitem,
MidoriTransfers* transfers)
{
WebKitDownload* download;
const gchar* uri;
download = g_object_get_data (G_OBJECT (menuitem), "WebKitDownload");
g_return_if_fail (download != NULL);
uri = webkit_download_get_destination_uri (download);
sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (transfers->treeview)),
uri, gtk_get_current_event_time (), NULL);
}
static void
midori_transfers_open_folder_activate_cb (GtkWidget* menuitem,
MidoriTransfers* transfers)
{
WebKitDownload* download;
const gchar* uri;
GFile* file;
GFile* folder;
download = g_object_get_data (G_OBJECT (menuitem), "WebKitDownload");
g_return_if_fail (download != NULL);
uri = webkit_download_get_destination_uri (download);
file = g_file_new_for_uri (uri);
if ((folder = g_file_get_parent (file)))
{
gchar* folder_uri = g_file_get_uri (folder);
sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (transfers->treeview)),
folder_uri, gtk_get_current_event_time (), NULL);
g_free (folder_uri);
g_object_unref (folder);
}
g_object_unref (file);
}
static void
midori_transfers_copy_address_activate_cb (GtkWidget* menuitem,
MidoriTransfers* transfers)
{
WebKitDownload* download;
const gchar* uri;
GtkClipboard* clipboard;
download = g_object_get_data (G_OBJECT (menuitem), "WebKitDownload");
g_return_if_fail (download != NULL);
uri = webkit_download_get_destination_uri (download);
clipboard = gtk_clipboard_get_for_display (
gtk_widget_get_display (GTK_WIDGET (menuitem)),
GDK_SELECTION_CLIPBOARD);
gtk_clipboard_set_text (clipboard, uri, -1);
}
static void
midori_transfers_popup (GtkWidget* widget,
GdkEventButton* event,
WebKitDownload* download,
MidoriTransfers* transfers)
{
GtkWidget* menu;
gboolean finished = FALSE;
if (webkit_download_get_status (download) == WEBKIT_DOWNLOAD_STATUS_FINISHED)
finished = TRUE;
menu = gtk_menu_new ();
midori_transfers_popup_menu_item (GTK_MENU (menu), GTK_STOCK_OPEN, NULL, download,
midori_transfers_open_activate_cb, finished, transfers);
midori_transfers_popup_menu_item (GTK_MENU (menu), GTK_STOCK_DIRECTORY,
_("Open Destination _Folder"), download,
midori_transfers_open_folder_activate_cb, TRUE, transfers);
midori_transfers_popup_menu_item (GTK_MENU (menu), GTK_STOCK_COPY,
_("Copy Link Loc_ation"), download,
midori_transfers_copy_address_activate_cb, FALSE, transfers);
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
}
#endif
static gboolean
midori_transfers_popup_menu_cb (GtkWidget* widget,
MidoriTransfers* transfers)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
#if WEBKIT_CHECK_VERSION (1, 1, 3)
WebKitDownload* download;
gtk_tree_model_get (model, &iter, 1, &download, -1);
midori_transfers_popup (widget, NULL, download, transfers);
g_object_unref (download);
return TRUE;
#endif
}
return FALSE;
}
static gboolean
midori_transfers_button_release_event_cb (GtkWidget* widget,
GdkEventButton* event,
MidoriTransfers* transfers)
{
GtkTreeModel* model;
GtkTreeIter iter;
if (event->button != 3)
return FALSE;
if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
#if WEBKIT_CHECK_VERSION (1, 1, 3)
WebKitDownload* download;
gtk_tree_model_get (model, &iter, 1, &download, -1);
midori_transfers_popup (widget, NULL, download, transfers);
g_object_unref (download);
return TRUE;
#endif
}
return FALSE;
}
static void static void
midori_transfers_init (MidoriTransfers* transfers) midori_transfers_init (MidoriTransfers* transfers)
{ {
@ -400,9 +563,14 @@ midori_transfers_init (MidoriTransfers* transfers)
transfers->treeview, NULL); transfers->treeview, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (transfers->treeview), column); gtk_tree_view_append_column (GTK_TREE_VIEW (transfers->treeview), column);
g_object_unref (treestore); g_object_unref (treestore);
g_signal_connect (transfers->treeview, "row-activated", g_object_connect (transfers->treeview,
G_CALLBACK (midori_transfers_treeview_row_activated_cb), "signal::row-activated",
transfers); midori_transfers_treeview_row_activated_cb, transfers,
"signal::button-release-event",
midori_transfers_button_release_event_cb, transfers,
"signal::popup-menu",
midori_transfers_popup_menu_cb, transfers,
NULL);
gtk_widget_show (transfers->treeview); gtk_widget_show (transfers->treeview);
gtk_box_pack_start (GTK_BOX (transfers), transfers->treeview, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (transfers), transfers->treeview, TRUE, TRUE, 0);

View file

@ -1,2 +1,2 @@
# set of available languages (in alphabetic order) # set of available languages (in alphabetic order)
cs da de el en_GB es et fi fr gl he hu id it ja nl pl pt ro ru sk sv tr uk zh_CN zh_TW cs da de el en_GB es et fi fr gl he hu id it ja nl pl pt ro ru sk sr sr@latin sv tr uk zh_CN zh_TW

View file

@ -5,6 +5,8 @@ midori/main.c
midori/midori-app.c midori/midori-app.c
midori/midori-array.c midori/midori-array.c
midori/midori-browser.c midori/midori-browser.c
midori/midori-locationaction.c
midori/midori-locationentry.c
midori/midori-panel.c midori/midori-panel.c
midori/midori-websettings.c midori/midori-websettings.c
midori/midori-view.c midori/midori-view.c
@ -28,6 +30,7 @@ extensions/adblock.c
extensions/colorful-tabs.c extensions/colorful-tabs.c
extensions/cookie-manager/cookie-manager.c extensions/cookie-manager/cookie-manager.c
extensions/cookie-manager/cookie-manager-page.c extensions/cookie-manager/cookie-manager-page.c
extensions/cookie-manager/main.c
extensions/feed-panel/feed-atom.c extensions/feed-panel/feed-atom.c
extensions/feed-panel/feed-panel.c extensions/feed-panel/feed-panel.c
extensions/feed-panel/feed-parse.c extensions/feed-panel/feed-parse.c
@ -35,4 +38,7 @@ extensions/feed-panel/feed-rss.c
extensions/feed-panel/main.c extensions/feed-panel/main.c
extensions/mouse-gestures/main.c extensions/mouse-gestures/main.c
extensions/page-holder.c extensions/page-holder.c
extensions/shortcuts.c
extensions/statusbar-features.c extensions/statusbar-features.c
extensions/tab-panel.c
extensions/toolbar-editor.c

1133
po/da.po

File diff suppressed because it is too large Load diff

949
po/de.po

File diff suppressed because it is too large Load diff

1160
po/el.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1352
po/es.po

File diff suppressed because it is too large Load diff

958
po/fr.po

File diff suppressed because it is too large Load diff

1444
po/it.po

File diff suppressed because it is too large Load diff

1286
po/ja.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1959
po/pl.po

File diff suppressed because it is too large Load diff

1054
po/ru.po

File diff suppressed because it is too large Load diff

1681
po/sk.po

File diff suppressed because it is too large Load diff

2063
po/sr.po Normal file

File diff suppressed because it is too large Load diff

2063
po/sr@latin.po Normal file

File diff suppressed because it is too large Load diff

419
po/tr.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -282,6 +282,8 @@ int
main (int argc, main (int argc,
char** argv) char** argv)
{ {
/* libSoup uses threads, so we need to initialize threads. */
if (!g_thread_supported ()) g_thread_init (NULL);
g_test_init (&argc, &argv, NULL); g_test_init (&argc, &argv, NULL);
gtk_init_check (&argc, &argv); gtk_init_check (&argc, &argv);

View file

@ -167,15 +167,81 @@ extension_settings (void)
midori_extension_deactivate (extension); midori_extension_deactivate (extension);
} }
static void
extension_activate (gconstpointer data)
{
MidoriApp* app = midori_app_new ();
MidoriExtension* extension = MIDORI_EXTENSION (data);
/* g_signal_emit_by_name (extension, "activate", app);
midori_extension_deactivate (extension); */
g_object_unref (app);
}
static void
load_extensions (void)
{
if (g_module_supported ())
{
GDir* extension_dir = g_dir_open (EXTENSION_PATH, 0, NULL);
if (extension_dir != NULL)
{
const gchar* filename;
while ((filename = g_dir_read_name (extension_dir)))
{
gchar* fullname;
GModule* module;
typedef MidoriExtension* (*extension_init_func)(void);
extension_init_func extension_init;
/* Ignore files which don't have the correct suffix */
if (!g_str_has_suffix (filename, G_MODULE_SUFFIX))
continue;
fullname = g_build_filename (EXTENSION_PATH, filename, NULL);
module = g_module_open (fullname, G_MODULE_BIND_LOCAL);
g_free (fullname);
if (module && g_module_symbol (module, "extension_init",
(gpointer) &extension_init))
{
guint length;
gchar* name;
gchar* path;
typedef MidoriExtension* (*extension_test_func)(const gchar* path);
extension_test_func extension_test;
if (g_str_has_prefix (filename, "lib"))
filename = &filename[3];
length = strlen (filename);
name = g_strdup (filename);
name[length - strlen (G_MODULE_SUFFIX) - 1] = '\0';
path = g_strconcat ("/extensions/", name, "/activate", NULL);
g_free (name);
g_test_add_data_func (path, extension_init (), extension_activate);
g_free (path);
if (g_module_symbol (module, "extension_test",
(gpointer) &extension_test))
extension_test (path);
}
}
g_dir_close (extension_dir);
}
}
}
int int
main (int argc, main (int argc,
char** argv) char** argv)
{ {
g_test_init (&argc, &argv, NULL); g_test_init (&argc, &argv, NULL);
gtk_init_check (&argc, &argv); gtk_init_check (&argc, &argv);
if (!g_thread_supported ()) g_thread_init (NULL);
g_test_add_func ("/extensions/create", extension_create); g_test_add_func ("/extensions/create", extension_create);
g_test_add_func ("/extensions/settings", extension_settings); g_test_add_func ("/extensions/settings", extension_settings);
load_extensions ();
return g_test_run (); return g_test_run ();
} }

View file

@ -141,6 +141,7 @@ magic_uri_search (void)
test_input ("max@mustermann.de", NULL); test_input ("max@mustermann.de", NULL);
test_input ("g max@mustermann.de", NULL); test_input ("g max@mustermann.de", NULL);
test_input ("g inurl:http://twotoasts.de bug", NULL); test_input ("g inurl:http://twotoasts.de bug", NULL);
test_input ("sm", SM);
} }
static void static void

View file

@ -17,6 +17,29 @@
#include "midori-bookmarks.h" #include "midori-bookmarks.h"
#include "sokoke.h" #include "sokoke.h"
typedef struct
{
const gchar* type;
const gchar* property;
} ObjectProperty;
static ObjectProperty properties_object_skip[] =
{
{ "MidoriWebSettings", "ident-string" },
};
static gboolean
properties_should_skip (const gchar* type,
const gchar* property)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (properties_object_skip); i++)
if (g_str_equal (properties_object_skip[i].type, type))
if (g_str_equal (properties_object_skip[i].property, property))
return TRUE;
return FALSE;
}
#define pspec_is_writable(pspec) (pspec->flags & G_PARAM_WRITABLE \ #define pspec_is_writable(pspec) (pspec->flags & G_PARAM_WRITABLE \
&& !(pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))) && !(pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)))
@ -35,11 +58,26 @@ properties_object_get_set (GObject* object)
GType type = G_PARAM_SPEC_TYPE (pspec); GType type = G_PARAM_SPEC_TYPE (pspec);
const gchar* property = g_param_spec_get_name (pspec); const gchar* property = g_param_spec_get_name (pspec);
void* value = NULL; void* value = NULL;
guint j;
/* Skip properties of parent classes */ /* Skip properties of parent classes */
if (pspec->owner_type != G_OBJECT_TYPE (object)) if (pspec->owner_type != G_OBJECT_TYPE (object))
continue; continue;
/* Skip properties that cannot be tested generically */
if (properties_should_skip (G_OBJECT_TYPE_NAME (object), property))
continue;
/* Verify that the ID is unique */
if (pspecs[i]->owner_type == G_OBJECT_TYPE (object))
for (j = 0; j < n_properties; j++)
if (i != j && pspecs[j]->owner_type == G_OBJECT_TYPE (object))
if (pspec->param_id == pspecs[j]->param_id)
g_error ("Duplicate ID %d of %s and %s",
pspec->param_id,
g_param_spec_get_name (pspec),
g_param_spec_get_name (pspecs[j]));
g_object_get (object, property, &value, NULL); g_object_get (object, property, &value, NULL);
if (type == G_TYPE_PARAM_BOOLEAN) if (type == G_TYPE_PARAM_BOOLEAN)
{ {
@ -84,25 +122,25 @@ properties_object_get_set (GObject* object)
{ {
GEnumClass* enum_class = G_ENUM_CLASS ( GEnumClass* enum_class = G_ENUM_CLASS (
g_type_class_ref (pspec->value_type)); g_type_class_ref (pspec->value_type));
gint j;
if (pspec_is_writable (pspec)) if (pspec_is_writable (pspec))
{ {
gint k;
g_object_set (object, property, g_object_set (object, property,
G_PARAM_SPEC_ENUM (pspec)->default_value, NULL); G_PARAM_SPEC_ENUM (pspec)->default_value, NULL);
for (j = enum_class->minimum; j < enum_class->maximum; j++) for (k = enum_class->minimum; k < enum_class->maximum; k++)
{ {
GEnumValue* enum_value = g_enum_get_value (enum_class, j); GEnumValue* enum_value = g_enum_get_value (enum_class, k);
if (!enum_value) if (!enum_value)
g_error ("%s.%s has no value %d", g_error ("%s.%s has no value %d",
G_OBJECT_TYPE_NAME (object), property, j); G_OBJECT_TYPE_NAME (object), property, k);
GEnumValue* enum_value_ = g_enum_get_value_by_name (enum_class, GEnumValue* enum_value_ = g_enum_get_value_by_name (enum_class,
enum_value->value_name); enum_value->value_name);
if (!enum_value) if (!enum_value)
g_error ("%s.%s has no value '%s'", g_error ("%s.%s has no value '%s'",
G_OBJECT_TYPE_NAME (object), property, enum_value->value_name); G_OBJECT_TYPE_NAME (object), property, enum_value->value_name);
g_assert_cmpint (enum_value->value, ==, enum_value_->value); g_assert_cmpint (enum_value->value, ==, enum_value_->value);
g_object_set (object, property, j, NULL); g_object_set (object, property, k, NULL);
} }
} }

View file

@ -2,6 +2,8 @@
# WAF build script for midori # WAF build script for midori
# This file is licensed under the terms of the expat license, see the file EXPAT. # This file is licensed under the terms of the expat license, see the file EXPAT.
import os
tests = os.listdir ('tests') tests = os.listdir ('tests')
for test in tests: for test in tests:
folder = 'tests' + os.sep + test folder = 'tests' + os.sep + test
@ -24,6 +26,7 @@ for test in tests:
obj = bld.new_task_gen ('cc', 'program') obj = bld.new_task_gen ('cc', 'program')
obj.target = 'test-' + target obj.target = 'test-' + target
obj.includes = '.. ../midori ../panels' obj.includes = '.. ../midori ../panels'
obj.cflags = ['-DEXTENSION_PATH="' + os.path.abspath ('_build_/default/extensions') + '"']
obj.source = source obj.source = source
obj.uselib = 'UNIQUE LIBSOUP GIO GTK SQLITE WEBKIT LIBXML' obj.uselib = 'UNIQUE LIBSOUP GIO GTK SQLITE WEBKIT LIBXML'
obj.uselib_local = 'panels' obj.uselib_local = 'panels'

291
wscript
View file

@ -19,10 +19,13 @@ import Utils
import pproc as subprocess import pproc as subprocess
import os import os
import UnitTest import UnitTest
import Task
from TaskGen import extension
import misc
major = 0 major = 0
minor = 1 minor = 1
micro = 7 micro = 8
APPNAME = 'midori' APPNAME = 'midori'
VERSION = str (major) + '.' + str (minor) + '.' + str (micro) VERSION = str (major) + '.' + str (minor) + '.' + str (micro)
@ -38,24 +41,45 @@ srcdir = '.'
blddir = '_build_' blddir = '_build_'
def option_enabled (option): def option_enabled (option):
if eval ('Options.options.enable_' + option): if getattr (Options.options, 'enable_' + option):
return True return True
if eval ('Options.options.disable_' + option): if getattr (Options.options, 'disable_' + option):
return False return False
return True return True
def is_mingw (env):
if 'CC' in env:
cc = env['CC']
if not isinstance (cc, str):
cc = ''.join (cc)
return cc.find ('mingw') != -1# or cc.find ('wine') != -1
return False
# Compile Win32 res files to (resource) object files
@extension ('.rc')
def rc_file(self, node):
rctask = self.create_task ('winrc')
rctask.set_inputs (node)
rctask.set_outputs (node.change_ext ('.rc.o'))
self.compiled_tasks.append (rctask)
Task.simple_task_type ('winrc', '${WINRC} -o${TGT} ${SRC}', color='BLUE',
before='cc cxx', shell=False)
def configure (conf): def configure (conf):
def option_checkfatal (option, desc): def option_checkfatal (option, desc):
if eval ('Options.options.enable_' + option): if hasattr (Options.options, 'enable_' + option):
if getattr (Options.options, 'enable_' + option):
Utils.pprint ('RED', desc + ' N/A') Utils.pprint ('RED', desc + ' N/A')
sys.exit (1) sys.exit (1)
def dirname_default (dirname, default): def dirname_default (dirname, default, defname=None):
if eval ('Options.options.' + dirname) == '': if getattr (Options.options, dirname) == '':
dirvalue = default dirvalue = default
else: else:
dirvalue = eval ('Options.options.' + dirname) dirvalue = getattr (Options.options, dirname)
conf.define (dirname, dirvalue) if not defname:
defname = dirname
conf.define (defname, dirvalue)
return dirvalue return dirvalue
conf.check_tool ('compiler_cc') conf.check_tool ('compiler_cc')
@ -85,13 +109,47 @@ def configure (conf):
nls = 'no ' nls = 'no '
conf.define ('ENABLE_NLS', [0,1][nls == 'yes']) conf.define ('ENABLE_NLS', [0,1][nls == 'yes'])
dirname_default ('DATADIR', os.path.join (conf.env['PREFIX'], 'share')) if conf.find_program ('rsvg-convert', var='RSVG_CONVERT'):
dirname_default ('DOCDIR', os.path.join (conf.env['DATADIR'], 'doc')) icons = 'yes'
else:
icons = 'no '
if is_mingw (conf.env) or Options.platform == 'win32':
if not conf.find_program ('convert', var='CONVERT'):
Utils.pprint ('YELLOW', 'midori.ico won\'t be created')
conf.find_program ('windres', var='WINRC')
# This is specific to cross compiling with mingw
if is_mingw (conf.env) and Options.platform != 'win32':
if not 'AR' in os.environ and not 'RANLIB' in os.environ:
conf.env['AR'] = os.environ['CC'][:-3] + 'ar'
if conf.find_program (os.environ['CC'][:-3] + 'windres', var='WINRC'):
os.environ['WINRC'] = os.environ['CC'][:-3] + 'windres'
Options.platform = 'win32'
# Make sure we don't have -fPIC in the CCFLAGS
conf.env["shlib_CCFLAGS"] = []
# Adjust file naming
conf.env["shlib_PATTERN"] = 'lib%s.dll'
conf.env['program_PATTERN'] = '%s.exe'
# Use Visual C++ compatible alignment
conf.env.append_value ('CCFLAGS', '-mms-bitfields')
conf.env['staticlib_LINKFLAGS'] = []
Utils.pprint ('BLUE', 'Mingw recognized, assuming cross compile.')
if conf.env['CONVERT'] and not conf.env['WINRC']:
Utils.pprint ('YELLOW', 'midori.ico won\'t be created')
dirname_default ('LIBDIR', os.path.join (conf.env['PREFIX'], 'lib')) dirname_default ('LIBDIR', os.path.join (conf.env['PREFIX'], 'lib'))
if conf.env['PREFIX'] == '/usr': if conf.env['PREFIX'] == '/usr':
dirname_default ('SYSCONFDIR', '/etc') dirname_default ('SYSCONFDIR', '/etc')
else: else:
dirname_default ('SYSCONFDIR', os.path.join (conf.env['PREFIX'], 'etc')) dirname_default ('SYSCONFDIR', os.path.join (conf.env['PREFIX'], 'etc'))
dirname_default ('DATADIR', os.path.join (conf.env['PREFIX'], 'share'),
# Use MDATADIR because DATADIR is a constant in objidl.h on Windows
'MDATADIR')
conf.undefine ('DATADIR')
dirname_default ('DOCDIR', os.path.join (conf.env['MDATADIR'], 'doc'))
if option_enabled ('apidocs'): if option_enabled ('apidocs'):
conf.find_program ('gtkdoc-scan', var='GTKDOC_SCAN') conf.find_program ('gtkdoc-scan', var='GTKDOC_SCAN')
@ -107,33 +165,37 @@ def configure (conf):
else: else:
api_docs = 'no ' api_docs = 'no '
def check_pkg (name, version='', mandatory=True, var=None): def check_pkg (name, version='', mandatory=True, var=None, args=''):
if not var: if not var:
var = name.split ('-')[0].upper () var = name.split ('-')[0].upper ()
conf.check_cfg (package=name, uselib_store=var, args='--cflags --libs', conf.check_cfg (package=name, uselib_store=var, args='--cflags --libs ' + args,
atleast_version=version, mandatory=mandatory) atleast_version=version, mandatory=mandatory)
return conf.env['HAVE_' + var]
if option_enabled ('unique'): if option_enabled ('unique'):
check_pkg ('unique-1.0', '0.9', False) check_pkg ('unique-1.0', '0.9', False)
unique = ['N/A', 'yes'][conf.env['HAVE_UNIQUE'] == 1] unique = ['N/A', 'yes'][conf.env['HAVE_UNIQUE'] == 1]
if unique != 'yes':
option_checkfatal ('unique', 'single instance')
else: else:
option_checkfatal ('unique', 'single instance')
unique = 'no ' unique = 'no '
conf.define ('HAVE_UNIQUE', [0,1][unique == 'yes']) conf.define ('HAVE_UNIQUE', [0,1][unique == 'yes'])
if option_enabled ('libidn'): if option_enabled ('libidn'):
check_pkg ('libidn', '1.0', False) check_pkg ('libidn', '1.0', False)
libidn = ['N/A','yes'][conf.env['HAVE_LIBIDN'] == 1] libidn = ['N/A','yes'][conf.env['HAVE_LIBIDN'] == 1]
if libidn != 'yes':
option_checkfatal ('libidn', 'international domain names')
else: else:
option_checkfatal ('libidn', 'international domain names')
libidn = 'no ' libidn = 'no '
conf.define ('HAVE_LIBIDN', [0,1][libidn == 'yes']) conf.define ('HAVE_LIBIDN', [0,1][libidn == 'yes'])
if option_enabled ('sqlite'): if option_enabled ('sqlite'):
check_pkg ('sqlite3', '3.0', False, var='SQLITE') check_pkg ('sqlite3', '3.0', False, var='SQLITE')
sqlite = ['N/A','yes'][conf.env['HAVE_SQLITE'] == 1] sqlite = ['N/A','yes'][conf.env['HAVE_SQLITE'] == 1]
if sqlite != 'yes':
option_checkfatal ('sqlite', 'history database')
else: else:
option_checkfatal ('sqlite', 'history database')
sqlite = 'no ' sqlite = 'no '
conf.define ('HAVE_SQLITE', [0,1][sqlite == 'yes']) conf.define ('HAVE_SQLITE', [0,1][sqlite == 'yes'])
@ -141,29 +203,44 @@ def configure (conf):
check_pkg ('gmodule-2.0', '2.8.0', False) check_pkg ('gmodule-2.0', '2.8.0', False)
check_pkg ('gthread-2.0', '2.8.0', False) check_pkg ('gthread-2.0', '2.8.0', False)
check_pkg ('gio-2.0', '2.16.0') check_pkg ('gio-2.0', '2.16.0')
check_pkg ('gtk+-2.0', '2.10.0', var='GTK') args = ''
check_pkg ('webkit-1.0', '1.1.1') if Options.platform == 'win32':
args = '--define-variable=target=win32'
check_pkg ('gtk+-2.0', '2.10.0', var='GTK', args=args)
check_pkg ('webkit-1.0', '1.1.1', args=args)
check_pkg ('libsoup-2.4', '2.25.2') check_pkg ('libsoup-2.4', '2.25.2')
conf.define ('HAVE_LIBSOUP_2_25_2', 1) conf.define ('HAVE_LIBSOUP_2_25_2', 1)
check_pkg ('libxml-2.0', '2.6') check_pkg ('libxml-2.0', '2.6')
if option_enabled ('hildon'): if option_enabled ('hildon'):
check_pkg ('hildon-1', mandatory=False, var='HILDON') if check_pkg ('hildon-1', mandatory=False, var='HILDON'):
if conf.env['HAVE_HILDON'] == 1: check_pkg ('libosso', var='HILDON')
check_pkg ('libosso', mandatory=False, var='HILDON')
hildon = ['N/A','yes'][conf.env['HAVE_HILDON'] == 1] hildon = ['N/A','yes'][conf.env['HAVE_HILDON'] == 1]
if hildon != 'yes':
option_checkfatal ('hildon', 'Maemo integration')
else: else:
option_checkfatal ('hildon', 'Maemo integration')
hildon = 'no ' hildon = 'no '
conf.define ('HAVE_HILDON', [0,1][hildon == 'yes']) conf.define ('HAVE_HILDON', [0,1][hildon == 'yes'])
conf.check (header_name='unistd.h') # Store options in env, since 'Options' is not persistent
conf.define ('HAVE_OSX', int(sys.platform == 'darwin')) if 'CC' in os.environ: conf.env['CC'] = os.environ['CC'].split()
conf.env['addons'] = option_enabled ('addons')
conf.env['docs'] = option_enabled ('docs')
if conf.find_program ('rsvg-convert', var='RSVG_CONVERT'): conf.check (header_name='unistd.h')
icons = 'yes' if not conf.env['HAVE_UNIQUE']:
else: if Options.platform == 'win32':
icons = 'no ' conf.check (lib='ws2_32')
check_pkg ('openssl', mandatory=False)
conf.define ('USE_SSL', [0,1][conf.env['HAVE_OPENSSL'] == 1])
conf.define ('HAVE_NETDB_H', [0,1][conf.check (header_name='netdb.h')])
conf.check (header_name='sys/wait.h')
conf.check (header_name='sys/select.h')
conf.check (function_name='inet_aton')
conf.check (function_name='inet_addr')
conf.define ('HAVE_OSX', int(sys.platform == 'darwin'))
if Options.platform == 'win32':
conf.env.append_value ('LINKFLAGS', '-mwindows')
conf.define ('PACKAGE_VERSION', VERSION) conf.define ('PACKAGE_VERSION', VERSION)
conf.define ('PACKAGE_NAME', APPNAME) conf.define ('PACKAGE_NAME', APPNAME)
@ -205,22 +282,22 @@ def configure (conf):
Utils.pprint ('RED', 'No debugging level support for ' + compiler) Utils.pprint ('RED', 'No debugging level support for ' + compiler)
sys.exit (1) sys.exit (1)
print print '''
print "Optional build time dependencies:" Localization: %(nls)s (intltool)
print "Localization: " + nls + " (intltool)" Icon optimizations: %(icons)s (rsvg-convert)
print "Icon optimizations: " + icons + " (rsvg-convert)" Persistent history: %(sqlite)s (sqlite3)
print "User documentation: " + user_docs + " (docutils)"
print "API documentation: " + api_docs + " (gtk-doc)" IDN support: %(libidn)s (libidn)
print User documentation: %(user_docs)s (docutils)
print "Single instance: " + unique + " (unique)" API documentation: %(api_docs)s (gtk-doc)
''' % locals ()
if unique == 'yes' and conf.check_cfg (modversion='unique-1.0') == '1.0.4': if unique == 'yes' and conf.check_cfg (modversion='unique-1.0') == '1.0.4':
Utils.pprint ('RED', 'unique 1.0.4 found, this version is erroneous.') Utils.pprint ('RED', 'unique 1.0.4 found, this version is erroneous.')
Utils.pprint ('RED', 'Please use an older or newer version.') Utils.pprint ('RED', 'Please use an older or newer version.')
print "IDN support: " + libidn + " (libidn)"
print "Persistent history: " + sqlite + " (sqlite3)"
print "Maemo integration: " + hildon + " (hildon)"
def set_options (opt): def set_options (opt):
def is_maemo (): return os.path.exists ('/etc/osso-af-init/osso-gtk.defs')
def add_enable_option (option, desc, group=None, disable=False): def add_enable_option (option, desc, group=None, disable=False):
if group == None: if group == None:
group = opt group = opt
@ -258,15 +335,44 @@ def set_options (opt):
add_enable_option ('libidn', 'international domain name support', group) add_enable_option ('libidn', 'international domain name support', group)
add_enable_option ('sqlite', 'history database support', group) add_enable_option ('sqlite', 'history database support', group)
add_enable_option ('addons', 'building of extensions', group) add_enable_option ('addons', 'building of extensions', group)
add_enable_option ('hildon', 'Maemo integration', group) add_enable_option ('hildon', 'Maemo integration', group, disable=not is_maemo ())
def build (bld): def build (bld):
def image_to_win32ico (task):
'Converts an image to a Win32 ico'
if not os.path.exists (bld.env['CONVERT']):
return 1
infile = task.inputs[0].abspath (task.env)
outfile = task.outputs[0].abspath (task.env)
command = bld.env['CONVERT'] + ' -background transparent \
-geometry 16x16 -extent 16x16 ' + \
infile + ' ' + outfile
if Utils.exec_command (command):
return 1
if task.chmod:
os.chmod (outfile, task.chmod)
return 0
if bld.env['WINRC']:
obj = bld.new_task_gen ('copy',
fun = image_to_win32ico,
source = 'icons/16x16/midori.png',
target = 'data/midori.ico',
before = 'cc')
bld.add_group ()
bld.add_subdirs ('katze midori icons') bld.add_subdirs ('katze midori icons')
if option_enabled ('addons'): if bld.env['addons']:
bld.add_subdirs ('extensions') bld.add_subdirs ('extensions')
if option_enabled ('docs'): bld.add_group ()
if bld.env['docs']:
bld.install_files ('${DOCDIR}/' + APPNAME + '/', \ bld.install_files ('${DOCDIR}/' + APPNAME + '/', \
'AUTHORS ChangeLog COPYING EXPAT README TRANSLATE') 'AUTHORS ChangeLog COPYING EXPAT README TRANSLATE')
@ -295,39 +401,40 @@ def build (bld):
bld.add_subdirs ('docs/api') bld.add_subdirs ('docs/api')
bld.install_files ('${DOCDIR}/midori/api/', blddir + '/docs/api/*') bld.install_files ('${DOCDIR}/midori/api/', blddir + '/docs/api/*')
if bld.env['HAVE_HILDON']: if not is_mingw (bld.env) and Options.platform != 'win32':
appdir = '${DATADIR}/applications/hildon' if bld.env['HAVE_HILDON']:
bld.install_files ('${DATADIR}/dbus-1/services', appdir = '${MDATADIR}/applications/hildon'
'data/com.nokia.' + APPNAME + '.service') bld.install_files ('${MDATADIR}/dbus-1/services',
else: 'data/com.nokia.' + APPNAME + '.service')
appdir = '${DATADIR}/applications' else:
if bld.env['INTLTOOL']: appdir = '${MDATADIR}/applications'
obj = bld.new_task_gen ('intltool_in') if bld.env['INTLTOOL']:
obj.source = 'data/' + APPNAME + '.desktop.in' obj = bld.new_task_gen ('intltool_in')
obj.install_path = appdir obj.source = 'data/' + APPNAME + '.desktop.in'
obj.flags = '-d' obj.install_path = appdir
bld.install_files (appdir, 'data/' + APPNAME + '.desktop') obj.flags = ['-d', '-c']
else: bld.install_files (appdir, 'data/' + APPNAME + '.desktop')
folder = os.path.dirname (bld.env['waf_config_files'][0]) + '/data' else:
Utils.check_dir (folder) folder = os.path.abspath (blddir + '/default/data')
desktop = APPNAME + '.desktop' Utils.check_dir (folder)
pre = open ('data/' + desktop + '.in') desktop = APPNAME + '.desktop'
after = open (folder + '/' + desktop, 'w') pre = open ('data/' + desktop + '.in')
try: after = open (folder + '/' + desktop, 'w')
try: try:
for line in pre: try:
if line != '': for line in pre:
if line[0] == '_': if line != '':
after.write (line[1:]) if line[0] == '_':
else: after.write (line[1:])
after.write (line) else:
after.close () after.write (line)
Utils.pprint ('BLUE', desktop + '.in -> ' + desktop) after.close ()
bld.install_files (appdir, folder + '/' + desktop) Utils.pprint ('BLUE', desktop + '.in -> ' + desktop)
except: bld.install_files (appdir, folder + '/' + desktop)
Utils.pprint ('BLUE', 'File ' + desktop + ' not generated') except:
finally: Utils.pprint ('BLUE', 'File ' + desktop + ' not generated')
pre.close () finally:
pre.close ()
if bld.env['RSVG_CONVERT']: if bld.env['RSVG_CONVERT']:
Utils.check_dir (blddir + '/data') Utils.check_dir (blddir + '/data')
@ -335,20 +442,20 @@ def build (bld):
' -o ' + blddir + '/data/logo-shade.png ' + \ ' -o ' + blddir + '/data/logo-shade.png ' + \
srcdir + '/data/logo-shade.svg' srcdir + '/data/logo-shade.svg'
if not Utils.exec_command (command): if not Utils.exec_command (command):
bld.install_files ('${DATADIR}/' + APPNAME + '/res', blddir + '/data/logo-shade.png') bld.install_files ('${MDATADIR}/' + APPNAME + '/res', blddir + '/data/logo-shade.png')
else: else:
Utils.pprint ('BLUE', "logo-shade could not be rasterized.") Utils.pprint ('BLUE', "logo-shade could not be rasterized.")
bld.install_files ('${DATADIR}/' + APPNAME + '/res', 'data/error.html') bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/error.html')
bld.install_files ('${DATADIR}/' + APPNAME + '/res', 'data/speeddial-head.html') bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/speeddial-head.html')
bld.install_files ('${DATADIR}/' + APPNAME + '/res', 'data/speeddial.json') bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/speeddial.json')
bld.install_files ('${DATADIR}/' + APPNAME + '/res', 'data/mootools.js') bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/mootools.js')
if Options.commands['check']: if Options.commands['check']:
bld.add_subdirs ('tests') bld.add_subdirs ('tests')
def shutdown (): def shutdown ():
if Options.commands['install'] or Options.commands['uninstall']: if Options.commands['install'] or Options.commands['uninstall']:
dir = Build.bld.get_install_path ('${DATADIR}/icons/hicolor') dir = Build.bld.get_install_path ('${MDATADIR}/icons/hicolor')
icon_cache_updated = False icon_cache_updated = False
if not Options.options.destdir: if not Options.options.destdir:
# update the pixmap cache directory # update the pixmap cache directory
@ -394,9 +501,11 @@ def shutdown ():
Utils.pprint ('RED', "Make sure intltool is installed.") Utils.pprint ('RED', "Make sure intltool is installed.")
os.chdir ('..') os.chdir ('..')
elif Options.options.run: elif Options.options.run:
folder = os.path.dirname (Build.bld.env['waf_config_files'][0]) folder = os.path.abspath (blddir + '/default')
try: try:
relfolder = os.path.relpath (folder) relfolder = folder
if not is_mingw (Build.bld.env):
relfolder = os.path.relpath (folder)
except: except:
pass pass
try: try:
@ -417,8 +526,14 @@ def shutdown ():
'LC_MESSAGES' + os.sep + APPNAME + '.mo') 'LC_MESSAGES' + os.sep + APPNAME + '.mo')
except: except:
pass pass
command = relfolder + os.sep + APPNAME + os.sep + APPNAME command = ext + ' ' + nls + ' '
print ext + ' ' + nls + ' ' + command if is_mingw (Build.bld.env):
Utils.exec_command (ext + ' ' + nls + ' ' + command) # This works only if everything is installed to that prefix
except: os.chdir (Build.bld.env['PREFIX'] + os.sep + 'bin')
Utils.pprint ('RED', "Failed to run application.") command += ' wine cmd /k "PATH=%PATH%;' + Build.bld.env['PREFIX'] + os.sep + 'bin' + ' && ' + APPNAME + '.exe"'
else:
command += ' ' + relfolder + os.sep + APPNAME + os.sep + APPNAME
print command
Utils.exec_command (command)
except Exception, msg:
Utils.pprint ('RED', "Failed to run application: " + str (msg))