Merge commit 'upstream/0.1.8'

This commit is contained in:
Ryan Niebur 2009-07-30 14:00:37 -07:00
commit ace30a9234
81 changed files with 21257 additions and 8570 deletions

View file

@ -48,6 +48,7 @@ Translations:
hu: SZERVÁC Attila <sas@321.hu>
id: Andhika Padmawan <andhika.padmawan@gmail.com>
it: Sergio Durzu <sergio.durzu@ildeposito.org>
it: Luca Perri <kurama_luka@yahoo.it>
ja: Masato Hashimoto <cabezon.hashimoto@gmail.com>
nl: Vincent Tunru <projects@vinnl.nl>
pl: Przemysław Sitek <el.pescado@gazeta.pl>
@ -58,8 +59,10 @@ Translations:
ru: Troitskiy Nikita <niktr@mail.ru>
ru: Anton Shestakov <engored@ya.ru>
sk: Robert Hartl <hartl.robert@gmail.com>
sr: Miloš Popović <gpopac@gmail.com>
sv: Mikael Magnusson <mikachu@comhem.se>
tr: Mirat Can Bayrak <MiratCanBayrak@gmail.com>
tr: Gökmen Görgen <gkmngrgn@gmail.com>
uk: Dmitry Nikitin <luckas_fb@mail.ru>
zh_CN: Stanley Zhang <yatzhang@gmail.com>
zh_TW: Wei-Lun Chao <william.chao@ossii.com.tw>
@ -67,5 +70,7 @@ Translations:
Code from other projects:
GTK+/ GdkPixbuf, Matthias Clasen <mclasen@redhat.com>
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
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.
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:
+ Save the activation status of extensions
+ 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
. 'about:' uris: about, blank, cache, config, plugins
. Panel of open tabs (with tree-structure), optional thumbnail-view
. Spell check support
. Check specific bookmarks for updates automatically (extension)
. Mark "new" as well as "actually modified" tabs specially (even over sessions)
. SearchEngine: "Show in context menu"
. Use libnotify for events, e.g. download finished
. Save screenshot of a document?
. Right-click a textbox in a search form and choose 'add to websearch'
. Honor design principle "no warnings but undo of backups"?
. 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
. 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

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 p = a.getNext ();
cross.dispose ();
div.removeClass ('activated');
a.empty ();
cross.dispose ();
div.removeClass ('activated');
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.
import pproc as subprocess
import os
for module in ('midori', 'katze'):
try:

View file

@ -15,6 +15,9 @@
#include "config.h"
#include <glib/gstdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
static void
adblock_app_add_browser_cb (MidoriApp* app,
@ -36,17 +39,64 @@ adblock_deactivate_cb (MidoriExtension* extension,
}
static void
adblock_preferences_render_text (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
adblock_preferences_renderer_text_edited_cb (GtkCellRenderer* renderer,
const gchar* tree_path,
const gchar* new_text,
GtkTreeModel* model)
{
GtkTreeIter iter;
if (gtk_tree_model_get_iter_from_string (model, &iter, tree_path))
gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, new_text, -1);
}
static void
adblock_preferences_model_row_changed_cb (GtkTreeModel* model,
GtkTreePath* path,
GtkTreeIter* iter,
MidoriExtension* extension)
{
gchar* uri;
gsize length = gtk_tree_model_iter_n_children (model, NULL);
gchar** filters = g_new (gchar*, length + 1);
guint i = 0;
gtk_tree_model_get (model, iter, 0, &uri, -1);
g_object_set (renderer, "text", uri, NULL);
g_free (uri);
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*
@ -102,19 +152,26 @@ adblock_get_preferences_dialog (MidoriExtension* extension)
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
TRUE, TRUE, 12);
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));
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)adblock_preferences_render_icon_cb,
treeview, NULL); */
renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, TRUE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
(GtkTreeCellDataFunc)adblock_preferences_render_text,
extension, NULL);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer_text,
"text", 0, 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);
scrolled = gtk_scrolled_window_new (NULL, NULL);
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);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 4);
button = gtk_button_new_from_stock (GTK_STOCK_ADD);
/* g_signal_connect (button, "clicked",
G_CALLBACK (adblock_preferences_add_cb), extension); */
g_signal_connect (button, "clicked",
G_CALLBACK (adblock_preferences_add_clicked_cb), liststore);
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);
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_REMOVE);
/* g_signal_connect (button, "clicked",
G_CALLBACK (adblock_preferences_remove_cb), extension); */
g_signal_connect (button, "clicked",
G_CALLBACK (adblock_preferences_remove_clicked_cb), treeview);
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 */
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 8);
gtk_widget_set_sensitive (button, FALSE);
@ -223,14 +278,22 @@ adblock_app_add_browser_cb (MidoriApp* app,
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
adblock_session_request_queued_cb (SoupSession* session,
SoupMessage* msg,
GRegex* regex)
GHashTable* pattern)
{
SoupURI* soup_uri = soup_message_get_uri (msg);
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); */
/* 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);
}
static void
adblock_session_add_filter (SoupSession* session,
gchar* path)
static gchar*
adblock_parse_line (gchar* line)
{
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;
if ((file = g_fopen (path, "r")))
{
/* We assume filter lists found on the web are commonly very long */
GString* pattern = g_string_sized_new (1000 * 200);
GHashTable* pattern = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_regex_unref);
gboolean have_pattern = FALSE;
gchar line[255];
GRegex* regex;
GError* error;
while (fgets (line, 255, file))
{
/* Ignore comments and new lines */
if (line[0] == '!')
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, '|');
}
GError* error = NULL;
gchar* parsed;
error = NULL;
if (pattern->len > 2 &&
(regex = g_regex_new (pattern->str, G_REGEX_OPTIMIZE,
G_REGEX_MATCH_NOTEMPTY, &error)))
parsed = adblock_parse_line (line);
regex = g_regex_new (parsed, G_REGEX_OPTIMIZE,
G_REGEX_MATCH_NOTEMPTY, &error);
if (error)
{
/* g_debug ("%s: '%s'", G_STRFUNC, pattern->str); */
g_signal_connect_data (session, "request-queued",
G_CALLBACK (adblock_session_request_queued_cb),
regex, (GClosureNotify)g_regex_unref, 0);
}
else if (error)
{
/* g_warning ("%s: %s", G_STRFUNC, error->message); */
g_warning ("%s: %s", G_STRFUNC, error->message);
g_error_free (error);
g_free (parsed);
}
else
{
have_pattern = TRUE;
g_hash_table_insert (pattern, parsed, regex);
}
}
g_string_free (pattern, TRUE);
fclose (file);
if (have_pattern)
return pattern;
}
/* FIXME: This should presumably be freed, but there's a possible crash
g_free (path); */
return NULL;
}
#if WEBKIT_CHECK_VERSION (1, 1, 3)
@ -302,7 +382,11 @@ adblock_download_notify_status_cb (WebKitDownload* download,
gchar* path)
{
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); */
}
#endif
@ -359,7 +443,13 @@ adblock_activate_cb (MidoriExtension* extension,
#endif
}
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);
}
}
@ -367,6 +457,68 @@ adblock_activate_cb (MidoriExtension* extension,
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*
extension_init (void)
{

View file

@ -72,7 +72,7 @@ static void
colorful_tabs_button_toggled_cb (GtkWidget* button,
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_get_boolean (extension, "tint"));
@ -96,7 +96,7 @@ colorful_tabs_deactivate_cb (MidoriExtension* extension,
g_signal_handlers_disconnect_by_func (
extension, colorful_tabs_deactivate_cb, bbox);
/* 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);
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"
enum
{
COOKIE_MANAGER_COL_NAME,
COOKIE_MANAGER_COL_COOKIE,
COOKIE_MANAGER_COL_VISIBLE,
COOKIE_MANAGER_N_COLUMNS
};
struct _CookieManagerPagePrivate
{
CookieManager *parent;
GtkWidget *treeview;
GtkTreeStore *store;
GtkTreeModel *filter;
GtkWidget *filter_entry;
gboolean ignore_changed_filter;
GtkWidget *desc_label;
GtkWidget *delete_button;
@ -53,11 +48,13 @@ struct _CookieManagerPagePrivate
GtkWidget *toolbar;
GtkWidget *popup_menu;
};
GSList *cookies;
SoupCookieJar *jar;
guint timer_id;
gint ignore_changed_count;
enum
{
PROP_0,
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_expand_activate_cb(GtkMenuItem *item, CookieManagerPage *cmp);
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,
@ -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)
{
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);
g_object_ref(priv->filter);
gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), NULL);
}
gtk_tree_store_clear(priv->store);
/* free the old list */
cm_free_cookie_list(cmp);
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);
static void cookie_manager_page_cookies_changed_cb(CookieManager *cm, CookieManagerPage *cmp)
{
const gchar *filter_text;
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(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)
{
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
cm_refresh_store(cmp);
priv->timer_id = 0;
return FALSE;
}
static void cm_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new,
static void cookie_manager_page_filter_changed_cb(CookieManager *cm, const gchar *text,
CookieManagerPage *cmp)
{
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
if (priv->ignore_changed_count > 0)
{
priv->ignore_changed_count--;
return;
}
priv->ignore_changed_filter = TRUE;
gtk_entry_set_text(GTK_ENTRY(priv->filter_entry), text);
priv->ignore_changed_filter = FALSE;
}
/* 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) cm_delayed_refresh, cmp);
static void cookie_manager_page_finalize(GObject *object)
{
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(object);
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)
{
case PROP_STORE:
{
priv->store = g_value_get_object(value);
/* 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->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;
g_object_class = G_OBJECT_CLASS(klass);
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));
}
@ -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);
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 */
}
cookie_manager_delete_cookie(priv->parent, cookie);
}
@ -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)
{
const gchar *text = gtk_entry_get_text(GTK_ENTRY(editable));
const gchar *text;
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);
cookie_manager_update_filter(priv->parent, text);
if (*text != '\0')
gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
else
@ -830,20 +822,6 @@ static GtkWidget *cm_tree_prepare(CookieManagerPage *cmp)
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
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 */
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);
@ -909,9 +887,12 @@ static void cookie_manager_page_init(CookieManagerPage *self)
GtkWidget *filter_hbox;
GtkWidget *filter_label;
GtkWidget *treeview;
SoupSession *session;
CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(self);
priv->parent = NULL;
priv->store = NULL;
priv->ignore_changed_filter = FALSE;
cm_create_toolbar(self);
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), 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);
GtkWidget* cookie_manager_page_new (void);
GtkWidget* cookie_manager_page_new (CookieManager *parent,
GtkTreeStore *store,
const gchar *filter_text);
G_END_DECLS

View file

@ -16,115 +16,324 @@
#include "cookie-manager.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;
MidoriBrowser *browser;
MidoriExtension *extension;
GtkWidget *panel_page;
} CMData;
static void cm_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext);
static void cm_deactivate_cb(MidoriExtension *extension, CMData *cmdata);
GSList *panel_pages;
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);
g_signal_handlers_disconnect_by_func(cmdata->browser, cm_browser_close_cb, cmdata);
COOKIES_CHANGED,
PRE_COOKIES_CHANGE,
FILTER_CHANGED,
/* the panel_page widget gets destroyed automatically when a browser is closed but not
* when the extension is deactivated */
if (cmdata->panel_page != NULL && IS_COOKIE_MANAGER_PAGE(cmdata->panel_page))
gtk_widget_destroy(cmdata->panel_page);
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
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);
cm_browser_close_cb(NULL, cmdata);
if (ptr != NULL && GTK_IS_WIDGET(ptr))
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;
CMData *cmdata;
CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
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);
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);
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);
priv->panel_pages = g_slist_append(priv->panel_pages, page);
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;
KatzeArray *browsers;
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 */
browsers = katze_object_get_object(app, "browsers");
i = 0;
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_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__
#define __COOKIE_MANAGER_H__
G_BEGIN_DECLS
#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)
{
/* 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 (gesture->last == MOUSE_BUTTON_UNSET)
@ -177,32 +177,25 @@ static void mouse_gestures_browser_cb (MidoriApp *app, MidoriBrowser *browser)
static void mouse_gestures_deactivate (MidoriExtension *extension, MidoriApp *app)
{
gulong signal_id;
KatzeArray *browsers;
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
gint j;
GtkWidget *notebook;
signal_id =
g_signal_handler_find (app, G_SIGNAL_MATCH_FUNC,
0, 0, NULL,
signal_id = g_signal_handler_find (app, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
mouse_gestures_browser_cb, NULL);
if(signal_id != 0)
if (signal_id != 0)
g_signal_handler_disconnect (app, signal_id);
browsers = katze_object_get_object (app, "browsers");
for (i = 0; i < katze_array_get_length (browsers); i++)
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
{
MidoriBrowser *browser;
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);
gint j;
GtkWidget* notebook;
signal_id = g_signal_handler_find (browser, G_SIGNAL_MATCH_FUNC,
0, 0, NULL, mouse_gestures_tab_cb, NULL);
if (signal_id != 0)
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);
signal_id =
g_signal_handler_find (page, G_SIGNAL_MATCH_FUNC,
0, 0, NULL,
mouse_gestures_handle_events, NULL);
signal_id = g_signal_handler_find (page, G_SIGNAL_MATCH_FUNC,
0, 0, NULL, mouse_gestures_handle_events, NULL);
if (signal_id != 0)
g_signal_handler_disconnect (page, signal_id);
}
}
g_object_unref (browsers);
g_signal_handlers_disconnect_by_func (extension, mouse_gestures_deactivate, app);
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
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,
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
statusbar_features_deactivate_cb (MidoriExtension* extension,
GtkWidget* bbox)
{
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);
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 (
extension, statusbar_features_deactivate_cb, bbox);
g_signal_handlers_disconnect_by_func (
@ -37,6 +69,7 @@ statusbar_features_app_add_browser_cb (MidoriApp* app,
GtkWidget* statusbar;
GtkWidget* bbox;
MidoriWebSettings* settings;
GtkWidget* toolbar;
GtkWidget* button;
GtkWidget* image;
@ -46,36 +79,47 @@ statusbar_features_app_add_browser_cb (MidoriApp* app,
statusbar = katze_object_get_object (browser, "statusbar");
bbox = gtk_hbox_new (FALSE, 0);
settings = katze_object_get_object (browser, "settings");
toolbar = katze_object_get_object (browser, "navigationbar");
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);
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_button_set_image (GTK_BUTTON (button), image);
#if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Load images automatically"));
#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_widget_show (button);
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);
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_button_set_image (GTK_BUTTON (button), image);
#if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Enable scripts"));
#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_widget_show (button);
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);
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_button_set_image (GTK_BUTTON (button), image);
#if GTK_CHECK_VERSION(2, 12, 0)
gtk_widget_set_tooltip_text (button, _("Enable Netscape plugins"));
#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_widget_show (button);
gtk_widget_show (bbox);
gtk_box_pack_start (GTK_BOX (statusbar), bbox, FALSE, FALSE, 3);
g_object_unref (settings);
g_object_unref (statusbar);
g_signal_connect (extension, "deactivate",
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);
g_signal_connect (app, "add-browser",
G_CALLBACK (statusbar_features_app_add_browser_cb), extension);
g_object_unref (browsers);
}
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
# This file is licensed under the terms of the expat license, see the file EXPAT.
import os
extensions = os.listdir ('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
if extension == 'adblock.c':
continue

View file

@ -3,6 +3,7 @@
# This file is licensed under the terms of the expat license, see the file EXPAT.
import Utils
import os
def add_image (bld, category, name):
@ -14,10 +15,10 @@ def add_image (bld, category, name):
if rsvg_convert:
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)
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')
elif not rsvg_convert:
pass
@ -28,7 +29,7 @@ def add_image (bld, category, name):
' -o ' + blddir + '/icons/' + format + '/' + name + '.png' + \
' ' + srcdir + '/icons/scalable/' + name + '.svg'
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')
else:
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);
label = gtk_label_new (NULL);
/* 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_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
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
modify it under the terms of the GNU Lesser General Public
@ -147,7 +147,8 @@ katze_item_class_init (KatzeItemClass* class)
static void
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
@ -161,6 +162,8 @@ katze_item_finalize (GObject* object)
g_free (item->icon);
g_free (item->token);
g_hash_table_unref (item->metadata);
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");
}
/**
* 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:
* @item: a #KatzeItem

View file

@ -42,6 +42,7 @@ struct _KatzeItem
gchar* icon;
gchar* token;
gint64 added;
GHashTable* metadata;
KatzeItem* parent;
};
@ -102,6 +103,27 @@ void
katze_item_set_added (KatzeItem* item,
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
katze_item_get_parent (KatzeItem* item);

View file

@ -129,6 +129,22 @@ proxy_object_notify_string_cb (GObject* object,
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:
* @object: a #GObject
@ -153,6 +169,7 @@ proxy_object_notify_string_cb (GObject* object,
* Since 0.1.6 the following hints are also supported:
* "toggle": the widget created will be an empty toggle button. This
* is only supported with boolean properties.
* Since 0.1.8 "toggle" creates GtkCheckButton widgets without checkmarks.
*
* Any other values for @hint are silently ignored.
*
@ -196,16 +213,19 @@ katze_property_proxy (gpointer object,
gchar* notify_property;
gboolean toggled = katze_object_get_boolean (object, property);
widget = gtk_check_button_new ();
if (_hint == g_intern_string ("toggle"))
widget = gtk_toggle_button_new ();
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (widget), FALSE);
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);
g_signal_connect (widget, "toggled",
G_CALLBACK (proxy_toggle_button_toggled_cb), object);
notify_property = g_strdup_printf ("notify::%s", property);
g_signal_connect (object, notify_property,
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);
}
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);
g_signal_connect (object, notify_property,
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);
}
else if (type == G_TYPE_PARAM_FLOAT)
@ -602,6 +624,64 @@ katze_tree_view_get_selected_iter (GtkTreeView* treeview,
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:
* @object: a #GObject

View file

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

View file

@ -27,10 +27,13 @@ gtk_icon_entry_set_icon_from_pixbuf (GtkEntry* entry,
GtkEntryIconPosition position,
GdkPixbuf* pixbuf)
{
gboolean activatable;
/* 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_widget_show (GTK_WIDGET (entry));
gtk_entry_set_icon_activatable (entry, position, !activatable);
gtk_entry_set_icon_activatable (entry, position, activatable);
}
#else

View file

@ -220,9 +220,9 @@ settings_save_to_file (MidoriWebSettings* settings,
}
else if (type == G_TYPE_PARAM_BOOLEAN)
{
gboolean boolean;
g_object_get (settings, property, &boolean, NULL);
g_key_file_set_boolean (key_file, "settings", property, boolean);
gboolean truth;
g_object_get (settings, property, &truth, NULL);
g_key_file_set_boolean (key_file, "settings", property, truth);
}
else if (type == G_TYPE_PARAM_ENUM)
{
@ -744,6 +744,15 @@ settings_notify_cb (MidoriWebSettings* settings,
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
accel_map_changed_cb (GtkAccelMap* accel_map,
gchar* accel_path,
@ -1185,6 +1194,8 @@ midori_load_extensions (gpointer data)
if (extension_dir != NULL)
{
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)))
{
@ -1228,9 +1239,17 @@ midori_load_extensions (gpointer data)
if (!g_strcmp0 (filename, name))
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_dir_close (extension_dir);
g_free (config_file);
}
g_free (extension_path);
}
@ -1250,6 +1269,8 @@ midori_load_session (gpointer data)
KatzeArray* session;
KatzeItem* item;
guint i;
gint64 current;
gchar** command = g_object_get_data (G_OBJECT (app), "execute-command");
browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
@ -1285,7 +1306,11 @@ midori_load_session (gpointer data)
i = 0;
while ((item = katze_array_get_nth_item (_session, i++)))
midori_browser_add_item (browser, item);
/* FIXME: Switch to the last active page */
current = katze_item_get_meta_integer (KATZE_ITEM (_session), "current");
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), ""))
midori_browser_activate_action (browser, "Location");
@ -1304,9 +1329,13 @@ midori_load_session (gpointer data)
(GWeakNotify)(midori_browser_weak_notify_cb), browser);
}
if (command)
midori_app_send_command (app, command);
return FALSE;
}
#ifdef HAVE_JSCORE
static gint
midori_run_script (const gchar* filename)
{
@ -1344,6 +1373,7 @@ midori_run_script (const gchar* filename)
g_print ("%s - Exception: %s\n", filename, exception);
return 1;
}
#endif
#if WEBKIT_CHECK_VERSION (1, 1, 6)
static void
@ -1372,6 +1402,19 @@ snapshot_load_finished_cb (GtkWidget* web_view,
}
#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
main (int argc,
char** argv)
@ -1380,6 +1423,7 @@ main (int argc,
gchar* config;
gboolean run;
gchar* snapshot;
gboolean execute;
gboolean version;
gchar** uris;
MidoriApp* app;
@ -1391,12 +1435,16 @@ main (int argc,
N_("Run ADDRESS as a web application"), N_("ADDRESS") },
{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &config,
N_("Use FOLDER as configuration folder"), N_("FOLDER") },
#ifdef HAVE_JSCORE
{ "run", 'r', 0, G_OPTION_ARG_NONE, &run,
N_("Run the specified filename as javascript"), NULL },
#endif
#if WEBKIT_CHECK_VERSION (1, 1, 6)
{ "snapshot", 's', 0, G_OPTION_ARG_STRING, &snapshot,
N_("Take a snapshot of the specified URI"), NULL },
#endif
{ "execute", 'e', 0, G_OPTION_ARG_NONE, &execute,
N_("Execute the specified command"), NULL },
{ "version", 'V', 0, G_OPTION_ARG_NONE, &version,
N_("Display program version"), NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &uris,
@ -1430,7 +1478,15 @@ main (int argc,
if (g_getenv ("NLSPATH"))
bindtextdomain (GETTEXT_PACKAGE, g_getenv ("NLSPATH"));
else
#ifdef G_OS_WIN32
{
gchar* path = sokoke_find_data_filename ("locale");
bindtextdomain (GETTEXT_PACKAGE, path);
g_free (path);
}
#else
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
#endif
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
#endif
@ -1440,6 +1496,7 @@ main (int argc,
config = NULL;
run = FALSE;
snapshot = NULL;
execute = FALSE;
version = FALSE;
uris = NULL;
error = NULL;
@ -1515,10 +1572,13 @@ main (int argc,
"show-menubar", FALSE,
"show-navigationbar", TRUE,
"toolbar-items", "Back,Forward,ReloadStop,Location",
"homepage", NULL,
"show-statusbar", TRUE,
NULL);
g_object_unref (settings);
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);
g_object_set_data (G_OBJECT (browser), "locked", (void*)1);
g_signal_connect (browser, "destroy",
@ -1529,9 +1589,11 @@ main (int argc,
return 0;
}
#ifdef HAVE_JSCORE
/* Standalone javascript support */
if (run)
return midori_run_script (uris ? *uris : NULL);
#endif
#if HAVE_HILDON
osso_context = osso_initialize (PACKAGE_NAME, PACKAGE_VERSION, FALSE, NULL);
@ -1569,8 +1631,9 @@ main (int argc,
{
GtkWidget* dialog;
/* TODO: Open as many tabs as we have uris, seperated by pipes */
if (uris)
if (execute)
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);
else
result = midori_app_instance_send_new_browser (app);
@ -1606,6 +1669,15 @@ main (int argc,
}
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 ();
i = 0;
while (config_dirs[i])
@ -1625,6 +1697,7 @@ main (int argc,
g_build_filename (SYSCONFDIR, "xdg", PACKAGE_NAME, "search", NULL));
search_engines = search_engines_new_from_file (config_file, NULL);
}
#endif
}
else if (error)
{
@ -1730,6 +1803,9 @@ main (int argc,
}
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 */
i = 0;
while (uris && uris[i])
@ -1747,6 +1823,7 @@ main (int argc,
g_free (uri);
i++;
}
}
katze_assign (config_file, build_config_filename ("config"));
if (is_writable (config_file))
@ -1845,6 +1922,9 @@ main (int argc,
katze_item_set_parent (KATZE_ITEM (_session), app);
g_idle_add (midori_load_session, _session);
if (execute)
g_object_set_data (G_OBJECT (app), "execute-command", uris);
gtk_main ();
#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
modify it under the terms of the GNU Lesser General Public
@ -21,7 +21,14 @@
#include <glib/gi18n.h>
#if HAVE_UNIQUE
typedef gpointer MidoriAppInstance;
#define MidoriAppInstanceNull NULL
#include <unique/unique.h>
#define MIDORI_UNIQUE_COMMAND 1
#else
typedef gint MidoriAppInstance;
#define MidoriAppInstanceNull -1
#include "socket.h"
#endif
typedef struct _NotifyNotification NotifyNotification;
@ -54,7 +61,7 @@ struct _MidoriApp
KatzeArray* extensions;
KatzeArray* browsers;
gpointer instance;
MidoriAppInstance instance;
/* libnotify handling */
gchar* program_notify_send;
@ -197,6 +204,7 @@ _midori_app_add_browser (MidoriApp* app,
katze_array_add_item (app->browsers, browser);
app->browser = browser;
#if HAVE_UNIQUE
if (app->instance)
unique_app_watch_window (app->instance, GTK_WINDOW (browser));
@ -383,56 +391,56 @@ midori_app_class_init (MidoriAppClass* class)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
#if HAVE_UNIQUE
static UniqueResponse
midori_browser_message_received_cb (UniqueApp* instance,
UniqueCommand command,
UniqueMessageData* message,
guint timestamp,
MidoriApp* app)
static gboolean
midori_app_command_received (MidoriApp* app,
const gchar* command,
gchar** uris,
GdkScreen* screen)
{
UniqueResponse response;
MidoriBrowser* browser;
gchar** uris;
MidoriNewPage open_external_pages_in;
gboolean first;
switch (command)
if (!screen)
{
case UNIQUE_ACTIVATE:
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
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));
response = UNIQUE_RESPONSE_OK;
break;
case UNIQUE_NEW:
browser = midori_app_create_browser (app);
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),
unique_message_data_get_screen (message));
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_widget_show (GTK_WIDGET (browser));
response = UNIQUE_RESPONSE_OK;
break;
case UNIQUE_OPEN:
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
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));
uris = unique_message_data_get_uris (message);
if (!uris)
response = UNIQUE_RESPONSE_FAIL;
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),
unique_message_data_get_screen (message));
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_widget_show (GTK_WIDGET (browser));
}
else
@ -452,37 +460,137 @@ midori_browser_message_received_cb (UniqueApp* instance,
g_free (fixed_uri);
uris++;
}
/* g_strfreev (uris); */
response = UNIQUE_RESPONSE_OK;
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
static UniqueResponse
midori_browser_message_received_cb (UniqueApp* instance,
UniqueCommand command,
UniqueMessageData* message,
guint timestamp,
MidoriApp* app)
{
gboolean success;
GdkScreen* screen = unique_message_data_get_screen (message);
switch (command)
{
case UNIQUE_ACTIVATE:
success = midori_app_command_received (app, "activate", NULL, screen);
break;
case UNIQUE_NEW:
success = midori_app_command_received (app, "new", NULL, screen);
break;
case UNIQUE_OPEN:
{
gchar** uris = unique_message_data_get_uris (message);
success = midori_app_command_received (app, "open", uris, screen);
/* g_strfreev (uris); */
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:
response = UNIQUE_RESPONSE_FAIL;
success = FALSE;
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
static gpointer
static MidoriAppInstance
midori_app_create_instance (MidoriApp* app,
const gchar* name)
{
#if HAVE_UNIQUE
gpointer instance;
MidoriAppInstance instance;
GdkDisplay* display;
gchar* display_name;
gchar* instance_name;
guint i, n;
#if !HAVE_UNIQUE
gboolean exists;
GIOChannel* channel;
#endif
if (!name)
name = "midori";
#if HAVE_UNIQUE
if (!(display = gdk_display_get_default ()))
return NULL;
return MidoriAppInstanceNull;
display_name = g_strdup (gdk_display_get_name (display));
n = strlen (display_name);
@ -490,15 +598,25 @@ midori_app_create_instance (MidoriApp* app,
if (display_name[i] == ':' || display_name[i] == '.')
display_name[i] = '_';
instance_name = g_strdup_printf ("de.twotoasts.%s_%s", name, display_name);
#if HAVE_UNIQUE
instance = unique_app_new (instance_name, NULL);
g_free (instance_name);
g_free (display_name);
unique_app_add_command (instance, "midori-command", MIDORI_UNIQUE_COMMAND);
g_signal_connect (instance, "message-received",
G_CALLBACK (midori_browser_message_received_cb), app);
return instance;
#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
g_free (instance_name);
g_free (display_name);
return instance;
}
static void
@ -514,7 +632,7 @@ midori_app_init (MidoriApp* app)
app->extensions = NULL;
app->browsers = katze_array_new (MIDORI_TYPE_BROWSER);
app->instance = NULL;
app->instance = MidoriAppInstanceNull;
midori_app_init_libnotify (app);
}
@ -535,7 +653,11 @@ midori_app_finalize (GObject* object)
katze_object_assign (app->extensions, NULL);
katze_object_assign (app->browsers, NULL);
#if HAVE_UNIQUE
katze_object_assign (app->instance, NULL);
#else
sock_cleanup ();
#endif
if (app->libnotify_module)
{
@ -663,9 +785,6 @@ midori_app_new (void)
* Use the "name" property if you want to run more
* 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
**/
gboolean
@ -673,11 +792,13 @@ midori_app_instance_is_running (MidoriApp* app)
{
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
#if HAVE_UNIQUE
if (!app->instance)
if (app->instance == MidoriAppInstanceNull)
app->instance = midori_app_create_instance (app, app->name);
#if HAVE_UNIQUE
if (app->instance)
return unique_app_is_running (app->instance);
#else
return g_object_get_data (G_OBJECT (app), "sock-exists") != NULL;
#endif
return FALSE;
}
@ -710,6 +831,12 @@ midori_app_instance_send_activate (MidoriApp* app)
if (response == UNIQUE_RESPONSE_OK)
return TRUE;
}
#else
if (app->instance > -1)
{
send_open_command (app->instance, "activate", NULL);
return TRUE;
}
#endif
return FALSE;
}
@ -740,6 +867,12 @@ midori_app_instance_send_new_browser (MidoriApp* app)
if (response == UNIQUE_RESPONSE_OK)
return TRUE;
}
#else
if (app->instance > -1)
{
send_open_command (app->instance, "new", NULL);
return TRUE;
}
#endif
return FALSE;
}
@ -779,6 +912,63 @@ midori_app_instance_send_uris (MidoriApp* app,
if (response == UNIQUE_RESPONSE_OK)
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
return FALSE;
}

View file

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

View file

@ -22,6 +22,13 @@
#include <libxml/tree.h>
#endif
static void
katze_xbel_parse_info (KatzeItem* item,
xmlNodePtr cur);
static gchar*
katze_item_metadata_to_xbel (KatzeItem* item);
#if HAVE_LIBXML
static KatzeItem*
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));
g_free (key);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
katze_xbel_parse_info (item, cur);
cur = cur->next;
}
return item;
@ -109,6 +118,52 @@ katze_array_from_xmlNodePtr (xmlNodePtr cur)
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. */
static gboolean
katze_array_from_xmlDocPtr (KatzeArray* array,
@ -153,8 +208,8 @@ katze_array_from_xmlDocPtr (KatzeArray* array,
item = katze_item_from_xmlNodePtr (cur);
else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator"))
item = katze_item_new ();
/*else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
item = katze_xbel_parse_info (xbel, cur);*/
else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
katze_xbel_parse_info (KATZE_ITEM (array), cur);
if (item)
katze_array_add_item (array, item);
cur = cur->next;
@ -236,10 +291,12 @@ static gchar*
katze_item_to_data (KatzeItem* item)
{
gchar* markup;
gchar* metadata;
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
markup = NULL;
metadata = katze_item_metadata_to_xbel (item);
if (KATZE_IS_ARRAY (item))
{
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* title = _simple_xml_element ("title", katze_item_get_name (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 : "" */,
title, desc,
_markup->str);
_markup->str,
metadata);
g_string_free (_markup, TRUE);
/* g_free (folded); */
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",
href,
title, desc,
"");
metadata);
g_free (href);
g_free (title);
g_free (desc);
}
else
markup = g_strdup ("<separator/>\n");
g_free (metadata);
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*
katze_array_to_xbel (KatzeArray* array,
GError** error)
@ -291,8 +375,10 @@ katze_array_to_xbel (KatzeArray* array,
guint i;
KatzeItem* item;
gchar* item_xml;
const gchar* namespacing;
gchar* title;
gchar* desc;
gchar* metadata;
gchar* outer_markup;
inner_markup = g_string_new (NULL);
@ -304,20 +390,25 @@ katze_array_to_xbel (KatzeArray* array,
g_free (item_xml);
}
namespacing = " xmlns:midori=\"http://www.twotoasts.de\"";
title = _simple_xml_element ("title", katze_item_get_name (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 (
"%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",
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD "
"XML Bookmark Exchange Language 1.0//EN//XML\" "
"\"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">\n",
namespacing,
title,
desc,
metadata,
inner_markup->str);
g_string_free (inner_markup, TRUE);
g_free (title);
g_free (desc);
g_free (metadata);
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
midori_browser_quit (MidoriBrowser* browser);
const gchar**
midori_browser_get_toolbar_actions (MidoriBrowser* browser);
G_END_DECLS
#endif /* __MIDORI_BROWSER_H__ */

View file

@ -28,6 +28,7 @@ struct _MidoriExtensionPrivate
gchar* description;
gchar* version;
gchar* authors;
gchar* website;
MidoriApp* app;
gint active;
@ -129,7 +130,8 @@ enum
PROP_NAME,
PROP_DESCRIPTION,
PROP_VERSION,
PROP_AUTHORS
PROP_AUTHORS,
PROP_WEBSITE
};
enum {
@ -227,6 +229,22 @@ midori_extension_class_init (MidoriExtensionClass* class)
NULL,
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));
}
@ -346,6 +364,7 @@ midori_extension_finalize (GObject* object)
katze_assign (extension->priv->description, NULL);
katze_assign (extension->priv->version, NULL);
katze_assign (extension->priv->authors, NULL);
katze_assign (extension->priv->website, NULL);
katze_assign (extension->priv->config_dir, NULL);
g_list_free (extension->priv->lsettings);
@ -376,6 +395,9 @@ midori_extension_set_property (GObject* object,
case PROP_AUTHORS:
katze_assign (extension->priv->authors, g_value_dup_string (value));
break;
case PROP_WEBSITE:
katze_assign (extension->priv->website, g_value_dup_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -404,6 +426,9 @@ midori_extension_get_property (GObject* object,
case PROP_AUTHORS:
g_value_set_string (value, extension->priv->authors);
break;
case PROP_WEBSITE:
g_value_set_string (value, extension->priv->website);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -36,6 +36,8 @@ struct _MidoriLocationAction
GtkTreeModel* sort_model;
GdkPixbuf* default_icon;
GHashTable* items;
KatzeNet* net;
KatzeArray* history;
};
struct _MidoriLocationActionClass
@ -50,12 +52,14 @@ enum
PROP_0,
PROP_PROGRESS,
PROP_SECONDARY_ICON
PROP_SECONDARY_ICON,
PROP_HISTORY
};
enum
{
ACTIVE_CHANGED,
FOCUS_IN,
FOCUS_OUT,
SECONDARY_ICON_RELEASED,
RESET_URI,
@ -72,6 +76,7 @@ enum
TITLE_COL,
VISITS_COL,
VISIBLE_COL,
YALIGN_COL,
N_COLS
};
@ -104,6 +109,10 @@ static void
midori_location_action_disconnect_proxy (GtkAction* action,
GtkWidget* proxy);
static void
midori_location_action_completion_init (MidoriLocationAction* location_action,
GtkEntry* entry);
static void
midori_location_action_class_init (MidoriLocationActionClass* class)
{
@ -120,6 +129,22 @@ midori_location_action_class_init (MidoriLocationActionClass* class)
G_TYPE_NONE, 1,
G_TYPE_INT);
/**
* MidoriLocationAction:focus-in:
*
* The focus-in signal is emitted when the entry obtains the focus.
*
* Since 0.1.8
*/
signals[FOCUS_IN] = g_signal_new ("focus-in",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[FOCUS_OUT] = g_signal_new ("focus-out",
G_TYPE_FROM_CLASS (class),
(GSignalFlags) (G_SIGNAL_RUN_LAST),
@ -187,6 +212,24 @@ midori_location_action_class_init (MidoriLocationActionClass* class)
"The stock ID of the secondary icon",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* MidoriLocationAction:history:
*
* The list of history items.
*
* This is actually a reference to a history instance.
*
* Since 0.1.8
*/
g_object_class_install_property (gobject_class,
PROP_HISTORY,
g_param_spec_object (
"history",
"History",
"The list of history items",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
/* 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)
{
GtkWidget* alignment = gtk_bin_get_child (GTK_BIN (proxy));
GtkWidget* hbox = 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);
GtkWidget* entry = gtk_bin_get_child (GTK_BIN (alignment));
return entry;
}
@ -218,9 +258,7 @@ midori_location_action_set_model (MidoriLocationAction* location_action,
entry = gtk_bin_get_child (GTK_BIN (location_entry));
g_object_set (location_entry, "model", model, NULL);
gtk_entry_completion_set_model (
gtk_entry_get_completion (GTK_ENTRY (entry)),
model ? location_action->filter_model : NULL);
midori_location_action_completion_init (location_action, GTK_ENTRY (entry));
}
}
@ -285,10 +323,10 @@ midori_location_action_thaw (MidoriLocationAction* location_action)
filter_model = gtk_tree_model_filter_new (sort_model, NULL);
gtk_tree_model_filter_set_visible_column (
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->sort_model = sort_model;
midori_location_action_set_model (location_action, location_action->model);
i = MAX_ITEMS;
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
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->default_icon = NULL;
location_action->model = (GtkTreeModel*)gtk_list_store_new (N_COLS,
GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INT, G_TYPE_BOOLEAN);
location_action->model = midori_location_action_create_model ();
location_action->filter_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,
g_free, g_free);
location_action->net = katze_net_new ();
location_action->history = NULL;
}
static void
@ -335,10 +382,55 @@ midori_location_action_finalize (GObject* object)
katze_object_assign (location_action->default_icon, NULL);
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);
}
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
midori_location_action_set_property (GObject* object,
guint prop_id,
@ -357,6 +449,35 @@ midori_location_action_set_property (GObject* object,
midori_location_action_set_secondary_icon (location_action,
g_value_get_string (value));
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:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -379,6 +500,9 @@ midori_location_action_get_property (GObject* object,
case PROP_SECONDARY_ICON:
g_value_set_string (value, location_action->secondary_icon);
break;
case PROP_HISTORY:
g_value_set_object (value, location_action->history);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -407,29 +531,12 @@ midori_location_action_activate (GtkAction* 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*
midori_location_action_create_tool_item (GtkAction* action)
{
GtkWidget* toolitem;
GtkWidget* alignment;
GtkWidget* hbox;
GtkWidget* location_entry;
GtkWidget* go_button;
GtkWidget* go_icon;
toolitem = GTK_WIDGET (gtk_tool_item_new ());
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);
gtk_widget_show (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 ();
gtk_widget_show (location_entry);
gtk_box_pack_start (GTK_BOX (hbox), location_entry, TRUE, TRUE, 0);
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);
gtk_container_add (GTK_CONTAINER (alignment), location_entry);
return toolitem;
}
@ -485,6 +580,15 @@ midori_location_action_key_press_event_cb (GtkWidget* widget,
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
midori_location_action_focus_out_event_cb (GtkWidget* widget,
GdkEventKey* event,
@ -504,23 +608,6 @@ midori_location_action_icon_released_cb (GtkWidget* 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
midori_location_entry_render_text_cb (GtkCellLayout* layout,
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_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);
if (item->favicon)
@ -820,16 +907,26 @@ midori_location_action_add_actions (GtkEntryCompletion* completion,
static void
midori_location_action_completion_init (MidoriLocationAction* location_action,
GtkWidget* location_entry)
GtkEntry* entry)
{
GtkWidget* entry;
GtkEntryCompletion* completion;
GtkCellRenderer* renderer;
entry = gtk_bin_get_child (GTK_BIN (location_entry));
completion = gtk_entry_completion_new ();
if ((completion = gtk_entry_get_completion (entry)))
{
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);
#if GTK_CHECK_VERSION (2, 12, 0)
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 ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, FALSE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer,
midori_location_entry_render_pixbuf_cb,
NULL, NULL);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer,
"pixbuf", FAVICON_COL, "yalign", YALIGN_COL, NULL);
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_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer,
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,
midori_location_entry_completion_match_cb, NULL, NULL);
gtk_entry_set_completion (GTK_ENTRY (entry), completion);
g_signal_connect (completion, "match-selected",
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);
g_signal_connect (completion, "action-activated",
G_CALLBACK (midori_location_entry_action_activated_cb), location_action);
g_object_unref (completion);
}
static void
@ -923,21 +1020,24 @@ midori_location_action_connect_proxy (GtkAction* action,
/* Setup the renderer for the favicon */
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, FALSE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
renderer, midori_location_entry_render_pixbuf_cb, NULL, NULL);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (entry), renderer,
"pixbuf", FAVICON_COL, "yalign", YALIGN_COL, NULL);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, TRUE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
renderer, midori_location_entry_render_text_cb, NULL, NULL);
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_CALLBACK (midori_location_action_entry_changed_cb), action);
g_object_connect (gtk_bin_get_child (GTK_BIN (entry)),
"signal::key-press-event",
midori_location_action_key_press_event_cb, action,
"signal::focus-in-event",
midori_location_action_focus_in_event_cb, action,
"signal::focus-out-event",
midori_location_action_focus_out_event_cb, action,
"signal::icon-release",
@ -1271,6 +1371,7 @@ midori_location_action_set_search_engines (MidoriLocationAction* location_action
entry = midori_location_action_entry_for_proxy (proxies->data);
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));
i = 0;
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
* @uri: a string
*

View file

@ -231,7 +231,6 @@ static void
midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton,
MidoriPanel* panel)
{
/* FIXME: Use stock icon for window */
/* FIXME: What happens when the browser is destroyed? */
/* FIXME: What about multiple browsers? */
/* 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);
g_object_set_data (G_OBJECT (window), "scrolled", scrolled);
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_transient_for (GTK_WINDOW (window),
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);
gtk_widget_set_sensitive (GTK_WIDGET (toolitem), FALSE);
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),
_("Whether to detach the chosen panel from the window"));
_("Detach chosen panel from the window"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_detach_clicked_cb), panel);
#if HAVE_OSX
@ -341,10 +339,8 @@ midori_panel_init (MidoriPanel* panel)
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
#endif
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),
_("Whether to align the sidepanel on the right"));
_("Align sidepanel to the right"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_align_clicked_cb), panel);
#if HAVE_OSX
@ -488,7 +484,7 @@ midori_panel_set_compact (MidoriPanel* panel,
/**
* 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.
*
@ -508,6 +504,9 @@ midori_panel_set_right_aligned (MidoriPanel* panel,
gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (panel->button_align),
right_aligned ? GTK_STOCK_GO_BACK : GTK_STOCK_GO_FORWARD);
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");
}
@ -662,7 +661,7 @@ midori_panel_append_page (MidoriPanel* panel,
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_panel_menu_item_activate_cb),
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_signal_connect (viewable, "destroy",
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
* silently ignore the attempt to switch the page.
*
* Since 0.1.8 the "page" property is notifying changes.
**/
void
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));
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)))
{
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));
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);
label = gtk_label_new (_("Fixed-width Font Family"));
INDENTED_ADD (label, 0, 1, 1, 2);
hbox = gtk_hbox_new (FALSE, 4);
button = katze_property_proxy (settings, "monospace-font-family", "font");
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"));
INDENTED_ADD (label, 0, 1, 2, 3);
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);
button = katze_property_proxy (settings, "open-new-pages-in", NULL);
FILLED_ADD (button, 1, 2, 0, 1);
#if HAVE_UNIQUE
label = katze_property_label (settings, "open-external-pages-in");
INDENTED_ADD (label, 0, 1, 1, 2);
button = katze_property_proxy (settings, "open-external-pages-in", NULL);
FILLED_ADD (button, 1, 2, 1, 2);
#endif
button = katze_property_proxy (settings, "always-show-tabbar", NULL);
INDENTED_ADD (button, 0, 1, 2, 3);
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);
}
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
midori_search_action_dialog_add_cb (GtkWidget* widget,
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)),
"changed", G_CALLBACK (midori_search_action_treeview_selection_cb),
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);
g_object_set_data (G_OBJECT (treeview), "search-action", search_action);
column = gtk_tree_view_column_new ();

View file

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

View file

@ -16,6 +16,7 @@
#include "midori-view.h"
#include "midori-stock.h"
#include "midori-browser.h"
#include "compat.h"
#include "marshal.h"
@ -26,6 +27,7 @@
#include <glib/gi18n.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gdk/gdkkeysyms.h>
#include <webkit/webkit.h>
/* This is unstable API, so we need to declare it */
@ -45,6 +47,11 @@ midori_search_action_get_icon (KatzeNet* net,
static void
midori_view_construct_web_view (MidoriView* view);
GdkPixbuf*
midori_view_get_snapshot (MidoriView* view,
gint width,
gint height);
struct _MidoriView
{
GtkScrolledWindow parent_instance;
@ -74,6 +81,7 @@ struct _MidoriView
GtkWidget* menu_item;
GtkWidget* tab_label;
/* GtkWidget* tooltip_image; */
GtkWidget* tab_icon;
GtkWidget* tab_title;
GtkWidget* tab_close;
@ -514,6 +522,7 @@ midori_view_class_init (MidoriViewClass* class)
static void
midori_view_update_title (MidoriView* view)
{
#ifndef G_OS_WIN32
/* 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
"‪بستيان نوصر (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);
katze_assign (view->title, new_title);
}
#endif
#define title midori_view_get_display_title (view)
if (view->tab_label)
{
@ -547,7 +557,9 @@ midori_view_update_title (MidoriView* view)
soup_uri_free (uri);
}
gtk_label_set_text (GTK_LABEL (view->tab_title), title);
#if 1
gtk_widget_set_tooltip_text (view->tab_title, title);
#endif
}
if (view->menu_item)
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,
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;
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;
guint port;
@ -754,9 +768,11 @@ webkit_web_view_load_error_cb (WebKitWebView* web_view,
g_free (res_root);
g_free (stock_root);
g_free (result);
g_free (path);
return TRUE;
}
g_free (path);
return FALSE;
}
@ -777,7 +793,7 @@ webkit_web_frame_load_done_cb (WebKitWebFrame* web_frame,
data = g_strdup_printf (
"<html><head><title>%s</title></head>"
"<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;\">"
"<p />The page you were opening doesn't exist."
"<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; }"
"feeds (document.getElementsByTagName ('link'))", NULL);
gchar** items = g_strsplit (value, ",", 0);
gchar** iter;
guint i = 0;
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,
"uri", parts ? *parts : "",
"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);
g_object_unref (item);
g_strfreev (parts);
i++;
}
g_strfreev (items);
g_object_set_data (G_OBJECT (view), "news-feeds",
@ -1007,6 +1025,9 @@ gtk_widget_button_press_event_cb (WebKitWebView* web_view,
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;
}
@ -1016,15 +1037,16 @@ gtk_widget_key_press_event_cb (WebKitWebView* web_view,
MidoriView* view)
{
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';
else if (!view->find_while_typing)
return FALSE;
/* Skip control characters */
if (character == (event->keyval | 0x01000000))
return FALSE;
if (!webkit_web_view_can_cut_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);
}
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
midori_web_view_menu_search_web_activate_cb (GtkWidget* widget,
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);
}
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
webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
GtkWidget* menu,
MidoriView* view)
{
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (view));
GtkActionGroup* actions = midori_browser_get_action_group (browser);
GtkWidget* menuitem;
GtkWidget* icon;
gchar* stock_id;
@ -1301,63 +1310,74 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
}
}
g_list_free (items);
menuitem = gtk_image_menu_item_new_with_mnemonic (_("Undo Close Tab"));
icon = gtk_image_new_from_stock (GTK_STOCK_UNDELETE, GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "UndoTabClose"));
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 ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
menuitem = gtk_image_menu_item_new_from_stock (STOCK_BOOKMARK_ADD, NULL);
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);
g_object_set_data (G_OBJECT (menuitem), "action", "BookmarkAdd");
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
gtk_widget_show (menuitem);
menuitem = 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))
{
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);
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);
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
saving either. If that changes, we need to think of something. */
if (!midori_view_can_view_source (view))
gtk_widget_set_sensitive (menuitem, FALSE);
menuitem = gtk_image_menu_item_new_with_mnemonic (_("View _Source"));
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "SourceView"));
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_STOCK_SAVE, 1,
GTK_STOCK_SAVE_AS, 4,
GTK_STOCK_CANCEL, 2,
GTK_STOCK_OPEN, 3,
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);
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:
g_object_set_data (G_OBJECT (view), "open-download", (gpointer)1);
case 1:
@ -1525,7 +1551,10 @@ webkit_web_view_download_requested_cb (GtkWidget* web_view,
gboolean handled;
g_object_set_data (G_OBJECT (download), "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), "save-as-download", (gpointer)0);
g_signal_emit (view, signals[DOWNLOAD_REQUESTED], 0, download, &handled);
return handled;
}
@ -2038,7 +2067,7 @@ midori_view_set_uri (MidoriView* view,
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);
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_get_contents (DATADIR "/midori/res/speeddial.json",
if (g_file_get_contents (MDATADIR "/midori/res/speeddial.json",
&speed_dial_body, NULL, NULL))
g_file_set_contents (body_fname, speed_dial_body, -1, NULL);
else
@ -2101,7 +2130,7 @@ midori_view_set_uri (MidoriView* view,
data = g_strdup_printf (
"<html><head><title>%s</title></head>"
"<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;\">"
"<p />The document %s of type '%s' cannot be displayed."
"</body></html>",
@ -2118,7 +2147,7 @@ midori_view_set_uri (MidoriView* view,
data = g_strdup_printf (
"<html><head><title>%s</title></head>"
"<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;\">"
"<p />There is no documentation installed at %s."
"You may want to ask your distribution or "
@ -2178,6 +2207,8 @@ midori_view_is_blank (MidoriView* view)
*
* Retrieves the icon of the view.
*
* The returned icon is owned by the @view and must not be modified.
*
* Return value: a #GdkPixbuf
**/
GdkPixbuf*
@ -2396,6 +2427,84 @@ midori_view_get_proxy_menu_item (MidoriView* view)
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
midori_view_tab_label_button_release_event (GtkWidget* tab_label,
GdkEventButton* event,
@ -2407,6 +2516,15 @@ midori_view_tab_label_button_release_event (GtkWidget* tab_label,
gtk_widget_destroy (widget);
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;
}
@ -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:
* @view: a #MidoriView
@ -2609,6 +2744,11 @@ midori_view_get_proxy_tab_label (MidoriView* view)
G_CALLBACK (midori_view_tab_close_clicked), view);
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_CALLBACK (gtk_widget_destroyed),
&view->tab_icon);
@ -2768,6 +2908,8 @@ midori_view_reload (MidoriView* view,
#endif
if (view->title && strstr (title, view->title))
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)
webkit_web_view_reload (WEBKIT_WEB_VIEW (view->web_view));
else
@ -2978,10 +3120,12 @@ midori_view_execute_script (MidoriView* view,
/* For now this is private API */
GdkPixbuf*
midori_view_get_snapshot (MidoriView* view,
guint width,
guint height)
gint width,
gint height)
{
GtkWidget* web_view;
gboolean fast;
gint x, y, w, h;
GdkRectangle rect;
GdkPixmap* pixmap;
GdkEvent event;
@ -2993,13 +3137,30 @@ midori_view_get_snapshot (MidoriView* view,
web_view = gtk_bin_get_child (GTK_BIN (view));
g_return_val_if_fail (web_view->window, NULL);
rect.x = web_view->allocation.x;
rect.y = web_view->allocation.y;
rect.width = web_view->allocation.width;
rect.height = web_view->allocation.height;
x = web_view->allocation.x;
y = web_view->allocation.y;
w = web_view->allocation.width;
h = web_view->allocation.height;
pixmap = gdk_pixmap_new (web_view->window,
web_view->allocation.width, web_view->allocation.height,
/* If width and height are both negative, we try to render faster at
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));
event.expose.type = GDK_EXPOSE;
event.expose.window = pixmap;
@ -3025,8 +3186,9 @@ midori_view_get_snapshot (MidoriView* view,
width = rect.width;
if (!height)
height = rect.height;
scaled = gdk_pixbuf_scale_simple (pixbuf, width, height,
GDK_INTERP_TILES);
fast ? GDK_INTERP_NEAREST : GDK_INTERP_TILES);
g_object_unref (pixbuf);
return scaled;
}

View file

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

View file

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

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>
#endif
#ifdef HAVE_JSCORE
static gchar*
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);
return string_utf8;
}
#endif
gchar*
sokoke_js_script_eval (JSContextRef js_context,
const gchar* script,
gchar** exception)
{
#ifdef HAVE_JSCORE
gchar* value;
JSStringRef js_value_string;
#endif
g_return_val_if_fail (js_context, FALSE);
g_return_val_if_fail (script, FALSE);
#ifdef HAVE_JSCORE
JSStringRef js_script = JSStringCreateWithUTF8CString (script);
JSValueRef js_exception = NULL;
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);
JSStringRelease (js_value_string);
return value;
#else
return g_strdup ("");
#endif
}
static void
@ -92,8 +100,6 @@ error_dialog (const gchar* short_message,
gtk_widget_show (dialog);
g_signal_connect_swapped (dialog, "response",
G_CALLBACK (gtk_widget_destroy), dialog);
}
/**
@ -355,11 +361,11 @@ sokoke_magic_uri (const gchar* uri,
search_uri = NULL;
/* Do we have a keyword and a string? */
parts = g_strsplit (uri, " ", 2);
if (parts[0] && parts[1])
if (parts[0])
if ((item = katze_array_find_token (search_engines, parts[0])))
{
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);
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 */
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);
GtkWidget* label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), title_bold);
g_free (title_bold);
gtk_frame_set_label_widget (GTK_FRAME (frame), label);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
#endif
return frame;
}
@ -735,6 +745,9 @@ sokoke_action_create_popup_menu_item (GtkAction* action)
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,
"label", &label,
"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);
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem),
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)
{
@ -839,6 +855,7 @@ sokoke_register_stock_items (void)
{
{ STOCK_EXTENSION, NULL, 0, 0, GTK_STOCK_CONVERT },
{ 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_SCRIPT, NULL, 0, 0, GTK_STOCK_EXECUTE },
{ 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_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_EXTENSIONS, N_("_Extensions"), 0, 0, GTK_STOCK_CONVERT },
{ STOCK_HISTORY, N_("_History"), 0, 0, GTK_STOCK_SORT_ASCENDING },
@ -948,6 +965,32 @@ sokoke_remove_path (const gchar* path,
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
res_server_handler_cb (SoupServer* res_server,
SoupMessage* msg,
@ -958,13 +1001,15 @@ res_server_handler_cb (SoupServer* res_server,
{
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;
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);
gchar* mime_type = g_content_type_get_mime_type (content_type);
g_free (content_type);
@ -975,7 +1020,7 @@ res_server_handler_cb (SoupServer* res_server,
}
else
soup_message_set_status (msg, 404);
g_free (filename);
g_free (filepath);
}
else if (g_str_has_prefix (path, "/stock/"))
{

View file

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

View file

@ -5,12 +5,12 @@
import platform
obj = bld.new_task_gen ('cc', 'staticlib')
obj.name = 'midori'
obj.name = 'midori-core'
obj.target = 'midori'
obj.includes = '. ..'
obj.find_sources_in_dirs ('.', excludes=['main.c'])
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.install_path = None
@ -20,12 +20,14 @@ obj.target = 'panels'
obj.includes = '. ..'
obj.find_sources_in_dirs ('../panels')
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 = bld.new_task_gen ('cc', 'program')
obj.target = 'midori'
obj.includes = '. .. ../panels'
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_local = 'panels'

View file

@ -306,49 +306,6 @@ _addons_get_files (MidoriAddons* addons)
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
midori_addons_directory_monitor_changed (GFileMonitor* monitor,
GFile* child,
@ -359,67 +316,6 @@ midori_addons_directory_monitor_changed (GFileMonitor* monitor,
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
midori_addons_button_add_clicked_cb (GtkToolItem* toolitem,
MidoriAddons* addons)
@ -435,7 +331,7 @@ midori_addons_button_add_clicked_cb (GtkToolItem* toolitem,
}
static void
midori_addons_treeview_render_icon_cb (GtkTreeViewColumn* column,
midori_addons_treeview_render_tick_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
@ -445,10 +341,10 @@ midori_addons_treeview_render_icon_cb (GtkTreeViewColumn* column,
gtk_tree_model_get (model, iter, 0, &element, -1);
if (element->broken)
g_object_set (renderer, "stock-id", GTK_STOCK_STOP, NULL);
else
g_object_set (renderer, "stock-id", GTK_STOCK_FILE, NULL);
g_object_set (renderer,
"active", element->enabled,
"sensitive", !element->broken,
NULL);
}
static void
@ -475,14 +371,48 @@ midori_addons_treeview_row_activated_cb (GtkTreeView* treeview,
GtkTreeViewColumn* column,
MidoriAddons* addons)
{
/*GtkTreeModel* model = gtk_tree_view_get_model (treeview);
GtkTreeModel* model = gtk_tree_view_get_model (treeview);
GtkTreeIter iter;
if (gtk_tree_model_get_iter (model, &iter, path))
{
gchar* b;
gtk_tree_model_get (model, &iter, 2, &b, -1);
g_free (b);
}*/
struct AddonElement *element;
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
@ -490,7 +420,7 @@ midori_addons_init (MidoriAddons* addons)
{
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_pixbuf;
GtkCellRenderer* renderer_toggle;
addons->web_widget = NULL;
addons->elements = NULL;
@ -498,11 +428,15 @@ midori_addons_init (MidoriAddons* addons)
addons->treeview = gtk_tree_view_new ();
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (addons->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_addons_treeview_render_icon_cb,
renderer_toggle = gtk_cell_renderer_toggle_new ();
gtk_tree_view_column_pack_start (column, renderer_toggle, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_toggle,
(GtkTreeCellDataFunc)midori_addons_treeview_render_tick_cb,
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 ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
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_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 */
toolitem = gtk_separator_tool_item_new ();
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));
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_CALLBACK (gtk_widget_destroyed),
&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_MODEL (liststore));
/* In case a row was selected, that selection will be cancelled
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);
}
gtk_widget_queue_draw (GTK_WIDGET (addons->treeview));
}

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-view.h"
#include "midori-viewable.h"
#include "midori-bookmark-store.h"
#include "sokoke.h"
@ -725,8 +726,10 @@ midori_bookmarks_open_in_window_activate_cb (GtkWidget* menuitem,
if (uri && *uri)
{
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (bookmarks));
g_signal_emit_by_name (browser, "new-window", uri);
MidoriBrowser* new_browser = midori_app_create_browser (bookmarks->app);
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 ();
/* 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));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
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
modify it under the terms of the GNU Lesser General Public
@ -59,6 +59,9 @@ midori_extensions_get_property (GObject* object,
GValue* value,
GParamSpec* pspec);
static void
midori_extensions_finalize (GObject* object);
static void
midori_extensions_class_init (MidoriExtensionsClass* class)
{
@ -68,6 +71,7 @@ midori_extensions_class_init (MidoriExtensionsClass* class)
gobject_class = G_OBJECT_CLASS (class);
gobject_class->set_property = midori_extensions_set_property;
gobject_class->get_property = midori_extensions_get_property;
gobject_class->finalize = midori_extensions_finalize;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
@ -93,37 +97,6 @@ midori_extensions_get_stock_id (MidoriViewable* viewable)
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*
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_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;
}
@ -173,6 +126,21 @@ midori_extensions_viewable_iface_init (MidoriViewableIface* iface)
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
midori_extensions_add_item_cb (KatzeArray* array,
MidoriExtension* extension,
@ -184,6 +152,10 @@ midori_extensions_add_item_cb (KatzeArray* array,
model = gtk_tree_view_get_model (GTK_TREE_VIEW (extensions->treeview));
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
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
@ -239,13 +211,19 @@ midori_extensions_get_property (GObject* object,
}
static void
midori_extensions_treeview_render_icon_cb (GtkTreeViewColumn* column,
midori_extensions_treeview_render_tick_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
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
@ -266,13 +244,13 @@ midori_extensions_treeview_render_text_cb (GtkTreeViewColumn* column,
name = katze_object_get_string (extension, "name");
version = katze_object_get_string (extension, "version");
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 (version);
g_free (desc);
g_object_set (renderer, "text", text,
"sensitive", midori_extension_is_active (extension),
NULL);
g_object_set (renderer, "markup", text, NULL);
g_free (text);
g_object_unref (extension);
}
@ -283,16 +261,10 @@ midori_extensions_treeview_row_activated_cb (GtkTreeView* treeview,
GtkTreeViewColumn* column,
MidoriExtensions* extensions)
{
GtkToolItem* button_enable;
GtkToolItem* button_disable;
GtkTreeModel* model;
GtkTreeIter 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;
@ -302,45 +274,198 @@ midori_extensions_treeview_row_activated_cb (GtkTreeView* treeview,
midori_extension_deactivate (extension);
else
g_signal_emit_by_name (extension, "activate", extensions->app);
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));
/* FIXME: Update only the appropriate row */
gtk_widget_queue_draw (GTK_WIDGET (treeview));
g_object_unref (extension);
}
}
static void
midori_extensions_treeview_cursor_changed_cb (GtkTreeView* treeview,
midori_extensions_preferences_activate_cb (GtkWidget* menuitem,
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;
GtkTreePath* path;
GtkTreeIter iter;
GtkToolItem* button_enable;
GtkToolItem* button_disable;
gtk_tree_view_get_cursor (treeview, &path, NULL);
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 (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
{
MidoriExtension* extension;
MidoriExtension *extension;
if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
{
gtk_tree_model_get (model, &iter, 0, &extension, -1);
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));
midori_extensions_popup (widget, NULL, extension, extensions);
g_object_unref (extension);
return TRUE;
}
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;
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
@ -349,16 +474,24 @@ midori_extensions_init (MidoriExtensions* extensions)
/* Create the treeview */
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_pixbuf;
GtkCellRenderer* renderer_toggle;
GtkListStore* liststore = gtk_list_store_new (1, G_TYPE_OBJECT);
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);
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_extensions_treeview_render_icon_cb,
renderer_toggle = gtk_cell_renderer_toggle_new ();
gtk_tree_view_column_pack_start (column, renderer_toggle, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_toggle,
(GtkTreeCellDataFunc)midori_extensions_treeview_render_tick_cb,
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 ();
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
@ -366,16 +499,39 @@ midori_extensions_init (MidoriExtensions* extensions)
extensions->treeview, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (extensions->treeview), column);
g_object_unref (liststore);
g_signal_connect (extensions->treeview, "row-activated",
G_CALLBACK (midori_extensions_treeview_row_activated_cb),
extensions);
g_signal_connect (extensions->treeview, "cursor-changed",
G_CALLBACK (midori_extensions_treeview_cursor_changed_cb),
extensions);
g_object_connect (extensions->treeview,
"signal::row-activated",
midori_extensions_treeview_row_activated_cb, extensions,
"signal::button-release-event",
midori_extensions_button_release_event_cb, extensions,
"signal::popup-menu",
midori_extensions_popup_menu_cb, extensions,
NULL);
gtk_widget_show (extensions->treeview);
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:
*

View file

@ -757,8 +757,10 @@ midori_history_open_in_window_activate_cb (GtkWidget* menuitem,
if (uri && *uri)
{
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (history));
g_signal_emit_by_name (browser, "new-window", uri);
MidoriBrowser* new_browser = midori_app_create_browser (history->app);
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_pixbuf;
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));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (plugins->treeview), FALSE);
column = gtk_tree_view_column_new ();
@ -242,76 +243,34 @@ midori_plugins_init (MidoriPlugins* plugins)
gtk_widget_show (plugins->treeview);
gtk_box_pack_start (GTK_BOX (plugins), plugins->treeview, TRUE, TRUE, 0);
if (1)
{
/* FIXME: WebKit should have API to obtain the list of plugins. */
/* FIXME: Monitor folders for newly added and removes files */
if (g_module_supported ())
GtkWidget* web_view = webkit_web_view_new ();
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 (items != NULL)
while (items[i] != NULL)
{
/* FIXME: WebKit is also looking in legacy folders,
we should have API to obtain that same list. */
gchar** plugin_dirs;
gsize i = 0;
if (g_getenv ("MOZ_PLUGIN_PATH"))
plugin_dirs = g_strsplit (g_getenv ("MOZ_PLUGIN_PATH"), ":", 0);
else
plugin_dirs = g_strsplit ("/usr/lib/mozilla/plugins", ":", 0);
while (plugin_dirs[i])
{
gchar* plugin_path;
GDir* plugin_dir;
plugin_path = g_build_filename (plugin_dirs[i], NULL);
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);
gchar** parts = g_strsplit (items[i], "|", 2);
if (parts && *parts && !g_str_equal (parts[1], "undefined"))
midori_plugins_add_item (plugins, *parts, parts[1]);
g_strfreev (parts);
i++;
}
g_strfreev (plugin_dirs);
g_strfreev (items);
}
}

View file

@ -372,6 +372,169 @@ midori_transfers_hierarchy_changed_cb (MidoriTransfers* transfers,
#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
midori_transfers_init (MidoriTransfers* transfers)
{
@ -400,9 +563,14 @@ midori_transfers_init (MidoriTransfers* transfers)
transfers->treeview, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (transfers->treeview), column);
g_object_unref (treestore);
g_signal_connect (transfers->treeview, "row-activated",
G_CALLBACK (midori_transfers_treeview_row_activated_cb),
transfers);
g_object_connect (transfers->treeview,
"signal::row-activated",
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_box_pack_start (GTK_BOX (transfers), transfers->treeview, TRUE, TRUE, 0);

View file

@ -1,2 +1,2 @@
# 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-array.c
midori/midori-browser.c
midori/midori-locationaction.c
midori/midori-locationentry.c
midori/midori-panel.c
midori/midori-websettings.c
midori/midori-view.c
@ -28,6 +30,7 @@ extensions/adblock.c
extensions/colorful-tabs.c
extensions/cookie-manager/cookie-manager.c
extensions/cookie-manager/cookie-manager-page.c
extensions/cookie-manager/main.c
extensions/feed-panel/feed-atom.c
extensions/feed-panel/feed-panel.c
extensions/feed-panel/feed-parse.c
@ -35,4 +38,7 @@ extensions/feed-panel/feed-rss.c
extensions/feed-panel/main.c
extensions/mouse-gestures/main.c
extensions/page-holder.c
extensions/shortcuts.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,
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);
gtk_init_check (&argc, &argv);

View file

@ -167,15 +167,81 @@ extension_settings (void)
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
main (int argc,
char** argv)
{
g_test_init (&argc, &argv, NULL);
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/settings", extension_settings);
load_extensions ();
return g_test_run ();
}

View file

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

View file

@ -17,6 +17,29 @@
#include "midori-bookmarks.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 \
&& !(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);
const gchar* property = g_param_spec_get_name (pspec);
void* value = NULL;
guint j;
/* Skip properties of parent classes */
if (pspec->owner_type != G_OBJECT_TYPE (object))
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);
if (type == G_TYPE_PARAM_BOOLEAN)
{
@ -84,25 +122,25 @@ properties_object_get_set (GObject* object)
{
GEnumClass* enum_class = G_ENUM_CLASS (
g_type_class_ref (pspec->value_type));
gint j;
if (pspec_is_writable (pspec))
{
gint k;
g_object_set (object, property,
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)
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,
enum_value->value_name);
if (!enum_value)
g_error ("%s.%s has no value '%s'",
G_OBJECT_TYPE_NAME (object), property, enum_value->value_name);
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
# This file is licensed under the terms of the expat license, see the file EXPAT.
import os
tests = os.listdir ('tests')
for test in tests:
folder = 'tests' + os.sep + test
@ -24,6 +26,7 @@ for test in tests:
obj = bld.new_task_gen ('cc', 'program')
obj.target = 'test-' + target
obj.includes = '.. ../midori ../panels'
obj.cflags = ['-DEXTENSION_PATH="' + os.path.abspath ('_build_/default/extensions') + '"']
obj.source = source
obj.uselib = 'UNIQUE LIBSOUP GIO GTK SQLITE WEBKIT LIBXML'
obj.uselib_local = 'panels'

231
wscript
View file

@ -19,10 +19,13 @@ import Utils
import pproc as subprocess
import os
import UnitTest
import Task
from TaskGen import extension
import misc
major = 0
minor = 1
micro = 7
micro = 8
APPNAME = 'midori'
VERSION = str (major) + '.' + str (minor) + '.' + str (micro)
@ -38,24 +41,45 @@ srcdir = '.'
blddir = '_build_'
def option_enabled (option):
if eval ('Options.options.enable_' + option):
if getattr (Options.options, 'enable_' + option):
return True
if eval ('Options.options.disable_' + option):
if getattr (Options.options, 'disable_' + option):
return False
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 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')
sys.exit (1)
def dirname_default (dirname, default):
if eval ('Options.options.' + dirname) == '':
def dirname_default (dirname, default, defname=None):
if getattr (Options.options, dirname) == '':
dirvalue = default
else:
dirvalue = eval ('Options.options.' + dirname)
conf.define (dirname, dirvalue)
dirvalue = getattr (Options.options, dirname)
if not defname:
defname = dirname
conf.define (defname, dirvalue)
return dirvalue
conf.check_tool ('compiler_cc')
@ -85,13 +109,47 @@ def configure (conf):
nls = 'no '
conf.define ('ENABLE_NLS', [0,1][nls == 'yes'])
dirname_default ('DATADIR', os.path.join (conf.env['PREFIX'], 'share'))
dirname_default ('DOCDIR', os.path.join (conf.env['DATADIR'], 'doc'))
if conf.find_program ('rsvg-convert', var='RSVG_CONVERT'):
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'))
if conf.env['PREFIX'] == '/usr':
dirname_default ('SYSCONFDIR', '/etc')
else:
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'):
conf.find_program ('gtkdoc-scan', var='GTKDOC_SCAN')
@ -107,33 +165,37 @@ def configure (conf):
else:
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:
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)
return conf.env['HAVE_' + var]
if option_enabled ('unique'):
check_pkg ('unique-1.0', '0.9', False)
unique = ['N/A', 'yes'][conf.env['HAVE_UNIQUE'] == 1]
else:
if unique != 'yes':
option_checkfatal ('unique', 'single instance')
else:
unique = 'no '
conf.define ('HAVE_UNIQUE', [0,1][unique == 'yes'])
if option_enabled ('libidn'):
check_pkg ('libidn', '1.0', False)
libidn = ['N/A','yes'][conf.env['HAVE_LIBIDN'] == 1]
else:
if libidn != 'yes':
option_checkfatal ('libidn', 'international domain names')
else:
libidn = 'no '
conf.define ('HAVE_LIBIDN', [0,1][libidn == 'yes'])
if option_enabled ('sqlite'):
check_pkg ('sqlite3', '3.0', False, var='SQLITE')
sqlite = ['N/A','yes'][conf.env['HAVE_SQLITE'] == 1]
else:
if sqlite != 'yes':
option_checkfatal ('sqlite', 'history database')
else:
sqlite = 'no '
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 ('gthread-2.0', '2.8.0', False)
check_pkg ('gio-2.0', '2.16.0')
check_pkg ('gtk+-2.0', '2.10.0', var='GTK')
check_pkg ('webkit-1.0', '1.1.1')
args = ''
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')
conf.define ('HAVE_LIBSOUP_2_25_2', 1)
check_pkg ('libxml-2.0', '2.6')
if option_enabled ('hildon'):
check_pkg ('hildon-1', mandatory=False, var='HILDON')
if conf.env['HAVE_HILDON'] == 1:
check_pkg ('libosso', mandatory=False, var='HILDON')
if check_pkg ('hildon-1', mandatory=False, var='HILDON'):
check_pkg ('libosso', var='HILDON')
hildon = ['N/A','yes'][conf.env['HAVE_HILDON'] == 1]
else:
if hildon != 'yes':
option_checkfatal ('hildon', 'Maemo integration')
else:
hildon = 'no '
conf.define ('HAVE_HILDON', [0,1][hildon == 'yes'])
conf.check (header_name='unistd.h')
conf.define ('HAVE_OSX', int(sys.platform == 'darwin'))
# Store options in env, since 'Options' is not persistent
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'):
icons = 'yes'
else:
icons = 'no '
conf.check (header_name='unistd.h')
if not conf.env['HAVE_UNIQUE']:
if Options.platform == 'win32':
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_NAME', APPNAME)
@ -205,22 +282,22 @@ def configure (conf):
Utils.pprint ('RED', 'No debugging level support for ' + compiler)
sys.exit (1)
print
print "Optional build time dependencies:"
print "Localization: " + nls + " (intltool)"
print "Icon optimizations: " + icons + " (rsvg-convert)"
print "User documentation: " + user_docs + " (docutils)"
print "API documentation: " + api_docs + " (gtk-doc)"
print
print "Single instance: " + unique + " (unique)"
print '''
Localization: %(nls)s (intltool)
Icon optimizations: %(icons)s (rsvg-convert)
Persistent history: %(sqlite)s (sqlite3)
IDN support: %(libidn)s (libidn)
User documentation: %(user_docs)s (docutils)
API documentation: %(api_docs)s (gtk-doc)
''' % locals ()
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', '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 is_maemo (): return os.path.exists ('/etc/osso-af-init/osso-gtk.defs')
def add_enable_option (option, desc, group=None, disable=False):
if group == None:
group = opt
@ -258,15 +335,44 @@ def set_options (opt):
add_enable_option ('libidn', 'international domain name support', group)
add_enable_option ('sqlite', 'history database support', 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 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')
if option_enabled ('addons'):
if bld.env['addons']:
bld.add_subdirs ('extensions')
if option_enabled ('docs'):
bld.add_group ()
if bld.env['docs']:
bld.install_files ('${DOCDIR}/' + APPNAME + '/', \
'AUTHORS ChangeLog COPYING EXPAT README TRANSLATE')
@ -295,20 +401,21 @@ def build (bld):
bld.add_subdirs ('docs/api')
bld.install_files ('${DOCDIR}/midori/api/', blddir + '/docs/api/*')
if not is_mingw (bld.env) and Options.platform != 'win32':
if bld.env['HAVE_HILDON']:
appdir = '${DATADIR}/applications/hildon'
bld.install_files ('${DATADIR}/dbus-1/services',
appdir = '${MDATADIR}/applications/hildon'
bld.install_files ('${MDATADIR}/dbus-1/services',
'data/com.nokia.' + APPNAME + '.service')
else:
appdir = '${DATADIR}/applications'
appdir = '${MDATADIR}/applications'
if bld.env['INTLTOOL']:
obj = bld.new_task_gen ('intltool_in')
obj.source = 'data/' + APPNAME + '.desktop.in'
obj.install_path = appdir
obj.flags = '-d'
obj.flags = ['-d', '-c']
bld.install_files (appdir, 'data/' + APPNAME + '.desktop')
else:
folder = os.path.dirname (bld.env['waf_config_files'][0]) + '/data'
folder = os.path.abspath (blddir + '/default/data')
Utils.check_dir (folder)
desktop = APPNAME + '.desktop'
pre = open ('data/' + desktop + '.in')
@ -335,20 +442,20 @@ def build (bld):
' -o ' + blddir + '/data/logo-shade.png ' + \
srcdir + '/data/logo-shade.svg'
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:
Utils.pprint ('BLUE', "logo-shade could not be rasterized.")
bld.install_files ('${DATADIR}/' + APPNAME + '/res', 'data/error.html')
bld.install_files ('${DATADIR}/' + APPNAME + '/res', 'data/speeddial-head.html')
bld.install_files ('${DATADIR}/' + APPNAME + '/res', 'data/speeddial.json')
bld.install_files ('${DATADIR}/' + APPNAME + '/res', 'data/mootools.js')
bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/error.html')
bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/speeddial-head.html')
bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/speeddial.json')
bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/mootools.js')
if Options.commands['check']:
bld.add_subdirs ('tests')
def shutdown ():
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
if not Options.options.destdir:
# update the pixmap cache directory
@ -394,8 +501,10 @@ def shutdown ():
Utils.pprint ('RED', "Make sure intltool is installed.")
os.chdir ('..')
elif Options.options.run:
folder = os.path.dirname (Build.bld.env['waf_config_files'][0])
folder = os.path.abspath (blddir + '/default')
try:
relfolder = folder
if not is_mingw (Build.bld.env):
relfolder = os.path.relpath (folder)
except:
pass
@ -417,8 +526,14 @@ def shutdown ():
'LC_MESSAGES' + os.sep + APPNAME + '.mo')
except:
pass
command = relfolder + os.sep + APPNAME + os.sep + APPNAME
print ext + ' ' + nls + ' ' + command
Utils.exec_command (ext + ' ' + nls + ' ' + command)
except:
Utils.pprint ('RED', "Failed to run application.")
command = ext + ' ' + nls + ' '
if is_mingw (Build.bld.env):
# This works only if everything is installed to that prefix
os.chdir (Build.bld.env['PREFIX'] + os.sep + 'bin')
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))