Imported Upstream version 0.2.2

This commit is contained in:
Ryan Niebur 2009-12-24 15:50:19 -08:00
parent 79bb58a7fe
commit 67e400912e
76 changed files with 21903 additions and 12382 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
Makefile
.waf-*
.lock-wscript
_build_
po/.intltool-merge-cache
po/POTFILES
po/stamp-it
po/*.gmo
midori.desktop

View File

@ -52,6 +52,7 @@ Translations:
it: Luca Perri <kurama_luka@yahoo.it>
ja: Masato Hashimoto <cabezon.hashimoto@gmail.com>
nl: Vincent Tunru <projects@vinnl.nl>
no: Olav Andreas Lindekleiv <olalinde@gmail.com>
pl: Przemysław Sitek <el.pescado@gazeta.pl>
pl: Lukasz Romanowicz <romanowicz88@gmail.com>
pt_PT: Sérgio Marques <smarquespt@gmail.com>

View File

@ -1,5 +1,49 @@
This file is licensed under the terms of the expat license, see the file EXPAT.
v0.2.2
+ Turn libnotify into a proper build-time dependency
+ Use Ctrl + Return to open tabs from the location entry
+ Support right-click on bookmark menu items
+ Support -e in midori -a and with multiple commands
+ Make Middle click open selection search if needed
+ Make Ctrl+C work as expected again
+ Fix order of History, Trash and Recently opened pages
+ Revise Shortcuts dialogue to fix oddities
+ Perform Form history completion case insensitive
+ Add 'Web Cache' to Delete Private data dialogue
+ Load accels from /etc/xdg if present
+ Improve XBEL format compatibility and performance
+ Fix inline find by correcting key handling
+ Add option to open panels in separate windows
+ Support Portrait orientation in Fremantle
+ Support Hildon MIME and URI handling
+ Check status before caching in Web Cache
+ Show popup menu on news feed icon if needed
+ Support Colourful Tabs with Tab Panel
+ Tweak sqlite and dbus handling for Win32
+ 'Run as web app' and 'Show in toolbar' for bookmarks
+ Add 'Small icons' toolbar style
+ Fix build with Glib < 2.20 and GTK+ < 2.12
+ Add Import bookmarks for XBEL, Opera and RDF
+ Add Open Link in Foreground/ Background Tab menu
+ Allow closing all tabs
+ Hildon file chooser support
v0.2.1
+ Fix Mouse Gestures to work after activation
+ Explicitly link to X11 to support gold
+ Implement various Hildon specific features
+ Hide the navigationbar in fullscreen
+ Implement permanent storage of form history
+ Support keyboard shortcuts like Ctrl+Tab or "a"
+ Handle SIGHUP, SIGINT, SIGTERM and SIGQUIT
+ Make creation of new windows fast
+ Introduce the Tab History List extension
+ Load icons laziy at startup to speed up startup
+ Introduce a Web Cache extension
+ Refactor and tweak the Preferences dialogue
+ Implement combos to choose external applications
v0.2.0
+ (Kinetic) drag scrolling on touchscreen devices
+ Workaround a speed dial crasher

10
INSTALL
View File

@ -16,8 +16,8 @@ You can now run Midori from the build folder like so
'./waf build --run'
This is a convenience that will load extensions as well as
localizations from the build folder.
Using --run as shown above will make sure extensions as well as
localizations are used from the build folder.
You can install it with './waf install'
@ -51,6 +51,12 @@ If you are interested in HTTP communication, try this:
Where '2' can be a level between 0 and 3.
If you are interested in (non-) touchscreen behaviour, try this:
'MIDORI_TOUCHSCREEN=1 _build_/default/midori/midori', or
'MIDORI_TOUCHSCREEN=0 _build_/default/midori/midori'
For further information a tutorial for gdb and
reading up on how you can install debugging
symbols for libraries used by Midori are recommended.

4
TODO
View File

@ -3,10 +3,8 @@ This file is licensed under the terms of the expat license, see the file EXPAT.
TODO:
. Use an update timeout in KatzePropertyProxy instead of only focus-out
. Show a loading mouse pointer
. Scroll tabs w/o switching tabs
. Import and export of the bookmarks file, or using one from a specific path
. Custom context menu actions, like in Thunar or Epiphany
. Custom tab names
. Analogus to blocked popups, blocked scripts moving layers on load (extension)
. Per-site blocking of individual elements on a page
. Statusbar icon 'cookies blocked', icon 'popups blocked'
@ -17,7 +15,6 @@ TODO:
. Mark (dogear) a selection so that it isn't cleared implicitly, multiply on one page
. 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
. Check specific bookmarks for updates automatically (extension)
. Mark "new" as well as "actually modified" tabs specially (even over sessions)
. SearchEngine: "Show in context menu"
@ -32,7 +29,6 @@ TODO:
. Style: none, compatible (b/w), default, [styles], "media", ["media" styles], ...
. Mouse pointer coordinates in the status bar (extension)
. Draw rectangle with the mouse, x/y/x2/y2 in the statusbar (extension)
. Formfill (like Opera's magic wand)
. Private browsing mode (no browsing, download or search history)
. Shared bookmarks and config
. Custom-mode, e.g. hide menubar and use help icon to have a help viewer

View File

@ -1,9 +1,9 @@
/**
* An autosuggest textbox control.
* from Nicholas C. Zakas (Author) example: http://www.nczonline.net/
* @class
* @scope public
* Adopted for Midori by Alexander V. Butenko <a.butenka@gmail.com>
*/
function AutoSuggestControl(oTextbox /*:HTMLInputElement*/,
oProvider /*:SuggestionProvider*/) {
/**
@ -28,7 +28,6 @@ function AutoSuggestControl(oTextbox /*:HTMLInputElement*/,
this.textbox /*:HTMLInputElement*/ = oTextbox;
//initialize the control
this.init();
}
/**
@ -38,13 +37,9 @@ function AutoSuggestControl(oTextbox /*:HTMLInputElement*/,
* @param aSuggestions An array of suggestion strings.
* @param bTypeAhead If the control should provide a type ahead suggestion.
*/
AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/,
bTypeAhead /*:boolean*/) {
AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/) {
//make sure theres at least one suggestion
if (aSuggestions.length > 0) {
if (bTypeAhead) {
this.typeAhead(aSuggestions[0]);
}
this.showSuggestions(aSuggestions);
} else {
this.hideSuggestions();
@ -56,17 +51,14 @@ AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/,
* @scope private
*/
AutoSuggestControl.prototype.createDropDown = function () {
var oThis = this;
//create the layer and assign styles
this.layer = document.createElement("div");
this.layer.className = "suggestions";
this.layer.style.visibility = "hidden";
this.layer.style.width = this.textbox.offsetWidth + 10;
this.layer.style.width = this.textbox.offsetWidth;
//when the user clicks on the a suggestion, get the text (innerHTML)
//and place it into a textbox
this.layer.onmousedown =
this.layer.onmouseup =
this.layer.onmouseover = function (oEvent) {
@ -82,8 +74,6 @@ AutoSuggestControl.prototype.createDropDown = function () {
oThis.textbox.focus();
}
};
document.body.appendChild(this.layer);
};
@ -93,7 +83,6 @@ AutoSuggestControl.prototype.createDropDown = function () {
* @return The left coordinate of the textbox in pixels.
*/
AutoSuggestControl.prototype.getLeft = function () /*:int*/ {
var oNode = this.textbox;
var iLeft = 0;
@ -148,8 +137,7 @@ AutoSuggestControl.prototype.handleKeyUp = function (oEvent /*:Event*/) {
var iKeyCode = oEvent.keyCode;
//for backspace (8) and delete (46), shows suggestions without typeahead
if (iKeyCode == 8 || iKeyCode == 46) {
this.provider.requestSuggestions(this, false);
this.provider.requestSuggestions(this);
//make sure not to interfere with non-character keys
} else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode < 46) || (iKeyCode >= 112 && iKeyCode <= 123) ) {
//ignore
@ -158,11 +146,8 @@ AutoSuggestControl.prototype.handleKeyUp = function (oEvent /*:Event*/) {
this.hideSuggestions();
} else {
//request suggestions from the suggestion provider with typeahead
this.provider.requestSuggestions(this, true);
this.provider.requestSuggestions(this);
}
};
/**
@ -195,44 +180,35 @@ AutoSuggestControl.prototype.highlightSuggestion = function (oSuggestionNode) {
* @scope private
*/
AutoSuggestControl.prototype.init = function () {
//save a reference to this object
var oThis = this;
//assign the onkeyup event handler
this.textbox.onkeyup = function (oEvent) {
//check for the proper location of the event object
if (!oEvent) {
oEvent = window.event;
}
//call the handleKeyUp() method with the event object
oThis.handleKeyUp(oEvent);
};
//assign onkeydown event handler
this.textbox.onkeydown = function (oEvent) {
//check for the proper location of the event object
if (!oEvent) {
oEvent = window.event;
}
//call the handleKeyDown() method with the event object
oThis.handleKeyDown(oEvent);
};
//assign onblur event handler (hides suggestions)
this.textbox.onblur = function () {
oThis.hideSuggestions();
};
this.textbox.onblur =
this.textbox.onclick = function () {
oThis.hideSuggestions();
};
//create the suggestions dropdown
this.createDropDown();
};
@ -274,20 +250,9 @@ AutoSuggestControl.prototype.previousSuggestion = function () {
* @param iLength The number of characters to select.
*/
AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*:int*/) {
//use text ranges for Internet Explorer
if (this.textbox.createTextRange) {
var oRange = this.textbox.createTextRange();
oRange.moveStart("character", iStart);
oRange.moveEnd("character", iLength - this.textbox.value.length);
oRange.select();
//use setSelectionRange() for Mozilla
} else if (this.textbox.setSelectionRange) {
if (this.textbox.setSelectionRange) {
this.textbox.setSelectionRange(iStart, iLength);
}
//set focus back to the textbox
this.textbox.focus();
};
@ -298,7 +263,6 @@ AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*
* @param aSuggestions An array of suggestions for the control.
*/
AutoSuggestControl.prototype.showSuggestions = function (aSuggestions /*:Array*/) {
var oDiv = null;
this.layer.innerHTML = ""; //clear contents of the layer
@ -311,59 +275,41 @@ AutoSuggestControl.prototype.showSuggestions = function (aSuggestions /*:Array*/
this.layer.style.left = this.getLeft() + "px";
this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
this.layer.style.visibility = "visible";
};
/**
* Inserts a suggestion into the textbox, highlighting the
* suggested part of the text.
* @scope private
* @param sSuggestion The suggestion for the textbox.
*/
AutoSuggestControl.prototype.typeAhead = function (sSuggestion /*:String*/) {
//check for support of typeahead functionality
if (this.textbox.createTextRange || this.textbox.setSelectionRange){
var iLen = this.textbox.value.length;
this.textbox.value = sSuggestion;
this.selectRange(iLen, sSuggestion.length);
}
};
/**
* Request suggestions for the given autosuggest control.
* @scope protected
* @param oAutoSuggestControl The autosuggest control to provide suggestions for.
*/
FormSuggestions.prototype.requestSuggestions = function (oAutoSuggestControl /*:AutoSuggestControl*/,
bTypeAhead /*:boolean*/) {
FormSuggestions.prototype.requestSuggestions = function (oAutoSuggestControl /*:AutoSuggestControl*/) {
var aSuggestions = [];
var sTextboxValue = oAutoSuggestControl.textbox.value;
var sTextboxValue = oAutoSuggestControl.textbox.value.toLowerCase();
if (!this.suggestions)
return;
if (!sTextboxValue.length)
return;
if (sTextboxValue.length > 0){
//search for matching suggestions
for (var i=0; i < this.suggestions.length; i++) {
if (this.suggestions[i].indexOf(sTextboxValue) == 0) {
aSuggestions.push(this.suggestions[i]);
}
}
//search for matching suggestions
for (var i=0; i < this.suggestions.length; i++) {
if (this.suggestions[i].toLowerCase().indexOf(sTextboxValue) == 0) {
aSuggestions.push(this.suggestions[i]);
}
}
//provide suggestions to the control
oAutoSuggestControl.autosuggest(aSuggestions, bTypeAhead);
oAutoSuggestControl.autosuggest(aSuggestions);
};
function initSuggestions () {
var inputs = document.getElementsByTagName("input");
for (i=0;i<inputs.length;i++)
{
var ename = inputs[i].getAttribute("name");
var eid = inputs[i].getAttribute("id");
if (!ename && eid)
ename=eid;
ename=eid;
if (inputs[i].type == "text")
var smth = new AutoSuggestControl(inputs[i], new FormSuggestions(ename));
}

View File

@ -1,4 +1,4 @@
.. |(version)| replace:: 0.1.6
.. |(version)| replace:: 0.2.2
'''''''
Midori
@ -9,7 +9,7 @@
-----------------------------------------
:Authors: Christian Dywan
:Date: $Date: 2009-04-14 18:00:35 +0100 (Tue, 14 Apr 2009) $
:Date: $Date: 2009-11-18 18:20:11 +0100 (Wed, 18 Nov 2009) $
:Version: |(version)|
Copyright © 2008-2009
@ -132,6 +132,8 @@ The following arguments are supported if you call Midori from a command line.
+-------+--------------------+------------------------------------------------+
| -r | --run | Run the specified filename as javascript |
+-------+--------------------+------------------------------------------------+
| -s | --snapshot + Take a snapshot of the specified URI |
+-------+--------------------+------------------------------------------------+
| -V | --version | Show version information and exit. |
+-------+--------------------+------------------------------------------------+
@ -159,8 +161,12 @@ The files stored in the primary configuration folder are the following:
+----------------+------------------------------------------------------------+
| history.db | History, sqlite3 |
+----------------+------------------------------------------------------------+
| logins | Usernames and passwords, plain text |
+----------------+------------------------------------------------------------+
| running | A file created to track whether Midori quit cleanly |
+----------------+------------------------------------------------------------+
| search | Search engines, text key file |
+----------------+------------------------------------------------------------+
| session.xbel | The current or last session, ie. open tabs, |
+----------------+------------------------------------------------------------+
| tabtrash.xbel | The 10 last closed tabs |
@ -173,10 +179,6 @@ replace the 'bookmarks.xbel' as long as it is valid XBEL/ XML.
Currently while Midori is running it will happily overwrite files as needed and
never read back any changes.
Incidentally Midori will recognize readonly files and not write modifications
to readonly files back to disk. This can be useful for kiosk systems where
particular changes shouldn't be saved.
Keyboard shortcuts
------------------
@ -190,9 +192,8 @@ The navigationbar
The navigationbar is the primary toolbar containing notably back and forward
buttons, the location entry and a search entry. Except for the location entry
any item can be removed and others can be added by right-clicking the toolbar
and using the Add and Remove menu items.
buttons, the location entry and a search entry. The "Toolbar Editor" extension
can be used to add or remove items.
The sidepanel

View File

@ -26,13 +26,47 @@
(__filter && (g_str_has_prefix (__filter, "http") \
|| g_str_has_prefix (__filter, "file")))
typedef struct
{
const gchar* page_uri;
const gchar* uri;
const gchar* query;
} Matcher;
static GHashTable* pattern;
static gchar* blockcss = NULL;
static gchar* blockcssprivate = NULL;
static gchar* blockscript = NULL;
static void
adblock_parse_file (gchar* path);
static gchar*
adblock_build_js (const gchar* style,
const gchar* private)
{
return g_strdup_printf (
"window.addEventListener ('DOMContentLoaded',"
"function () {"
" var URL = location.href;"
" var sites = new Array(); %s;"
" var public = '%s';"
" for (var i in sites) {"
" if (URL.indexOf(i) != -1) {"
" public += sites[i];"
" break;"
" }}"
" public += ' {display: none !important;}';"
" var mystyle = document.createElement('style');"
" mystyle.setAttribute('type', 'text/css');"
" mystyle.appendChild(document.createTextNode(public));"
" var head = document.getElementsByTagName('head')[0];"
" if (head) head.appendChild(mystyle);"
"}, true);",
private,
style);
}
static gchar *
adblock_fixup_regexp (gchar* src)
{
@ -45,10 +79,6 @@ adblock_fixup_regexp (gchar* src)
/* FIXME: Avoid always allocating twice the string */
s = dst = g_malloc (strlen (src) * 2);
/* |http:// means ^http:// */
if (src[0] == '|')
src[0] = '^';
while (*src)
{
switch (*src)
@ -65,6 +95,12 @@ adblock_fixup_regexp (gchar* src)
case '|':
*s++ = '\\';
break;
/* FIXME: We actually need to match :[0-9]+ or '/'. Sign means
"here could be port number or nothing". So bla.com^ will match
bla.com/ or bla.com:8080/ but not bla.com.au/ */
case '^':
*src = '?';
break;
}
*s++ = *src;
src++;
@ -102,7 +138,8 @@ adblock_reload_rules (MidoriExtension* extension)
pattern = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_regex_unref);
katze_assign (blockcss, NULL);
katze_assign (blockcss, g_strdup ("z-non-exist"));
katze_assign (blockcssprivate, g_strdup (""));
while (filters[i++] != NULL)
{
@ -130,6 +167,7 @@ adblock_reload_rules (MidoriExtension* extension)
}
g_free (filename);
}
katze_assign (blockscript, adblock_build_js (blockcss, blockcssprivate));
g_strfreev (filters);
g_free (folder);
}
@ -265,6 +303,26 @@ adblock_preferences_add_clicked_cb (GtkWidget* button,
gtk_entry_set_text (entry, "");
}
static void
adblock_preferences_edit_clicked_cb (GtkWidget* button,
GtkTreeViewColumn* column)
{
GdkEvent* event = gtk_get_current_event ();
GtkTreeView* treeview = g_object_get_data (G_OBJECT (button), "treeview");
GtkTreeModel* model;
GtkTreeIter iter;
if (katze_tree_view_get_selected_iter (treeview, &model, &iter))
{
gchar* path = gtk_tree_model_get_string_from_iter (model, &iter);
GtkTreePath* tree_path = gtk_tree_path_new_from_string (path);
/* gtk_cell_renderer_start_editing */
gtk_tree_view_set_cursor (treeview, tree_path, column, TRUE);
gtk_tree_path_free (tree_path);
g_free (path);
}
gdk_event_free (event);
}
static void
adblock_preferences_remove_clicked_cb (GtkWidget* button,
GtkTreeView* treeview)
@ -280,7 +338,11 @@ static gboolean
adblock_activate_link_cb (GtkWidget* label,
const gchar* uri)
{
return sokoke_show_uri (gtk_widget_get_screen (label), uri, GDK_CURRENT_TIME, NULL);
MidoriBrowser* browser = midori_browser_get_for_widget (label);
gint n = midori_browser_add_uri (browser, uri);
if (n > -1)
midori_browser_set_current_page (browser, n);
return n > -1;
}
#endif
@ -316,7 +378,9 @@ adblock_get_preferences_dialog (MidoriExtension* extension)
dialog = gtk_dialog_new_with_buttons (dialog_title, GTK_WINDOW (browser),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
#if !HAVE_OSX
#if !HAVE_HILDON
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
#endif
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
#endif
NULL);
@ -417,8 +481,10 @@ adblock_get_preferences_dialog (MidoriExtension* extension)
G_CALLBACK (adblock_preferences_add_clicked_cb), liststore);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
button = gtk_button_new_from_stock (GTK_STOCK_EDIT);
g_object_set_data (G_OBJECT (button), "treeview", treeview);
g_signal_connect (button, "clicked",
G_CALLBACK (adblock_preferences_edit_clicked_cb), column);
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_clicked_cb), treeview);
@ -488,11 +554,39 @@ adblock_browser_populate_tool_menu_cb (MidoriBrowser* browser,
}
static gboolean
adblock_is_matched (const gchar* patt,
adblock_is_matched (const gchar* opts,
const GRegex* regex,
const gchar* uri)
Matcher* data)
{
return g_regex_match_full (regex, uri, -1, 0, 0, NULL, NULL);
gchar* patt;
patt = g_strdup (data->uri);
/* TODO: To figure out
if (g_regex_match_simple ("type=fulluri,", opts, G_REGEX_UNGREEDY, G_REGEX_MATCH_NOTEMPTY))
patt = g_strdup (data->uri);
else
patt = g_strdup (data->query);
*/
if (g_regex_match_full (regex, patt, -1, 0, 0, NULL, NULL))
{
if (g_regex_match_simple (",third-party", opts,
G_REGEX_CASELESS, G_REGEX_MATCH_NOTEMPTY))
{
if (data->page_uri && g_regex_match_full (regex, data->page_uri, -1, 0, 0, NULL, NULL))
{
g_free (patt);
return FALSE;
}
}
/* TODO: Domain opt check */
g_free (patt);
return TRUE;
}
else
{
g_free (patt);
return FALSE;
}
}
#if HAVE_WEBKIT_RESOURCE_REQUEST
@ -502,15 +596,53 @@ adblock_resource_request_starting_cb (WebKitWebView* web_view,
WebKitWebResource* web_resource,
WebKitNetworkRequest* request,
WebKitNetworkResponse* response,
MidoriView* view)
GtkWidget* image)
{
const gchar* uri = webkit_network_request_get_uri (request);
if (!strncmp (uri, "data", 4))
Matcher data;
const char *page_uri;
const gchar* uri;
SoupMessage* msg;
SoupURI* soup_uri;
uri = webkit_network_request_get_uri (request);
if (!strncmp (uri, "data", 4) || !strncmp (uri, "file", 4))
return;
if (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched, (char*)uri))
msg = webkit_network_request_get_message (request);
if (!msg)
return;
if (msg->method && !strncmp (msg->method, "POST", 4))
return;
soup_uri = soup_uri_new (uri);
if (soup_uri->query)
data.query = g_strdup_printf ("%s?%s", soup_uri->path, soup_uri->query);
else
data.query = g_strdup (soup_uri->path);
soup_uri_free (soup_uri);
data.uri = uri;
page_uri = webkit_web_view_get_uri (web_view);
if (!page_uri || !strcmp (page_uri, "about:blank"))
page_uri = uri;
data.page_uri = page_uri;
if (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched, &data))
{
#if 0
gchar* text;
if (gtk_widget_get_has_tooltip (image))
text = g_strdup_printf ("%s\n%s", gtk_widget_get_tooltip_text (image), uri);
else
text = g_strdup_printf ("Blocked content: \n%s", uri);
gtk_widget_set_tooltip_text (image, text);
g_free (text);
#endif
webkit_network_request_set_uri (request, "about:blank");
/* TODO: Need to figure out how to indicate what was blocked */
}
}
#else
@ -518,10 +650,34 @@ static void
adblock_session_request_queued_cb (SoupSession* session,
SoupMessage* msg)
{
SoupURI* soup_uri = soup_message_get_uri (msg);
gchar* uri = soup_uri ? soup_uri_to_string (soup_uri, FALSE) : g_strdup ("");
if (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched, uri))
Matcher data;
SoupURI* soup_uri;
gchar* uri;
gchar* page_uri;
if (msg->method && !strncmp (msg->method, "POST", 4))
return;
/* FIXME: There is a crasher somewhere introduced with the refactoring */
soup_uri = soup_message_get_uri (msg);
uri = soup_uri_to_string (soup_uri, FALSE);
if (soup_uri->query)
data.query = g_strdup_printf ("%s?%s", soup_uri->path, soup_uri->query);
else
data.query = g_strdup (soup_uri->path);
data.uri = uri;
page_uri = NULL; /* FIXME */
if (!page_uri || !strcmp (page_uri, "about:blank"))
page_uri = uri;
data.page_uri = page_uri;
if (g_hash_table_find (pattern, (GHRFunc) adblock_is_matched, &data))
{
/* FIXME: Update image tooltip */
soup_uri = soup_uri_new ("http://.invalid");
soup_message_set_uri (msg, soup_uri);
soup_uri_free (soup_uri);
@ -530,22 +686,6 @@ adblock_session_request_queued_cb (SoupSession* session,
}
#endif
static gchar*
adblock_build_js (gchar* style)
{
return g_strdup_printf (
"window.addEventListener ('DOMContentLoaded',"
"function () {"
"var mystyle = document.createElement(\"style\");"
"mystyle.setAttribute(\"type\", \"text/css\");"
"mystyle.appendChild(document.createTextNode('%s'));"
"var head = document.getElementsByTagName(\"head\")[0];"
"if (head) head.appendChild(mystyle);"
"else document.documentElement.insertBefore(mystyle, document.documentElement.firstChild);"
"}, true);",
style);
}
static void
adblock_window_object_cleared_cb (GtkWidget* web_view,
WebKitWebFrame* web_frame,
@ -557,26 +697,28 @@ adblock_window_object_cleared_cb (GtkWidget* web_view,
static void
adblock_add_tab_cb (MidoriBrowser* browser,
MidoriView* view)
MidoriView* view,
GtkWidget* image)
{
GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view));
g_signal_connect (web_view, "window-object-cleared",
G_CALLBACK (adblock_window_object_cleared_cb), 0);
#if HAVE_WEBKIT_RESOURCE_REQUEST
g_signal_connect (web_view, "resource-request-starting",
G_CALLBACK (adblock_resource_request_starting_cb), view);
G_CALLBACK (adblock_resource_request_starting_cb), image);
#endif
}
static void
adblock_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser);
GtkWidget* image);
static void
adblock_add_tab_foreach_cb (MidoriView* view,
MidoriBrowser* browser)
MidoriBrowser* browser,
GtkWidget* image)
{
adblock_add_tab_cb (browser, view);
adblock_add_tab_cb (browser, view, image);
}
static void
@ -584,13 +726,88 @@ adblock_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
GtkWidget* statusbar;
GtkWidget* image;
statusbar = katze_object_get_object (browser, "statusbar");
#if 0
image = gtk_image_new_from_stock (STOCK_IMAGE, GTK_ICON_SIZE_MENU);
gtk_widget_show (image);
gtk_box_pack_start (GTK_BOX (statusbar), image, FALSE, FALSE, 3);
#else
image = GTK_WIDGET (browser);
#endif
midori_browser_foreach (browser,
(GtkCallback)adblock_add_tab_foreach_cb, browser);
g_signal_connect (browser, "add-tab", G_CALLBACK (adblock_add_tab_cb), 0);
(GtkCallback)adblock_add_tab_foreach_cb, image);
g_signal_connect (browser, "add-tab",
G_CALLBACK (adblock_add_tab_cb), image);
g_signal_connect (browser, "populate-tool-menu",
G_CALLBACK (adblock_browser_populate_tool_menu_cb), extension);
g_signal_connect (extension, "deactivate",
G_CALLBACK (adblock_deactivate_cb), browser);
G_CALLBACK (adblock_deactivate_cb), image);
g_object_unref (statusbar);
}
static void
adblock_compile_regexp (GHashTable* tbl,
gchar* patt,
gchar* opts)
{
GRegex* regex;
GError* error = NULL;
/* TODO: Play with optimization flags */
regex = g_regex_new (patt, G_REGEX_OPTIMIZE,
G_REGEX_MATCH_NOTEMPTY, &error);
if (!error)
g_hash_table_insert (tbl, opts, regex);
else
{
g_warning ("%s: %s", G_STRFUNC, error->message);
g_error_free (error);
}
}
static void
adblock_add_url_pattern (gchar* format,
gchar* type,
gchar* line)
{
gchar** data;
gchar* patt;
gchar* fixed_patt;
gchar* format_patt;
gchar* opts;
data = g_strsplit (line, "$", -1);
if (data && data[0] && data[1] && data[2])
{
patt = g_strdup_printf ("%s%s", data[0], data[1]);
opts = g_strdup_printf ("type=%s,regexp=%s,%s", type, patt, data[2]);
}
else if (data && data[0] && data[1])
{
patt = g_strdup (data[0]);
opts = g_strdup_printf ("type=%s,regexp=%s,%s", type, patt, data[1]);
}
else
{
patt = g_strdup (data[0]);
opts = g_strdup_printf ("type=%s,regexp=%s", type, patt);
}
fixed_patt = adblock_fixup_regexp (patt);
format_patt = g_strdup_printf (format, fixed_patt);
/* g_debug ("got: %s opts %s", format_patt, opts); */
adblock_compile_regexp (pattern, format_patt, opts);
g_strfreev (data);
g_free (patt);
g_free (fixed_patt);
g_free (format_patt);
}
static void
@ -600,11 +817,41 @@ adblock_frame_add (gchar* line)
(void)*line++;
(void)*line++;
new_blockcss = g_strdup_printf ("%s %s { display: none !important; }",
blockcss, line);
new_blockcss = g_strdup_printf ("%s, %s", blockcss, line);
katze_assign (blockcss, new_blockcss);
}
static void
adblock_frame_add_private (const gchar* line,
const gchar* sep)
{
gchar* new_blockcss;
gchar** data;
data = g_strsplit (line, sep, 2);
if (strstr (data[0],","))
{
gchar** domains;
gint max, i;
domains = g_strsplit (data[0], ",", -1);
for (max = i = 0; domains[i]; i++)
{
new_blockcss = g_strdup_printf ("%s;\nsites['%s']+=',%s'",
blockcssprivate, g_strstrip (domains[i]), data[1]);
katze_assign (blockcssprivate, new_blockcss);
}
g_strfreev (domains);
}
else
{
new_blockcss = g_strdup_printf ("%s;\nsites['%s']+=',%s'",
blockcssprivate, data[0], data[1]);
katze_assign (blockcssprivate, new_blockcss);
}
g_strfreev (data);
}
static gchar*
adblock_parse_line (gchar* line)
{
@ -617,97 +864,108 @@ adblock_parse_line (gchar* line)
/* FIXME: No support for whitelisting */
if (line[0] == '@' && line[1] == '@')
return NULL;
/* FIXME: What is this? */
if (line[0] == '|' && line[1] == '|')
/* FIXME: No support for [include] and [exclude] tags */
if (line[0] == '[')
return NULL;
/* ditto */
if (strstr (line,"$"))
return NULL;
/* Got block hider */
if (line[0] == '#' && line[1] == '#' && (line[2] == '.'||line[2] == '#'||line[2] == 'a'))
/* Got CSS block hider */
if (line[0] == '#' && line[1] == '#' )
{
adblock_frame_add (line);
return NULL;
}
/* FIXME: Do we have smth else starting with ##? */
if (line[0] == '#' && line[1] == '#')
/* Got CSS block hider. Workaround */
if (line[0] == '#')
return NULL;
/* FIXME: No support for per domain element hiding */
/* Got per domain CSS hider rule */
if (strstr (line,"##"))
{
adblock_frame_add_private (line,"##");
return NULL;
/* FIXME: No support for [include] and [exclude] tags */
if (line[0] == '[')
}
/* Got per domain CSS hider rule. Workaround */
if (strstr (line,"#"))
{
adblock_frame_add_private (line,"#");
return NULL;
return adblock_fixup_regexp (line);
}
/* Got URL blocker rule */
if (line[0] == '|' && line[1] == '|' )
{
(void)*line++;
(void)*line++;
adblock_add_url_pattern ("^https?://([a-z0-9\\.]+)?%s", "fulluri", line);
return NULL;
}
if (line[0] == '|')
{
(void)*line++;
adblock_add_url_pattern ("^%s", "fulluri", line);
return NULL;
}
adblock_add_url_pattern ("%s", "uri", line);
return line;
}
static void
adblock_parse_file (gchar* path)
{
FILE* file;
gchar line[500];
if ((file = g_fopen (path, "r")))
{
gchar line[500];
GRegex* regex;
while (fgets (line, 500, file))
{
GError* error = NULL;
gchar* parsed;
parsed = adblock_parse_line (line);
if (!parsed)
continue;
regex = g_regex_new (parsed, G_REGEX_OPTIMIZE,
G_REGEX_MATCH_NOTEMPTY, &error);
if (error)
{
g_warning ("%s: %s", G_STRFUNC, error->message);
g_error_free (error);
g_free (parsed);
}
else
g_hash_table_insert (pattern, parsed, regex);
}
katze_assign (blockscript, adblock_build_js (blockcss));
adblock_parse_line (line);
fclose (file);
}
}
static void
adblock_deactivate_tabs (MidoriView* view,
MidoriBrowser* browser)
adblock_deactivate_tabs (MidoriView* view,
GtkWidget* image)
{
GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view));
MidoriBrowser* browser = midori_browser_get_for_widget (image);
g_signal_handlers_disconnect_by_func (
browser, adblock_add_tab_cb, 0);
g_signal_handlers_disconnect_by_func (
web_view, adblock_window_object_cleared_cb, 0);
#if HAVE_WEBKIT_RESOURCE_REQUEST
g_signal_handlers_disconnect_by_func (
web_view, adblock_resource_request_starting_cb, view);
#else
g_signal_handlers_disconnect_by_func (
webkit_get_default_session (), adblock_session_request_queued_cb, NULL);
web_view, adblock_resource_request_starting_cb, image);
#endif
#if 0
gtk_widget_destroy (image);
#endif
}
static void
adblock_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser)
GtkWidget* image)
{
MidoriBrowser* browser = midori_browser_get_for_widget (image);
MidoriApp* app = midori_extension_get_app (extension);
#if !HAVE_WEBKIT_RESOURCE_REQUEST
g_signal_handlers_disconnect_matched (webkit_get_default_session (),
G_SIGNAL_MATCH_FUNC,
g_signal_lookup ("request-queued", SOUP_TYPE_SESSION), 0,
NULL, adblock_session_request_queued_cb, NULL);
#endif
g_signal_handlers_disconnect_by_func (
browser, adblock_browser_populate_tool_menu_cb, extension);
g_signal_handlers_disconnect_by_func (
extension, adblock_deactivate_cb, browser);
g_signal_handlers_disconnect_by_func (
app, adblock_app_add_browser_cb, extension);
midori_browser_foreach (browser, (GtkCallback)adblock_deactivate_tabs, browser);
midori_browser_foreach (browser, (GtkCallback)adblock_deactivate_tabs, image);
katze_assign (blockcss, NULL);
katze_assign (blockcssprivate, NULL);
g_hash_table_destroy (pattern);
}
@ -768,6 +1026,7 @@ test_adblock_pattern (void)
temp = g_file_open_tmp ("midori_adblock_match_test_XXXXXX", &filename, NULL);
/* TODO: Update some tests and add new ones. */
g_file_set_contents (filename,
"*ads.foo.bar*\n"
"*ads.bogus.name*\n"

View File

@ -23,12 +23,6 @@ colorful_tabs_view_notify_uri_cb (MidoriView* view,
GdkColor color;
label = midori_view_get_proxy_tab_label (view);
if (!midori_extension_get_boolean (extension, "tint"))
{
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, NULL);
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, NULL);
return;
}
/* Find a color that is unique to an address. We merely compute
a hash value, pick the first 6 + 1 characters and turn the
@ -60,45 +54,35 @@ colorful_tabs_view_notify_uri_cb (MidoriView* view,
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, NULL);
}
}
static void
colorful_tabs_browser_foreach_cb (GtkWidget* view,
colorful_tabs_browser_add_tab_cb (MidoriBrowser* browser,
GtkWidget* view,
MidoriExtension* extension)
{
colorful_tabs_view_notify_uri_cb (MIDORI_VIEW (view), NULL, extension);
}
static void
colorful_tabs_button_toggled_cb (GtkWidget* button,
MidoriExtension* extension)
{
MidoriBrowser* browser = midori_browser_get_for_widget (button);
midori_extension_set_boolean (extension, "tint",
!midori_extension_get_boolean (extension, "tint"));
midori_browser_foreach (browser,
(GtkCallback)colorful_tabs_browser_foreach_cb, extension);
}
static void
colorful_tabs_browser_add_tab_cb (MidoriBrowser* browser,
MidoriView* view,
MidoriExtension* extension)
{
g_signal_connect (view, "notify::uri",
G_CALLBACK (colorful_tabs_view_notify_uri_cb), extension);
}
static void
colorful_tabs_deactivate_cb (MidoriExtension* extension,
GtkWidget* bbox)
MidoriBrowser* browser)
{
guint i;
GtkWidget* view;
g_signal_handlers_disconnect_by_func (
extension, colorful_tabs_deactivate_cb, bbox);
/* FIXME: Disconnect signals */
midori_browser_foreach (midori_browser_get_for_widget (bbox),
(GtkCallback)colorful_tabs_browser_foreach_cb, extension);
gtk_widget_destroy (bbox);
extension, colorful_tabs_deactivate_cb, browser);
i = 0;
while ((view = midori_browser_get_nth_tab (browser, i++)))
{
GtkWidget* label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view));
gtk_event_box_set_visible_window (GTK_EVENT_BOX (label), FALSE);
gtk_widget_modify_bg (label, GTK_STATE_NORMAL, NULL);
gtk_widget_modify_bg (label, GTK_STATE_ACTIVE, NULL);
g_signal_handlers_disconnect_by_func (
view, colorful_tabs_view_notify_uri_cb, extension);
}
}
static void
@ -106,26 +90,16 @@ colorful_tabs_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
GtkWidget* statusbar;
GtkWidget* bbox;
GtkWidget* button;
guint i;
GtkWidget* view;
statusbar = katze_object_get_object (browser, "statusbar");
bbox = gtk_hbox_new (FALSE, 0);
button = gtk_check_button_new_with_label (_("Tint tabs distinctly"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
midori_extension_get_boolean (extension, "tint"));
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_signal_connect (button, "toggled",
G_CALLBACK (colorful_tabs_button_toggled_cb), extension);
i = 0;
while ((view = midori_browser_get_nth_tab (browser, i++)))
colorful_tabs_browser_add_tab_cb (browser, view, extension);
g_signal_connect (browser, "add-tab",
G_CALLBACK (colorful_tabs_browser_add_tab_cb), extension);
g_signal_connect (extension, "deactivate",
G_CALLBACK (colorful_tabs_deactivate_cb), bbox);
G_CALLBACK (colorful_tabs_deactivate_cb), browser);
}
static void
@ -142,6 +116,8 @@ colorful_tabs_activate_cb (MidoriExtension* extension,
colorful_tabs_app_add_browser_cb (app, browser, extension);
g_signal_connect (app, "add-browser",
G_CALLBACK (colorful_tabs_app_add_browser_cb), extension);
g_object_unref (browsers);
}
MidoriExtension*
@ -153,7 +129,6 @@ extension_init (void)
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
midori_extension_install_boolean (extension, "tint", FALSE);
g_signal_connect (extension, "activate",
G_CALLBACK (colorful_tabs_activate_cb), NULL);

View File

@ -91,7 +91,7 @@ feed_panel_treeview_render_icon_cb (GtkTreeViewColumn* column,
uri = katze_item_get_uri (pitem);
if (uri)
{
pixbuf = katze_net_load_icon (panel->net, uri, NULL, NULL, NULL);
pixbuf = katze_load_cached_icon (uri, NULL);
if (!pixbuf)
pixbuf = panel->pixbuf;
}
@ -509,8 +509,11 @@ feed_panel_open_in_window_activate_cb (GtkWidget* menuitem,
if (uri && *uri)
{
MidoriBrowser* browser;
MidoriBrowser* new_browser;
browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
g_signal_emit_by_name (browser, "new-window", uri);
g_signal_emit_by_name (browser, "new-window", NULL, &new_browser);
midori_browser_add_uri (new_browser, uri);
}
}
@ -550,8 +553,8 @@ feed_panel_popup (GtkWidget* widget,
item, feed_panel_delete_activate_cb, panel);
}
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
katze_widget_popup (widget, GTK_MENU (menu),
event, KATZE_MENU_POSITION_CURSOR);
}
static gboolean

View File

@ -1,5 +1,6 @@
/*
Copyright (C) 2009 Alexander Butenko <a.butenka@gmail.com>
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
@ -7,18 +8,23 @@
version 2.1 of the License, or (at your option) any later version.
*/
#define MAXCHARS 20
#define MAXCHARS 60
#define MINCHARS 2
#include <midori/midori.h>
#include "config.h"
#include "midori/sokoke.h"
#include <glib/gstdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SQLITE
#include <sqlite3.h>
#endif
static GHashTable* global_keys;
static gchar* jsforms;
@ -30,7 +36,7 @@ formhistory_prepare_js ()
guint i;
gchar* file;
gchar* data_path = g_build_filename (MDATADIR, PACKAGE_NAME, NULL);
gchar* data_path = g_build_filename (MDATADIR, PACKAGE_NAME, "res", NULL);
file = g_build_filename (data_path,"/autosuggestcontrol.js",NULL);
if (!g_file_test (file, G_FILE_TEST_EXISTS))
return FALSE;
@ -72,6 +78,22 @@ formhistory_prepare_js ()
return TRUE;
}
static gchar*
formhistory_fixup_value (char* value)
{
guint i = 0;
g_strchomp (value);
while (value[i])
{
if (value[i] == '\n')
value[i] = ' ';
else if (value[i] == '"')
value[i] = '\'';
i++;
}
return value;
}
static gchar*
formhistory_build_js ()
{
@ -95,11 +117,133 @@ formhistory_build_js ()
suggestions,
jsforms);
g_free (suggestions);
return script;
return script;
}
static void
formhistory_update_main_hash (GHashTable* keys)
formhistory_update_database (gpointer db,
const gchar* key,
const gchar* value)
{
#if HAVE_SQLITE
gchar* sqlcmd;
gchar* errmsg;
gint success;
sqlcmd = sqlite3_mprintf ("INSERT INTO forms VALUES"
"('%q', '%q', '%q')",
NULL, key, value);
success = sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg);
sqlite3_free (sqlcmd);
if (success != SQLITE_OK)
{
g_printerr (_("Failed to add form value: %s\n"), errmsg);
g_free (errmsg);
return;
}
#endif
}
static gboolean
formhistory_update_main_hash (gchar* key,
gchar* value)
{
guint length;
gchar* tmp;
if (!(value && *value))
return FALSE;
length = strlen (value);
if (length > MAXCHARS || length < MINCHARS)
return FALSE;
formhistory_fixup_value (value);
if ((tmp = g_hash_table_lookup (global_keys, (gpointer)key)))
{
gchar* rvalue = g_strdup_printf ("\"%s\"",value);
if (!g_regex_match_simple (rvalue, tmp,
G_REGEX_CASELESS, G_REGEX_MATCH_NOTEMPTY))
{
gchar* new_value = g_strdup_printf ("%s%s,", tmp, rvalue);
g_hash_table_insert (global_keys, g_strdup (key), new_value);
g_free (rvalue);
}
else
{
g_free (rvalue);
return FALSE;
}
}
else
{
gchar* new_value = g_strdup_printf ("\"%s\",",value);
g_hash_table_replace (global_keys, g_strdup (key), new_value);
}
return TRUE;
}
#if WEBKIT_CHECK_VERSION (1, 1, 4)
static gboolean
formhistory_navigation_decision_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
WebKitNetworkRequest* request,
WebKitWebNavigationAction* action,
WebKitWebPolicyDecision* decision,
MidoriExtension* extension)
{
JSContextRef js_context = webkit_web_frame_get_global_context (web_frame);
/* The script returns form data in the form "field_name|,|value|,|field_type".
We are handling only input fields with 'text' or 'password' type.
The field separator is "|||" */
const gchar* script = "function dumpForm (inputs) {"
" var out = '';"
" for (i=0;i<inputs.length;i++) {"
" if (inputs[i].value && (inputs[i].type == 'text' || inputs[i].type == 'password')) {"
" var ename = inputs[i].getAttribute('name');"
" var eid = inputs[i].getAttribute('id');"
" if (!ename && eid)"
" ename=eid;"
" out += ename+'|,|'+inputs[i].value +'|,|'+inputs[i].type +'|||';"
" }"
" }"
" return out;"
"}"
"dumpForm (document.getElementsByTagName('input'))";
if (webkit_web_navigation_action_get_reason (action) == WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED
|| webkit_web_navigation_action_get_reason (action) == WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED)
{
gchar* value = sokoke_js_script_eval (js_context, script, NULL);
if (value)
{
gpointer db = g_object_get_data (G_OBJECT (extension), "formhistory-db");
gchar** inputs = g_strsplit (value, "|||", 0);
guint i = 0;
while (inputs[i] != NULL)
{
gchar** parts = g_strsplit (inputs[i], "|,|", 3);
if (parts && parts[0] && parts[1] && parts[2])
{
/* FIXME: We need to handle passwords */
if (strcmp (parts[2], "password"))
{
if (formhistory_update_main_hash (parts[0], parts[1]))
formhistory_update_database (db, parts[0], parts[1]);
}
}
g_strfreev (parts);
i++;
}
g_strfreev (inputs);
g_free (value);
}
}
return FALSE;
}
#else
static void
formhistory_feed_keys (GHashTable* keys,
gpointer db)
{
GHashTableIter iter;
gchar* key;
@ -108,58 +252,38 @@ formhistory_update_main_hash (GHashTable* keys)
g_hash_table_iter_init (&iter, keys);
while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&value))
{
guint length;
gchar* tmp;
if (!(value && *value))
continue;
length = strlen (value);
if (length > MAXCHARS || length < MINCHARS)
continue;
tmp = g_hash_table_lookup (global_keys, (gpointer)key);
if (tmp)
{
gchar* rvalue = g_strdup_printf ("\"%s\"",value);
if (!g_regex_match_simple (rvalue, tmp,
G_REGEX_CASELESS, G_REGEX_MATCH_NOTEMPTY))
{
gchar* new_value = g_strdup_printf ("%s%s,", tmp, rvalue);
g_hash_table_replace (global_keys, key, new_value);
}
g_free (rvalue);
}
else
{
gchar* new_value = g_strdup_printf ("\"%s\",",value);
g_hash_table_insert (global_keys, key, new_value);
}
if (formhistory_update_main_hash (key, value))
formhistory_update_database (db, key, value);
}
}
static void
formhistory_session_request_queued_cb (SoupSession* session,
SoupMessage* msg)
formhistory_session_request_queued_cb (SoupSession* session,
SoupMessage* msg,
MidoriExtension* extension)
{
gchar* method = katze_object_get_string (msg, "method");
if (method && !strncmp (method, "POST", 4))
{
/* SoupMessageHeaders* hdrs = msg->request_headers;
const gchar* referer; */
SoupMessageBody* body = msg->request_body;
if (soup_message_body_get_accumulate (body))
{
SoupBuffer* buffer = soup_message_body_flatten (body);
GHashTable* keys = soup_form_decode (body->data);
formhistory_update_main_hash (keys);
SoupBuffer* buffer;
GHashTable* keys;
gpointer db;
buffer = soup_message_body_flatten (body);
keys = soup_form_decode (body->data);
db = g_object_get_data (G_OBJECT (extension), "formhistory-db");
formhistory_feed_keys (keys, db);
soup_buffer_free (buffer);
g_hash_table_destroy (keys);
}
/* FIXME: Need a permanent storage implementation */
/* referer = soup_message_headers_get_one (hdrs, "Referer"); */
}
g_free (method);
}
#endif
static void
formhistory_window_object_cleared_cb (GtkWidget* web_view,
@ -172,15 +296,20 @@ formhistory_window_object_cleared_cb (GtkWidget* web_view,
}
static void
formhistory_add_tab_cb (MidoriBrowser* browser,
MidoriView* view)
formhistory_add_tab_cb (MidoriBrowser* browser,
MidoriView* view,
MidoriExtension* extension)
{
GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view));
SoupSession *session = webkit_get_default_session ();
g_signal_connect (web_view, "window-object-cleared",
G_CALLBACK (formhistory_window_object_cleared_cb), 0);
g_signal_connect (session, "request-queued",
G_CALLBACK (formhistory_session_request_queued_cb), 0);
G_CALLBACK (formhistory_window_object_cleared_cb), NULL);
#if WEBKIT_CHECK_VERSION (1, 1, 4)
g_signal_connect (web_view, "navigation-policy-decision-requested",
G_CALLBACK (formhistory_navigation_decision_cb), extension);
#else
g_signal_connect (webkit_get_default_session (), "request-queued",
G_CALLBACK (formhistory_session_request_queued_cb), extension);
#endif
}
static void
@ -188,10 +317,11 @@ formhistory_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser);
static void
formhistory_add_tab_foreach_cb (MidoriView* view,
MidoriBrowser* browser)
formhistory_add_tab_foreach_cb (MidoriView* view,
MidoriBrowser* browser,
MidoriExtension* extension)
{
formhistory_add_tab_cb (browser, view);
formhistory_add_tab_cb (browser, view, extension);
}
static void
@ -200,24 +330,30 @@ formhistory_app_add_browser_cb (MidoriApp* app,
MidoriExtension* extension)
{
midori_browser_foreach (browser,
(GtkCallback)formhistory_add_tab_foreach_cb, browser);
g_signal_connect (browser, "add-tab", G_CALLBACK (formhistory_add_tab_cb), 0);
(GtkCallback)formhistory_add_tab_foreach_cb, extension);
g_signal_connect (browser, "add-tab",
G_CALLBACK (formhistory_add_tab_cb), extension);
g_signal_connect (extension, "deactivate",
G_CALLBACK (formhistory_deactivate_cb), browser);
}
static void
formhistory_deactivate_tabs (MidoriView* view,
MidoriBrowser* browser)
formhistory_deactivate_tabs (MidoriView* view,
MidoriBrowser* browser,
MidoriExtension* extension)
{
GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view));
SoupSession *session = webkit_get_default_session ();
g_signal_handlers_disconnect_by_func (
browser, formhistory_add_tab_cb, 0);
browser, formhistory_add_tab_cb, extension);
g_signal_handlers_disconnect_by_func (
web_view, formhistory_window_object_cleared_cb, 0);
web_view, formhistory_window_object_cleared_cb, NULL);
#if WEBKIT_CHECK_VERSION (1, 1, 4)
g_signal_handlers_disconnect_by_func (
session, formhistory_session_request_queued_cb, 0);
web_view, formhistory_navigation_decision_cb, extension);
#else
g_signal_handlers_disconnect_by_func (
webkit_get_default_session (), formhistory_session_request_queued_cb, extension);
#endif
}
static void
@ -225,22 +361,67 @@ formhistory_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser)
{
MidoriApp* app = midori_extension_get_app (extension);
#if HAVE_SQLITE
sqlite3* db;
#endif
g_signal_handlers_disconnect_by_func (
extension, formhistory_deactivate_cb, browser);
g_signal_handlers_disconnect_by_func (
app, formhistory_app_add_browser_cb, extension);
midori_browser_foreach (browser, (GtkCallback)formhistory_deactivate_tabs, browser);
midori_browser_foreach (browser,
(GtkCallback)formhistory_deactivate_tabs, extension);
jsforms = "";
if (global_keys)
g_hash_table_destroy (global_keys);
#if HAVE_SQLITE
if ((db = g_object_get_data (G_OBJECT (extension), "formhistory-db")))
sqlite3_close (db);
#endif
}
#if HAVE_SQLITE
static int
formhistory_add_field (gpointer data,
int argc,
char** argv,
char** colname)
{
gint i;
gint ncols = 3;
/* Test whether have the right number of columns */
g_return_val_if_fail (argc % ncols == 0, 1);
for (i = 0; i < (argc - ncols) + 1; i++)
{
if (argv[i])
{
if (colname[i] && !g_ascii_strcasecmp (colname[i], "domain")
&& colname[i + 1] && !g_ascii_strcasecmp (colname[i + 1], "field")
&& colname[i + 2] && !g_ascii_strcasecmp (colname[i + 2], "value"))
{
gchar* key = argv[i + 1];
formhistory_update_main_hash (g_strdup (key), g_strdup (argv[i + 2]));
}
}
}
return 0;
}
#endif
static void
formhistory_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
#if HAVE_SQLITE
const gchar* config_dir;
gchar* filename;
sqlite3* db;
char* errmsg = NULL, *errmsg2 = NULL;
#endif
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
@ -248,6 +429,39 @@ formhistory_activate_cb (MidoriExtension* extension,
global_keys = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_free);
#if HAVE_SQLITE
config_dir = midori_extension_get_config_dir (extension);
katze_mkdir_with_parents (config_dir, 0700);
filename = g_build_filename (config_dir, "forms.db", NULL);
if (sqlite3_open (filename, &db))
{
g_warning (_("Failed to open database: %s\n"), sqlite3_errmsg (db));
sqlite3_close (db);
}
g_free (filename);
if ((sqlite3_exec (db, "CREATE TABLE IF NOT EXISTS "
"forms (domain text, field text, value text)",
NULL, NULL, &errmsg) == SQLITE_OK)
&& (sqlite3_exec (db, "SELECT domain, field, value FROM forms ",
formhistory_add_field,
NULL, &errmsg2) == SQLITE_OK))
g_object_set_data (G_OBJECT (extension), "formhistory-db", db);
else
{
if (errmsg)
{
g_critical (_("Failed to execute database statement: %s\n"), errmsg);
sqlite3_free (errmsg);
if (errmsg2)
{
g_critical (_("Failed to execute database statement: %s\n"), errmsg2);
sqlite3_free (errmsg2);
}
}
sqlite3_close (db);
}
#endif
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
@ -278,8 +492,10 @@ MidoriExtension*
extension_init (void)
{
gboolean should_init = TRUE;
gchar* ver;
const gchar* ver;
gchar* desc;
MidoriExtension* extension;
if (formhistory_prepare_js ())
{
ver = "0.1";
@ -292,7 +508,8 @@ extension_init (void)
ver = NULL;
should_init = FALSE;
}
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Form history filler"),
"description", desc,
"version", ver,

298
extensions/mouse-gestures.c Normal file
View File

@ -0,0 +1,298 @@
/*
Copyright (C) 2009 Matthias Kruk <mkruk@matthiaskruk.de>
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>
typedef struct _MouseGesture MouseGesture;
typedef enum _MouseButton MouseButton;
enum _MouseButton {
MOUSE_BUTTON_LEFT = 1,
MOUSE_BUTTON_RIGHT = 3,
MOUSE_BUTTON_MIDDLE = 2,
MOUSE_BUTTON_UNSET = 0
};
struct MouseGestureNode {
double x;
double y;
} MouseGestureNode_t;
struct _MouseGesture {
struct MouseGestureNode start;
struct MouseGestureNode middle;
struct MouseGestureNode end;
MouseButton last;
};
#define DEVIANCE 20
#define MINLENGTH 50
#define MOUSE_GESTURES_BUTTON MOUSE_BUTTON_MIDDLE
MouseGesture *gesture;
void mouse_gesture_clear (MouseGesture *g)
{
g->start.x = 0;
g->start.y = 0;
g->middle.x = 0;
g->middle.y = 0;
g->end.x = 0;
g->end.y = 0;
g->last = MOUSE_BUTTON_UNSET;
}
MouseGesture* mouse_gesture_new (void)
{
MouseGesture* g = g_new (MouseGesture, 1);
mouse_gesture_clear (g);
return g;
}
static gboolean
mouse_gestures_button_press_event_cb (GtkWidget* web_view,
GdkEvent* event,
MidoriBrowser* browser)
{
if (event->button.button == MOUSE_GESTURES_BUTTON)
{
/* If the gesture was previously cleaned,
start a new gesture and coordinates. */
if (gesture->last == MOUSE_BUTTON_UNSET)
{
gesture->start.x = event->button.x;
gesture->start.y = event->button.y;
gesture->last = event->button.button;
}
return TRUE;
}
return FALSE;
}
static gboolean
mouse_gestures_motion_notify_event_cb (GtkWidget* web_view,
GdkEvent* event,
MidoriBrowser* browser)
{
if (gesture->last != MOUSE_BUTTON_UNSET)
{
guint x, y;
x = event->motion.x;
y = event->motion.y;
if ((gesture->start.x - x < DEVIANCE && gesture->start.x - x > -DEVIANCE) ||
(gesture->start.y - y < DEVIANCE && gesture->start.y - y > -DEVIANCE))
{
gesture->middle.x = x;
gesture->middle.y = y;
}
else if ((gesture->middle.x - x < DEVIANCE && gesture->middle.x - x > -DEVIANCE) ||
(gesture->middle.y - y < DEVIANCE && gesture->middle.y - y > -DEVIANCE))
{
gesture->end.x = x;
gesture->end.y = y;
}
return TRUE;
}
return FALSE;
}
static gboolean
mouse_gestures_button_release_event_cb (GtkWidget* web_view,
GdkEvent* event,
MidoriBrowser* browser)
{
/* All mouse gestures will use this mouse button */
if (gesture->last == MOUSE_GESTURES_BUTTON)
{
/* The initial horizontal move is between the bounds */
if ((gesture->middle.x - gesture->start.x < DEVIANCE) &&
(gesture->middle.x - gesture->start.x > -DEVIANCE))
{
/* We initially moved down more than MINLENGTH pixels */
if (gesture->middle.y > gesture->start.y + MINLENGTH)
{
/* Then we the final vertical move is between the bounds and
we moved right more than MINLENGTH pixels */
if ((gesture->middle.y - gesture->end.y < DEVIANCE) &&
(gesture->middle.y - gesture->end.y > -DEVIANCE) &&
(gesture->end.x > gesture->middle.x + MINLENGTH))
/* We moved down then right: close the tab */
midori_browser_activate_action (browser, "TabClose");
/* Then we the final vertical move is between the bounds and
we moved left more than MINLENGTH pixels */
else if ((gesture->middle.y - gesture->end.y < DEVIANCE) &&
(gesture->middle.y - gesture->end.y > -DEVIANCE) &&
(gesture->end.x + MINLENGTH < gesture->middle.x))
/* We moved down then left: reload */
midori_browser_activate_action (browser, "Reload");
/* The end node was never updated, we only did a vertical move */
else if(gesture->end.y == 0 && gesture->end.x == 0)
/* We moved down then: create a new tab */
midori_browser_activate_action (browser, "TabNew");
}
/* We initially moved up more than MINLENGTH pixels */
else if (gesture->middle.y + MINLENGTH < gesture->start.y)
{
/* The end node was never updated, we only did a vertical move */
if (gesture->end.y == 0 && gesture->end.x == 0)
/* We moved up: stop */
midori_browser_activate_action (browser, "Stop");
}
}
/* The initial horizontal move is between the bounds */
else if ((gesture->middle.y - gesture->start.y < DEVIANCE) &&
(gesture->middle.y - gesture->start.y > -DEVIANCE))
{
/* We initially moved right more than MINLENGTH pixels */
if (gesture->middle.x > gesture->start.x + MINLENGTH)
{
/* The end node was never updated, we only did an horizontal move */
if (gesture->end.x == 0 && gesture->end.y == 0)
/* We moved right: forward */
midori_browser_activate_action (browser, "Forward");
}
/* We initially moved left more than MINLENGTH pixels */
else if (gesture->middle.x + MINLENGTH < gesture->start.x)
{
/* The end node was never updated, we only did an horizontal move */
if (gesture->end.x == 0 && gesture->end.y == 0)
/* We moved left: back */
midori_browser_activate_action (browser, "Back");
}
}
mouse_gesture_clear (gesture);
return TRUE;
}
return FALSE;
}
static void
mouse_gestures_add_tab_cb (MidoriBrowser* browser,
MidoriView* view,
MidoriExtension* extension)
{
GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view));
g_object_connect (web_view,
"signal::button-press-event",
mouse_gestures_button_press_event_cb, browser,
"signal::motion-notify-event",
mouse_gestures_motion_notify_event_cb, browser,
"signal::button-release-event",
mouse_gestures_button_release_event_cb, browser,
NULL);
}
static void
mouse_gestures_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser);
static void
mouse_gestures_add_tab_foreach_cb (MidoriView* view,
MidoriBrowser* browser,
MidoriExtension* extension)
{
mouse_gestures_add_tab_cb (browser, view, extension);
}
static void
mouse_gestures_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
midori_browser_foreach (browser,
(GtkCallback)mouse_gestures_add_tab_foreach_cb, extension);
g_signal_connect (browser, "add-tab",
G_CALLBACK (mouse_gestures_add_tab_cb), extension);
g_signal_connect (extension, "deactivate",
G_CALLBACK (mouse_gestures_deactivate_cb), browser);
}
static void
mouse_gestures_deactivate_tabs (MidoriView* view,
MidoriBrowser* browser)
{
GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view));
g_object_disconnect (web_view,
"any_signal::button-press-event",
mouse_gestures_button_press_event_cb, browser,
"any_signal::motion-notify-event",
mouse_gestures_motion_notify_event_cb, browser,
"any_signal::button-release-event",
mouse_gestures_button_release_event_cb, browser,
NULL);
}
static void
mouse_gestures_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser)
{
MidoriApp* app = midori_extension_get_app (extension);
g_signal_handlers_disconnect_by_func (
extension, mouse_gestures_deactivate_cb, browser);
g_signal_handlers_disconnect_by_func (
app, mouse_gestures_app_add_browser_cb, extension);
g_signal_handlers_disconnect_by_func (
browser, mouse_gestures_add_tab_cb, extension);
midori_browser_foreach (browser,
(GtkCallback)mouse_gestures_deactivate_tabs, browser);
g_free (gesture);
}
static void
mouse_gestures_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
gesture = mouse_gesture_new ();
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
mouse_gestures_app_add_browser_cb (app, browser, extension);
g_signal_connect (app, "add-browser",
G_CALLBACK (mouse_gestures_app_add_browser_cb), extension);
g_object_unref (browsers);
}
MidoriExtension*
extension_init (void)
{
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Mouse Gestures"),
"description", _("Control Midori by moving the mouse"),
"version", "0.1",
"authors", "Matthias Kruk <mkruk@matthiaskruk.de>", NULL);
midori_extension_install_integer (extension, "button", MOUSE_GESTURES_BUTTON);
g_signal_connect (extension, "activate",
G_CALLBACK (mouse_gestures_activate_cb), NULL);
return extension;
}

View File

@ -1,255 +0,0 @@
/*
Copyright (C) 2009 Matthias Kruk <mkruk@matthiaskruk.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 "mouse-gestures.h"
#define MOUSE_GESTURES_VERSION "0.1"
#define DEVIANCE 20
#define MINLENGTH 50
/* #define __MOUSE_GESTURES_DEBUG__ */
MouseGesture *gesture;
void mouse_gesture_clear (MouseGesture *g)
{
g->start.x = 0;
g->start.y = 0;
g->middle.x = 0;
g->middle.y = 0;
g->end.x = 0;
g->end.y = 0;
g->last = MOUSE_BUTTON_UNSET;
}
MouseGesture* mouse_gesture_new (void)
{
MouseGesture *g = g_new (MouseGesture, 1);
mouse_gesture_clear (g);
return g;
}
static gboolean mouse_gestures_handle_events (GtkWidget *widget,
GdkEvent *event,
MidoriBrowser *browser)
{
/* A button was pressed */
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)
{
gesture->start.x = event->button.x;
gesture->start.y = event->button.y;
gesture->last = event->button.button;
}
return TRUE;
}
else if (event->type == GDK_MOTION_NOTIFY)
{
if (gesture->last != MOUSE_BUTTON_UNSET)
{
guint x, y;
x = event->motion.x;
y = event->motion.y;
if ((gesture->start.x - x < DEVIANCE && gesture->start.x - x > -DEVIANCE) ||
(gesture->start.y - y < DEVIANCE && gesture->start.y - y > -DEVIANCE))
{
gesture->middle.x = x;
gesture->middle.y = y;
}
else if ((gesture->middle.x - x < DEVIANCE && gesture->middle.x - x > -DEVIANCE) ||
(gesture->middle.y - y < DEVIANCE && gesture->middle.y - y > -DEVIANCE))
{
gesture->end.x = x;
gesture->end.y = y;
}
}
return TRUE;
}
else if (event->type == GDK_BUTTON_RELEASE)
{
/* All mouse gestures will use the middle mouse button */
if (gesture->last == MOUSE_BUTTON_MIDDLE)
{
/* The initial horizontal move is between the bounds */
if ((gesture->middle.x - gesture->start.x < DEVIANCE) &&
(gesture->middle.x - gesture->start.x > -DEVIANCE))
{
/* We initially moved down more than MINLENGTH pixels */
if (gesture->middle.y > gesture->start.y + MINLENGTH)
{
/* Then we the final vertical move is between the bounds and
we moved right more than MINLENGTH pixels */
if ((gesture->middle.y - gesture->end.y < DEVIANCE) &&
(gesture->middle.y - gesture->end.y > -DEVIANCE) &&
(gesture->end.x > gesture->middle.x + MINLENGTH))
{
/* We moved down then right: close the tab */
midori_browser_activate_action (browser, "TabClose");
}
/* Then we the final vertical move is between the bounds and
we moved left more than MINLENGTH pixels */
else if ((gesture->middle.y - gesture->end.y < DEVIANCE) &&
(gesture->middle.y - gesture->end.y > -DEVIANCE) &&
(gesture->end.x + MINLENGTH < gesture->middle.x))
{
/* We moved down then left: reload */
midori_browser_activate_action (browser, "Reload");
}
/* The end node was never updated, we only did a vertical move */
else if(gesture->end.y == 0 && gesture->end.x == 0)
{
/* We moved down then: create a new tab */
midori_browser_activate_action (browser, "TabNew");
}
}
/* We initially moved up more than MINLENGTH pixels */
else if (gesture->middle.y + MINLENGTH < gesture->start.y)
{
/* The end node was never updated, we only did a vertical move */
if (gesture->end.y == 0 && gesture->end.x == 0)
{
/* We moved up: stop */
midori_browser_activate_action (browser, "Stop");
}
}
}
/* The initial horizontal move is between the bounds */
else if ((gesture->middle.y - gesture->start.y < DEVIANCE) &&
(gesture->middle.y - gesture->start.y > -DEVIANCE))
{
/* We initially moved right more than MINLENGTH pixels */
if (gesture->middle.x > gesture->start.x + MINLENGTH)
{
/* The end node was never updated, we only did an horizontal move */
if (gesture->end.x == 0 && gesture->end.y == 0)
{
/* We moved right: forward */
midori_browser_activate_action (browser, "Forward");
}
}
/* We initially moved left more than MINLENGTH pixels */
else if (gesture->middle.x + MINLENGTH < gesture->start.x)
{
/* The end node was never updated, we only did an horizontal move */
if (gesture->end.x == 0 && gesture->end.y == 0)
{
/* We moved left: back */
midori_browser_activate_action (browser, "Back");
}
}
}
}
mouse_gesture_clear (gesture);
return TRUE;
}
else
return FALSE;
}
static void mouse_gestures_tab_cb (MidoriBrowser* browser, GtkWidget *view)
{
g_signal_connect (view, "event", G_CALLBACK (mouse_gestures_handle_events), browser);
}
static void mouse_gestures_browser_cb (MidoriApp *app, MidoriBrowser *browser)
{
g_signal_connect (browser, "add-tab", G_CALLBACK (mouse_gestures_tab_cb), NULL);
}
static void mouse_gestures_deactivate (MidoriExtension *extension, MidoriApp *app)
{
gulong signal_id;
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
signal_id = g_signal_handler_find (app, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
mouse_gestures_browser_cb, NULL);
if (signal_id != 0)
g_signal_handler_disconnect (app, signal_id);
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
{
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);
notebook = katze_object_get_object (browser, "notebook");
for (j = 0; j < gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); j++)
{
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);
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);
}
static void mouse_gestures_activate (MidoriExtension *extension, MidoriApp *app)
{
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
gesture = mouse_gesture_new ();
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
mouse_gestures_browser_cb (app, browser);
g_object_unref (browsers);
g_signal_connect (app, "add-browser",
G_CALLBACK (mouse_gestures_browser_cb), NULL);
g_signal_connect (extension, "deactivate",
G_CALLBACK (mouse_gestures_deactivate), app);
}
MidoriExtension* extension_init (void)
{
MidoriExtension* extension;
extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Mouse Gestures"),
"description", _("Control Midori by moving the mouse"),
"version", MOUSE_GESTURES_VERSION,
"authors", "Matthias Kruk <mkruk@matthiaskruk.de>", NULL);
g_signal_connect (extension, "activate",
G_CALLBACK (mouse_gestures_activate), NULL);
return extension;
}

View File

@ -1,37 +0,0 @@
/*
Copyright (C) 2009 Matthias Kruk <mkruk@matthiaskruk.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 __MOUSE_GESTURES_H__
#define __MOUSE_GESTURES_H__
typedef struct _MouseGesture MouseGesture;
typedef enum _MouseButton MouseButton;
enum _MouseButton {
MOUSE_BUTTON_LEFT = 1,
MOUSE_BUTTON_RIGHT = 3,
MOUSE_BUTTON_MIDDLE = 2,
MOUSE_BUTTON_UNSET = 0
};
struct MouseGestureNode {
double x;
double y;
} MouseGestureNode_t;
struct _MouseGesture {
struct MouseGestureNode start;
struct MouseGestureNode middle;
struct MouseGestureNode end;
MouseButton last;
};
#endif

View File

@ -175,7 +175,7 @@ extension_init (void)
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Pageholder"),
"description", "",
"description", _("Keep one or multiple pages open in parallel to your tabs"),
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);

View File

@ -38,67 +38,6 @@ shortcuts_deactivate_cb (MidoriExtension* extension,
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,
@ -113,11 +52,19 @@ shortcuts_accel_edited_cb (GtkCellRenderer* renderer,
{
GtkAction* action;
const gchar* accel_path;
GtkTreeIter child_iter;
GtkTreeModel* liststore;
gtk_tree_model_get (model, &iter, 0, &action, -1);
gtk_tree_model_get (model, &iter, 6, &action, -1);
accel_path = gtk_action_get_accel_path (action);
gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, TRUE);
gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model),
&child_iter, &iter);
liststore = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
gtk_list_store_set (GTK_LIST_STORE (liststore),
&child_iter, 1, accel_key, 2, accel_mods, -1);
g_object_unref (action);
}
}
@ -133,15 +80,58 @@ shortcuts_accel_cleared_cb (GtkCellRenderer* renderer,
{
GtkAction* action;
const gchar* accel_path;
GtkTreeIter child_iter;
GtkTreeModel* liststore;
gtk_tree_model_get (model, &iter, 0, &action, -1);
gtk_tree_model_get (model, &iter, 6, &action, -1);
accel_path = gtk_action_get_accel_path (action);
gtk_accel_map_change_entry (accel_path, 0, 0, FALSE);
gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model),
&child_iter, &iter);
liststore = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
gtk_list_store_set (GTK_LIST_STORE (liststore),
&child_iter, 1, 0, 2, 0, -1);
g_object_unref (action);
}
}
static gchar*
shortcuts_label_for_action (GtkAction* action)
{
gchar* label;
gchar* stripped;
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);
return stripped;
}
static gboolean
shortcuts_hotkey_for_action (GtkAction* action,
GtkAccelKey* key)
{
const gchar* accel_path = gtk_action_get_accel_path (action);
if (accel_path)
if (gtk_accel_map_lookup_entry (accel_path, key))
return TRUE;
return FALSE;
}
static GtkWidget*
shortcuts_get_preferences_dialog (MidoriExtension* extension)
{
@ -153,10 +143,10 @@ shortcuts_get_preferences_dialog (MidoriExtension* extension)
GtkWidget* xfce_heading;
GtkWidget* hbox;
GtkListStore* liststore;
GtkTreeModel* model;
GtkWidget* treeview;
GtkTreeViewColumn* column;
GtkCellRenderer* renderer_text;
GtkCellRenderer* renderer_accel;
GtkCellRenderer* renderer;
GtkWidget* scrolled;
GtkActionGroup* action_group;
GList* actions;
@ -190,26 +180,29 @@ shortcuts_get_preferences_dialog (MidoriExtension* extension)
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));
liststore = gtk_list_store_new (7,
G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_BOOLEAN,
G_TYPE_STRING, GTK_TYPE_ACTION);
model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (liststore));
treeview = gtk_tree_view_new_with_model (model);
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);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), renderer, "text", 0);
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);
renderer = gtk_cell_renderer_accel_new ();
gtk_tree_view_column_pack_start (column, renderer, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), renderer, "accel-key", 1);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), renderer, "accel-mods", 2);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), renderer, "accel-mode", 3);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), renderer, "sensitive", 4);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), renderer, "editable", 4);
g_signal_connect (renderer, "accel-edited",
G_CALLBACK (shortcuts_accel_edited_cb), model);
g_signal_connect (renderer, "accel-cleared",
G_CALLBACK (shortcuts_accel_cleared_cb), model);
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),
@ -224,11 +217,22 @@ shortcuts_get_preferences_dialog (MidoriExtension* extension)
i = 0;
/* FIXME: Catch added and removed actions */
while ((action = g_list_nth_data (actions, i++)))
{
gchar* label = shortcuts_label_for_action (action);
GtkAccelKey key;
gboolean has_hotkey = shortcuts_hotkey_for_action (action, &key);
gtk_list_store_insert_with_values (GTK_LIST_STORE (liststore),
NULL, G_MAXINT, 0, action, -1);
NULL, G_MAXINT, 0, label, 1, key.accel_key, 2, key.accel_mods,
3, GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
4, has_hotkey, 6, action, -1);
g_free (label);
}
g_list_free (actions);
g_object_unref (liststore);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
0, GTK_SORT_ASCENDING);
g_object_unref (model);
gtk_widget_show_all (GTK_DIALOG (dialog)->vbox);

View File

@ -196,8 +196,7 @@ tab_panel_popup (GtkWidget* widget,
{
GtkWidget* menu = midori_view_get_tab_menu (MIDORI_VIEW (view));
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR);
}
static gboolean
@ -355,9 +354,12 @@ tab_panel_view_notify_title_cb (GtkWidget* view,
GtkTreeIter iter;
if (tab_panel_get_iter_for_view (model, &iter, view))
{
GtkWidget* label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view));
GtkStyle* style = gtk_widget_get_style (label);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
4, title,
5, midori_view_get_label_ellipsize (MIDORI_VIEW (view)), -1);
5, midori_view_get_label_ellipsize (MIDORI_VIEW (view)),
6, &style->bg[GTK_STATE_NORMAL], -1);
}
}
}
@ -421,7 +423,7 @@ tab_panel_browser_add_tab_cb (MidoriBrowser* browser,
gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
&iter, NULL, page, 0, view, 1, GTK_STOCK_CLOSE, 2, buttons,
3, icon, 4, title, 5, ellipsize , -1);
3, icon, 4, title, 5, ellipsize, 6, NULL, -1);
}
if (!g_signal_handler_find (view, G_SIGNAL_MATCH_FUNC,
@ -499,8 +501,8 @@ tab_panel_app_add_browser_cb (MidoriApp* app,
panel = katze_object_get_object (browser, "panel");
model = gtk_tree_store_new (6, MIDORI_TYPE_VIEW,
G_TYPE_STRING, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT);
model = gtk_tree_store_new (7, MIDORI_TYPE_VIEW,
G_TYPE_STRING, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_COLOR);
g_object_set_data (G_OBJECT (browser), "tab-panel-ext-model", model);
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
@ -514,18 +516,19 @@ tab_panel_app_add_browser_cb (MidoriApp* app,
renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer_pixbuf,
"pixbuf", 3, NULL);
"pixbuf", 3, "cell-background-gdk", 6, NULL);
renderer_text = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer_text, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer_text,
"text", 4, "ellipsize", 5, NULL);
"text", 4, "ellipsize", 5, "cell-background-gdk", 6, NULL);
gtk_tree_view_column_set_expand (column, TRUE);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
column = gtk_tree_view_column_new ();
renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer_pixbuf,
"stock-id", 1, "follow-state", 2, "visible", 2, NULL);
"stock-id", 1, "follow-state", 2,
"visible", 2, "cell-background-gdk", 6, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
g_object_connect (treeview,
"signal::row-activated",

415
extensions/tab-switcher.c Normal file
View File

@ -0,0 +1,415 @@
/*
Copyright (C) 2009 André Stösel <Midori-Plugin@PyIT.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>
enum { TAB_ICON, TAB_NAME, TAB_POINTER, TAB_CELL_COUNT };
static MidoriExtension *thisExtension;
static gboolean switchEvent;
static GdkPixbuf* tab_selector_get_snapshot(MidoriView* view,
gint maxwidth,
gint maxheight)
{
GtkWidget* web_view;
guint width, height;
gfloat factor;
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
web_view = gtk_bin_get_child (GTK_BIN (view));
if(maxwidth < 0) {
maxwidth *= -1;
}
if(maxheight < 0) {
maxheight *= -1;
}
factor = MIN((gfloat) maxwidth / web_view->allocation.width, (gfloat) maxheight / web_view->allocation.height);
width = (int)(factor * web_view->allocation.width);
height = (int)(factor * web_view->allocation.height);
return midori_view_get_snapshot(view, width, height);
}
static void tab_selector_list_foreach (GtkWidget *view,
GtkListStore *store)
{
GtkTreeIter it;
GdkPixbuf* icon = midori_view_get_icon (MIDORI_VIEW (view));
const gchar *title = midori_view_get_display_title (MIDORI_VIEW (view));
gtk_list_store_append (store, &it);
gtk_list_store_set (store, &it, TAB_ICON, icon, -1);
gtk_list_store_set (store, &it, TAB_NAME, title, -1);
gtk_list_store_set (store, &it, TAB_POINTER, view, -1);
}
static GtkWidget* tab_selector_init_window (MidoriBrowser *browser)
{
GList *list;
gint col_offset;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkWidget *window, *treeview, *sw, *hbox;
GtkListStore *store;
GtkWidget *page;
GtkWidget *image;
GdkPixbuf *snapshot;
window = gtk_window_new(GTK_WINDOW_POPUP);
gtk_window_set_default_size(GTK_WINDOW(window), 320, 20);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
hbox = gtk_hbox_new(FALSE, 1);
gtk_container_add(GTK_CONTAINER(window), hbox);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 1);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
GTK_SHADOW_ETCHED_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_box_pack_start (GTK_BOX (hbox), sw, TRUE, TRUE, 0);
store = gtk_list_store_new(TAB_CELL_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
g_object_set_data(G_OBJECT(window), "tab_selector_treeview", treeview);
list = g_object_get_data(G_OBJECT(browser), "tab_selector_list");
g_list_foreach(list, (GFunc) tab_selector_list_foreach, store);
g_object_unref(store);
g_object_set(treeview, "headers-visible", FALSE, NULL);
renderer = gtk_cell_renderer_pixbuf_new();
gtk_tree_view_insert_column_with_attributes(
GTK_TREE_VIEW(treeview), -1, "Icon", renderer, "pixbuf", TAB_ICON, NULL);
renderer = gtk_cell_renderer_text_new();
col_offset = gtk_tree_view_insert_column_with_attributes(
GTK_TREE_VIEW(treeview), -1, "Title", renderer, "text", TAB_NAME, NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column),
midori_extension_get_integer(thisExtension, "TitleColumnWidth"));
gtk_container_add (GTK_CONTAINER (sw), treeview);
page = katze_object_get_object(browser, "tab");
snapshot = tab_selector_get_snapshot(MIDORI_VIEW(page),
midori_extension_get_integer(thisExtension, "TabPreviewWidth"),
midori_extension_get_integer(thisExtension, "TabPreviewHeight"));
image = gtk_image_new_from_pixbuf (snapshot);
gtk_box_pack_start (GTK_BOX (hbox), image, TRUE, TRUE, 0);
g_object_set_data(G_OBJECT(window), "tab_selector_image", image);
gtk_widget_show_all(window);
return window;
}
static void tab_selector_window_walk ( GtkWidget *window,
GdkEventKey *event,
MidoriBrowser *browser)
{
gint *pindex, iindex, items;
GtkWidget *view;
GtkTreeIter iter;
GtkTreePath *path;
GtkTreeView *treeview;
GtkTreeModel *model;
GtkTreeViewColumn *column;
treeview = g_object_get_data (G_OBJECT (window), "tab_selector_treeview");
model = gtk_tree_view_get_model (treeview);
items = gtk_tree_model_iter_n_children (model, NULL) -1;
gtk_tree_view_get_cursor (treeview, &path, &column);
pindex = gtk_tree_path_get_indices (path);
if(!pindex)
return;
iindex = *pindex;
gtk_tree_path_free(path);
if (event->state & GDK_SHIFT_MASK)
iindex = iindex == 0 ? items : iindex-1;
else
iindex = iindex == items ? 0 : iindex+1;
path = gtk_tree_path_new_from_indices(iindex, -1);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 1);
gtk_tree_view_set_cursor (GTK_TREE_VIEW (treeview), path, column, FALSE);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, TAB_POINTER, &view, -1);
if (midori_extension_get_boolean (thisExtension, "ShowTabInBackground")) {
midori_browser_set_current_tab (browser, view);
} else {
GtkImage *image;
GdkPixbuf *snapshot = tab_selector_get_snapshot(MIDORI_VIEW(view),
midori_extension_get_integer(thisExtension, "TabPreviewWidth"),
midori_extension_get_integer(thisExtension, "TabPreviewHeight"));
image = g_object_get_data(G_OBJECT(window), "tab_selector_image");
gtk_image_set_from_pixbuf(image, snapshot);
}
gtk_tree_path_free(path);
}
static gboolean tab_selector_handle_events (GtkWidget *widget,
GdkEventKey *event,
MidoriBrowser *browser)
{
/* tab -> 23
ctrl -> 37 */
gint treeitems;
static GtkWidget *window;
if(event->type == GDK_KEY_PRESS && event->hardware_keycode == 23 && event->state & GDK_CONTROL_MASK) {
treeitems = gtk_notebook_get_n_pages (GTK_NOTEBOOK (
katze_object_get_object(browser, "notebook")));
if(treeitems > 1) {
if(!GTK_IS_WINDOW(window)) {
switchEvent = FALSE;
window = tab_selector_init_window(browser);
}
tab_selector_window_walk(window, event, browser);
}
return TRUE;
} else if(event->type == GDK_KEY_RELEASE && event->hardware_keycode == 37 && GTK_IS_WINDOW(window)) {
switchEvent = TRUE;
if(midori_extension_get_boolean(thisExtension, "ShowTabInBackground")) {
GtkWidget *page;
page = katze_object_get_object(browser, "tab");
GList *list = g_object_get_data(G_OBJECT(browser), "tab_selector_list");
list = g_list_remove(list, page);
list = g_list_prepend(list, page);
g_object_set_data(G_OBJECT(browser), "tab_selector_list", list);
} else {
GtkTreePath *path;
GtkTreeViewColumn *column;
GtkTreeIter iter;
GtkWidget *view, *treeview;
GtkTreeModel *model;
treeview = g_object_get_data(G_OBJECT(window), "tab_selector_treeview");
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
gtk_tree_view_get_cursor (
GTK_TREE_VIEW(treeview), &path, &column);
gtk_tree_model_get_iter (
model, &iter, path);
gtk_tree_model_get (
model, &iter, TAB_POINTER, &view, -1);
midori_browser_set_current_tab (browser, view);
gtk_tree_path_free (path);
}
gtk_widget_destroy(window);
window = NULL;
return TRUE;
}
return FALSE;
}
static void tab_selector_switch_page (GtkNotebook *notebook,
GtkNotebookPage *page_,
guint page_num,
MidoriBrowser *browser)
{
if(switchEvent) {
/* Don't know why *page_ points to the wrong address */
GtkWidget *page;
page = katze_object_get_object(browser, "tab");
GList *list = g_object_get_data(G_OBJECT(browser), "tab_selector_list");
list = g_list_remove(list, page);
list = g_list_prepend(list, page);
g_object_set_data(G_OBJECT(browser), "tab_selector_list", list);
}
}
static void
tab_selector_browser_add_tab_cb (MidoriBrowser *browser,
GtkWidget *view,
MidoriExtension *extension)
{
g_signal_connect (view, "key_press_event",
G_CALLBACK (tab_selector_handle_events), browser);
g_signal_connect (view, "key_release_event",
G_CALLBACK (tab_selector_handle_events), browser);
GList *list = g_object_get_data(G_OBJECT(browser), "tab_selector_list");
list = g_list_append(list, view);
g_object_set_data(G_OBJECT(browser), "tab_selector_list", list);
}
static void
tab_selector_browser_remove_tab_cb (MidoriBrowser *browser,
GtkWidget *view,
MidoriExtension *extension)
{
GList *list = g_object_get_data(G_OBJECT(browser), "tab_selector_list");
list = g_list_remove(list, view);
g_object_set_data(G_OBJECT(browser), "tab_selector_list", list);
}
static void
tab_selector_disconnect_tab_cb (GtkWidget *view,
MidoriBrowser *browser)
{
g_signal_handlers_disconnect_by_func (
view, tab_selector_handle_events, browser);
}
static void
tab_selector_app_add_browser_cb (MidoriApp *app,
MidoriBrowser *browser,
MidoriExtension *extension)
{
GtkWidget *navigationbar, *notebook;
g_object_set_data(G_OBJECT(browser), "tab_selector_list", NULL);
g_signal_connect (browser, "add-tab",
G_CALLBACK (tab_selector_browser_add_tab_cb), extension);
g_signal_connect (browser, "remove-tab",
G_CALLBACK (tab_selector_browser_remove_tab_cb), extension);
navigationbar = katze_object_get_object(browser, "navigationbar");
g_signal_connect (navigationbar, "key_press_event",
G_CALLBACK (tab_selector_handle_events), browser);
g_signal_connect (navigationbar, "key_release_event",
G_CALLBACK (tab_selector_handle_events), browser);
g_object_unref(navigationbar);
notebook = katze_object_get_object(browser, "notebook");
g_signal_connect_after (notebook, "switch-page",
G_CALLBACK (tab_selector_switch_page), browser);
g_object_unref(notebook);
}
static void
tab_selector_app_remove_browser_cb (MidoriApp *app,
MidoriBrowser *browser,
MidoriExtension *extension)
{
GList *list = g_object_get_data (G_OBJECT (browser), "tab_selector_list");
g_list_free (list);
}
static void
tab_selector_disconnect_browser_cb (MidoriApp *app,
MidoriBrowser *browser,
MidoriExtension *extension)
{
GtkWidget *navigationbar, *notebook;
midori_browser_foreach (browser,
(GtkCallback)tab_selector_disconnect_tab_cb, browser);
g_signal_handlers_disconnect_by_func (
browser, tab_selector_browser_add_tab_cb, extension);
g_signal_handlers_disconnect_by_func (
browser, tab_selector_browser_remove_tab_cb, extension);
g_signal_handlers_disconnect_by_func (
katze_object_get_object (browser, "navigationbar"),
tab_selector_handle_events, browser);
navigationbar = katze_object_get_object (browser, "navigationbar");
g_signal_handlers_disconnect_by_func (navigationbar,
tab_selector_handle_events, browser);
g_signal_handlers_disconnect_by_func (navigationbar,
tab_selector_handle_events, browser);
g_object_unref (navigationbar);
notebook = katze_object_get_object (browser, "notebook");
g_signal_handlers_disconnect_by_func (notebook,
tab_selector_switch_page, browser);
g_object_unref (notebook);
}
static void
tab_selector_activate_cb (MidoriExtension *extension,
MidoriApp *app)
{
GtkWidget *view;
KatzeArray *browsers;
MidoriBrowser *browser;
guint i, j;
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++))) {
j = 0;
tab_selector_app_add_browser_cb (app, browser, extension);
while((view = midori_browser_get_nth_tab(browser, j++)))
tab_selector_browser_add_tab_cb(browser, view, extension);
}
g_object_unref (browsers);
g_signal_connect (app, "add-browser",
G_CALLBACK (tab_selector_app_add_browser_cb), extension);
g_signal_connect (app, "remove-browser",
G_CALLBACK (tab_selector_app_remove_browser_cb), extension);
}
static void
tab_selector_deactivate_cb (MidoriExtension *extension,
GtkWidget *foo)
{
MidoriApp* app = midori_extension_get_app (extension);
KatzeArray *browsers;
MidoriBrowser *browser;
guint i;
g_signal_handlers_disconnect_by_func (
app, tab_selector_app_add_browser_cb, extension);
g_signal_handlers_disconnect_by_func (
app, tab_selector_app_remove_browser_cb, extension);
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
tab_selector_disconnect_browser_cb (app, browser, extension);
g_object_unref (browsers);
}
MidoriExtension*
extension_init (void)
{
MidoriExtension *extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Tab History List"),
"description", _("Allows to switch tabs by choosing from a "
"list sorted by last usage"),
"version", "0.1",
"authors", "André Stösel <Midori-Plugin@PyIT.de>",
NULL);
g_signal_connect (extension, "activate",
G_CALLBACK (tab_selector_activate_cb), NULL);
g_signal_connect (extension, "deactivate",
G_CALLBACK (tab_selector_deactivate_cb), NULL);
midori_extension_install_boolean (extension, "ShowTabInBackground", FALSE);
midori_extension_install_integer (extension, "TitleColumnWidth", 300);
midori_extension_install_integer (extension, "TabPreviewWidth", 200);
midori_extension_install_integer (extension, "TabPreviewHeight", 200);
thisExtension = extension;
switchEvent = TRUE;
return extension;
}

605
extensions/web-cache.c Normal file
View File

@ -0,0 +1,605 @@
/*
Copyright (C) 2009 Christian Dywan <christian@twotoasts.de>
Copyright (C) 2009 Alexander Butenko <a.butenka@gmail.com>
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"
#include <glib/gstdio.h>
#include <stdlib.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
static gboolean offline_mode = FALSE;
#define HAVE_WEBKIT_RESOURCE_REQUEST WEBKIT_CHECK_VERSION (1, 1, 14)
#define MAXLENGTH 1024 * 1024
static gchar*
web_cache_get_cached_path (MidoriExtension* extension,
const gchar* uri)
{
static const gchar* cache_path = NULL;
gchar* checksum;
gchar* folder;
gchar* sub_path;
gchar* encoded;
gchar* ext;
gchar* cached_filename;
gchar* cached_path;
if (!cache_path)
cache_path = midori_extension_get_string (extension, "path");
checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
folder = g_strdup_printf ("%c%c", checksum[0], checksum[1]);
sub_path = g_build_path (G_DIR_SEPARATOR_S, cache_path, folder, NULL);
g_mkdir (sub_path, 0700);
g_free (folder);
encoded = soup_uri_encode (uri, "/");
ext = g_strdup (g_strrstr (encoded, "."));
/* Make sure ext isn't becoming too long */
if (ext && ext[0] && ext[1] && ext[2] && ext[3] && ext[4])
ext[4] = '\0';
cached_filename = g_strdup_printf ("%s%s", checksum, ext ? ext : "");
g_free (ext);
g_free (encoded);
g_free (checksum);
cached_path = g_build_filename (sub_path, cached_filename, NULL);
g_free (cached_filename);
return cached_path;
}
static gboolean
web_cache_replace_frame_uri (MidoriExtension* extension,
const gchar* uri,
WebKitWebFrame* web_frame)
{
gchar* filename;
gboolean handled = FALSE;
filename = web_cache_get_cached_path (extension, uri);
/* g_debug ("cache lookup: %s => %s", uri, filename); */
if (g_file_test (filename, G_FILE_TEST_EXISTS))
{
gchar* data;
g_file_get_contents (filename, &data, NULL, NULL);
webkit_web_frame_load_alternate_string (web_frame, data, NULL, uri);
g_free (data);
handled = TRUE;
}
g_free (filename);
return handled;
}
static gboolean
web_cache_navigation_decision_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
WebKitNetworkRequest* request,
WebKitWebNavigationAction* action,
WebKitWebPolicyDecision* decision,
MidoriExtension* extension)
{
const gchar* uri = webkit_network_request_get_uri (request);
if (!(uri && g_str_has_prefix (uri, "http://")))
return FALSE;
if (offline_mode == FALSE)
return FALSE;
return web_cache_replace_frame_uri (extension, uri, web_frame);
}
#if WEBKIT_CHECK_VERSION (1, 1, 6)
static gboolean
web_cache_load_error_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
const gchar* uri,
GError* error,
MidoriExtension* extension)
{
if (offline_mode == FALSE)
return FALSE;
if (!(uri && g_str_has_prefix (uri, "http://")))
return FALSE;
return web_cache_replace_frame_uri (extension, uri, web_frame);
}
#endif
static void
web_cache_save_headers (SoupMessage* msg,
gchar* filename)
{
gchar* dsc_filename = g_strdup_printf ("%s.dsc.tmp", filename);
SoupMessageHeaders* hdrs = msg->response_headers;
SoupMessageHeadersIter iter;
const gchar* name, *value;
FILE* dscfd;
soup_message_headers_iter_init (&iter, hdrs);
dscfd = g_fopen (dsc_filename, "w");
while (soup_message_headers_iter_next (&iter, &name, &value))
g_fprintf (dscfd, "%s: %s\n", name, value);
fclose (dscfd);
g_free (dsc_filename);
}
GHashTable*
web_cache_get_headers (gchar* filename)
{
GHashTable* headers;
FILE* file;
gchar* dsc_filename;
headers = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_free);
if (!filename)
return headers;
if (!g_file_test (filename, G_FILE_TEST_EXISTS))
return headers;
dsc_filename = g_strdup_printf ("%s.dsc", filename);
if (!g_file_test (dsc_filename, G_FILE_TEST_EXISTS))
{
g_free (dsc_filename);
return headers;
}
if ((file = g_fopen (dsc_filename, "r")))
{
gchar line[128];
while (fgets (line, 128, file))
{
if (line==NULL)
continue;
g_strchomp (line);
gchar** data;
data = g_strsplit (line, ":", 2);
if (data[0] && data[1])
g_hash_table_insert (headers, g_strdup (data[0]),
g_strdup (g_strchug (data[1])));
g_strfreev (data);
}
}
fclose (file);
/* g_hash_table_destroy (headers); */
g_free (dsc_filename);
return headers;
}
static gboolean
web_cache_tmp_prepare (gchar* filename)
{
gchar* tmp_filename = g_strdup_printf ("%s.tmp", filename);
/* FIXME: If load was interruped we are ending up with a partical
cache files forever */
if (g_file_test (tmp_filename, G_FILE_TEST_EXISTS))
{
g_free (tmp_filename);
return FALSE;
}
g_file_set_contents (tmp_filename, "", -1, NULL);
g_free (tmp_filename);
return TRUE;
}
static void
web_cache_set_content_type (SoupMessage* msg,
SoupBuffer* buffer)
{
#if WEBKIT_CHECK_VERSION (1, 1, 15)
const char *ct;
SoupContentSniffer* sniffer = soup_content_sniffer_new ();
ct = soup_content_sniffer_sniff (sniffer, msg, buffer, NULL);
if (!ct)
ct = soup_message_headers_get_one (msg->response_headers, "Content-Type");
if (ct)
g_signal_emit_by_name (msg, "content-sniffed", ct, NULL);
#endif
}
static void
web_cache_message_finished_cb (SoupMessage* msg,
gchar* filename)
{
gchar* headers;
gchar* tmp_headers;
gchar* tmp_data;
headers = g_strdup_printf ("%s.dsc", filename);
tmp_headers = g_strdup_printf ("%s.dsc.tmp", filename);
tmp_data = g_strdup_printf ("%s.tmp", filename);
if (msg->status_code == SOUP_STATUS_OK)
{
g_rename (tmp_data, filename);
g_rename (tmp_headers, headers);
}
else
{
g_unlink (tmp_data);
g_unlink (tmp_headers);
}
g_free (headers);
g_free (tmp_headers);
g_free (tmp_data);
}
static void
web_cache_message_got_chunk_cb (SoupMessage* msg,
SoupBuffer* chunk,
gchar* filename)
{
GFile *file;
GOutputStream *stream;
gchar *tmp_filename;
if (!chunk->data || !chunk->length)
return;
tmp_filename = g_strdup_printf ("%s.tmp", filename);
file = g_file_new_for_path (tmp_filename);
if ((stream = (GOutputStream*)g_file_append_to (file, 0, NULL, NULL)))
{
g_output_stream_write (stream, chunk->data, chunk->length, NULL, NULL);
g_object_unref (stream);
}
g_object_unref (file);
g_free (tmp_filename);
}
static void
web_cache_message_rewrite (SoupMessage* msg,
gchar* filename)
{
GHashTable* cache_headers = web_cache_get_headers (filename);
GHashTableIter iter;
SoupBuffer *buffer;
gpointer key, value;
char *data;
gsize length;
soup_message_set_status (msg, SOUP_STATUS_OK);
g_hash_table_iter_init (&iter, cache_headers);
while (g_hash_table_iter_next (&iter, &key, &value))
soup_message_headers_replace (msg->response_headers, key, value);
g_signal_emit_by_name (msg, "got-headers", NULL);
msg->response_body = soup_message_body_new ();
g_file_get_contents (filename, &data, &length, NULL);
if (data && length)
{
buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY, data, length);
web_cache_set_content_type (msg, buffer);
soup_message_body_append_buffer (msg->response_body, buffer);
g_signal_emit_by_name (msg, "got-chunk", buffer, NULL);
soup_buffer_free (buffer);
}
soup_message_got_body (msg);
g_free (data);
#if 0
if (offline_mode == TRUE)
{
/* Workaroung for offline mode
FIXME: libsoup-CRITICAL **: queue_message: assertion `item != NULL' failed */
SoupSession *session = webkit_get_default_session ();
soup_session_requeue_message (session, msg);
}
soup_message_finished (msg);
#endif
}
static void
web_cache_mesage_got_headers_cb (SoupMessage* msg,
MidoriExtension* extension)
{
SoupURI* soup_uri = soup_message_get_uri (msg);
gchar* uri;
gchar* filename;
const gchar* nocache;
SoupMessageHeaders *hdrs = msg->response_headers;
/* Skip files downloaded by the user */
if (g_object_get_data (G_OBJECT (msg), "midori-web-cache-download"))
return;
/* Skip big files */
const char* cl = soup_message_headers_get_one (hdrs, "Content-Length");
if (cl && atoi (cl) > MAXLENGTH)
return;
nocache = soup_message_headers_get_one (hdrs, "Pragma");
if (!nocache)
nocache = soup_message_headers_get_one (hdrs, "Cache-Control");
if (nocache && g_regex_match_simple ("no-cache|no-store", nocache,
G_REGEX_CASELESS, G_REGEX_MATCH_NOTEMPTY))
{
return;
}
uri = soup_uri ? soup_uri_to_string (soup_uri, FALSE) : g_strdup ("");
filename = web_cache_get_cached_path (extension, uri);
if (msg->status_code == SOUP_STATUS_NOT_MODIFIED)
{
/* g_debug ("loading from cache: %s -> %s", uri, filename); */
g_signal_handlers_disconnect_by_func (msg,
web_cache_mesage_got_headers_cb, extension);
web_cache_message_rewrite (msg, filename);
g_free (filename);
}
else if (msg->status_code == SOUP_STATUS_OK)
{
/* g_debug ("updating cache: %s -> %s", uri, filename); */
if (!web_cache_tmp_prepare (filename))
return;
web_cache_save_headers (msg, filename);
g_signal_connect_data (msg, "got-chunk",
G_CALLBACK (web_cache_message_got_chunk_cb),
filename, (GClosureNotify)g_free, 0);
g_signal_connect (msg, "finished",
G_CALLBACK (web_cache_message_finished_cb), filename);
}
g_free (uri);
}
#if HAVE_WEBKIT_RESOURCE_REQUEST
static void
web_cache_resource_request_starting_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
WebKitWebResource* web_resource,
WebKitNetworkRequest* request,
WebKitNetworkResponse* response,
MidoriExtension* extension)
{
const gchar* uri;
gchar* filename;
/* TODO: Good place to check are we offline */
uri = webkit_network_request_get_uri (request);
if (!(uri && g_str_has_prefix (uri, "http://")))
return;
if (offline_mode == FALSE)
return;
filename = web_cache_get_cached_path (extension, uri);
/* g_debug ("loading %s -> %s",uri, filename); */
if (!g_file_test (filename, G_FILE_TEST_EXISTS))
{
g_free (filename);
return;
}
if (!(g_strcmp0 (uri, webkit_web_frame_get_uri (web_frame))
&& g_strcmp0 (webkit_web_data_source_get_unreachable_uri (
webkit_web_frame_get_data_source (web_frame)), uri)))
{
web_cache_replace_frame_uri (extension, uri, web_frame);
g_free (filename);
return;
}
gchar* file_uri = g_filename_to_uri (filename, NULL, NULL);
webkit_network_request_set_uri (request, file_uri);
g_free (file_uri);
g_free (filename);
}
#endif
static void
web_cache_session_request_queued_cb (SoupSession* session,
SoupMessage* msg,
MidoriExtension* extension)
{
/*FIXME: Should we need to free soupuri? */
SoupURI* soup_uri = soup_message_get_uri (msg);
gchar* uri = soup_uri ? soup_uri_to_string (soup_uri, FALSE) : g_strdup ("");
/* For now we are handling only online mode here */
if (offline_mode == TRUE)
return;
if (g_str_has_prefix (uri, "http") && !g_strcmp0 (msg->method, "GET"))
{
gchar* filename = web_cache_get_cached_path (extension, uri);
if (offline_mode == FALSE)
{
GHashTable* cache_headers;
gchar* etag;
gchar* last_modified;
cache_headers = web_cache_get_headers (filename);
etag = g_hash_table_lookup (cache_headers, "ETag");
last_modified = g_hash_table_lookup (cache_headers, "Last-Modified");
if (etag)
soup_message_headers_replace (msg->request_headers,
"If-None-Match", etag);
if (last_modified)
soup_message_headers_replace (msg->request_headers,
"If-Modified-Since", last_modified);
g_signal_connect (msg, "got-headers",
G_CALLBACK (web_cache_mesage_got_headers_cb), extension);
g_free (etag);
g_free (last_modified);
g_free (filename);
/* FIXME: uncoment this is leading to a crash
g_hash_table_destroy (cache_headers); */
return;
}
/*
else
{
g_debug("queued in offline mode: %s -> %s", uri, filename);
if (g_file_test (filename, G_FILE_TEST_EXISTS))
{
soup_message_set_status (msg, SOUP_STATUS_NOT_MODIFIED);
web_cache_message_rewrite (msg, filename);
}
}
*/
g_free (filename);
}
g_free (uri);
}
static void
web_cache_add_tab_cb (MidoriBrowser* browser,
MidoriView* view,
MidoriExtension* extension)
{
GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view));
g_signal_connect (web_view, "navigation-policy-decision-requested",
G_CALLBACK (web_cache_navigation_decision_cb), extension);
#if WEBKIT_CHECK_VERSION (1, 1, 6)
g_signal_connect (web_view, "load-error",
G_CALLBACK (web_cache_load_error_cb), extension);
#endif
#if HAVE_WEBKIT_RESOURCE_REQUEST
g_signal_connect (web_view, "resource-request-starting",
G_CALLBACK (web_cache_resource_request_starting_cb), extension);
#endif
}
#if WEBKIT_CHECK_VERSION (1, 1, 3)
static void
web_cache_add_download_cb (MidoriBrowser* browser,
WebKitDownload* download,
MidoriExtension* extension)
{
WebKitNetworkRequest* request = webkit_download_get_network_request (download);
SoupMessage* msg = webkit_network_request_get_message (request);
if (msg)
g_object_set_data (G_OBJECT (msg), "midori-web-cache-download",
(gpointer)0xdeadbeef);
}
#endif
static void
web_cache_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser);
static void
web_cache_add_tab_foreach_cb (MidoriView* view,
MidoriBrowser* browser,
MidoriExtension* extension)
{
web_cache_add_tab_cb (browser, view, extension);
}
static void
web_cache_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
midori_browser_foreach (browser,
(GtkCallback)web_cache_add_tab_foreach_cb, extension);
g_signal_connect (browser, "add-tab",
G_CALLBACK (web_cache_add_tab_cb), extension);
#if WEBKIT_CHECK_VERSION (1, 1, 3)
g_signal_connect (browser, "add-download",
G_CALLBACK (web_cache_add_download_cb), extension);
#endif
g_signal_connect (extension, "deactivate",
G_CALLBACK (web_cache_deactivate_cb), browser);
}
static void
web_cache_deactivate_tabs (MidoriView* view,
MidoriExtension* extension)
{
#if HAVE_WEBKIT_RESOURCE_REQUEST
GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view));
g_signal_handlers_disconnect_by_func (
web_view, web_cache_resource_request_starting_cb, extension);
#endif
}
static void
web_cache_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser)
{
MidoriApp* app = midori_extension_get_app (extension);
SoupSession* session = webkit_get_default_session ();
g_signal_handlers_disconnect_by_func (
session, web_cache_session_request_queued_cb, extension);
g_signal_handlers_disconnect_by_func (
extension, web_cache_deactivate_cb, browser);
g_signal_handlers_disconnect_by_func (
app, web_cache_app_add_browser_cb, extension);
g_signal_handlers_disconnect_by_func (
browser, web_cache_add_tab_cb, extension);
#if WEBKIT_CHECK_VERSION (1, 1, 3)
g_signal_handlers_disconnect_by_func (
browser, web_cache_add_download_cb, extension);
#endif
midori_browser_foreach (browser, (GtkCallback)web_cache_deactivate_tabs, extension);
}
static void
web_cache_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
const gchar* cache_path = midori_extension_get_string (extension, "path");
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
SoupSession* session = webkit_get_default_session ();
katze_mkdir_with_parents (cache_path, 0700);
g_signal_connect (session, "request-queued",
G_CALLBACK (web_cache_session_request_queued_cb), extension);
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
web_cache_app_add_browser_cb (app, browser, extension);
g_signal_connect (app, "add-browser",
G_CALLBACK (web_cache_app_add_browser_cb), extension);
g_object_unref (browsers);
}
MidoriExtension*
extension_init (void)
{
gchar* cache_path = g_build_filename (g_get_user_cache_dir (),
PACKAGE_NAME, "web", NULL);
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Web Cache"),
"description", _("Cache HTTP communication on disk"),
"version", "0.1",
"authors", "Christian Dywan <christian@twotoasts.de>",
NULL);
midori_extension_install_string (extension, "path", cache_path);
midori_extension_install_integer (extension, "size", 50);
g_free (cache_path);
g_signal_connect (extension, "activate",
G_CALLBACK (web_cache_activate_cb), NULL);
return extension;
}

View File

@ -15,7 +15,9 @@ def add_image (bld, category, name):
if rsvg_convert:
Utils.check_dir (blddir + '/icons')
for size in [16, 22, 24, 32, 48]:
icon_sizes = [16, 22, 24, 32, 48]
for size in icon_sizes:
format = str (size) + 'x' + str (size)
if os.access (srcdir + '/icons/' + format + '/' + name + '.png', os.F_OK):
bld.install_files ('${MDATADIR}/icons/hicolor/' + format + '/' + category,

View File

@ -20,12 +20,17 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#if HAVE_CONFIG_H
#include "config.h"
#endif
struct _KatzeArrayAction
{
GtkAction parent_instance;
KatzeArray* array;
KatzeNet* net;
gboolean reversed;
};
struct _KatzeArrayActionClass
@ -39,7 +44,8 @@ enum
{
PROP_0,
PROP_ARRAY
PROP_ARRAY,
PROP_REVERSED
};
enum
@ -154,6 +160,22 @@ katze_array_action_class_init (KatzeArrayActionClass* class)
"The array the action represents",
KATZE_TYPE_ARRAY,
G_PARAM_READWRITE));
/**
* KatzeArrayAction:reversed:
*
* Whether the array should be walked backwards when building menus.
*
* Since: 0.2.2
**/
g_object_class_install_property (gobject_class,
PROP_REVERSED,
g_param_spec_boolean (
"reversed",
"Reversed",
"Whether the array should be walked backwards when building menus",
FALSE,
G_PARAM_READWRITE));
}
static void
@ -161,6 +183,7 @@ katze_array_action_init (KatzeArrayAction* array_action)
{
array_action->array = NULL;
array_action->net = katze_net_new ();
array_action->reversed = FALSE;
}
static void
@ -187,6 +210,9 @@ katze_array_action_set_property (GObject* object,
case PROP_ARRAY:
katze_array_action_set_array (array_action, g_value_get_object (value));
break;
case PROP_REVERSED:
array_action->reversed = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -206,6 +232,9 @@ katze_array_action_get_property (GObject* object,
case PROP_ARRAY:
g_value_set_object (value, array_action->array);
break;
case PROP_REVERSED:
g_value_set_boolean (value, array_action->reversed);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -272,7 +301,8 @@ katze_array_action_generate_menu (KatzeArrayAction* array_action,
GtkWidget* menu,
GtkWidget* proxy)
{
guint i;
gint i;
gint summand;
KatzeItem* item;
GtkWidget* menuitem;
const gchar* icon_name;
@ -280,8 +310,17 @@ katze_array_action_generate_menu (KatzeArrayAction* array_action,
GtkWidget* image;
GtkWidget* submenu;
i = 0;
while ((item = katze_array_get_nth_item (array, i++)))
if (array_action->reversed)
{
i = katze_array_get_length (array);
summand = -1;
}
else
{
i = -1;
summand = +1;
}
while ((item = katze_array_get_nth_item (array, i += summand)))
{
/* FIXME: The menu item should reflect changes to the item */
if (!KATZE_IS_ARRAY (item) && !katze_item_get_uri (item))
@ -301,8 +340,7 @@ katze_array_action_generate_menu (KatzeArrayAction* array_action,
icon = gtk_widget_render_icon (menuitem,
GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
else
icon = katze_net_load_icon (array_action->net,
katze_item_get_uri (item), NULL, proxy, NULL);
icon = katze_load_cached_icon (katze_item_get_uri (item), proxy);
image = gtk_image_new_from_pixbuf (icon);
g_object_unref (icon);
}
@ -322,19 +360,12 @@ katze_array_action_generate_menu (KatzeArrayAction* array_action,
}
else
{
g_signal_connect (menuitem, "button-press-event",
G_CALLBACK (katze_array_action_menu_button_press_cb), array_action);
/* we need the 'activate' signal as well for keyboard events */
g_signal_connect (menuitem, "activate",
G_CALLBACK (katze_array_action_menu_activate_cb), array_action);
}
gtk_widget_show (menuitem);
}
if (!i)
{
menuitem = gtk_image_menu_item_new_with_label (_("Empty"));
gtk_widget_set_sensitive (menuitem, FALSE);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_signal_connect (menuitem, "button-press-event",
G_CALLBACK (katze_array_action_menu_button_press_cb), array_action);
gtk_widget_show (menuitem);
}
}
@ -370,9 +401,15 @@ katze_array_action_proxy_clicked_cb (GtkWidget* proxy,
return;
}
array = (KatzeArray*)g_object_get_data (G_OBJECT (proxy), "KatzeArray");
if (KATZE_IS_ITEM (array) && katze_item_get_uri ((KatzeItem*)array))
{
g_signal_emit (array_action, signals[ACTIVATE_ITEM], 0, array);
return;
}
menu = gtk_menu_new ();
array = (KatzeArray*)g_object_get_data (G_OBJECT (proxy), "KatzeArray");
if (!array)
array = array_action->array;
katze_array_action_generate_menu (array_action, array, menu, proxy);
@ -381,8 +418,14 @@ katze_array_action_proxy_clicked_cb (GtkWidget* proxy,
if (array == array_action->array)
g_signal_emit (array_action, signals[POPULATE_POPUP], 0, menu);
#if HAVE_HILDON
/* Avoid a bug in GTK+ messing up the initial scrolling position */
katze_widget_popup (NULL, GTK_MENU (menu),
NULL, KATZE_MENU_POSITION_LEFT);
#else
katze_widget_popup (GTK_WIDGET (proxy), GTK_MENU (menu),
NULL, KATZE_MENU_POSITION_LEFT);
#endif
}
static GtkWidget*
@ -399,7 +442,7 @@ katze_array_action_create_tool_item (GtkAction* action)
{
GtkWidget* toolitem;
toolitem = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
toolitem = GTK_WIDGET (gtk_tool_button_new (NULL, ""));
return toolitem;
}
@ -460,8 +503,7 @@ katze_array_action_item_notify_cb (KatzeItem* item,
}
else if (!KATZE_IS_ARRAY (item) && !strcmp (property, "uri"))
{
icon = katze_net_load_icon (array_action->net, katze_item_get_uri (item),
NULL, GTK_WIDGET (toolitem), NULL);
icon = katze_load_cached_icon (katze_item_get_uri (item), GTK_WIDGET (toolitem));
image = gtk_image_new_from_pixbuf (icon);
g_object_unref (icon);
gtk_widget_show (image);
@ -497,8 +539,7 @@ katze_array_action_proxy_create_menu_proxy_cb (GtkWidget* proxy,
icon = gtk_widget_render_icon (menuitem,
GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
else
icon = katze_net_load_icon (array_action->net,
katze_item_get_uri (item), NULL, proxy, NULL);
icon = katze_load_cached_icon (katze_item_get_uri (item), proxy);
image = gtk_image_new_from_pixbuf (icon);
g_object_unref (icon);
}
@ -508,16 +549,34 @@ katze_array_action_proxy_create_menu_proxy_cb (GtkWidget* proxy,
GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
#endif
g_object_set_data (G_OBJECT (menuitem), "KatzeItem", item);
g_signal_connect (menuitem, "button-press-event",
G_CALLBACK (katze_array_action_menu_button_press_cb), array_action);
/* we need the 'activate' signal as well for keyboard events */
g_signal_connect (menuitem, "activate",
G_CALLBACK (katze_array_action_menu_activate_cb), array_action);
if (KATZE_IS_ARRAY (item))
{
GtkWidget* submenu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
g_signal_connect (menuitem, "select",
G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);
}
else
{
g_signal_connect (menuitem, "button-press-event",
G_CALLBACK (katze_array_action_menu_button_press_cb), array_action);
/* we need the 'activate' signal as well for keyboard events */
g_signal_connect (menuitem, "activate",
G_CALLBACK (katze_array_action_menu_activate_cb), array_action);
}
gtk_tool_item_set_proxy_menu_item (GTK_TOOL_ITEM (proxy),
"katze-tool-item-menu", menuitem);
return TRUE;
}
static void
katze_array_action_toolitem_destroy_cb (GtkToolItem* toolitem,
KatzeItem* item)
{
g_signal_handlers_disconnect_by_func (item,
G_CALLBACK (katze_array_action_item_notify_cb), toolitem);
}
/**
* katze_array_action_create_tool_item_for:
* @array_action: a #KatzeArrayAction
@ -552,15 +611,14 @@ katze_array_action_create_tool_item_for (KatzeArrayAction* array_action,
if (!KATZE_IS_ARRAY (item) && !uri)
return gtk_separator_tool_item_new ();
toolitem = gtk_tool_button_new (NULL, NULL);
toolitem = gtk_tool_button_new (NULL, "");
g_signal_connect (toolitem, "create-menu-proxy",
G_CALLBACK (katze_array_action_proxy_create_menu_proxy_cb), item);
if (KATZE_IS_ARRAY (item))
icon = gtk_widget_render_icon (GTK_WIDGET (toolitem),
GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
else
icon = katze_net_load_icon (array_action->net, uri,
NULL, GTK_WIDGET (toolitem), NULL);
icon = katze_load_cached_icon (uri, GTK_WIDGET (toolitem));
image = gtk_image_new_from_pixbuf (icon);
g_object_unref (icon);
gtk_widget_show (image);
@ -585,16 +643,16 @@ katze_array_action_create_tool_item_for (KatzeArrayAction* array_action,
gtk_tool_item_set_tooltip_text (toolitem, desc);
else
gtk_tool_item_set_tooltip_text (toolitem, uri);
if (KATZE_IS_ARRAY (item))
{
g_object_set_data (G_OBJECT (toolitem), "KatzeArray", item);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (katze_array_action_proxy_clicked_cb), array_action);
}
g_object_set_data (G_OBJECT (toolitem), "KatzeArray", item);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (katze_array_action_proxy_clicked_cb), array_action);
g_object_set_data (G_OBJECT (toolitem), "KatzeArrayAction", array_action);
g_signal_connect (item, "notify",
G_CALLBACK (katze_array_action_item_notify_cb), toolitem);
g_signal_connect (toolitem, "destroy",
G_CALLBACK (katze_array_action_toolitem_destroy_cb), item);
return toolitem;
}

View File

@ -75,12 +75,14 @@ katze_item_class_init (KatzeItemClass* class)
*
* Emitted when a meta data value was changed.
*
* Since 0.2.2 details according to keys are supported.
*
* Since: 0.1.9
*/
signals[META_DATA_CHANGED] = g_signal_new (
"meta-data-changed",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST),
(GSignalFlags)(G_SIGNAL_RUN_LAST |G_SIGNAL_DETAILED),
0,
0,
NULL,
@ -510,7 +512,7 @@ katze_item_set_meta_data_value (KatzeItem* item,
g_hash_table_insert (item->metadata, g_strdup (&key[7]), value);
else
g_hash_table_insert (item->metadata, g_strdup (key), value);
g_signal_emit (item, signals[META_DATA_CHANGED], 0, key);
g_signal_emit (item, signals[META_DATA_CHANGED], g_quark_from_string (key), key);
}
/**
@ -590,7 +592,7 @@ katze_item_get_meta_integer (KatzeItem* item,
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 value ? g_ascii_strtoll (value, NULL, 0) : -1;
return -1;
}

View File

@ -157,7 +157,7 @@ katze_net_get_cached_path (KatzeNet* net,
cache_path = g_build_filename (net->cache_path, subfolder, NULL);
else
cache_path = net->cache_path;
g_mkdir_with_parents (cache_path, 0700);
katze_mkdir_with_parents (cache_path, 0700);
checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
extension = g_strrstr (uri, ".");

421
katze/katze-preferences.c Normal file
View File

@ -0,0 +1,421 @@
/*
Copyright (C) 2007-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 "katze-preferences.h"
#if HAVE_CONFIG_H
#include <config.h>
#endif
#if HAVE_HILDON
#include "katze-scrolled.h"
#include <hildon/hildon.h>
#endif
#include <string.h>
#include <glib/gi18n.h>
struct _KatzePreferencesPrivate
{
#if HAVE_HILDON
GtkWidget* scrolled;
GtkSizeGroup* sizegroup;
GtkSizeGroup* sizegroup2;
GtkWidget* box;
GtkWidget* hbox;
#else
GtkWidget* notebook;
GtkWidget* toolbar;
GtkWidget* toolbutton;
GtkSizeGroup* sizegroup;
GtkSizeGroup* sizegroup2;
GtkWidget* page;
GtkWidget* frame;
GtkWidget* box;
GtkWidget* hbox;
#endif
};
G_DEFINE_TYPE (KatzePreferences, katze_preferences, GTK_TYPE_DIALOG);
static void
katze_preferences_finalize (GObject* object);
static void
katze_preferences_class_init (KatzePreferencesClass* class)
{
GObjectClass* gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = katze_preferences_finalize;
g_type_class_add_private (class, sizeof (KatzePreferencesPrivate));
}
static void
katze_preferences_response_cb (KatzePreferences* preferences,
gint response)
{
if (response == GTK_RESPONSE_CLOSE || response == GTK_RESPONSE_APPLY)
gtk_widget_destroy (GTK_WIDGET (preferences));
}
#ifdef HAVE_HILDON_2_2
static void
katze_preferences_size_request_cb (KatzePreferences* preferences,
GtkRequisition* requisition)
{
GdkScreen* screen = gtk_widget_get_screen (GTK_WIDGET (preferences));
if (gdk_screen_get_height (screen) > gdk_screen_get_width (screen))
gtk_widget_hide (gtk_dialog_get_action_area (GTK_DIALOG (preferences)));
else
gtk_widget_show (gtk_dialog_get_action_area (GTK_DIALOG (preferences)));
}
#endif
static void
katze_preferences_init (KatzePreferences* preferences)
{
KatzePreferencesPrivate* priv;
gchar* dialog_title;
preferences->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE ((preferences),
KATZE_TYPE_PREFERENCES, KatzePreferencesPrivate);
dialog_title = g_strdup_printf (_("Preferences for %s"),
g_get_application_name ());
g_object_set (preferences,
"icon-name", GTK_STOCK_PREFERENCES,
"title", dialog_title,
"has-separator", FALSE,
NULL);
g_free (dialog_title);
#if !HAVE_OSX
gtk_dialog_add_buttons (GTK_DIALOG (preferences),
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
#if HAVE_HILDON
GTK_STOCK_SAVE, GTK_RESPONSE_APPLY,
#else
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
#endif
NULL);
#endif
g_object_connect (preferences,
"signal::response", katze_preferences_response_cb, NULL,
NULL);
#ifdef HAVE_HILDON_2_2
katze_preferences_size_request_cb (preferences, NULL);
g_object_connect (preferences,
"signal::size-request", katze_preferences_size_request_cb, NULL,
NULL);
#endif
}
static void
katze_preferences_finalize (GObject* object)
{
G_OBJECT_CLASS (katze_preferences_parent_class)->finalize (object);
}
/**
* katze_preferences_new:
* @parent: the parent window, or %NULL
*
* Creates a new preferences dialog.
*
* Return value: a new #KatzePreferences
*
* Since: 0.2.1
**/
GtkWidget*
katze_preferences_new (GtkWindow* parent)
{
KatzePreferences* preferences;
g_return_val_if_fail (!parent || GTK_IS_WINDOW (parent), NULL);
preferences = g_object_new (KATZE_TYPE_PREFERENCES,
"transient-for", parent,
NULL);
return GTK_WIDGET (preferences);
}
#if HAVE_OSX
static void
katze_preferences_help_clicked_cb (GtkWidget* button,
GtkDialog* dialog)
{
gtk_dialog_response (dialog, GTK_RESPONSE_HELP);
}
static void
katze_preferences_toolbutton_clicked_cb (GtkWidget* toolbutton,
GtkWidget* page)
{
gpointer notebook = g_object_get_data (G_OBJECT (toolbutton), "notebook");
guint n = gtk_notebook_page_num (notebook, page);
gtk_notebook_set_current_page (notebook, n);
}
#endif
static void
katze_preferences_prepare (KatzePreferences* preferences)
{
KatzePreferencesPrivate* priv = preferences->priv;
#if HAVE_HILDON
GtkWidget* viewport;
priv->scrolled = katze_scrolled_new (NULL, NULL);
gtk_box_pack_end (GTK_BOX (GTK_DIALOG (preferences)->vbox),
priv->scrolled, TRUE, TRUE, 4);
viewport = gtk_viewport_new (NULL, NULL);
gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
gtk_container_add (GTK_CONTAINER (priv->scrolled), viewport);
priv->box = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (viewport), priv->box);
priv->hbox = NULL;
priv->sizegroup = NULL;
priv->sizegroup2 = NULL;
g_signal_connect (priv->scrolled, "destroy",
G_CALLBACK (gtk_widget_destroyed), &priv->scrolled);
#else
priv->notebook = gtk_notebook_new ();
gtk_container_set_border_width (GTK_CONTAINER (priv->notebook), 6);
#if HAVE_OSX
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
priv->toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (priv->toolbar), GTK_TOOLBAR_BOTH);
gtk_toolbar_set_show_arrow (GTK_TOOLBAR (priv->toolbar), FALSE);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (preferences)->vbox),
priv->toolbar, FALSE, FALSE, 0);
#else
priv->toolbar = NULL;
#endif
priv->toolbutton = NULL;
gtk_box_pack_end (GTK_BOX (GTK_DIALOG (preferences)->vbox),
priv->notebook, FALSE, FALSE, 4);
priv->sizegroup = NULL;
priv->sizegroup2 = NULL;
priv->page = NULL;
priv->frame = NULL;
priv->box = NULL;
priv->hbox = NULL;
g_signal_connect (priv->notebook, "destroy",
G_CALLBACK (gtk_widget_destroyed), &priv->notebook);
#endif
#if HAVE_OSX
GtkWidget* icon;
GtkWidget* hbox = gtk_hbox_new (FALSE, 0);
GtkWidget* button = gtk_button_new ();
icon = gtk_image_new_from_stock (GTK_STOCK_HELP, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (button), icon);
g_signal_connect (button, "clicked",
G_CALLBACK (katze_preferences_help_clicked_cb), preferences);
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 4);
gtk_box_pack_end (GTK_BOX (GTK_DIALOG (preferences)->action_area),
hbox, FALSE, FALSE, 0);
#endif
gtk_widget_show_all (GTK_DIALOG (preferences)->vbox);
}
/**
* katze_preferences_add_category:
* @preferences: a #KatzePreferences instance
* @label: a category label
* @icon: an icon name
*
* Adds a new category with the specified label to the dialog.
*
* Since: 0.2.1
**/
void
katze_preferences_add_category (KatzePreferences* preferences,
const gchar* label,
const gchar* icon)
{
KatzePreferencesPrivate* priv = preferences->priv;
#if HAVE_HILDON
GtkWidget* widget;
gchar* markup;
if (!priv->scrolled)
katze_preferences_prepare (preferences);
widget = gtk_label_new (NULL);
gtk_widget_show (widget);
markup = g_markup_printf_escaped ("<b>%s</b>", label);
gtk_label_set_markup (GTK_LABEL (widget), markup);
g_free (markup);
gtk_box_pack_start (GTK_BOX (priv->box), widget, TRUE, TRUE, 0);
priv->sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
priv->sizegroup2 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
priv->hbox = NULL;
#else
if (!priv->notebook)
katze_preferences_prepare (preferences);
priv->page = gtk_vbox_new (FALSE, 0);
priv->sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_widget_show (priv->page);
gtk_container_set_border_width (GTK_CONTAINER (priv->page), 4);
gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
priv->page, gtk_label_new (label));
#if HAVE_OSX
priv->toolbutton = GTK_WIDGET (priv->toolbutton ?
gtk_radio_tool_button_new_from_widget (
GTK_RADIO_TOOL_BUTTON (priv->toolbutton))
: gtk_radio_tool_button_new (NULL));
gtk_widget_show (priv->toolbutton);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (priv->toolbutton), label);
gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (priv->toolbutton), icon);
gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar),
GTK_TOOL_ITEM (priv->toolbutton), -1);
g_signal_connect (priv->toolbutton, "clicked",
G_CALLBACK (katze_preferences_toolbutton_clicked_cb), priv->page);
if (priv->toolbutton)
g_object_set_data (G_OBJECT (priv->toolbutton), "notebook", priv->notebook);
#endif
#endif
}
#if !HAVE_HILDON
static GtkWidget*
katze_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;
}
#endif
/**
* katze_preferences_add_group:
* @preferences: a #KatzePreferences instance
* @label: a group label
*
* Adds a new group with the specified label to the dialog.
*
* Since: 0.2.1
**/
void
katze_preferences_add_group (KatzePreferences* preferences,
const gchar* label)
{
#if !HAVE_HILDON
KatzePreferencesPrivate* priv = preferences->priv;
priv->sizegroup2 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
priv->frame = katze_hig_frame_new (label);
gtk_container_set_border_width (GTK_CONTAINER (priv->frame), 4);
gtk_box_pack_start (GTK_BOX (priv->page), priv->frame, FALSE, FALSE, 0);
priv->box = gtk_vbox_new (FALSE, 4);
gtk_container_set_border_width (GTK_CONTAINER (priv->box), 4);
gtk_container_add (GTK_CONTAINER (priv->frame), priv->box);
gtk_widget_show_all (priv->frame);
#endif
}
/**
* katze_preferences_add_widget:
* @preferences: a #KatzePreferences instance
* @widget: a widget representing an option
* @type: "filled", "indented", or "spanned"
*
* Adds a widget to the dialog.
*
* Since: 0.2.1
**/
void
katze_preferences_add_widget (KatzePreferences* preferences,
GtkWidget* widget,
const gchar* type)
{
KatzePreferencesPrivate* priv;
const gchar* _type;
g_return_if_fail (KATZE_IS_PREFERENCES (preferences));
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (type != NULL);
priv = preferences->priv;
_type = g_intern_string (type);
/* Showing implicitly widget and children is not the best idea,
but lots of repeated function calls aren't either. */
gtk_widget_show_all (widget);
if (!priv->hbox)
_type = g_intern_string ("indented");
#ifdef HAVE_HILDON_2_2
else if (HILDON_IS_CHECK_BUTTON (widget) || HILDON_IS_PICKER_BUTTON (widget))
_type = g_intern_string ("indented");
#endif
if (_type != g_intern_static_string ("spanned"))
{
priv->hbox = gtk_hbox_new (FALSE, 4);
gtk_widget_show (priv->hbox);
gtk_box_pack_start (GTK_BOX (priv->hbox), widget, TRUE, FALSE, 0);
}
if (_type == g_intern_static_string ("filled"))
gtk_box_pack_start (GTK_BOX (priv->box), priv->hbox, TRUE, FALSE, 0);
else if (_type == g_intern_static_string ("indented"))
{
GtkWidget* align = gtk_alignment_new (0, 0.5, 0, 0);
gtk_widget_show (align);
gtk_container_add (GTK_CONTAINER (align), priv->hbox);
#if HAVE_HILDON
if (!GTK_IS_SPIN_BUTTON (widget) && !GTK_IS_LABEL (widget))
#else
if (!GTK_IS_SPIN_BUTTON (widget))
#endif
gtk_size_group_add_widget (priv->sizegroup, widget);
gtk_box_pack_start (GTK_BOX (priv->box), align, TRUE, FALSE, 0);
}
else if (_type == g_intern_static_string ("spanned"))
{
GtkWidget* align = gtk_alignment_new (0, 0.5, 0, 0);
gtk_widget_show (align);
gtk_container_add (GTK_CONTAINER (align), widget);
if (!GTK_IS_LABEL (widget) && !GTK_IS_SPIN_BUTTON (widget)
&& !(GTK_IS_BUTTON (widget) && !GTK_IS_TOGGLE_BUTTON (widget)))
gtk_size_group_add_widget (priv->sizegroup2, widget);
gtk_box_pack_start (GTK_BOX (priv->hbox), align, TRUE, FALSE, 0);
}
#if HAVE_HILDON
if (GTK_IS_BUTTON (widget) && !GTK_WIDGET_IS_SENSITIVE (widget))
gtk_widget_hide (widget);
#endif
}

70
katze/katze-preferences.h Normal file
View File

@ -0,0 +1,70 @@
/*
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.
*/
#ifndef __KATZE_PREFERENCES_H__
#define __KATZE_PREFERENCES_H__
#include "katze-utils.h"
G_BEGIN_DECLS
#define KATZE_TYPE_PREFERENCES \
(katze_preferences_get_type ())
#define KATZE_PREFERENCES(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_PREFERENCES, KatzePreferences))
#define KATZE_PREFERENCES_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_PREFERENCES, KatzePreferencesClass))
#define KATZE_IS_PREFERENCES(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_PREFERENCES))
#define KATZE_IS_PREFERENCES_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_PREFERENCES))
#define KATZE_PREFERENCES_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_PREFERENCES, KatzePreferencesClass))
typedef struct _KatzePreferences KatzePreferences;
typedef struct _KatzePreferencesClass KatzePreferencesClass;
typedef struct _KatzePreferencesPrivate KatzePreferencesPrivate;
struct _KatzePreferences
{
GtkDialog parent_instance;
KatzePreferencesPrivate* priv;
};
struct _KatzePreferencesClass
{
GtkDialogClass parent_class;
};
GType
katze_preferences_get_type (void);
GtkWidget*
katze_preferences_new (GtkWindow* parent);
void
katze_preferences_add_category (KatzePreferences* preferences,
const gchar* label,
const gchar* icon);
void
katze_preferences_add_group (KatzePreferences* preferences,
const gchar* label);
void
katze_preferences_add_widget (KatzePreferences* preferences,
GtkWidget* widget,
const gchar* type);
G_END_DECLS
#endif /* __KATZE_PREFERENCES_H__ */

View File

@ -16,6 +16,7 @@
#endif
#include "katze-scrolled.h"
#include "katze-utils.h"
#define DEFAULT_INTERVAL 50
#define DEFAULT_DECELERATION 0.7
@ -819,14 +820,13 @@ katze_scrolled_realize (GtkWidget* widget)
KatzeScrolled* scrolled = KATZE_SCROLLED (widget);
KatzeScrolledPrivate* priv = scrolled->priv;
gboolean drag_scrolling;
GtkSettings* settings = gtk_widget_get_settings (widget);
GtkPolicyType policy;
GdkWindowAttr attr;
GdkColor color;
(*GTK_WIDGET_CLASS (katze_scrolled_parent_class)->realize) (widget);
g_object_get (settings, "gtk-touchscreen-mode", &drag_scrolling, NULL);
drag_scrolling = katze_widget_has_touchscreen_mode (widget);
policy = drag_scrolling ? GTK_POLICY_NEVER : GTK_POLICY_AUTOMATIC;
g_object_set (scrolled, "drag-scrolling", drag_scrolling,
"hscrollbar-policy", policy, "vscrollbar-policy", policy, NULL);
@ -888,7 +888,6 @@ katze_scrolled_class_init (KatzeScrolledClass* class)
GtkWidgetClass* widget_class;
GtkContainerClass* container_class;
GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
GtkSettings* gtk_settings;
gobject_class = G_OBJECT_CLASS (class);
widget_class = GTK_WIDGET_CLASS (class);
@ -944,13 +943,8 @@ katze_scrolled_class_init (KatzeScrolledClass* class)
/* Usually touchscreen mode is either always set or it isn't, so it
should be a safe optimization to not setup events if not needed. */
if ((gtk_settings = gtk_settings_get_default ()))
{
gboolean touchscreen;
g_object_get (gtk_settings, "gtk-touchscreen-mode", &touchscreen, NULL);
if (touchscreen)
katze_scrolled_event_handler_append (katze_scrolled_event_handler, NULL);
}
if (katze_widget_has_touchscreen_mode (NULL))
katze_scrolled_event_handler_append (katze_scrolled_event_handler, NULL);
g_type_class_add_private (class, sizeof (KatzeScrolledPrivate));
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
Copyright (C) 2007-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
@ -11,15 +11,31 @@
#include "katze-utils.h"
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <string.h>
#if HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_HILDON_2_2
#include <hildon/hildon.h>
#endif
static void
proxy_toggle_button_toggled_cb (GtkToggleButton* button,
GObject* object)
{
gboolean toggled = gtk_toggle_button_get_active (button);
gboolean toggled;
#ifdef HAVE_HILDON_2_2
if (HILDON_IS_CHECK_BUTTON (button))
toggled = hildon_check_button_get_active (HILDON_CHECK_BUTTON (button));
#else
toggled = gtk_toggle_button_get_active (button);
#endif
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
g_object_set (object, property, toggled, NULL);
}
@ -60,6 +76,79 @@ proxy_combo_box_text_changed_cb (GtkComboBox* button,
g_object_set (object, property, text, NULL);
}
static const gchar*
katze_app_info_get_commandline (GAppInfo* info)
{
const gchar* exe;
#if GLIB_CHECK_VERSION (2, 20, 0)
exe = g_app_info_get_commandline (info);
#else
exe = g_object_get_data (G_OBJECT (info), "katze-cmdline");
#endif
if (!exe)
exe = g_app_info_get_executable (info);
return exe;
}
static gboolean
proxy_entry_focus_out_event_cb (GtkEntry* entry,
GdkEventFocus* event,
GObject* object);
static void
proxy_combo_box_apps_changed_cb (GtkComboBox* button,
GObject* object)
{
guint active = gtk_combo_box_get_active (button);
GtkTreeModel* model = gtk_combo_box_get_model (button);
GtkTreeIter iter;
if (gtk_tree_model_iter_nth_child (model, &iter, NULL, active))
{
GAppInfo* info;
gboolean use_entry;
GtkWidget* child;
const gchar* exe;
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
gtk_tree_model_get (model, &iter, 0, &info, -1);
use_entry = info && !g_app_info_get_icon (info);
child = gtk_bin_get_child (GTK_BIN (button));
if (use_entry && GTK_IS_CELL_VIEW (child))
{
GtkWidget* entry = gtk_entry_new ();
exe = g_app_info_get_executable (info);
if (exe && *exe && strcmp (exe, "%f"))
gtk_entry_set_text (GTK_ENTRY (entry), exe);
gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (button), entry);
gtk_widget_grab_focus (entry);
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_entry_focus_out_event_cb), object);
g_object_set_data_full (G_OBJECT (entry), "property",
g_strdup (property), g_free);
}
else if (!use_entry && GTK_IS_ENTRY (child))
{
/* Force the combo to change the item again */
gtk_widget_destroy (child);
gtk_combo_box_set_active (button, 0);
gtk_combo_box_set_active_iter (button, &iter);
}
if (info)
{
exe = katze_app_info_get_commandline (info);
g_object_set (object, property, exe, NULL);
g_object_unref (info);
}
else
g_object_set (object, property, "", NULL);
}
}
static void
proxy_entry_activate_cb (GtkEntry* entry,
GObject* object)
@ -99,14 +188,73 @@ proxy_spin_button_changed_cb (GtkSpinButton* button,
}
}
#ifdef HAVE_HILDON_2_2
static void
proxy_picker_button_changed_cb (HildonPickerButton* button,
GObject* object)
{
gint value = hildon_picker_button_get_active (button);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
g_object_set (object, property, value, NULL);
/* FIXME: Implement custom-PROPERTY */
}
#else
static void
proxy_combo_box_changed_cb (GtkComboBox* button,
GObject* object)
{
gint value = gtk_combo_box_get_active (button);
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
gint custom_value = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
"katze-custom-value"));
const gchar* custom_property = g_object_get_data (G_OBJECT (button),
"katze-custom-property");
if (custom_value)
{
GtkWidget* child = gtk_bin_get_child (GTK_BIN (button));
if (value == custom_value && GTK_IS_CELL_VIEW (child))
{
GtkWidget* entry = gtk_entry_new ();
gchar* custom_text = katze_object_get_string (object, custom_property);
if (custom_text && *custom_text)
gtk_entry_set_text (GTK_ENTRY (entry), custom_text);
g_free (custom_text);
gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (button), entry);
gtk_widget_grab_focus (entry);
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_entry_focus_out_event_cb), object);
g_object_set_data_full (G_OBJECT (entry), "property",
g_strdup (custom_property), g_free);
}
else if (value != custom_value && GTK_IS_ENTRY (child))
{
/* Force the combo to change the item again */
gtk_widget_destroy (child);
gtk_combo_box_set_active (button, value + 1);
gtk_combo_box_set_active (button, value);
}
}
g_object_set (object, property, value, NULL);
if (custom_value)
{
#if GTK_CHECK_VERSION (2, 12, 0)
if (value == custom_value)
gtk_widget_set_tooltip_text (GTK_WIDGET (button), NULL);
else
{
gchar* custom_text = katze_object_get_string (object, custom_property);
gtk_widget_set_tooltip_text (GTK_WIDGET (button), custom_text);
g_free (custom_text);
}
#endif
}
}
#endif
static void
proxy_object_notify_boolean_cb (GObject* object,
@ -145,6 +293,127 @@ proxy_widget_string_destroy_cb (GtkWidget* proxy,
proxy_object_notify_string_cb, proxy);
}
static GList*
katze_app_info_get_all_for_category (const gchar* category)
{
GList* all_apps = g_app_info_get_all ();
GList* apps = NULL;
guint i = 0;
GAppInfo* info;
while ((info = g_list_nth_data (all_apps, i++)))
{
#ifdef GDK_WINDOWING_X11
gchar* filename = g_strconcat ("applications/", g_app_info_get_id (info), NULL);
GKeyFile* file = g_key_file_new ();
if (g_key_file_load_from_data_dirs (file, filename, NULL, G_KEY_FILE_NONE, NULL))
{
gchar* cat = g_key_file_get_string (file, "Desktop Entry",
"Categories", NULL);
if (cat && g_strrstr (cat, category))
apps = g_list_append (apps, info);
g_free (cat);
}
g_key_file_free (file);
g_free (filename);
#else
apps = g_list_append (apps, info);
#endif
}
g_list_free (all_apps);
return apps;
}
#if !GLIB_CHECK_VERSION (2, 20, 0)
/* Icon tokenization, for Glib < 2.20 */
static gboolean
g_icon_to_string_tokenized (GIcon *icon,
GString *s)
{
GPtrArray *tokens;
guint i;
if (G_IS_THEMED_ICON (icon))
{
guint n;
const char * const *names;
tokens = g_ptr_array_new ();
g_object_get (icon, "names", &names, NULL);
for (n = 0; names[n] != NULL; n++)
g_ptr_array_add (tokens, g_strdup (names[n]));
}
else if (G_IS_FILE_ICON (icon))
{
tokens = g_ptr_array_new ();
g_ptr_array_add (tokens,
g_file_get_uri (g_file_icon_get_file (G_FILE_ICON (icon))));
}
else
return FALSE;
g_string_append (s, g_type_name_from_instance ((GTypeInstance *)icon));
for (i = 0; i < tokens->len; i++)
{
char *token = g_ptr_array_index (tokens, i);
g_string_append_c (s, ' ');
g_string_append_uri_escaped (s, token, "!$&'()*+,;=:@/", TRUE);
g_free (token);
}
g_ptr_array_free (tokens, TRUE);
return TRUE;
}
/* GIcon serialization, for Glib < 2.20 */
static gchar *
g_icon_to_string (GIcon *icon)
{
gchar *ret = NULL;
g_return_val_if_fail (G_IS_ICON (icon), NULL);
if (G_IS_FILE_ICON (icon))
{
GFile *file = g_file_icon_get_file (G_FILE_ICON (icon));
if (g_file_is_native (file))
{
ret = g_file_get_path (file);
if (!g_utf8_validate (ret, -1, NULL))
{
g_free (ret);
ret = NULL;
}
}
else
ret = g_file_get_uri (file);
}
else if (G_IS_THEMED_ICON (icon))
{
const char * const *names;
g_object_get (icon, "names", &names, NULL);
if (names && names[0] && names[0][0] != '.' &&
g_utf8_validate (names[0], -1, NULL) && names[1] == NULL)
ret = g_strdup (names[0]);
}
if (ret == NULL)
{
GString *s = g_string_new (". ");
if (g_icon_to_string_tokenized (icon, s))
ret = g_string_free (s, FALSE);
else
g_string_free (s, TRUE);
}
return ret;
}
#endif
/**
* katze_property_proxy:
* @object: a #GObject
@ -173,11 +442,22 @@ proxy_widget_string_destroy_cb (GtkWidget* proxy,
* Since 0.2.0 the following hints are also supported:
* "font-monospace": the widget created will be particularly suitable for
* choosing a fixed-width font from installed fonts.
* Since 0.2.1 the following hints are also supported:
* "application-TYPE": the widget created will be particularly suitable
* for choosing an application to open TYPE files, ie. "text/plain".
* "application-CATEGORY": the widget created will be particularly suitable
* for choosing an application to open CATEGORY files, ie. "Network".
* "custom-PROPERTY": the last value of an enumeration will be the "custom"
* value, where the user may enter text freely, which then updates
* the property PROPERTY instead. This applies only to enumerations.
*
* Any other values for @hint are silently ignored.
*
* Since 0.1.2 strings without hints and booleans are truly synchronous
* including property changes causing the proxy to be updated.
* including property changes causing the proxy to be updated.
*
* Since 0.2.1 the proxy may contain a label if the platform
* has according widgets.
*
* Return value: a new widget
**/
@ -216,12 +496,23 @@ 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"))
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (widget), FALSE);
else
#ifdef HAVE_HILDON_2_2
if (_hint != g_intern_string ("toggle"))
{
widget = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
gtk_button_set_label (GTK_BUTTON (widget), gettext (nick));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), toggled);
hildon_check_button_set_active (HILDON_CHECK_BUTTON (widget), toggled);
}
else
#endif
{
widget = gtk_check_button_new ();
if (_hint == g_intern_string ("toggle"))
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (widget), FALSE);
else
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);
@ -295,6 +586,9 @@ katze_property_proxy (gpointer object,
pango_context_list_families (context, &families, &n_families);
if (!string)
string = g_strdup (G_PARAM_SPEC_STRING (pspec)->default_value);
/* 'sans' and 'sans-serif' are presumably the same */
if (!g_strcmp0 (string, "sans-serif"))
katze_assign (string, g_strdup ("sans"));
if (string)
{
gint j = 0;
@ -315,6 +609,101 @@ katze_property_proxy (gpointer object,
G_CALLBACK (proxy_combo_box_text_changed_cb), object);
g_free (families);
}
else if (type == G_TYPE_PARAM_STRING && hint && g_str_has_prefix (hint, "application-"))
{
GtkListStore* model;
GtkCellRenderer* renderer;
GtkComboBox* combo;
GList* apps;
const gchar* app_type = &hint[12];
gint icon_width = 16;
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL);
model = gtk_list_store_new (4, G_TYPE_APP_INFO, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_INT);
widget = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model));
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, FALSE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "icon-name", 1);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "width", 3);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "text", 2);
combo = GTK_COMBO_BOX (widget);
apps = g_app_info_get_all_for_type (app_type);
if (!apps)
apps = katze_app_info_get_all_for_category (app_type);
string = katze_object_get_string (object, property);
if (!g_strcmp0 (string, ""))
katze_assign (string, NULL);
if (apps)
{
GtkTreeIter iter_none;
gint i = 0;
GAppInfo* info;
gtk_list_store_insert_with_values (model, &iter_none, 0,
0, NULL, 1, NULL, 2, _("None"), 3, icon_width, -1);
while ((info = g_list_nth_data (apps, i++)))
{
const gchar* name = g_app_info_get_name (info);
GIcon* icon = g_app_info_get_icon (info);
gchar* icon_name;
GtkTreeIter iter;
if (!g_app_info_should_show (info))
continue;
icon_name = icon ? g_icon_to_string (icon) : NULL;
gtk_list_store_insert_with_values (model, &iter, G_MAXINT,
0, info, 1, icon_name, 2, name, 3, icon_width, -1);
if (string && !strcmp (katze_app_info_get_commandline (info), string))
gtk_combo_box_set_active_iter (combo, &iter);
g_free (icon_name);
}
info = g_app_info_create_from_commandline ("",
"", G_APP_INFO_CREATE_NONE, NULL);
gtk_list_store_insert_with_values (model, NULL, G_MAXINT,
0, info, 1, NULL, 2, _("Custom..."), 3, icon_width, -1);
g_object_unref (info);
if (gtk_combo_box_get_active (combo) == -1)
{
if (string)
{
GtkWidget* entry;
const gchar* exe;
info = g_app_info_create_from_commandline (string,
NULL, G_APP_INFO_CREATE_NONE, NULL);
#if !GLIB_CHECK_VERSION (2, 20, 0)
g_object_set_data (G_OBJECT (info), "katze-cmdline", string);
#endif
entry = gtk_entry_new ();
exe = g_app_info_get_executable (info);
if (exe && *exe && strcmp (exe, "%f"))
gtk_entry_set_text (GTK_ENTRY (entry), string);
gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (combo), entry);
g_object_unref (info);
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_entry_focus_out_event_cb), object);
g_object_set_data_full (G_OBJECT (entry), "property",
g_strdup (property), g_free);
}
else
gtk_combo_box_set_active_iter (combo, &iter_none);
}
}
g_list_free (apps);
g_signal_connect (widget, "changed",
G_CALLBACK (proxy_combo_box_apps_changed_cb), object);
}
else if (type == G_TYPE_PARAM_STRING)
{
gchar* notify_property;
@ -356,6 +745,10 @@ katze_property_proxy (gpointer object,
widget = gtk_spin_button_new_with_range (
G_PARAM_SPEC_INT (pspec)->minimum,
G_PARAM_SPEC_INT (pspec)->maximum, 1);
#if HAVE_HILDON
hildon_gtk_entry_set_input_mode (GTK_ENTRY (widget),
HILDON_GTK_INPUT_MODE_NUMERIC);
#endif
/* Keep it narrow, 5 digits are usually fine */
gtk_entry_set_width_chars (GTK_ENTRY (widget), 5);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
@ -368,23 +761,81 @@ katze_property_proxy (gpointer object,
GEnumClass* enum_class = G_ENUM_CLASS (
g_type_class_ref (pspec->value_type));
gint value = katze_object_get_enum (object, property);
const gchar* custom = NULL;
if (hint && g_str_has_prefix (hint, "custom-"))
custom = &hint[7];
#ifdef HAVE_HILDON_2_2
GtkWidget* selector;
widget = hildon_picker_button_new (
HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
selector = hildon_touch_selector_new_text ();
hildon_button_set_title (HILDON_BUTTON (widget), gettext (nick));
hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (widget),
HILDON_TOUCH_SELECTOR (selector));
#else
widget = gtk_combo_box_new_text ();
#endif
for (i = 0; i < enum_class->n_values; i++)
{
const gchar* label = gettext (enum_class->values[i].value_nick);
#ifdef HAVE_HILDON_2_2
hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector), label);
#else
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), label);
#endif
}
#ifdef HAVE_HILDON_2_2
hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, value);
g_signal_connect (widget, "value-changed",
G_CALLBACK (proxy_picker_button_changed_cb), object);
#else
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), value);
g_signal_connect (widget, "changed",
G_CALLBACK (proxy_combo_box_changed_cb), object);
#endif
if (custom)
{
gchar* custom_text = katze_object_get_string (object, custom);
if (value == (gint)(enum_class->n_values - 1))
{
GtkWidget* entry = gtk_entry_new ();
gchar* text = katze_object_get_string (object, custom);
if (text && *text)
gtk_entry_set_text (GTK_ENTRY (entry), text);
gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (widget), entry);
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_entry_focus_out_event_cb), object);
g_object_set_data_full (G_OBJECT (entry), "property",
g_strdup (custom), g_free);
}
#if GTK_CHECK_VERSION (2, 12, 0)
else
gtk_widget_set_tooltip_text (widget, custom_text);
#endif
g_free (custom_text);
g_object_set_data (G_OBJECT (widget), "katze-custom-value",
GINT_TO_POINTER (enum_class->n_values - 1));
g_object_set_data (G_OBJECT (widget), "katze-custom-property",
(gpointer)custom);
}
g_type_class_unref (enum_class);
}
else
widget = gtk_label_new (gettext (nick));
g_free (string);
gtk_widget_set_tooltip_text (widget, g_param_spec_get_blurb (pspec));
#if GTK_CHECK_VERSION (2, 12, 0)
if (!gtk_widget_get_tooltip_text (widget))
gtk_widget_set_tooltip_text (widget, g_param_spec_get_blurb (pspec));
#endif
gtk_widget_set_sensitive (widget, pspec->flags & G_PARAM_WRITABLE);
g_object_set_data_full (G_OBJECT (widget), "property",
@ -401,6 +852,9 @@ katze_property_proxy (gpointer object,
* Create a label widget displaying the name of the specified object's property.
*
* Return value: a new label widget
*
* Since 0.2.1 the label will be empty if the property proxy for the
* same property would contain a label already.
**/
GtkWidget*
katze_property_label (gpointer object,
@ -421,8 +875,18 @@ katze_property_label (gpointer object,
property, G_OBJECT_CLASS_NAME (class));
return gtk_label_new (property);
}
#ifdef HAVE_HILDON_2_2
if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_ENUM)
return gtk_label_new (NULL);
#endif
nick = g_param_spec_get_nick (pspec);
widget = gtk_label_new (nick);
#if GTK_CHECK_VERSION (2, 12, 0)
gtk_widget_set_tooltip_text (widget, g_param_spec_get_blurb (pspec));
#endif
gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
return widget;
}
@ -849,3 +1313,167 @@ katze_object_get_object (gpointer object,
g_object_get (object, property, &value, NULL);
return value;
}
/**
* katze_mkdir_with_parents:
* @pathname: a pathname in the GLib file name encoding
* @mode: permissions to use for newly created directories
*
* Create a directory if it doesn't already exist. Create intermediate
* parent directories as needed, too.
*
* Similar to g_mkdir_with_parents() but returning early if the
* @pathname refers to an existing directory.
*
* Returns: 0 if the directory already exists, or was successfully
* created. Returns -1 if an error occurred, with errno set.
*
* Since: 0.2.1
*/
/* Creating directories recursively
Copyright 2000 Red Hat, Inc.
Originally copied from Glib 2.20, coding style adjusted
Modified to determine file existence early and pathname must be != NULL */
int
katze_mkdir_with_parents (const gchar* pathname,
int mode)
{
gchar* fn, *p;
if (g_file_test (pathname, G_FILE_TEST_EXISTS))
return 0;
fn = g_strdup (pathname);
if (g_path_is_absolute (fn))
p = (gchar *) g_path_skip_root (fn);
else
p = fn;
do
{
while (*p && !G_IS_DIR_SEPARATOR (*p))
p++;
if (!*p)
p = NULL;
else
*p = '\0';
if (!g_file_test (fn, G_FILE_TEST_EXISTS))
{
if (g_mkdir (fn, mode) == -1)
{
g_free (fn);
return -1;
}
}
else if (!g_file_test (fn, G_FILE_TEST_IS_DIR))
{
g_free (fn);
return -1;
}
if (p)
{
*p++ = G_DIR_SEPARATOR;
while (*p && G_IS_DIR_SEPARATOR (*p))
p++;
}
}
while (p);
g_free (fn);
return 0;
}
/**
* katze_widget_has_touchscreen_mode:
* @widget: a #GtkWidget, or %NULL
*
* Determines whether @widget should operate in touchscreen
* mode, as determined by GtkSettings or the environment
* variable MIDORI_TOUCHSCREEN.
*
* If @widget is %NULL, the default screen will be used.
*
* Returns: %TRUE if touchscreen mode should be used
*
* Since: 0.2.1
*/
gboolean
katze_widget_has_touchscreen_mode (GtkWidget* widget)
{
const gchar* touchscreen = g_getenv ("MIDORI_TOUCHSCREEN");
if (touchscreen && touchscreen[0] == '1')
return TRUE;
else if (touchscreen && touchscreen[0] == '0')
return FALSE;
else
{
GdkScreen* screen = widget && gtk_widget_has_screen (widget)
? gtk_widget_get_screen (widget) : gdk_screen_get_default ();
GtkSettings* gtk_settings = gtk_settings_get_for_screen (screen);
gboolean enabled;
g_object_get (gtk_settings, "gtk-touchscreen-mode", &enabled, NULL);
return enabled;
}
}
/**
* katze_load_cached_icon:
* @uri: an URI string
* @widget: a #GtkWidget, or %NULL
*
* Loads a cached icon for the specified @uri. If there is no
* icon and @widget is specified, a default will be returned.
*
* Returns: a #GdkPixbuf, or %NULL
*
* Since: 0.2.2
*/
GdkPixbuf*
katze_load_cached_icon (const gchar* uri,
GtkWidget* widget)
{
GdkPixbuf* icon = NULL;
if (g_str_has_prefix (uri, "http://"))
{
guint i;
gchar* icon_uri;
gchar* checksum;
gchar* ext;
gchar* filename;
gchar* path;
i = 8;
while (uri[i] != '\0' && uri[i] != '/')
i++;
if (uri[i] == '/')
{
icon_uri = g_strdup (uri);
icon_uri[i] = '\0';
icon_uri = g_strdup_printf ("%s/favicon.ico", icon_uri);
}
else
icon_uri = g_strdup_printf ("%s/favicon.ico", uri);
checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, icon_uri, -1);
ext = g_strrstr (icon_uri, ".");
g_free (icon_uri);
filename = g_strdup_printf ("%s%s", checksum, ext ? ext : "");
g_free (checksum);
path = g_build_filename (g_get_user_cache_dir (), PACKAGE_NAME,
"icons", filename, NULL);
if ((icon = gdk_pixbuf_new_from_file_at_size (path, 16, 16, NULL)))
{
g_free (path);
return icon;
}
g_free (path);
}
return icon || !widget ? icon : gtk_widget_render_icon (widget,
GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
}

View File

@ -34,11 +34,12 @@ G_BEGIN_DECLS
* Frees @lvalue if needed and assigns it the value of @rvalue.
**/
#define katze_assign(lvalue, rvalue) \
if (1) \
do \
{ \
g_free (lvalue); \
lvalue = rvalue; \
}
} \
while (0)
/**
* katze_object_assign:
@ -48,12 +49,13 @@ G_BEGIN_DECLS
* Unrefs @lvalue if needed and assigns it the value of @rvalue.
**/
#define katze_object_assign(lvalue, rvalue) \
if (1) \
do \
{ \
if (lvalue) \
g_object_unref (lvalue); \
lvalue = rvalue; \
}
} \
while (0)
/**
* katze_strv_assign:
@ -65,11 +67,12 @@ G_BEGIN_DECLS
* Since: 0.1.7
**/
#define katze_strv_assign(lvalue, rvalue) \
if (1) \
do \
{ \
g_strfreev (lvalue); \
lvalue = rvalue; \
}
} \
while (0)
GtkWidget*
katze_property_proxy (gpointer object,
@ -137,6 +140,17 @@ gpointer
katze_object_get_object (gpointer object,
const gchar* property);
int
katze_mkdir_with_parents (const gchar* pathname,
int mode);
gboolean
katze_widget_has_touchscreen_mode (GtkWidget* widget);
GdkPixbuf*
katze_load_cached_icon (const gchar* uri,
GtkWidget* widget);
G_END_DECLS
#endif /* __KATZE_UTILS_H__ */

View File

@ -22,5 +22,6 @@
#include "katze-separatoraction.h"
#include "katze-net.h"
#include "katze-scrolled.h"
#include "katze-preferences.h"
#endif /* __KATZE_H__ */

View File

@ -10,5 +10,5 @@ obj.target = 'katze'
obj.includes = '. ../.'
obj.find_sources_in_dirs ('.')
obj.add_marshal_file ('marshal.list', 'katze_cclosure_marshal')
obj.uselib = 'M GMODULE LIBSOUP GTK LIBXML WEBKIT'
obj.uselib = 'M GMODULE LIBSOUP GTK HILDON LIBXML WEBKIT'
obj.install_path = None

View File

@ -39,6 +39,7 @@ G_BEGIN_DECLS
#define GTK_TYPE_ICON_ENTRY GTK_TYPE_ENTRY
#define gtk_icon_entry_new gtk_entry_new
#define gtk_icon_entry_set_icon_from_stock gtk_entry_set_icon_from_stock
#define gtk_icon_entry_set_icon_from_icon_name gtk_entry_set_icon_from_icon_name
void
gtk_icon_entry_set_icon_from_pixbuf (GtkEntry* entry,

View File

@ -29,12 +29,8 @@
#if HAVE_UNISTD_H
#include <unistd.h>
#define is_writable(_cfg_filename) \
!g_access (_cfg_filename, W_OK) || \
!g_file_test (_cfg_filename, G_FILE_TEST_EXISTS)
#else
#define is_writable(_cfg_filename) 1
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@ -50,8 +46,14 @@
#include <locale.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_HILDON
#include <libosso.h>
#define BOOKMARK_FILE "/home/user/.bookmarks/MyBookmarks.xml"
#else
#define BOOKMARK_FILE "bookmarks.xbel"
#endif
#define MIDORI_HISTORY_ERROR g_quark_from_string("MIDORI_HISTORY_ERROR")
@ -66,8 +68,11 @@ typedef enum
static gchar*
build_config_filename (const gchar* filename)
{
const gchar* path = sokoke_set_config_dir (NULL);
g_mkdir_with_parents (path, 0700);
const gchar* path;
if (g_path_is_absolute (filename))
return g_strdup (filename);
path = sokoke_set_config_dir (NULL);
return g_build_filename (path, filename, NULL);
}
@ -199,47 +204,52 @@ settings_save_to_file (MidoriWebSettings* settings,
type = G_PARAM_SPEC_TYPE (pspec);
property = g_param_spec_get_name (pspec);
if (!(pspec->flags & G_PARAM_WRITABLE))
{
gchar* prop_comment = g_strdup_printf ("# %s", property);
g_key_file_set_string (key_file, "settings", prop_comment, "");
g_free (prop_comment);
continue;
}
if (type == G_TYPE_PARAM_STRING)
{
gchar* string;
const gchar* def_string = G_PARAM_SPEC_STRING (pspec)->default_value;
g_object_get (settings, property, &string, NULL);
g_key_file_set_string (key_file, "settings", property,
string ? string : "");
if (!string)
string = g_strdup ("");
if (!def_string)
def_string = "";
if (strcmp (string, def_string))
g_key_file_set_string (key_file, "settings", property, string);
g_free (string);
}
else if (type == G_TYPE_PARAM_INT)
{
gint integer;
g_object_get (settings, property, &integer, NULL);
g_key_file_set_integer (key_file, "settings", property, integer);
if (integer != G_PARAM_SPEC_INT (pspec)->default_value)
g_key_file_set_integer (key_file, "settings", property, integer);
}
else if (type == G_TYPE_PARAM_FLOAT)
{
gfloat number;
g_object_get (settings, property, &number, NULL);
g_key_file_set_double (key_file, "settings", property, number);
if (number != G_PARAM_SPEC_FLOAT (pspec)->default_value)
g_key_file_set_double (key_file, "settings", property, number);
}
else if (type == G_TYPE_PARAM_BOOLEAN)
{
gboolean truth;
g_object_get (settings, property, &truth, NULL);
g_key_file_set_boolean (key_file, "settings", property, truth);
if (truth != G_PARAM_SPEC_BOOLEAN (pspec)->default_value)
g_key_file_set_boolean (key_file, "settings", property, truth);
}
else if (type == G_TYPE_PARAM_ENUM)
{
GEnumClass* enum_class = G_ENUM_CLASS (
g_type_class_ref (pspec->value_type));
gint integer;
GEnumValue* enum_value;
g_object_get (settings, property, &integer, NULL);
GEnumValue* enum_value = g_enum_get_value (enum_class, integer);
g_key_file_set_string (key_file, "settings", property,
enum_value->value_name);
enum_value = g_enum_get_value (enum_class, integer);
if (integer != G_PARAM_SPEC_ENUM (pspec)->default_value)
g_key_file_set_string (key_file, "settings", property,
enum_value->value_name);
}
else
g_warning (_("Invalid configuration value '%s'"), property);
@ -445,7 +455,7 @@ midori_history_remove_item_cb (KatzeArray* history,
sqlcmd = sqlite3_mprintf (
"DELETE FROM history WHERE uri = '%q' AND"
" title = '%q' AND date = %" G_GINT64_FORMAT,
" title = '%q' AND date = %llu",
katze_item_get_uri (item),
katze_item_get_name (item),
katze_item_get_added (item));
@ -491,7 +501,7 @@ midori_history_notify_item_cb (KatzeItem* item,
GError* error = NULL;
sqlcmd = sqlite3_mprintf ("UPDATE history SET title='%q' WHERE "
"uri='%q' AND date=%" G_GUINT64_FORMAT,
"uri='%q' AND date=%llu",
katze_item_get_name (item),
katze_item_get_uri (item),
katze_item_get_added (item));
@ -539,8 +549,8 @@ midori_history_add_item_cb (KatzeArray* array,
}
}
sqlcmd = sqlite3_mprintf ("INSERT INTO history VALUES"
"('%q', '%q', %" G_GUINT64_FORMAT ","
" %" G_GUINT64_FORMAT ")",
"('%q', '%q', %llu,"
" %llu)",
katze_item_get_uri (item),
katze_item_get_name (item),
katze_item_get_added (item),
@ -810,7 +820,7 @@ midori_bookmarks_notify_item_cb (KatzeArray* folder,
gchar* config_file;
GError* error;
config_file = build_config_filename ("bookmarks.xbel");
config_file = build_config_filename (BOOKMARK_FILE);
error = NULL;
if (!midori_array_to_file (bookmarks, config_file, "xbel", &error))
{
@ -822,7 +832,7 @@ midori_bookmarks_notify_item_cb (KatzeArray* folder,
static void
midori_bookmarks_add_item_cb (KatzeArray* folder,
GObject* item,
KatzeItem* item,
KatzeArray* bookmarks);
static void
@ -831,24 +841,17 @@ midori_bookmarks_remove_item_cb (KatzeArray* folder,
KatzeArray* bookmarks);
static void
midori_bookmarks_add_item_cb (KatzeArray* folder,
GObject* item,
KatzeArray* bookmarks)
midori_bookmarks_connect_item (KatzeArray* folder,
KatzeItem* item,
KatzeArray* bookmarks)
{
gchar* config_file;
GError* error;
config_file = build_config_filename ("bookmarks.xbel");
error = NULL;
if (!midori_array_to_file (bookmarks, config_file, "xbel", &error))
if (KATZE_IS_ARRAY (item))
{
g_warning (_("The bookmarks couldn't be saved. %s"), error->message);
g_error_free (error);
}
g_free (config_file);
KatzeItem* child;
guint i = 0;
while ((child = katze_array_get_nth_item ((KatzeArray*)item, i++)))
midori_bookmarks_connect_item ((KatzeArray*)item, child, bookmarks);
if (folder == bookmarks && KATZE_IS_ARRAY (item))
{
g_signal_connect_after (item, "add-item",
G_CALLBACK (midori_bookmarks_add_item_cb), bookmarks);
g_signal_connect_after (item, "remove-item",
@ -859,6 +862,26 @@ midori_bookmarks_add_item_cb (KatzeArray* folder,
G_CALLBACK (midori_bookmarks_notify_item_cb), bookmarks);
}
static void
midori_bookmarks_add_item_cb (KatzeArray* folder,
KatzeItem* item,
KatzeArray* bookmarks)
{
gchar* config_file;
GError* error;
config_file = build_config_filename (BOOKMARK_FILE);
error = NULL;
if (!midori_array_to_file (bookmarks, config_file, "xbel", &error))
{
g_warning (_("The bookmarks couldn't be saved. %s"), error->message);
g_error_free (error);
}
g_free (config_file);
midori_bookmarks_connect_item (folder, item, bookmarks);
}
static void
midori_bookmarks_remove_item_cb (KatzeArray* folder,
GObject* item,
@ -867,7 +890,7 @@ midori_bookmarks_remove_item_cb (KatzeArray* folder,
gchar* config_file;
GError* error;
config_file = build_config_filename ("bookmarks.xbel");
config_file = build_config_filename (BOOKMARK_FILE);
error = NULL;
if (!midori_array_to_file (bookmarks, config_file, "xbel", &error))
{
@ -877,8 +900,15 @@ midori_bookmarks_remove_item_cb (KatzeArray* folder,
g_free (config_file);
if (KATZE_IS_ARRAY (item))
{
g_signal_handlers_disconnect_by_func (item,
midori_bookmarks_add_item_cb, bookmarks);
g_signal_handlers_disconnect_by_func (item,
midori_bookmarks_remove_item_cb, bookmarks);
}
g_signal_handlers_disconnect_by_func (item,
midori_bookmarks_notify_item_cb, bookmarks);
}
static void
@ -966,8 +996,9 @@ midori_app_add_browser_cb (MidoriApp* app,
midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
/* Extensions */
addon = g_object_new (MIDORI_TYPE_EXTENSIONS, "app", app, NULL);
addon = g_object_new (MIDORI_TYPE_EXTENSIONS, NULL);
gtk_widget_show (addon);
g_object_set (addon, "app", app, NULL);
midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
g_object_unref (panel);
@ -1308,7 +1339,6 @@ midori_load_extensions (gpointer data)
{
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)))
{
@ -1352,13 +1382,10 @@ 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_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);
@ -1419,15 +1446,14 @@ midori_load_session (gpointer data)
GtkAction* action = gtk_action_group_get_action (action_group, "LastSession");
g_signal_connect (action, "activate",
G_CALLBACK (midori_browser_action_last_session_activate_cb), browser);
gtk_action_set_sensitive (action, TRUE);
gtk_action_set_visible (action, TRUE);
}
midori_app_add_browser (app, browser);
gtk_widget_show (GTK_WIDGET (browser));
katze_assign (config_file, build_config_filename ("accels"));
if (is_writable (config_file))
g_signal_connect_after (gtk_accel_map_get (), "changed",
G_CALLBACK (accel_map_changed_cb), NULL);
g_signal_connect_after (gtk_accel_map_get (), "changed",
G_CALLBACK (accel_map_changed_cb), NULL);
if (katze_array_is_empty (_session))
{
@ -1465,17 +1491,14 @@ midori_load_session (gpointer data)
g_object_unref (_session);
katze_assign (config_file, build_config_filename ("session.xbel"));
if (is_writable (config_file))
{
g_signal_connect_after (browser, "notify::uri",
G_CALLBACK (midori_browser_session_cb), session);
g_signal_connect_after (browser, "add-tab",
G_CALLBACK (midori_browser_session_cb), session);
g_signal_connect_after (browser, "remove-tab",
G_CALLBACK (midori_browser_session_cb), session);
g_object_weak_ref (G_OBJECT (session),
(GWeakNotify)(midori_browser_weak_notify_cb), browser);
}
g_signal_connect_after (browser, "notify::uri",
G_CALLBACK (midori_browser_session_cb), session);
g_signal_connect_after (browser, "add-tab",
G_CALLBACK (midori_browser_session_cb), session);
g_signal_connect_after (browser, "remove-tab",
G_CALLBACK (midori_browser_session_cb), session);
g_object_weak_ref (G_OBJECT (session),
(GWeakNotify)(midori_browser_weak_notify_cb), browser);
if (command)
midori_app_send_command (app, command);
@ -1569,12 +1592,22 @@ midori_remove_config_file (gint clear_prefs,
if ((clear_prefs & flag) == flag)
{
gchar* config_file = build_config_filename (filename);
if (is_writable (config_file))
g_unlink (config_file);
g_unlink (config_file);
g_free (config_file);
}
}
#ifdef HAVE_SIGNAL_H
static void
signal_handler (int signal_id)
{
signal (signal_id, 0);
midori_app_quit_cb (NULL);
if (kill (getpid (), signal_id))
exit (1);
}
#endif
int
main (int argc,
char** argv)
@ -1593,8 +1626,10 @@ main (int argc,
{
{ "app", 'a', 0, G_OPTION_ARG_STRING, &webapp,
N_("Run ADDRESS as a web application"), N_("ADDRESS") },
#if !HAVE_HILDON
{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &config,
N_("Use FOLDER as configuration folder"), N_("FOLDER") },
#endif
{ "run", 'r', 0, G_OPTION_ARG_NONE, &run,
N_("Run the specified filename as javascript"), NULL },
#if WEBKIT_CHECK_VERSION (1, 1, 6)
@ -1627,9 +1662,6 @@ main (int argc,
sqlite3* db;
gint max_history_age;
#endif
#if HAVE_HILDON
osso_context_t* osso_context;
#endif
gint clear_prefs = MIDORI_CLEAR_NONE;
#if ENABLE_NLS
@ -1650,6 +1682,21 @@ main (int argc,
textdomain (GETTEXT_PACKAGE);
#endif
#ifdef HAVE_SIGNAL_H
#ifdef SIGHUP
signal (SIGHUP, &signal_handler);
#endif
#ifdef SIGINT
signal (SIGINT, &signal_handler);
#endif
#ifdef SIGTERM
signal (SIGTERM, &signal_handler);
#endif
#ifdef SIGQUIT
signal (SIGQUIT, &signal_handler);
#endif
#endif
/* Parse cli options */
webapp = NULL;
config = NULL;
@ -1736,14 +1783,26 @@ main (int argc,
NULL);
g_object_unref (settings);
g_object_set (browser, "settings", settings, NULL);
sokoke_set_config_dir ("/");
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, "quit",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (browser, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show (GTK_WIDGET (browser));
midori_browser_activate_action (browser, "Location");
if (execute)
{
i = 0;
while (uris[i] != NULL)
{
midori_browser_activate_action (browser, uris[i]);
i++;
}
}
gtk_main ();
return 0;
}
@ -1752,16 +1811,6 @@ main (int argc,
if (run)
return midori_run_script (uris ? *uris : NULL);
#if HAVE_HILDON
osso_context = osso_initialize (PACKAGE_NAME, PACKAGE_VERSION, FALSE, NULL);
if (!osso_context)
{
g_critical ("Error initializing OSSO D-Bus context - Midori");
return 1;
}
#endif
if (config && !g_path_is_absolute (config))
{
g_critical (_("The specified configuration folder is invalid."));
@ -1819,12 +1868,16 @@ main (int argc,
return 1;
}
katze_mkdir_with_parents (sokoke_set_config_dir (NULL), 0700);
/* Load configuration files */
error_messages = g_string_new (NULL);
config_file = build_config_filename ("config");
error = NULL;
settings = settings_new_from_file (config_file, &extensions);
katze_assign (config_file, build_config_filename ("accels"));
if (!g_file_test (config_file, G_FILE_TEST_EXISTS))
katze_assign (config_file, sokoke_find_config_filename (NULL, "accels"));
gtk_accel_map_load (config_file);
katze_assign (config_file, build_config_filename ("search"));
error = NULL;
@ -1862,7 +1915,7 @@ main (int argc,
}
bookmarks = katze_array_new (KATZE_TYPE_ARRAY);
#if HAVE_LIBXML
katze_assign (config_file, build_config_filename ("bookmarks.xbel"));
katze_assign (config_file, build_config_filename (BOOKMARK_FILE));
error = NULL;
if (!midori_array_from_file (bookmarks, config_file, "xbel", &error))
{
@ -1974,7 +2027,9 @@ main (int argc,
{
item = katze_item_new ();
/* Construct an absolute path if the file is relative */
if (g_file_test (uri, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
if (g_path_is_absolute (uri))
uri_ready = g_strconcat ("file://", uri, NULL);
else if (g_file_test (uri, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
{
gchar* current_dir = g_get_current_dir ();
uri_ready = g_strconcat ("file://", current_dir,
@ -1994,12 +2049,11 @@ main (int argc,
}
katze_assign (config_file, build_config_filename ("config"));
if (is_writable (config_file))
g_signal_connect_after (settings, "notify",
G_CALLBACK (settings_notify_cb), app);
g_signal_connect_after (settings, "notify",
G_CALLBACK (settings_notify_cb), app);
katze_assign (config_file, build_config_filename ("search"));
if (is_writable (config_file))
if (1)
{
g_signal_connect_after (search_engines, "add-item",
G_CALLBACK (midori_search_engines_modify_cb), search_engines);
@ -2013,47 +2067,27 @@ main (int argc,
G_CALLBACK (midori_search_engines_modify_cb), search_engines);
}
}
katze_assign (config_file, build_config_filename ("bookmarks.xbel"));
if (is_writable (config_file))
katze_assign (config_file, build_config_filename (BOOKMARK_FILE));
/* Don't save bookmarks if they are not our own */
if (!g_path_is_absolute (BOOKMARK_FILE))
{
midori_bookmarks_connect_item (NULL, (KatzeItem*)bookmarks, bookmarks);
g_signal_connect_after (bookmarks, "add-item",
G_CALLBACK (midori_bookmarks_add_item_cb), bookmarks);
g_signal_connect_after (bookmarks, "remove-item",
G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);
if (!katze_array_is_empty (bookmarks))
{
i = 0;
while ((item = katze_array_get_nth_item (bookmarks, i++)))
{
if (KATZE_IS_ARRAY (item))
{
g_signal_connect_after (item, "add-item",
G_CALLBACK (midori_bookmarks_add_item_cb), bookmarks);
g_signal_connect_after (item, "remove-item",
G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);
}
g_signal_connect_after (item, "notify",
G_CALLBACK (midori_bookmarks_notify_item_cb), bookmarks);
}
}
}
katze_assign (config_file, build_config_filename ("tabtrash.xbel"));
if (is_writable (config_file))
{
g_signal_connect_after (trash, "add-item",
G_CALLBACK (midori_trash_add_item_cb), NULL);
g_signal_connect_after (trash, "remove-item",
G_CALLBACK (midori_trash_remove_item_cb), NULL);
}
g_signal_connect_after (trash, "add-item",
G_CALLBACK (midori_trash_add_item_cb), NULL);
g_signal_connect_after (trash, "remove-item",
G_CALLBACK (midori_trash_remove_item_cb), NULL);
#if HAVE_SQLITE
katze_assign (config_file, build_config_filename ("history.db"));
if (is_writable (config_file))
{
g_signal_connect_after (history, "add-item",
G_CALLBACK (midori_history_add_item_cb), db);
g_signal_connect_after (history, "clear",
G_CALLBACK (midori_history_clear_cb), db);
}
g_signal_connect_after (history, "add-item",
G_CALLBACK (midori_history_add_item_cb), db);
g_signal_connect_after (history, "clear",
G_CALLBACK (midori_history_clear_cb), db);
#endif
katze_item_set_parent (KATZE_ITEM (_session), app);
@ -2095,10 +2129,6 @@ main (int argc,
gtk_main ();
#if HAVE_HILDON
osso_deinitialize (osso_context);
#endif
settings = katze_object_get_object (app, "settings");
#if HAVE_SQLITE
g_object_get (settings, "maximum-history-age", &max_history_age, NULL);
@ -2128,14 +2158,20 @@ main (int argc,
g_free (cache);
}
midori_remove_config_file (clear_prefs, MIDORI_CLEAR_TRASH, "tabtrash.xbel");
if ((clear_prefs & MIDORI_CLEAR_WEB_CACHE) == MIDORI_CLEAR_WEB_CACHE)
{
gchar* cache = g_build_filename (g_get_user_cache_dir (),
PACKAGE_NAME, "web", NULL);
sokoke_remove_path (cache, TRUE);
g_free (cache);
}
}
if (katze_object_get_boolean (settings, "load-on-startup")
!= MIDORI_STARTUP_LAST_OPEN_PAGES)
{
katze_assign (config_file, build_config_filename ("session.xbel"));
if (is_writable (config_file))
g_unlink (config_file);
g_unlink (config_file);
}
g_object_unref (settings);

View File

@ -1,5 +1,6 @@
BOOLEAN:OBJECT
BOOLEAN:VOID
OBJECT:OBJECT
VOID:BOOLEAN,STRING
VOID:OBJECT,ENUM
VOID:STRING,BOOLEAN

View File

@ -20,7 +20,16 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#if HAVE_UNIQUE
#if HAVE_HILDON
#include <libosso.h>
#ifdef HAVE_HILDON_2_2
#include <dbus/dbus.h>
#include <mce/mode-names.h>
#include <mce/dbus-names.h>
#endif
typedef osso_context_t* MidoriAppInstance;
#define MidoriAppInstanceNull NULL
#elif HAVE_UNIQUE
typedef gpointer MidoriAppInstance;
#define MidoriAppInstanceNull NULL
#include <unique/unique.h>
@ -31,19 +40,9 @@
#include "socket.h"
#endif
typedef struct _NotifyNotification NotifyNotification;
typedef struct
{
gboolean (*init) (const gchar* app_name);
void (*uninit) (void);
NotifyNotification* (*notification_new) (const gchar* summary,
const gchar* body,
const gchar* icon,
GtkWidget* attach);
gboolean (*notification_show) (NotifyNotification* notification,
GError** error);
} LibNotifyFuncs;
#if HAVE_LIBNOTIFY
#include <libnotify/notify.h>
#endif
struct _MidoriApp
{
@ -63,10 +62,9 @@ struct _MidoriApp
MidoriAppInstance instance;
/* libnotify handling */
gchar* program_notify_send;
GModule* libnotify_module;
LibNotifyFuncs libnotify_funcs;
#if !HAVE_HILDON
gchar* program_notify_send;
#endif
};
struct _MidoriAppClass
@ -115,9 +113,6 @@ static guint signals[LAST_SIGNAL];
static void
midori_app_finalize (GObject* object);
static void
midori_app_init_libnotify (MidoriApp* app);
static void
midori_app_set_property (GObject* object,
guint prop_id,
@ -140,21 +135,26 @@ midori_browser_focus_in_event_cb (MidoriBrowser* browser,
return FALSE;
}
static void
static MidoriBrowser*
midori_browser_new_window_cb (MidoriBrowser* browser,
MidoriBrowser* new_browser,
MidoriApp* app)
{
g_object_set (new_browser,
"settings", app->settings,
"bookmarks", app->bookmarks,
"trash", app->trash,
"search-engines", app->search_engines,
"history", app->history,
NULL);
if (new_browser)
g_object_set (new_browser,
"settings", app->settings,
"bookmarks", app->bookmarks,
"trash", app->trash,
"search-engines", app->search_engines,
"history", app->history,
NULL);
else
new_browser = midori_app_create_browser (app);
midori_app_add_browser (app, new_browser);
gtk_widget_show (GTK_WIDGET (new_browser));
return new_browser;
}
static gboolean
@ -407,6 +407,9 @@ midori_app_command_received (MidoriApp* app,
if (g_str_equal (command, "activate"))
{
if (!app->browser)
return FALSE;
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_window_present (GTK_WINDOW (app->browser));
return TRUE;
@ -424,6 +427,9 @@ midori_app_command_received (MidoriApp* app,
}
else if (g_str_equal (command, "open"))
{
if (!app->browser)
return FALSE;
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_window_present (GTK_WINDOW (app->browser));
if (!uris)
@ -465,16 +471,51 @@ midori_app_command_received (MidoriApp* app,
}
else if (g_str_equal (command, "command"))
{
guint i = 0;
if (!uris || !app->browser)
return FALSE;
midori_browser_activate_action (app->browser, *uris);
while (uris[i] != NULL)
{
midori_browser_activate_action (app->browser, uris[i]);
i++;
}
return TRUE;
}
return FALSE;
}
#if HAVE_UNIQUE
#if HAVE_HILDON
static osso_return_t
midori_app_osso_rpc_handler_cb (const gchar* interface,
const gchar* method,
GArray* arguments,
gpointer data,
osso_rpc_t * retval)
{
MidoriApp* app = MIDORI_APP (data);
GdkScreen* screen = NULL;
gboolean success;
if (!g_strcmp0 (method, "top_application"))
success = midori_app_command_received (app, "activate", NULL, screen);
else if (!g_strcmp0 (method, "new"))
success = midori_app_command_received (app, "new", NULL, screen);
else if (!g_strcmp0 (method, "open"))
{
/* FIXME: Handle arguments */
success = midori_app_command_received (app, "open", NULL, screen);
}
else if (!g_strcmp0 (method, "command"))
{
/* FIXME: Handle arguments */
success = midori_app_command_received (app, "command", NULL, screen);
}
return success ? OSSO_OK : OSSO_INVALID;
}
#elif HAVE_UNIQUE
static UniqueResponse
midori_browser_message_received_cb (UniqueApp* instance,
UniqueCommand command,
@ -577,6 +618,30 @@ midori_app_create_instance (MidoriApp* app,
const gchar* name)
{
MidoriAppInstance instance;
#if HAVE_HILDON
instance = osso_initialize (PACKAGE_NAME, PACKAGE_VERSION, FALSE, NULL);
if (!instance)
{
g_critical ("Error initializing OSSO D-Bus context - Midori");
return NULL;
}
if (osso_rpc_set_default_cb_f (instance, midori_app_osso_rpc_handler_cb,
app) != OSSO_OK)
{
g_critical ("Error initializing remote procedure call handler - Midori");
osso_deinitialize (instance);
return NULL;
}
#ifdef HAVE_HILDON_2_2
if (OSSO_OK == osso_rpc_run_system (instance, MCE_SERVICE, MCE_REQUEST_PATH,
MCE_REQUEST_IF, MCE_ACCELEROMETER_ENABLE_REQ, NULL, DBUS_TYPE_INVALID))
/* Accelerometer enabled */;
#endif
#else
GdkDisplay* display;
gchar* display_name;
gchar* instance_name;
@ -595,7 +660,8 @@ midori_app_create_instance (MidoriApp* app,
display_name = g_strdup (gdk_display_get_name (display));
n = strlen (display_name);
for (i = 0; i < n; i++)
if (display_name[i] == ':' || display_name[i] == '.')
if (display_name[i] == ':' || display_name[i] == '.'
|| display_name[i] == '\\')
display_name[i] = '_';
instance_name = g_strdup_printf ("de.twotoasts.%s_%s", name, display_name);
@ -608,14 +674,18 @@ midori_app_create_instance (MidoriApp* app,
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);
if (instance != MidoriAppInstanceNull)
{
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);
#endif
return instance;
}
@ -634,7 +704,11 @@ midori_app_init (MidoriApp* app)
app->instance = MidoriAppInstanceNull;
midori_app_init_libnotify (app);
#if HAVE_LIBNOTIFY
notify_init ("midori");
#endif
app->program_notify_send = g_find_program_in_path ("notify-send");
}
static void
@ -653,17 +727,19 @@ midori_app_finalize (GObject* object)
katze_object_assign (app->extensions, NULL);
katze_object_assign (app->browsers, NULL);
#if HAVE_UNIQUE
#if HAVE_HILDON
osso_deinitialize (app->instance);
app->instance = NULL;
#elif HAVE_UNIQUE
katze_object_assign (app->instance, NULL);
#else
sock_cleanup ();
#endif
if (app->libnotify_module)
{
app->libnotify_funcs.uninit ();
g_module_close (app->libnotify_module);
}
#if HAVE_LIBNOTIFY
if (notify_is_initted ())
notify_uninit ();
#endif
katze_assign (app->program_notify_send, NULL);
G_OBJECT_CLASS (midori_app_parent_class)->finalize (object);
@ -794,7 +870,12 @@ midori_app_instance_is_running (MidoriApp* app)
if (app->instance == MidoriAppInstanceNull)
app->instance = midori_app_create_instance (app, app->name);
#if HAVE_UNIQUE
#if HAVE_HILDON
/* FIXME: Determine if application is running already */
if (app->instance)
return FALSE;
#elif HAVE_UNIQUE
if (app->instance)
return unique_app_is_running (app->instance);
#else
@ -824,7 +905,9 @@ midori_app_instance_send_activate (MidoriApp* app)
/* g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); */
g_return_val_if_fail (midori_app_instance_is_running (app), FALSE);
#if HAVE_UNIQUE
#if HAVE_HILDON
osso_application_top (app->instance, PACKAGE_NAME, NULL);
#elif HAVE_UNIQUE
if (app->instance)
{
response = unique_app_send_message (app->instance, UNIQUE_ACTIVATE, NULL);
@ -860,7 +943,9 @@ midori_app_instance_send_new_browser (MidoriApp* app)
/* g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); */
g_return_val_if_fail (midori_app_instance_is_running (app), FALSE);
#if HAVE_UNIQUE
#if HAVE_HILDON
osso_application_top (app->instance, PACKAGE_NAME, "new");
#elif HAVE_UNIQUE
if (app->instance)
{
response = unique_app_send_message (app->instance, UNIQUE_NEW, NULL);
@ -902,7 +987,9 @@ midori_app_instance_send_uris (MidoriApp* app,
g_return_val_if_fail (midori_app_instance_is_running (app), FALSE);
g_return_val_if_fail (uris != NULL, FALSE);
#if HAVE_UNIQUE
#if HAVE_HILDON
/* FIXME: Implement */
#elif HAVE_UNIQUE
if (app->instance)
{
message = unique_message_data_new ();
@ -952,7 +1039,9 @@ midori_app_send_command (MidoriApp* app,
if (!midori_app_instance_is_running (app))
return midori_app_command_received (app, "command", command, NULL);
#if HAVE_UNIQUE
#if HAVE_HILDON
/* FIXME: Implement */
#elif HAVE_UNIQUE
if (app->instance)
{
message = unique_message_data_new ();
@ -1003,6 +1092,9 @@ midori_app_add_browser (MidoriApp* app,
* Creates a #MidoriBrowser which inherits its settings,
* bookmarks, trash, search engines and history from @app.
*
* Note that creating a browser this way can be a lot
* faster than setting it up manually.
*
* Return value: a new #MidoriBrowser
*
* Since: 0.1.2
@ -1037,52 +1129,16 @@ midori_app_quit (MidoriApp* app)
g_signal_emit (app, signals[QUIT], 0);
}
static void
midori_app_init_libnotify (MidoriApp* app)
{
gint i;
const gchar* sonames[] = { "libnotify.so", "libnotify.so.1", NULL };
for (i = 0; sonames[i] != NULL && app->libnotify_module == NULL; i++ )
{
app->libnotify_module = g_module_open (sonames[i], G_MODULE_BIND_LOCAL);
}
if (app->libnotify_module != NULL)
{
g_module_symbol (app->libnotify_module, "notify_init",
(void*) &(app->libnotify_funcs.init));
g_module_symbol (app->libnotify_module, "notify_uninit",
(void*) &(app->libnotify_funcs.uninit));
g_module_symbol (app->libnotify_module, "notify_notification_new",
(void*) &(app->libnotify_funcs.notification_new));
g_module_symbol (app->libnotify_module, "notify_notification_show",
(void*) &(app->libnotify_funcs.notification_show));
/* init libnotify */
if (!app->libnotify_funcs.init || !app->libnotify_funcs.init ("midori"))
{
g_module_close (app->libnotify_module);
app->libnotify_module = NULL;
}
}
app->program_notify_send = g_find_program_in_path ("notify-send");
}
/**
* midori_app_send_notification:
* @app: a #MidoriApp
* @title: title of the notification
* @message: text of the notification, or NULL
*
* Send #message to the notification daemon to display it.
* This is done by using libnotify if available or by using the program
* "notify-send" as a fallback.
* Send #message to a notification service to display it.
*
* There is no guarantee that the message have been sent and displayed, as
* neither libnotify nor "notify-send" might be available or the
* notification daemon might not be running.
* There is no guarantee that the message has been sent and displayed, as
* there might not be any notification service available.
*
* Since 0.1.7
**/
@ -1091,19 +1147,26 @@ midori_app_send_notification (MidoriApp* app,
const gchar* title,
const gchar* message)
{
gboolean sent = FALSE;
g_return_if_fail (MIDORI_IS_APP (app));
g_return_if_fail (title);
if (app->libnotify_module)
{
NotifyNotification* n;
#if HAVE_HILDON
hildon_banner_show_information_with_markup (GTK_WIDGET (app->browser),
"midori", message);
#else
gboolean sent = FALSE;
n = app->libnotify_funcs.notification_new (title, message, "midori", NULL);
sent = app->libnotify_funcs.notification_show (n, NULL);
g_object_unref (n);
#if HAVE_LIBNOTIFY
if (notify_is_initted ())
{
NotifyNotification* note;
note = notify_notification_new (title, message, "midori", NULL);
sent = notify_notification_show (note, NULL);
g_object_unref (note);
}
#endif
/* Fall back to the command line program "notify-send" */
if (!sent && app->program_notify_send)
{
@ -1118,4 +1181,5 @@ midori_app_send_notification (MidoriApp* app,
g_free (msgq);
g_free (command);
}
#endif
}

View File

@ -15,6 +15,7 @@
#include <config.h>
#endif
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#if HAVE_LIBXML
@ -22,6 +23,8 @@
#include <libxml/tree.h>
#endif
#define katze_str_equal(str1, str2) !strcmp (str1, str2)
static void
katze_xbel_parse_info (KatzeItem* item,
xmlNodePtr cur);
@ -34,29 +37,18 @@ static KatzeItem*
katze_item_from_xmlNodePtr (xmlNodePtr cur)
{
KatzeItem* item;
xmlChar* key;
item = katze_item_new ();
key = xmlGetProp (cur, (xmlChar*)"href");
katze_item_set_uri (item, (gchar*)key);
g_free (key);
item->uri = (gchar*)xmlGetProp (cur, (xmlChar*)"href");
cur = cur->xmlChildrenNode;
while (cur)
{
if (!xmlStrcmp (cur->name, (const xmlChar*)"title"))
{
key = xmlNodeGetContent (cur);
katze_item_set_name (item, g_strstrip ((gchar*)key));
g_free (key);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"desc"))
{
key = xmlNodeGetContent (cur);
katze_item_set_text (item, g_strstrip ((gchar*)key));
g_free (key);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
if (katze_str_equal ((gchar*)cur->name, "title"))
item->name = g_strstrip ((gchar*)xmlNodeGetContent (cur));
else if (katze_str_equal ((gchar*)cur->name, "desc"))
item->text = g_strstrip ((gchar*)xmlNodeGetContent (cur));
else if (katze_str_equal ((gchar*)cur->name, "info"))
katze_xbel_parse_info (item, cur);
cur = cur->next;
}
@ -88,27 +80,23 @@ katze_array_from_xmlNodePtr (xmlNodePtr cur)
cur = cur->xmlChildrenNode;
while (cur)
{
if (!xmlStrcmp (cur->name, (const xmlChar*)"title"))
{
key = xmlNodeGetContent (cur);
katze_item_set_name (KATZE_ITEM (array), g_strstrip ((gchar*)key));
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"desc"))
{
key = xmlNodeGetContent (cur);
katze_item_set_text (KATZE_ITEM (array), g_strstrip ((gchar*)key));
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"folder"))
if (katze_str_equal ((gchar*)cur->name, "title"))
((KatzeItem*)array)->name = g_strstrip ((gchar*)xmlNodeGetContent (cur));
else if (katze_str_equal ((gchar*)cur->name, "desc"))
((KatzeItem*)array)->text = g_strstrip ((gchar*)xmlNodeGetContent (cur));
else if (katze_str_equal ((gchar*)cur->name, "info"))
katze_xbel_parse_info ((KatzeItem*)array, cur);
else if (katze_str_equal ((gchar*)cur->name, "folder"))
{
item = (KatzeItem*)katze_array_from_xmlNodePtr (cur);
katze_array_add_item (array, item);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"bookmark"))
else if (katze_str_equal ((gchar*)cur->name, "bookmark"))
{
item = katze_item_from_xmlNodePtr (cur);
katze_array_add_item (array, item);
}
else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator"))
else if (katze_str_equal ((gchar*)cur->name, "separator"))
{
item = katze_item_new ();
katze_array_add_item (array, item);
@ -125,22 +113,29 @@ katze_xbel_parse_info (KatzeItem* item,
cur = cur->xmlChildrenNode;
while (cur)
{
if (!xmlStrcmp (cur->name, (const xmlChar*)"metadata"))
if (katze_str_equal ((gchar*)cur->name, "metadata"))
{
xmlChar* owner = xmlGetProp (cur, (xmlChar*)"owner");
g_strstrip ((gchar*)owner);
if (owner)
g_strstrip ((gchar*)owner);
else
/* Albeit required, "owner" is not set by MicroB */
owner = (xmlChar*)NULL;
/* FIXME: Save metadata from unknown owners */
if (!g_strcmp0 ((gchar*)owner, "http://www.twotoasts.de"))
if (!owner || katze_str_equal ((gchar*)owner, "http://www.twotoasts.de"))
{
xmlAttrPtr properties = cur->properties;
xmlNodePtr children = cur->children;
while (properties)
{
if (!xmlStrcmp (properties->name, (xmlChar*)"owner"))
xmlChar* value;
if (katze_str_equal ((gchar*)properties->name, "owner"))
{
properties = properties->next;
continue;
}
xmlChar* value = xmlGetProp (cur, properties->name);
value = xmlGetProp (cur, properties->name);
if (properties->ns && properties->ns->prefix)
{
gchar* ns_value = g_strdup_printf ("%s:%s",
@ -155,10 +150,30 @@ katze_xbel_parse_info (KatzeItem* item,
xmlFree (value);
properties = properties->next;
}
while (children)
{
xmlNodePtr grand_children = children->children;
while (grand_children)
{
xmlChar* value = grand_children->content;
gchar* ns_value;
if (!owner)
ns_value = g_strdup_printf (":%s", children->name);
else if (katze_str_equal ((gchar*)owner, "http://www.twotoasts.de"))
ns_value = g_strdup_printf ("midori:%s", children->name);
else /* FIXME: Save metadata from unknown owners */
ns_value = g_strdup_printf (":%s", children->name);
katze_item_set_meta_string (item, ns_value, (gchar*)value);
g_free (ns_value);
grand_children = grand_children->next;
}
children = children->next;
}
}
xmlFree (owner);
}
else if (g_strcmp0 ((gchar*)cur->name, "text"))
else if (!katze_str_equal ((gchar*)cur->name, "text"))
g_critical ("Unexpected element <%s> in <metadata>.", cur->name);
cur = cur->next;
}
@ -170,46 +185,102 @@ katze_array_from_xmlDocPtr (KatzeArray* array,
xmlDocPtr doc)
{
xmlNodePtr cur;
xmlChar* version;
gchar* value;
KatzeItem* item;
cur = xmlDocGetRootElement (doc);
version = xmlGetProp (cur, (xmlChar*)"version");
if (xmlStrcmp (version, (xmlChar*)"1.0"))
g_warning ("XBEL version is not 1.0.");
xmlFree (version);
value = (gchar*)xmlGetProp (cur, (xmlChar*)"title");
katze_item_set_name (KATZE_ITEM (array), value);
g_free (value);
value = (gchar*)xmlGetProp (cur, (xmlChar*)"desc");
katze_item_set_text (KATZE_ITEM (array), value);
g_free (value);
if ((cur = xmlDocGetRootElement (doc)) == NULL)
{
/* Empty document */
return FALSE;
}
if (xmlStrcmp (cur->name, (const xmlChar*)"xbel"))
if (katze_str_equal ((gchar*)cur->name, "xbel"))
{
/* XBEL 1.0 */
gchar* value;
value = (gchar*)xmlGetProp (cur, (xmlChar*)"version");
if (!katze_str_equal (value, "1.0"))
g_warning ("XBEL version is not 1.0.");
g_free (value);
value = (gchar*)xmlGetProp (cur, (xmlChar*)"title");
katze_item_set_name (KATZE_ITEM (array), value);
g_free (value);
value = (gchar*)xmlGetProp (cur, (xmlChar*)"desc");
katze_item_set_text (KATZE_ITEM (array), value);
g_free (value);
}
else if (katze_str_equal ((gchar*)cur->name, "RDF"))
{
/* Minimal RSS 1.0 support, enough to read bookmarks */
cur = cur->xmlChildrenNode;
while (cur)
{
item = NULL;
if (katze_str_equal ((gchar*)cur->name, "item"))
{
xmlNodePtr cur_item;
item = katze_item_new ();
cur_item = cur->xmlChildrenNode;
while (cur_item)
{
if (katze_str_equal ((gchar*)cur_item->name, "title"))
item->name = g_strstrip ((gchar*)xmlNodeGetContent (cur_item));
else if (katze_str_equal ((gchar*)cur_item->name, "link"))
item->uri = g_strstrip ((gchar*)xmlNodeGetContent (cur_item));
else if (katze_str_equal ((gchar*)cur_item->name, "subject"))
{
gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur_item));
/* FIXME: Create a folder according to the tag */
g_free (value);
}
cur_item = cur_item->next;
}
}
else if (katze_str_equal ((gchar*)cur->name, "channel"))
/* Ignored */;
else if (!katze_str_equal ((gchar*)cur->name, "text"))
g_warning ("Unexpected attribute: %s", (gchar*)cur->name);
if (item)
katze_array_add_item (array, item);
cur = cur->next;
}
return TRUE;
}
else
{
/* Wrong document kind */
return FALSE;
}
cur = cur->xmlChildrenNode;
while (cur)
{
item = NULL;
if (!xmlStrcmp (cur->name, (const xmlChar*)"folder"))
if (katze_str_equal ((gchar*)cur->name, "folder"))
item = (KatzeItem*)katze_array_from_xmlNodePtr (cur);
else if (!xmlStrcmp (cur->name, (const xmlChar*)"bookmark"))
else if (katze_str_equal ((gchar*)cur->name, "bookmark"))
item = katze_item_from_xmlNodePtr (cur);
else if (!xmlStrcmp (cur->name, (const xmlChar*)"separator"))
else if (katze_str_equal ((gchar*)cur->name, "separator"))
item = katze_item_new ();
else if (!xmlStrcmp (cur->name, (const xmlChar*)"info"))
else if (katze_str_equal ((gchar*)cur->name, "info"))
katze_xbel_parse_info (KATZE_ITEM (array), cur);
else if (katze_str_equal ((gchar*)cur->name, "title"))
{
xmlNodePtr node = cur->xmlChildrenNode;
katze_item_set_name (KATZE_ITEM (array), (gchar*)node->content);
}
else if (katze_str_equal ((gchar*)cur->name, "desc"))
{
xmlNodePtr node = cur->xmlChildrenNode;
katze_item_set_text (KATZE_ITEM (array), (gchar*)node->content);
}
else if (!katze_str_equal ((gchar*)cur->name, "text"))
g_warning ("Unexpected attribute: %s", (gchar*)cur->name);
if (item)
katze_array_add_item (array, item);
cur = cur->next;
@ -217,15 +288,120 @@ katze_array_from_xmlDocPtr (KatzeArray* array,
return TRUE;
}
static gboolean
katze_array_from_opera_file (KatzeArray* array,
FILE* file)
{
gchar line[200];
gchar* partial_line = NULL;
KatzeArray* folder = array;
KatzeItem* item = NULL;
while (fgets (line, 200, file))
{
gboolean incomplete_line = (strlen (line) == 199);
g_strstrip (line);
if (line[0] == '\0')
{
item = NULL;
continue;
}
else if (line[0] == '-')
{
item = NULL;
if (folder != array)
folder = katze_item_get_parent ((KatzeItem*)folder);
else
g_warning ("A level-up although we are at the top level");
continue;
}
if (line[0] == '#')
{
const gchar* element = &line[1];
if (!g_ascii_strncasecmp (element, "FOLDER", 6))
{
item = (KatzeItem*)katze_array_new (KATZE_TYPE_ARRAY);
katze_array_add_item (folder, item);
folder = (KatzeArray*)item;
}
else if (!g_ascii_strncasecmp (element, "URL", 3))
{
item = katze_item_new ();
katze_array_add_item (folder, item);
}
else
g_warning ("Unexpected element: %s", element);
}
else if (item)
{
gchar** parts;
/* Handle lines longer than 200 characters */
if (incomplete_line)
{
if (partial_line)
{
gchar* chunk = g_strconcat (partial_line, line, NULL);
katze_assign (partial_line, chunk);
}
else
partial_line = g_strdup (line);
continue;
}
if (partial_line)
{
gchar* full_line = g_strconcat (partial_line, line, NULL);
katze_assign (partial_line, NULL);
parts = g_strsplit (full_line, "=", 2);
g_free (full_line);
}
else
parts = g_strsplit (line, "=", 2);
if (parts && parts[0] && parts[1])
{
if (katze_str_equal (parts[0], "NAME"))
item->name = g_strdup (parts[1]);
else if (katze_str_equal (parts[0], "URL"))
item->uri = g_strdup (parts[1]);
else if (katze_str_equal (parts[0], "DESCRIPTION"))
item->text = g_strdup (parts[1]);
else if (katze_str_equal (parts[0], "CREATED"))
item->added = g_ascii_strtoull (parts[1], NULL, 10);
/* FIXME: Implement visited time
else if (katze_str_equal (parts[0], "VISITED"))
item->visited = g_ascii_strtoull (parts[1], NULL, 10); */
else if (katze_str_equal (parts[0], "ON PERSONALBAR"))
katze_item_set_meta_integer (item, "toolbar",
katze_str_equal (parts[1], "YES") ? 1 : -1);
/* FIXME: Implement websites as panels
else if (katze_str_equal (parts[0], "IN PANEL"))
; */
}
else
g_warning ("Broken property: %s", line);
g_strfreev (parts);
}
else
g_warning ("Unexpected property outside of element: %s", line);
}
return TRUE;
}
/**
* midori_array_from_file:
* @array: a #KatzeArray
* @filename: a filename to load from
* @format: the desired format
* @format: "xbel", "opera", or %NULL
* @error: a #GError or %NULL
*
* Loads the contents of a file in the specified format.
*
* Since 0.2.2 @format can be %NULL to indicate that the
* file should be loaded if it's any supported format.
*
* Return value: %TRUE on success, %FALSE otherwise
*
* Since: 0.1.6
@ -236,11 +412,8 @@ midori_array_from_file (KatzeArray* array,
const gchar* format,
GError** error)
{
xmlDocPtr doc;
g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (!g_strcmp0 (format, "xbel"), FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
if (!g_file_test (filename, G_FILE_TEST_EXISTS))
@ -252,97 +425,191 @@ midori_array_from_file (KatzeArray* array,
return FALSE;
}
if ((doc = xmlParseFile (filename)) == NULL)
if (!format)
format = "";
/* Opera6 */
if (katze_str_equal (format, "opera")
|| (!*format && g_str_has_suffix (filename, ".adr")))
{
/* No valid xml or broken encoding */
if (error)
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Malformed document."));
return FALSE;
FILE* file;
if ((file = g_fopen (filename, "r")))
{
guint verify;
gchar line[50];
verify = 0;
while (fgets (line, 50, file))
{
g_strstrip (line);
if (verify == 0 && katze_str_equal (line, "Opera Hotlist version 2.0"))
verify++;
else if (verify == 1
&& katze_str_equal (line, "Options: encoding = utf8, version=3"))
verify++;
else if (verify == 2)
{
if (!katze_array_from_opera_file (array, file))
{
/* Parsing failed */
fclose (file);
if (error)
*error = g_error_new_literal (G_FILE_ERROR,
G_FILE_ERROR_FAILED, _("Malformed document."));
return FALSE;
}
return TRUE;
}
else
break;
}
fclose (file);
}
}
if (!katze_array_from_xmlDocPtr (array, doc))
/* XBEL */
if (katze_str_equal (format, "xbel")
|| !*format)
{
/* Parsing failed */
xmlDocPtr doc;
if ((doc = xmlParseFile (filename)) == NULL)
{
/* No valid xml or broken encoding */
if (error)
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Malformed document."));
return FALSE;
}
if (!katze_array_from_xmlDocPtr (array, doc))
{
/* Parsing failed */
xmlFreeDoc (doc);
if (error)
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Malformed document."));
return FALSE;
}
xmlFreeDoc (doc);
if (error)
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Malformed document."));
return FALSE;
return TRUE;
}
xmlFreeDoc (doc);
return TRUE;
if (error)
*error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unrecognized bookmark format."));
return FALSE;
}
#endif
static gchar*
_simple_xml_element (const gchar* name,
const gchar* value)
/* Inspired by append_escaped_text() from gmarkup.c in Glib.
The main difference is that we filter out control characters. */
static void
string_append_escaped (GString *str,
const gchar *text)
{
gchar* value_escaped;
gchar* markup;
gssize length;
const gchar* p;
const gchar* end;
gunichar c;
if (!value)
return g_strdup ("");
value_escaped = g_markup_escape_text (value, -1);
markup = g_strdup_printf ("<%s>%s</%s>\n", name, value_escaped, name);
g_free (value_escaped);
return markup;
length = strlen (text);
p = text;
end = text + length;
while (p != end)
{
const gchar *next;
next = g_utf8_next_char (p);
switch (*p)
{
case '&':
g_string_append (str, "&amp;");
break;
case '<':
g_string_append (str, "&lt;");
break;
case '>':
g_string_append (str, "&gt;");
break;
case '\'':
g_string_append (str, "&apos;");
break;
case '"':
g_string_append (str, "&quot;");
break;
default:
c = g_utf8_get_char (p);
if (g_unichar_iscntrl (c))
g_string_append_c (str, ' ');
else if ((0x1 <= c && c <= 0x8)
|| (0xb <= c && c <= 0xc)
|| (0xe <= c && c <= 0x1f)
|| (0x7f <= c && c <= 0x84)
|| (0x86 <= c && c <= 0x9f))
g_string_append_printf (str, "&#x%x;", c);
else
g_string_append_len (str, p, next - p);
break;
}
p = next;
}
}
static gchar*
katze_item_to_data (KatzeItem* item)
static void
string_append_xml_element (GString* string,
const gchar* name,
const gchar* value)
{
if (value)
{
g_string_append_printf (string, "<%s>", name);
string_append_escaped (string, value);
g_string_append_printf (string, "</%s>\n", name);
}
}
static void
string_append_item (GString* string,
KatzeItem* item)
{
gchar* markup;
gchar* metadata;
g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
g_return_if_fail (KATZE_IS_ITEM (item));
markup = NULL;
metadata = katze_item_metadata_to_xbel (item);
if (KATZE_IS_ARRAY (item))
{
GString* _markup = g_string_new (NULL);
guint i = 0;
KatzeItem* _item;
while ((_item = katze_array_get_nth_item (KATZE_ARRAY (item), i++)))
{
gchar* item_markup = katze_item_to_data (_item);
g_string_append (_markup, item_markup);
g_free (item_markup);
}
/* 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%s</folder>\n",
"" /* folded ? folded : "" */,
title, desc,
_markup->str,
metadata);
g_string_free (_markup, TRUE);
/* g_free (folded); */
g_free (title);
g_free (desc);
KatzeArray* array = KATZE_ARRAY (item);
g_string_append (string, "<folder>\n");
/* FIXME: " folded=\"no\" */
string_append_xml_element (string, "title", katze_item_get_name (item));
string_append_xml_element (string, "desc", katze_item_get_text (item));
while ((_item = katze_array_get_nth_item (array, i++)))
string_append_item (string, _item);
g_string_append (string, metadata);
g_string_append (string, "</folder>\n");
}
else if (katze_item_get_uri (item))
{
gchar* href_escaped = g_markup_escape_text (katze_item_get_uri (item), -1);
gchar* href = g_strdup_printf (" href=\"%s\"", href_escaped);
g_free (href_escaped);
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 ("<bookmark%s>\n%s%s%s</bookmark>\n",
href,
title, desc,
metadata);
g_free (href);
g_free (title);
g_free (desc);
g_string_append (string, "<bookmark href=\"");
string_append_escaped (string, katze_item_get_uri (item));
g_string_append (string, "\">\n");
string_append_xml_element (string, "title", katze_item_get_name (item));
string_append_xml_element (string, "desc", katze_item_get_text (item));
g_string_append (string, metadata);
g_string_append (string, "</bookmark>\n");
}
else
markup = g_strdup ("<separator/>\n");
g_string_append (string, "<separator/>\n");
g_free (metadata);
return markup;
}
static gchar*
@ -350,28 +617,55 @@ 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";
GString* markdown;
/* FIXME: Allow specifying an alternative default namespace */
/* FIXME: Support foreign namespaces with their own URI */
gchar* namespace = NULL;
const gchar* namespace_uri;
gsize i;
const gchar* key;
const gchar* value;
if (!keys)
return g_strdup ("");
markup = g_string_new ("<info>\n<metadata owner=\"");
g_string_append_printf (markup, "%s\"", namespace_uri);
markup = g_string_new ("<info>\n<metadata");
markdown = g_string_new (NULL);
i = 0;
while ((key = g_list_nth_data (keys, i++)))
if (katze_item_get_meta_string (item, key))
if ((value = katze_item_get_meta_string (item, key)))
{
gchar* escaped =
g_markup_escape_text (katze_item_get_meta_string (item, key), -1);
g_string_append_printf (markup, " %s:%s=\"%s\"", namespace, key,
escaped);
g_free (escaped);
namespace = strchr (key, ':');
if (key[0] == ':') /* MicroB uses un-namespaced children */
{
key = &key[1];
g_string_append_printf (markdown, "<%s>", key);
string_append_escaped (markdown, value);
g_string_append_printf (markdown, "</%s>\n", key);
}
else if (namespace)
{
g_string_append_printf (markup, " %s=\"", key);
string_append_escaped (markup, value);
g_string_append_c (markup, '\"');
}
else
{
g_string_append_printf (markup, " midori:%s=\"", key);
string_append_escaped (markup, value);
g_string_append_c (markup, '\"');
}
}
g_string_append_printf (markup, "/>\n</info>\n");
if (!namespace)
{
namespace_uri = "http://www.twotoasts.de";
g_string_append_printf (markup, " owner=\"%s\"", namespace_uri);
}
if (markdown->len)
g_string_append_printf (markup, ">\n%s</metadata>\n</info>\n", markdown->str);
else
g_string_append_printf (markup, "/>\n</info>\n");
g_string_free (markdown, TRUE);
return g_string_free (markup, FALSE);
}
@ -379,46 +673,29 @@ static gchar*
katze_array_to_xbel (KatzeArray* array,
GError** error)
{
GString* inner_markup;
gchar* metadata = katze_item_metadata_to_xbel (KATZE_ITEM (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);
GString* markup = g_string_new (
"<?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"
"<xbel version=\"1.0\""
" xmlns:midori=\"http://www.twotoasts.de\""
">\n");
string_append_xml_element (markup, "title", katze_item_get_name (KATZE_ITEM (array)));
string_append_xml_element (markup, "desc", katze_item_get_text (KATZE_ITEM (array)));
g_string_append (markup, metadata);
i = 0;
while ((item = katze_array_get_nth_item (array, i++)))
{
item_xml = katze_item_to_data (item);
g_string_append (inner_markup, item_xml);
g_free (item_xml);
}
string_append_item (markup, item);
g_string_append (markup, "</xbel>\n");
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\"%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;
return g_string_free (markup, FALSE);
}
static gboolean

File diff suppressed because it is too large Load Diff

View File

@ -658,7 +658,7 @@ midori_extension_set_boolean (MidoriExtension* extension,
/* FIXME: Handle readonly folder/ file */
gchar* config_file = g_build_filename (extension->priv->config_dir,
"config", NULL);
g_mkdir_with_parents (extension->priv->config_dir, 0700);
katze_mkdir_with_parents (extension->priv->config_dir, 0700);
g_key_file_set_boolean (extension->priv->key_file,
"settings", name, value);
sokoke_key_file_save_to_file (extension->priv->key_file, config_file, &error);
@ -755,7 +755,7 @@ midori_extension_set_integer (MidoriExtension* extension,
/* FIXME: Handle readonly folder/ file */
gchar* config_file = g_build_filename (extension->priv->config_dir,
"config", NULL);
g_mkdir_with_parents (extension->priv->config_dir, 0700);
katze_mkdir_with_parents (extension->priv->config_dir, 0700);
g_key_file_set_integer (extension->priv->key_file,
"settings", name, value);
sokoke_key_file_save_to_file (extension->priv->key_file, config_file, &error);
@ -852,7 +852,7 @@ midori_extension_set_string (MidoriExtension* extension,
/* FIXME: Handle readonly folder/ file */
gchar* config_file = g_build_filename (extension->priv->config_dir,
"config", NULL);
g_mkdir_with_parents (extension->priv->config_dir, 0700);
katze_mkdir_with_parents (extension->priv->config_dir, 0700);
g_key_file_set_string (extension->priv->key_file,
"settings", name, value);
sokoke_key_file_save_to_file (extension->priv->key_file, config_file, &error);
@ -964,7 +964,7 @@ midori_extension_set_string_list (MidoriExtension* extension,
/* FIXME: Handle readonly folder/ file */
gchar* config_file = g_build_filename (extension->priv->config_dir,
"config", NULL);
g_mkdir_with_parents (extension->priv->config_dir, 0700);
katze_mkdir_with_parents (extension->priv->config_dir, 0700);
g_key_file_set_string_list (extension->priv->key_file,
"settings", name, (const gchar**)value, length);
sokoke_key_file_save_to_file (extension->priv->key_file, config_file, &error);

View File

@ -15,6 +15,7 @@
#include "gtkiconentry.h"
#include "marshal.h"
#include "sokoke.h"
#include "midori-browser.h"
#include <string.h>
#include <glib/gi18n.h>
@ -421,13 +422,8 @@ midori_location_action_insert_history_item (MidoriLocationAction* action,
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);
}
@ -576,7 +572,7 @@ midori_location_action_key_press_event_cb (GtkEntry* entry,
if ((uri = gtk_entry_get_text (entry)) && *uri)
{
g_signal_emit (action, signals[SUBMIT_URI], 0, uri,
(event->state & GDK_MOD1_MASK) ? TRUE : FALSE);
(event->state & GDK_CONTROL_MASK) ? TRUE : FALSE);
return TRUE;
}
}
@ -630,6 +626,7 @@ midori_location_entry_render_text_cb (GtkCellLayout* layout,
{
gchar* uri;
gchar* title;
GdkPixbuf* icon;
gchar* desc;
gchar* desc_uri;
gchar* desc_title;
@ -641,19 +638,39 @@ midori_location_entry_render_text_cb (GtkCellLayout* layout,
gchar** parts;
size_t len;
gtk_tree_model_get (model, iter, URI_COL, &uri, TITLE_COL, &title, -1);
entry = data;
gtk_tree_model_get (model, iter, URI_COL, &uri, TITLE_COL, &title,
FAVICON_COL, &icon, -1);
if (G_UNLIKELY (!icon) && uri)
{
#if !HAVE_HILDON
MidoriLocationAction* action
= g_object_get_data (G_OBJECT (renderer), "location-action");
if ((icon = katze_load_cached_icon (uri, NULL)))
{
midori_location_action_set_icon_for_uri (action, icon, uri);
g_object_unref (icon);
}
else
midori_location_action_set_icon_for_uri (action, action->default_icon, uri);
#endif
}
else if (icon)
g_object_unref (icon);
desc = desc_uri = desc_title = key = NULL;
if (G_LIKELY (data))
key = title ? g_utf8_strdown (gtk_entry_get_text (GTK_ENTRY (entry)), -1)
: g_ascii_strdown (gtk_entry_get_text (GTK_ENTRY (entry)), -1);
len = 0;
/* g_uri_unescape_segment () sometimes produces garbage */
if (G_UNLIKELY (uri && !g_utf8_validate (uri, -1, (const gchar **)&temp)))
temp[0]='\0';
else if (G_LIKELY (uri))
{
entry = gtk_entry_completion_get_entry (GTK_ENTRY_COMPLETION (data));
key = title ? g_utf8_strdown (gtk_entry_get_text (GTK_ENTRY (entry)), -1)
: g_ascii_strdown (gtk_entry_get_text (GTK_ENTRY (entry)), -1);
len = 0;
}
if (G_LIKELY (data && uri))
{
temp = g_ascii_strdown (uri, -1);
temp = g_utf8_strdown (uri, -1);
if (key && *key && (start = strstr (temp, key)))
{
len = strlen (key);
@ -662,11 +679,9 @@ midori_location_entry_render_text_cb (GtkCellLayout* layout,
if (skey && *skey && (parts = g_strsplit (uri, skey, 2)))
{
if (parts[0] && parts[1])
{
desc_uri = g_markup_printf_escaped ("%s<b>%s</b>%s",
parts[0], skey, parts[1]);
g_strfreev (parts);
}
g_strfreev (parts);
}
g_free (skey);
}
@ -674,7 +689,11 @@ midori_location_entry_render_text_cb (GtkCellLayout* layout,
}
if (uri && !desc_uri)
desc_uri = g_markup_escape_text (uri, -1);
if (G_LIKELY (data && title))
/* g_uri_unescape_segment () sometimes produces garbage */
if (G_UNLIKELY (title && !g_utf8_validate (title, -1, (const gchar **)&temp)))
temp[0]='\0';
else if (G_LIKELY (title))
{
temp = g_utf8_strdown (title, -1);
if (key && *key && (start = strstr (temp, key)))
@ -724,7 +743,6 @@ midori_location_entry_completion_match_cb (GtkEntryCompletion* completion,
gchar* uri;
gchar* title;
gboolean match;
gchar* temp;
model = gtk_entry_completion_get_model (completion);
gtk_tree_model_get (model, iter, URI_COL, &uri, TITLE_COL, &title, -1);
@ -732,17 +750,20 @@ midori_location_entry_completion_match_cb (GtkEntryCompletion* completion,
match = FALSE;
if (G_LIKELY (uri))
{
temp = g_utf8_casefold (uri, -1);
match = (strstr (temp, key) != NULL);
g_free (temp);
gchar* fkey = g_utf8_casefold (key, -1);
gchar* furi = g_utf8_casefold (uri, -1);
g_free (uri);
match = strstr (furi, fkey) != NULL;
g_free (furi);
if (!match && G_LIKELY (title))
{
temp = g_utf8_casefold (title, -1);
match = (strstr (temp, key) != NULL);
g_free (temp);
gchar* ftitle = g_utf8_casefold (title, -1);
match = strstr (ftitle, fkey) != NULL;
g_free (ftitle);
}
g_free (fkey);
}
g_free (title);
@ -880,7 +901,7 @@ midori_location_action_set_item (MidoriLocationAction* location_action,
g_object_unref (original_icon);
}
else
new_icon = location_action->default_icon;
new_icon = NULL;
if (new_icon)
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
FAVICON_COL, new_icon, -1);
@ -998,13 +1019,14 @@ midori_location_action_completion_init (MidoriLocationAction* location_action,
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer,
"pixbuf", FAVICON_COL, "yalign", YALIGN_COL, NULL);
renderer = gtk_cell_renderer_text_new ();
g_object_set_data (G_OBJECT (renderer), "location-action", location_action);
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,
completion, NULL);
entry, NULL);
gtk_entry_completion_set_match_func (completion,
midori_location_entry_completion_match_cb, NULL, NULL);
@ -1052,11 +1074,27 @@ midori_location_action_entry_changed_cb (GtkComboBox* combo_box,
}
}
static void
midori_location_action_populate_popup_cb (GtkWidget* entry,
GtkMenuShell* menu,
MidoriLocationAction* location_action)
{
MidoriBrowser* browser = midori_browser_get_for_widget (entry);
GtkActionGroup* actions = midori_browser_get_action_group (browser);
GtkWidget* menuitem;
menuitem = gtk_separator_menu_item_new ();
gtk_widget_show (menuitem);
gtk_menu_shell_append (menu, menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "ManageSearchEngines"));
gtk_menu_shell_append (menu, menuitem);
}
static void
midori_location_action_connect_proxy (GtkAction* action,
GtkWidget* proxy)
{
GtkWidget* entry;
MidoriLocationAction* location_action;
GtkCellRenderer* renderer;
@ -1070,7 +1108,8 @@ midori_location_action_connect_proxy (GtkAction* action,
if (GTK_IS_TOOL_ITEM (proxy))
{
entry = midori_location_action_entry_for_proxy (proxy);
GtkWidget* entry = midori_location_action_entry_for_proxy (proxy);
GtkWidget* child = gtk_bin_get_child (GTK_BIN (entry));
midori_location_entry_set_progress (MIDORI_LOCATION_ENTRY (entry),
MIDORI_LOCATION_ACTION (action)->progress);
@ -1086,17 +1125,17 @@ midori_location_action_connect_proxy (GtkAction* action,
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (entry), renderer,
"pixbuf", FAVICON_COL, "yalign", YALIGN_COL, NULL);
renderer = gtk_cell_renderer_text_new ();
g_object_set_data (G_OBJECT (renderer), "location-action", action);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, TRUE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
renderer, midori_location_entry_render_text_cb, NULL, NULL);
renderer, midori_location_entry_render_text_cb, child, NULL);
gtk_combo_box_set_active (GTK_COMBO_BOX (entry), -1);
midori_location_action_completion_init (location_action,
GTK_ENTRY (gtk_bin_get_child (GTK_BIN (entry))));
midori_location_action_completion_init (location_action, GTK_ENTRY (child));
g_signal_connect (entry, "changed",
G_CALLBACK (midori_location_action_entry_changed_cb), action);
g_object_connect (gtk_bin_get_child (GTK_BIN (entry)),
g_object_connect (child,
"signal::changed",
midori_location_action_changed_cb, action,
"signal::key-press-event",
@ -1107,6 +1146,8 @@ midori_location_action_connect_proxy (GtkAction* action,
midori_location_action_focus_out_event_cb, action,
"signal::icon-release",
midori_location_action_icon_released_cb, action,
"signal::populate-popup",
midori_location_action_populate_popup_cb, action,
NULL);
}
}
@ -1246,11 +1287,11 @@ void
midori_location_action_set_icon (MidoriLocationAction* location_action,
GdkPixbuf* icon)
{
#if !HAVE_HILDON
GSList* proxies;
GtkWidget* location_entry;
GtkWidget* entry;
#if !HAVE_HILDON
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (!icon || GDK_IS_PIXBUF (icon));
@ -1293,9 +1334,11 @@ midori_location_action_add_item (MidoriLocationAction* location_action,
GdkPixbuf* icon,
const gchar* title)
{
#if !HAVE_HILDON
GSList* proxies;
GtkWidget* location_entry;
GtkWidget* entry;
#endif
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (uri != NULL);
@ -1328,9 +1371,11 @@ midori_location_action_set_icon_for_uri (MidoriLocationAction* location_action,
GdkPixbuf* icon,
const gchar* uri)
{
#if !HAVE_HILDON
GSList* proxies;
GtkWidget* location_entry;
GtkWidget* entry;
#endif
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (!icon || GDK_IS_PIXBUF (icon));
@ -1405,8 +1450,9 @@ midori_location_action_set_search_engines (MidoriLocationAction* location_action
completion = gtk_entry_get_completion (GTK_ENTRY (child));
i = 0;
if (location_action->search_engines)
while ((item = katze_array_get_nth_item (location_action->search_engines, i++)))
gtk_entry_completion_delete_action (completion, 0);
while ((item = katze_array_get_nth_item (location_action->search_engines, i++)))
gtk_entry_completion_delete_action (completion, 0);
midori_location_action_add_actions (completion, search_engines);
}
@ -1449,9 +1495,11 @@ void
midori_location_action_set_secondary_icon (MidoriLocationAction* location_action,
const gchar* stock_id)
{
#if !HAVE_HILDON
GSList* proxies;
GtkWidget* entry;
GtkWidget* child;
#endif
GtkStockItem stock_item;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));

View File

@ -369,6 +369,9 @@ static void
midori_location_entry_init (MidoriLocationEntry* location_entry)
{
GtkWidget* entry;
#if HAVE_HILDON
HildonGtkInputMode mode;
#endif
/* We want the widget to have appears-as-list applied */
gtk_rc_parse_string ("style \"midori-location-entry-style\" {\n"
@ -378,8 +381,13 @@ midori_location_entry_init (MidoriLocationEntry* location_entry)
location_entry->progress = 0.0;
#if HAVE_HILDON
entry = gtk_entry_new ();
mode = hildon_gtk_entry_get_input_mode (GTK_ENTRY (entry));
mode &= ~HILDON_GTK_INPUT_MODE_AUTOCAP;
hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry), mode);
#else
entry = gtk_icon_entry_new ();
#if !HAVE_HILDON
gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, GTK_STOCK_FILE);
gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY (entry),

View File

@ -19,6 +19,12 @@
#include <glib/gi18n.h>
#include "config.h"
#ifdef HAVE_HILDON_2_2
#include <hildon/hildon.h>
#endif
struct _MidoriPanel
{
GtkHBox parent_instance;
@ -31,11 +37,13 @@ struct _MidoriPanel
GtkWidget* frame;
GtkWidget* toolbook;
GtkWidget* notebook;
GtkActionGroup* action_group;
GtkMenu* menu;
gboolean show_titles;
gboolean show_controls;
gboolean right_aligned;
gboolean open_panels_in_windows;
};
struct _MidoriPanelClass
@ -54,11 +62,13 @@ enum
PROP_0,
PROP_SHADOW_TYPE,
PROP_ACTION_GROUP,
PROP_MENU,
PROP_PAGE,
PROP_SHOW_TITLES,
PROP_SHOW_CONTROLS,
PROP_RIGHT_ALIGNED,
PROP_OPEN_PANELS_IN_WINDOWS,
};
enum {
@ -138,6 +148,23 @@ midori_panel_class_init (MidoriPanelClass* class)
GTK_SHADOW_NONE,
flags));
/**
* MidoriWebSettings:action-group:
*
* This is the action group the panel will add actions
* corresponding to pages to.
*
* Since: 0.2.1
*/
g_object_class_install_property (gobject_class,
PROP_ACTION_GROUP,
g_param_spec_object (
"action-group",
"Action Group",
"The action group the panel will add actions to",
GTK_TYPE_ACTION_GROUP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* MidoriWebSettings:menu:
*
@ -212,6 +239,22 @@ midori_panel_class_init (MidoriPanelClass* class)
"Whether the panel is aligned to the right",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* MidoriWebSettings:open-panels-in-windows:
*
* Whether to open panels in separate windows.
*
* Since: 0.2.2
*/
g_object_class_install_property (gobject_class,
PROP_OPEN_PANELS_IN_WINDOWS,
g_param_spec_boolean (
"open-panels-in-windows",
"Open panels in windows",
"Whether to open panels in standalone windows by default",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
@ -241,6 +284,7 @@ midori_panel_detached_window_delete_event_cb (GtkWidget* window,
GtkWidget* scrolled = g_object_get_data (G_OBJECT (window), "scrolled");
GtkWidget* toolbar = g_object_get_data (G_OBJECT (scrolled), "panel-toolbar");
GtkWidget* menuitem = g_object_get_data (G_OBJECT (scrolled), "panel-menuitem");
GtkWidget* viewable = _midori_panel_child_for_scrolled (panel, scrolled);
GtkToolItem* toolitem;
gint n;
@ -252,15 +296,10 @@ midori_panel_detached_window_delete_event_cb (GtkWidget* window,
gtk_container_remove (GTK_CONTAINER (vbox), scrolled);
n = gtk_notebook_append_page (GTK_NOTEBOOK (panel->notebook), scrolled, NULL);
g_object_unref (scrolled);
toolitem = midori_panel_construct_tool_item (panel,
MIDORI_VIEWABLE (_midori_panel_child_for_scrolled (panel, scrolled)));
toolitem = midori_panel_construct_tool_item (panel, MIDORI_VIEWABLE (viewable));
if (menuitem)
{
gtk_widget_show (menuitem);
g_object_set_data (G_OBJECT (menuitem), "toolitem", toolitem);
}
midori_panel_set_current_page (panel, n);
gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (toolitem), TRUE);
return FALSE;
}
@ -274,13 +313,9 @@ midori_panel_widget_destroy_cb (GtkWidget* viewable,
}
static void
midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton,
MidoriPanel* panel)
midori_panel_detach_page (MidoriPanel* panel,
gint n)
{
/* FIXME: What happens when the browser is destroyed? */
/* FIXME: What about multiple browsers? */
/* FIXME: Should we remember if the child was detached? */
gint n = midori_panel_get_current_page (panel);
GtkToolItem* toolitem = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (panel->toolbar), n);
const gchar* title = gtk_tool_button_get_label (GTK_TOOL_BUTTON (toolitem));
@ -288,26 +323,32 @@ midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton,
GTK_NOTEBOOK (panel->toolbook), n);
GtkWidget* scrolled = gtk_notebook_get_nth_page (
GTK_NOTEBOOK (panel->notebook), n);
GtkWidget* menuitem = g_object_get_data (G_OBJECT (scrolled), "panel-menuitem");
GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
g_object_set_data (G_OBJECT (window), "scrolled", scrolled);
gtk_window_set_title (GTK_WINDOW (window), title);
#if HAVE_HILDON
GtkWidget* window = hildon_window_new ();
hildon_program_add_window (hildon_program_get_instance (), HILDON_WINDOW (window));
#else
GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
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)));
#endif
gtk_widget_show (vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
if (menuitem)
gtk_widget_hide (menuitem);
g_object_set_data (G_OBJECT (window), "scrolled", scrolled);
gtk_window_set_title (GTK_WINDOW (window), title);
g_signal_handlers_disconnect_by_func (
_midori_panel_child_for_scrolled (panel, scrolled),
midori_panel_widget_destroy_cb, toolitem);
gtk_container_remove (GTK_CONTAINER (panel->toolbar), GTK_WIDGET (toolitem));
g_object_ref (toolbar);
gtk_container_remove (GTK_CONTAINER (panel->toolbook), toolbar);
#if HAVE_HILDON
hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (toolbar));
#else
gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
#endif
g_object_unref (toolbar);
g_object_set_data (G_OBJECT (scrolled), "panel-toolbar", toolbar);
g_object_ref (scrolled);
@ -317,14 +358,24 @@ midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton,
midori_panel_set_current_page (panel, n > 0 ? n - 1 : 0);
toolitem = gtk_toolbar_get_nth_item (GTK_TOOLBAR (panel->toolbar),
n > 0 ? n - 1 : 0);
gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (toolitem), TRUE);
if (!gtk_notebook_get_n_pages (GTK_NOTEBOOK (panel->notebook)))
gtk_widget_set_sensitive (toolbutton, FALSE);
gtk_widget_set_sensitive (GTK_WIDGET (panel->button_detach), FALSE);
g_signal_connect (window, "delete-event",
G_CALLBACK (midori_panel_detached_window_delete_event_cb), panel);
gtk_widget_show (window);
}
static void
midori_panel_button_detach_clicked_cb (GtkWidget* toolbutton,
MidoriPanel* panel)
{
/* FIXME: What happens when the browser is destroyed? */
/* FIXME: What about multiple browsers? */
/* FIXME: Should we remember if the child was detached? */
gint n = midori_panel_get_current_page (panel);
midori_panel_detach_page (panel, n);
}
static void
midori_panel_button_align_clicked_cb (GtkWidget* toolitem,
MidoriPanel* panel)
@ -347,6 +398,7 @@ midori_panel_init (MidoriPanel* panel)
GtkWidget* labelbar;
GtkToolItem* toolitem;
panel->action_group = NULL;
panel->show_titles = TRUE;
panel->show_controls = TRUE;
panel->right_aligned = FALSE;
@ -370,6 +422,7 @@ midori_panel_init (MidoriPanel* panel)
toolitem = gtk_tool_item_new ();
gtk_tool_item_set_expand (toolitem, TRUE);
panel->toolbar_label = gtk_label_new (NULL);
gtk_label_set_ellipsize (GTK_LABEL (panel->toolbar_label), PANGO_ELLIPSIZE_END);
gtk_misc_set_alignment (GTK_MISC (panel->toolbar_label), 0, 0.5);
gtk_container_add (GTK_CONTAINER (toolitem), panel->toolbar_label);
gtk_container_set_border_width (GTK_CONTAINER (toolitem), 6);
@ -454,6 +507,9 @@ midori_panel_set_property (GObject* object,
gtk_frame_set_shadow_type (GTK_FRAME (panel->frame),
g_value_get_enum (value));
break;
case PROP_ACTION_GROUP:
katze_object_assign (panel->action_group, g_value_dup_object (value));
break;
case PROP_MENU:
katze_object_assign (panel->menu, g_value_dup_object (value));
break;
@ -462,9 +518,6 @@ midori_panel_set_property (GObject* object,
break;
case PROP_SHOW_TITLES:
panel->show_titles = g_value_get_boolean (value);
#if HAVE_HILDON
panel->show_titles = TRUE;
#endif
gtk_toolbar_set_style (GTK_TOOLBAR (panel->toolbar),
panel->show_titles ? GTK_TOOLBAR_BOTH : GTK_TOOLBAR_ICONS);
break;
@ -476,6 +529,9 @@ midori_panel_set_property (GObject* object,
case PROP_RIGHT_ALIGNED:
midori_panel_set_right_aligned (panel, g_value_get_boolean (value));
break;
case PROP_OPEN_PANELS_IN_WINDOWS:
panel->open_panels_in_windows = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -496,6 +552,9 @@ midori_panel_get_property (GObject* object,
g_value_set_enum (value,
gtk_frame_get_shadow_type (GTK_FRAME (panel->frame)));
break;
case PROP_ACTION_GROUP:
g_value_set_object (value, panel->action_group);
break;
case PROP_MENU:
g_value_set_object (value, panel->menu);
break;
@ -511,6 +570,9 @@ midori_panel_get_property (GObject* object,
case PROP_RIGHT_ALIGNED:
g_value_set_boolean (value, panel->right_aligned);
break;
case PROP_OPEN_PANELS_IN_WINDOWS:
g_value_set_boolean (value, panel->open_panels_in_windows);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -581,50 +643,20 @@ midori_panel_set_right_aligned (MidoriPanel* panel,
g_object_notify (G_OBJECT (panel), "right-aligned");
}
static void
midori_panel_menu_item_activate_cb (GtkWidget* widget,
MidoriPanel* panel)
{
GtkWidget* child;
GtkToolItem* toolitem;
guint n;
child = g_object_get_data (G_OBJECT (widget), "page");
n = midori_panel_page_num (panel, child);
toolitem = gtk_toolbar_get_nth_item (GTK_TOOLBAR (panel->toolbar), n);
if (toolitem)
{
/* Unsetting the button before setting it ensures that
it will emit signals even if it was active before */
GtkToggleToolButton* button = GTK_TOGGLE_TOOL_BUTTON (toolitem);
g_signal_handlers_block_by_func (widget,
midori_panel_menu_item_activate_cb, panel);
gtk_toggle_tool_button_set_active (button, FALSE);
gtk_toggle_tool_button_set_active (button, TRUE);
g_signal_handlers_unblock_by_func (widget,
midori_panel_menu_item_activate_cb, panel);
}
midori_panel_set_current_page (panel, n);
g_signal_emit (panel, signals[SWITCH_PAGE], 0, n);
gtk_widget_show (GTK_WIDGET (panel));
}
/* Private function, used by MidoriBrowser */
/* static */ GtkWidget*
midori_panel_construct_menu_item (MidoriPanel* panel,
MidoriViewable* viewable)
{
const gchar* stock_id;
GtkAction* action;
GtkWidget* menuitem;
stock_id = midori_viewable_get_stock_id (viewable);
menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
gtk_widget_show (menuitem);
action = g_object_get_data (G_OBJECT (viewable), "midori-panel-action");
menuitem = gtk_action_create_menu_item (action);
g_object_set_data (G_OBJECT (menuitem), "page", viewable);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_panel_menu_item_activate_cb), panel);
if (GTK_WIDGET_VISIBLE (viewable))
gtk_widget_show (menuitem);
return menuitem;
}
@ -644,35 +676,23 @@ static GtkToolItem*
midori_panel_construct_tool_item (MidoriPanel* panel,
MidoriViewable* viewable)
{
const gchar* label = midori_viewable_get_label (viewable);
const gchar* stock_id = midori_viewable_get_stock_id (viewable);
GtkToolItem* toolitem;
GtkWidget* image;
GtkAction* action;
GtkWidget* toolitem;
toolitem = gtk_radio_tool_button_new_from_stock (NULL, stock_id);
g_object_set (toolitem, "group",
gtk_toolbar_get_nth_item (GTK_TOOLBAR (panel->toolbar), 0), NULL);
image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
if (label)
{
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), label);
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem), label);
}
action = g_object_get_data (G_OBJECT (viewable), "midori-panel-action");
toolitem = gtk_action_create_tool_item (action);
g_object_set_data (G_OBJECT (toolitem), "page", viewable);
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_menu_item_activate_cb), panel);
gtk_widget_show_all (GTK_WIDGET (toolitem));
gtk_toolbar_insert (GTK_TOOLBAR (panel->toolbar), toolitem, -1);
gtk_toolbar_insert (GTK_TOOLBAR (panel->toolbar), GTK_TOOL_ITEM (toolitem), -1);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), toolitem);
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (panel->notebook)))
gtk_widget_set_sensitive (GTK_WIDGET (panel->button_detach), TRUE);
return toolitem;
return GTK_TOOL_ITEM (toolitem);
}
#if !HAVE_HILDON
static void
midori_panel_show_titles_toggled_cb (GtkWidget* menuitem,
MidoriPanel* panel)
@ -699,7 +719,6 @@ midori_panel_options_clicked_cb (GtkToolItem* toolitem,
n = midori_panel_get_current_page (panel);
viewable = midori_panel_get_nth_page (panel, n);
menu = gtk_menu_new ();
#if !HAVE_HILDON
menuitem = gtk_check_menu_item_new_with_mnemonic (_("Show panel _titles"));
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem),
panel->show_titles);
@ -707,7 +726,6 @@ midori_panel_options_clicked_cb (GtkToolItem* toolitem,
G_CALLBACK (midori_panel_show_titles_toggled_cb), panel);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
#endif
menuitem = gtk_check_menu_item_new_with_mnemonic (_("Show operating _controls"));
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem),
panel->show_controls);
@ -718,7 +736,35 @@ midori_panel_options_clicked_cb (GtkToolItem* toolitem,
g_signal_emit_by_name (viewable, "populate-option-menu", menu);
katze_widget_popup (GTK_WIDGET (toolitem), GTK_MENU (menu),
NULL, SOKOKE_MENU_POSITION_LEFT);
NULL, KATZE_MENU_POSITION_LEFT);
}
#endif
static void
midori_panel_action_activate_cb (GtkRadioAction* action,
MidoriPanel* panel)
{
GtkWidget* viewable = g_object_get_data (G_OBJECT (action), "viewable");
gint n = midori_panel_page_num (panel, viewable);
/* If the panel is detached, focus the window */
if (n == -1)
{
GtkWidget* toplevel = gtk_widget_get_toplevel (viewable);
gtk_window_present (GTK_WINDOW (toplevel));
return;
}
if (panel->open_panels_in_windows
&& gtk_radio_action_get_current_value (action)
== katze_object_get_int (action, "value"))
midori_panel_detach_page (panel, n);
else
{
midori_panel_set_current_page (panel, n);
g_signal_emit (panel, signals[SWITCH_PAGE], 0, n);
gtk_widget_show (GTK_WIDGET (panel));
}
}
/**
@ -735,6 +781,10 @@ midori_panel_options_clicked_cb (GtkToolItem* toolitem,
* Since 0.1.3 destroying the @viewable implicitly removes
* the page including the menu and eventual toolbar.
*
* Since 0.2.1 a hidden @viewable will not be shown in the panel.
*
* Since 0.2.1 an action with an accelerator is created implicitly.
*
* In the case of an error, -1 is returned.
*
* Return value: the index of the new page, or -1
@ -748,8 +798,9 @@ midori_panel_append_page (MidoriPanel* panel,
GtkWidget* widget;
GtkWidget* toolbar;
GtkToolItem* toolitem;
const gchar* label;
guint n;
gchar* action_name;
GtkAction* action;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
g_return_val_if_fail (MIDORI_IS_VIEWABLE (viewable), -1);
@ -778,25 +829,57 @@ midori_panel_append_page (MidoriPanel* panel,
gtk_container_add (GTK_CONTAINER (panel->notebook), scrolled);
toolbar = midori_viewable_get_toolbar (viewable);
#if !HAVE_HILDON
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_PROPERTIES);
gtk_tool_item_set_tooltip_text (toolitem, _("Options"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_options_clicked_cb), panel);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, 0);
gtk_widget_show (GTK_WIDGET (toolitem));
#endif
gtk_widget_show (toolbar);
gtk_container_add (GTK_CONTAINER (panel->toolbook), toolbar);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), toolbar);
n = midori_panel_page_num (panel, scrolled);
label = midori_viewable_get_label (viewable);
n = midori_panel_get_n_pages (panel) - 1;
/* FIXME: Use something better than the stock ID */
action_name = g_strconcat ("PanelPage",
midori_viewable_get_stock_id (viewable), NULL);
action = (GtkAction*)gtk_radio_action_new (action_name,
midori_viewable_get_label (viewable),
NULL, midori_viewable_get_stock_id (viewable), n);
g_object_set_data (G_OBJECT (action), "viewable", viewable);
g_signal_connect (action, "activate",
G_CALLBACK (midori_panel_action_activate_cb), panel);
if (panel->action_group)
{
/* FIXME: For some reason the accelerator only works if a menuitem
is created, but not before that. */
GtkWidget* toplevel = gtk_widget_get_toplevel (GTK_WIDGET (panel));
GSList* groups = gtk_accel_groups_from_object (G_OBJECT (toplevel));
gtk_action_set_accel_group (action, g_slist_nth_data (groups, 0));
gtk_action_group_add_action_with_accel (panel->action_group,
action, NULL);
}
if (n > 0)
g_object_set (action, "group", g_object_get_data (
G_OBJECT (midori_panel_get_nth_page (panel, 0)),
"midori-panel-action"), NULL);
g_object_set_data (G_OBJECT (viewable), "midori-panel-action", action);
g_free (action_name);
g_object_set_data (G_OBJECT (viewable), "parent", scrolled);
midori_panel_construct_tool_item (panel, viewable);
toolitem = midori_panel_construct_tool_item (panel, viewable);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_viewable_destroy_cb), panel);
if (!GTK_WIDGET_VISIBLE (viewable))
{
gtk_widget_hide (scrolled);
gtk_widget_hide (GTK_WIDGET (toolitem));
}
return n;
}
@ -925,6 +1008,8 @@ midori_panel_page_num (MidoriPanel* panel,
* silently ignore the attempt to switch the page.
*
* Since 0.1.8 the "page" property is notifying changes.
*
* Since 0.2.1 switching to hidden pages fails silently.
**/
void
midori_panel_set_current_page (MidoriPanel* panel,
@ -938,6 +1023,8 @@ midori_panel_set_current_page (MidoriPanel* panel,
{
const gchar* label;
if (!GTK_WIDGET_VISIBLE (viewable))
return;
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));

View File

@ -22,15 +22,18 @@
#include <glib/gi18n.h>
#include <libsoup/soup.h>
#if HAVE_LIBNOTIFY
#include <libnotify/notify.h>
#endif
struct _MidoriPreferences
{
GtkDialog parent_instance;
KatzePreferences parent_instance;
MidoriWebSettings* settings;
GtkWidget* notebook;
gpointer settings;
};
G_DEFINE_TYPE (MidoriPreferences, midori_preferences, GTK_TYPE_DIALOG)
G_DEFINE_TYPE (MidoriPreferences, midori_preferences, KATZE_TYPE_PREFERENCES);
enum
{
@ -62,6 +65,11 @@ midori_preferences_class_init (MidoriPreferencesClass* class)
gobject_class->set_property = midori_preferences_set_property;
gobject_class->get_property = midori_preferences_get_property;
/**
* MidoriPreferences:settings:
*
* The settings to proxy properties from.
*/
g_object_class_install_property (gobject_class,
PROP_SETTINGS,
g_param_spec_object (
@ -72,38 +80,10 @@ midori_preferences_class_init (MidoriPreferencesClass* class)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
midori_preferences_response_cb (MidoriPreferences* preferences,
gint response)
{
if (response == GTK_RESPONSE_CLOSE)
gtk_widget_destroy (GTK_WIDGET (preferences));
}
static void
midori_preferences_init (MidoriPreferences* preferences)
{
gchar* dialog_title;
preferences->settings = NULL;
preferences->notebook = NULL;
dialog_title = g_strdup_printf (_("Preferences for %s"),
g_get_application_name ());
g_object_set (preferences,
"icon-name", GTK_STOCK_PREFERENCES,
"title", dialog_title,
"has-separator", FALSE,
NULL);
g_free (dialog_title);
#if !HAVE_OSX
gtk_dialog_add_buttons (GTK_DIALOG (preferences),
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
NULL);
#endif
g_signal_connect (preferences, "response",
G_CALLBACK (midori_preferences_response_cb), NULL);
}
static void
@ -179,9 +159,17 @@ midori_preferences_new (GtkWindow* parent,
return GTK_WIDGET (preferences);
}
#if GTK_CHECK_VERSION (2, 16, 0)
static void
midori_preferences_homepage_icon_press_cb (GtkWidget* button,
GtkEntryIconPosition position,
GdkEvent* event,
MidoriWebSettings* settings)
#else
static void
midori_preferences_homepage_current_clicked_cb (GtkWidget* button,
MidoriWebSettings* settings)
#endif
{
GtkWidget* preferences = gtk_widget_get_toplevel (button);
GtkWidget* browser = katze_object_get_object (preferences, "transient-for");
@ -194,53 +182,7 @@ midori_preferences_homepage_current_clicked_cb (GtkWidget* button,
}
}
static gboolean
proxy_download_manager_icon_cb (GtkWidget* entry,
GdkEventFocus* event,
GtkImage* icon)
{
const gchar* command;
gchar* first_space;
gchar* first_part;
gchar* path;
command = gtk_entry_get_text (GTK_ENTRY (entry));
if ((first_space = strstr (command, " ")))
first_part = g_strndup (command, first_space - command);
else
first_part = g_strdup (command);
path = g_find_program_in_path (first_part);
if (path)
{
if (gtk_icon_theme_has_icon (gtk_icon_theme_get_for_screen (
gtk_widget_get_screen (entry)), first_part))
gtk_image_set_from_icon_name (icon, first_part, GTK_ICON_SIZE_MENU);
else
gtk_image_set_from_stock (icon, GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU);
g_free (path);
}
else if (first_part && *first_part)
gtk_image_set_from_stock (icon, GTK_STOCK_STOP, GTK_ICON_SIZE_MENU);
else
gtk_image_clear (icon);
g_free (first_part);
return FALSE;
}
static void
midori_preferences_notify_preferred_encoding_cb (MidoriWebSettings* settings,
GParamSpec* pspec,
GtkWidget* entry)
{
MidoriPreferredEncoding preferred_encoding;
preferred_encoding = katze_object_get_enum (settings, "preferred-encoding");
gtk_widget_set_sensitive (entry, preferred_encoding == MIDORI_ENCODING_CUSTOM);
}
#if !HAVE_HILDON
static void
midori_preferences_notify_auto_detect_proxy_cb (MidoriWebSettings* settings,
GParamSpec* pspec,
@ -251,25 +193,9 @@ midori_preferences_notify_auto_detect_proxy_cb (MidoriWebSettings* settings,
gtk_widget_set_sensitive (entry, !auto_detect_proxy);
}
static void
midori_preferences_notify_identify_as_cb (MidoriWebSettings* settings,
GParamSpec* pspec,
GtkWidget* entry)
{
MidoriIdentity identify_as = katze_object_get_enum (settings, "identify-as");
gtk_widget_set_sensitive (entry, identify_as == MIDORI_IDENT_CUSTOM);
}
#endif
#if HAVE_OSX
static void
midori_preferences_help_clicked_cb (GtkWidget* button,
GtkDialog* dialog)
{
gtk_dialog_response (dialog, GTK_RESPONSE_HELP);
}
static void
midori_preferences_toolbutton_clicked_cb (GtkWidget* toolbutton,
GtkWidget* page)
@ -298,6 +224,28 @@ midori_preferences_add_toolbutton (GtkWidget* toolbar,
#endif
}
#if 0
static void
midori_preferences_list_dicts_cb (const gchar* lang_tag,
const gchar* provider_name,
const gchar* provider_desc,
const gchar* provider_file,
GList** dicts)
{
*dicts = g_list_prepend (*dicts, (gchar*)lang_tag);
}
static GList*
midori_preferences_get_spell_languages (void)
{
GList* dicts = NULL;
gpointer broker = enchant_broker_init ();
enchant_broker_list_dicts (broker, (GCallback)midori_preferences_list_dicts_cb, &dicts);
enchant_broker_free (broker);
return dicts;
}
#endif
/**
* midori_preferences_set_settings:
* @settings: the settings
@ -315,393 +263,262 @@ midori_preferences_set_settings (MidoriPreferences* preferences,
GtkWidget* header;
GtkWindow* parent;
const gchar* icon_name;
#if WEBKIT_CHECK_VERSION (1, 1, 15)
GtkSettings* gtk_settings;
#endif
GtkSizeGroup* sizegroup;
GtkWidget* toolbar;
GtkWidget* toolbutton;
GtkWidget* page;
GtkWidget* frame;
GtkWidget* table;
GtkWidget* align;
KatzePreferences* _preferences;
GtkWidget* label;
GtkWidget* button;
GtkWidget* entry;
GtkWidget* hbox;
gint icon_width, icon_height;
g_return_if_fail (MIDORI_IS_PREFERENCES (preferences));
g_return_if_fail (MIDORI_IS_WEB_SETTINGS (settings));
g_return_if_fail (!preferences->notebook);
g_return_if_fail (!preferences->settings);
katze_assign (preferences->settings, g_object_ref (settings));
preferences->settings = settings;
g_object_get (preferences, "transient-for", &parent, NULL);
icon_name = parent ? gtk_window_get_icon_name (parent) : NULL;
if ((header = sokoke_xfce_header_new (icon_name,
gtk_window_get_title (GTK_WINDOW (preferences)))))
{
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (preferences)->vbox),
header, FALSE, FALSE, 0);
#if WEBKIT_CHECK_VERSION (1, 1, 15)
gtk_settings = parent ? gtk_widget_get_settings (GTK_WIDGET (parent)) : NULL;
#endif
gtk_widget_show_all (header);
}
_preferences = KATZE_PREFERENCES (preferences);
preferences->notebook = gtk_notebook_new ();
gtk_container_set_border_width (GTK_CONTAINER (preferences->notebook), 6);
#if HAVE_OSX
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (preferences->notebook), FALSE);
gtk_notebook_set_show_border (GTK_NOTEBOOK (preferences->notebook), FALSE);
toolbar = gtk_toolbar_new ();
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH);
gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (preferences)->vbox),
toolbar, FALSE, FALSE, 0);
#else
toolbar = NULL;
#endif
toolbutton = NULL;
sizegroup = NULL;
#define PAGE_NEW(__icon, __label) \
page = gtk_vbox_new (FALSE, 0); \
midori_preferences_add_toolbutton (toolbar, &toolbutton, \
__icon, __label, page); \
if (toolbutton) g_object_set_data (G_OBJECT (toolbutton), \
"notebook", preferences->notebook); \
if (sizegroup) g_object_unref (sizegroup); \
sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); \
gtk_container_set_border_width (GTK_CONTAINER (page), 4); \
gtk_notebook_append_page (GTK_NOTEBOOK (preferences->notebook), page, \
gtk_label_new (__label))
#define FRAME_NEW(__label) frame = sokoke_hig_frame_new (__label); \
gtk_container_set_border_width (GTK_CONTAINER (frame), 4); \
gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
#define TABLE_NEW(__rows, __cols) table = gtk_table_new ( \
__rows, __cols, FALSE); \
gtk_container_set_border_width (GTK_CONTAINER (table), 4); \
gtk_container_add (GTK_CONTAINER (frame), table);
#define WIDGET_ADD(__widget, __left, __right, __top, __bottom) \
gtk_table_attach (GTK_TABLE (table), __widget \
, __left, __right, __top, __bottom \
, GTK_FILL, GTK_FILL, 8, 2)
#define FILLED_ADD(__widget, __left, __right, __top, __bottom) \
gtk_table_attach (GTK_TABLE (table), __widget \
, __left, __right, __top, __bottom\
, GTK_EXPAND | GTK_FILL, GTK_FILL, 8, 2)
#define INDENTED_ADD(__widget, __left, __right, __top, __bottom) \
align = gtk_alignment_new (0, 0.5, 0, 0); \
gtk_container_add (GTK_CONTAINER (align), __widget); \
gtk_size_group_add_widget (sizegroup, align); \
WIDGET_ADD (align, __left, __right, __top, __bottom)
#define SPANNED_ADD(__widget, __left, __right, __top, __bottom) \
align = gtk_alignment_new (0, 0.5, 0, 0); \
gtk_container_add (GTK_CONTAINER (align), __widget); \
FILLED_ADD (align, __left, __right, __top, __bottom)
katze_preferences_add_category (_preferences, __label, __icon)
#define FRAME_NEW(__label) \
katze_preferences_add_group (_preferences, __label)
#define FILLED_ADD(__widget) \
katze_preferences_add_widget (_preferences, __widget, "filled")
#define INDENTED_ADD(__widget) \
katze_preferences_add_widget (_preferences, __widget, "indented")
#define SPANNED_ADD(__widget) \
katze_preferences_add_widget (_preferences, __widget, "spanned")
/* Page "General" */
PAGE_NEW (GTK_STOCK_HOME, _("General"));
FRAME_NEW (_("Startup"));
TABLE_NEW (3, 2);
label = katze_property_label (settings, "load-on-startup");
INDENTED_ADD (label, 0, 1, 0, 1);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "load-on-startup", NULL);
FILLED_ADD (button, 1, 2, 0, 1);
SPANNED_ADD (button);
label = katze_property_label (settings, "homepage");
INDENTED_ADD (label, 0, 1, 1, 2);
hbox = gtk_hbox_new (FALSE, 4);
INDENTED_ADD (label);
entry = katze_property_proxy (settings, "homepage", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
SPANNED_ADD (entry);
if (parent && katze_object_has_property (parent, "uri"))
{
#if GTK_CHECK_VERSION (2, 16, 0)
gtk_entry_set_icon_from_stock (GTK_ENTRY (entry),
GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_JUMP_TO);
gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
GTK_ENTRY_ICON_SECONDARY, _("Use current page as homepage"));
g_signal_connect (entry, "icon-press",
G_CALLBACK (midori_preferences_homepage_icon_press_cb), settings);
#else
button = gtk_button_new ();
label = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (button), label);
gtk_widget_set_tooltip_text (button, _("Use current page as homepage"));
g_signal_connect (button, "clicked",
G_CALLBACK (midori_preferences_homepage_current_clicked_cb), settings);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
SPANNED_ADD (button);
#endif
}
FILLED_ADD (hbox, 1, 2, 1, 2);
button = katze_property_proxy (settings, "show-crash-dialog", NULL);
INDENTED_ADD (button, 0, 1, 2, 3);
INDENTED_ADD (button);
button = katze_property_proxy (settings, "speed-dial-in-new-tabs", NULL);
FILLED_ADD (button, 1, 2, 2, 3);
SPANNED_ADD (button);
FRAME_NEW (_("Transfers"));
TABLE_NEW (2, 2);
#if !HAVE_HILDON
label = katze_property_label (settings, "download-folder");
INDENTED_ADD (label, 0, 1, 0, 1);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "download-folder", "folder");
FILLED_ADD (button, 1, 2, 0, 1);
SPANNED_ADD (button);
label = katze_property_proxy (settings, "ask-for-destination-folder", NULL);
INDENTED_ADD (label, 0, 1, 1, 2);
button = katze_property_proxy (settings, "notify-transfer-completed", NULL);
/* FIXME: Disable the option if notifications presumably cannot be sent
gtk_widget_set_sensitive (button, FALSE); */
SPANNED_ADD (button, 1, 2, 1, 2);
INDENTED_ADD (label);
#if HAVE_LIBNOTIFY
if (notify_is_initted () || g_find_program_in_path ("notify-send"))
{
button = katze_property_proxy (settings, "notify-transfer-completed", NULL);
SPANNED_ADD (button);
}
#endif
#endif
/* Page "Appearance" */
PAGE_NEW (GTK_STOCK_SELECT_FONT, _("Appearance"));
FRAME_NEW (_("Font settings"));
TABLE_NEW (7, 2);
#if !HAVE_HILDON
label = gtk_label_new (_("Default Font Family"));
INDENTED_ADD (label, 0, 1, 0, 1);
hbox = gtk_hbox_new (FALSE, 4);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "default-font-family", "font");
gtk_widget_set_tooltip_text (button, _("The default font family used to display text"));
gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
SPANNED_ADD (button);
entry = katze_property_proxy (settings, "default-font-size", NULL);
gtk_widget_set_tooltip_text (entry, _("The default font size used to display text"));
gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 4);
FILLED_ADD (hbox, 1, 2, 0, 1);
SPANNED_ADD (entry);
label = gtk_label_new (_("Fixed-width Font Family"));
INDENTED_ADD (label, 0, 1, 1, 2);
hbox = gtk_hbox_new (FALSE, 4);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "monospace-font-family", "font-monospace");
gtk_widget_set_tooltip_text (button, _("The font family used to display fixed-width text"));
gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
SPANNED_ADD (button);
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);
SPANNED_ADD (entry);
label = gtk_label_new (_("Minimum Font Size"));
INDENTED_ADD (label, 0, 1, 2, 3);
INDENTED_ADD (label);
entry = katze_property_proxy (settings, "minimum-font-size", NULL);
gtk_widget_set_tooltip_text (entry, _("The minimum font size used to display text"));
INDENTED_ADD (entry, 1, 2, 2, 3);
SPANNED_ADD (entry);
#endif
label = katze_property_label (settings, "preferred-encoding");
INDENTED_ADD (label, 0, 1, 3, 4);
button = katze_property_proxy (settings, "preferred-encoding", NULL);
FILLED_ADD (button, 1, 2, 3, 4);
label = katze_property_label (settings, "default-encoding");
gtk_label_set_label (GTK_LABEL (label), _("Encoding"));
INDENTED_ADD (label, 0, 1, 4, 5);
entry = katze_property_proxy (settings, "default-encoding", NULL);
gtk_widget_set_tooltip_text (entry, _("The character encoding to use by default"));
g_signal_connect (settings, "notify::preferred-encoding",
G_CALLBACK (midori_preferences_notify_preferred_encoding_cb), entry);
midori_preferences_notify_preferred_encoding_cb (settings, NULL, entry);
FILLED_ADD (entry, 1, 2, 4, 5);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "preferred-encoding", "custom-default-encoding");
SPANNED_ADD (button);
/* Page "Behavior" */
PAGE_NEW (GTK_STOCK_SELECT_COLOR, _("Behavior"));
FRAME_NEW (_("Features"));
TABLE_NEW (6, 2);
#if !HAVE_HILDON
button = katze_property_proxy (settings, "auto-load-images", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Load images automatically"));
gtk_widget_set_tooltip_text (button, _("Load and display images automatically"));
INDENTED_ADD (button, 0, 1, 0, 1);
#if WEBKIT_CHECK_VERSION (1, 1, 15)
if (katze_object_get_boolean (gtk_settings, "gtk-touchscreen-mode"))
INDENTED_ADD (button);
#endif
#if WEBKIT_CHECK_VERSION (1, 1, 15) || HAVE_HILDON
if (katze_widget_has_touchscreen_mode (parent ?
GTK_WIDGET (parent) : GTK_WIDGET (preferences)))
button = katze_property_proxy (settings, "kinetic-scrolling", NULL);
else
{
button = katze_property_proxy (settings, "auto-shrink-images", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Shrink images automatically"));
gtk_widget_set_tooltip_text (button, _("Automatically shrink standalone images to fit"));
}
button = katze_property_proxy (settings, "open-panels-in-windows", NULL);
#else
button = katze_property_proxy (settings, "middle-click-opens-selection", NULL);
#endif
SPANNED_ADD (button, 1, 2, 0, 1);
SPANNED_ADD (button);
#if !HAVE_HILDON
button = katze_property_proxy (settings, "enable-scripts", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enable scripts"));
gtk_widget_set_tooltip_text (button, _("Enable embedded scripting languages"));
INDENTED_ADD (button, 0, 1, 2, 3);
INDENTED_ADD (button);
button = katze_property_proxy (settings, "enable-plugins", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enable Netscape plugins"));
gtk_widget_set_tooltip_text (button, _("Enable embedded Netscape plugin objects"));
SPANNED_ADD (button, 1, 2, 2, 3);
SPANNED_ADD (button);
button = katze_property_proxy (settings, "enforce-96-dpi", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enforce 96 dots per inch"));
gtk_widget_set_tooltip_text (button, _("Enforce a video dot density of 96 DPI"));
SPANNED_ADD (button, 0, 1, 3, 4);
INDENTED_ADD (button);
button = katze_property_proxy (settings, "enable-developer-extras", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enable developer tools"));
gtk_widget_set_tooltip_text (button, _("Enable special extensions for developers"));
SPANNED_ADD (button, 1, 2, 3, 4);
SPANNED_ADD (button);
#endif
button = katze_property_proxy (settings, "zoom-text-and-images", NULL);
SPANNED_ADD (button, 0, 1, 4, 5);
INDENTED_ADD (button);
button = katze_property_proxy (settings, "find-while-typing", NULL);
SPANNED_ADD (button, 1, 2, 4, 5);
SPANNED_ADD (button);
#if WEBKIT_CHECK_VERSION (1, 1, 6)
FRAME_NEW (_("Spell Checking"));
TABLE_NEW (1, 2);
/* FIXME: Provide a nice dictionary selection */
button = katze_property_proxy (settings, "enable-spell-checking", NULL);
gtk_button_set_label (GTK_BUTTON (button), _("Enable Spell Checking"));
gtk_widget_set_tooltip_text (button, _("Enable spell checking while typing"));
INDENTED_ADD (button, 0, 1, 0, 1);
INDENTED_ADD (button);
entry = katze_property_proxy (settings, "spell-checking-languages", NULL);
/* i18n: The example should be adjusted to contain a good local default */
gtk_widget_set_tooltip_text (entry, _("A comma separated list of languages to be used for spell checking, for example \"en_GB,de_DE\""));
FILLED_ADD (entry, 1, 2, 0, 1);
gtk_widget_set_tooltip_text (entry, _("A comma separated list of "
"languages to be used for spell checking, for example \"en_GB,de_DE\""));
SPANNED_ADD (entry);
#endif
/* Page "Interface" */
PAGE_NEW (GTK_STOCK_CONVERT, _("Interface"));
FRAME_NEW (_("Navigationbar"));
TABLE_NEW (2, 2);
#if !HAVE_HILDON
INDENTED_ADD (katze_property_label (settings, "toolbar-style"), 0, 1, 0, 1);
INDENTED_ADD (katze_property_label (settings, "toolbar-style"));
button = katze_property_proxy (settings, "toolbar-style", NULL);
FILLED_ADD (button, 1, 2, 0, 1);
#endif
SPANNED_ADD (button);
button = katze_property_proxy (settings, "progress-in-location", NULL);
FILLED_ADD (button, 0, 1, 1, 2);
INDENTED_ADD (button);
button = katze_property_proxy (settings, "search-engines-in-completion", NULL);
FILLED_ADD (button, 1, 2, 1, 2);
SPANNED_ADD (button);
#endif
FRAME_NEW (_("Browsing"));
TABLE_NEW (5, 2);
hbox = gtk_hbox_new (FALSE, 4);
label = katze_property_label (settings, "open-new-pages-in");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "open-new-pages-in", NULL);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 4);
INDENTED_ADD (hbox, 0, 1, 0, 1);
hbox = gtk_hbox_new (FALSE, 4);
SPANNED_ADD (button);
label = katze_property_label (settings, "open-external-pages-in");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "open-external-pages-in", NULL);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 4);
FILLED_ADD (hbox, 1, 2, 0, 1);
SPANNED_ADD (button);
#if !HAVE_HILDON
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);
INDENTED_ADD (button, 1, 2, 2, 3);
button = katze_property_proxy (settings, "open-tabs-next-to-current", NULL);
WIDGET_ADD (button, 0, 1, 5, 6);
INDENTED_ADD (button);
button = katze_property_proxy (settings, "close-buttons-on-tabs", NULL);
WIDGET_ADD (button, 1, 2, 5, 6);
SPANNED_ADD (button);
#endif
button = katze_property_proxy (settings, "open-tabs-next-to-current", NULL);
INDENTED_ADD (button);
button = katze_property_proxy (settings, "open-tabs-in-the-background", NULL);
SPANNED_ADD (button);
#if !HAVE_HILDON
/* Page "Applications" */
PAGE_NEW (GTK_STOCK_CONVERT, _("Applications"));
FRAME_NEW (_("External applications"));
TABLE_NEW (3, 2);
label = katze_property_label (settings, "text-editor");
INDENTED_ADD (label, 0, 1, 0, 1);
hbox = gtk_hbox_new (FALSE, 4);
button = gtk_image_new ();
gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
gtk_widget_set_size_request (button, icon_width, icon_height);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 4);
entry = katze_property_proxy (settings, "text-editor", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
proxy_download_manager_icon_cb (entry, NULL, GTK_IMAGE (button));
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_download_manager_icon_cb), button);
FILLED_ADD (hbox, 1, 2, 0, 1);
INDENTED_ADD (label);
entry = katze_property_proxy (settings, "text-editor", "application-text/plain");
SPANNED_ADD (entry);
label = katze_property_label (settings, "download-manager");
INDENTED_ADD (label, 0, 1, 1, 2);
hbox = gtk_hbox_new (FALSE, 4);
button = gtk_image_new ();
gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
gtk_widget_set_size_request (button, icon_width, icon_height);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 4);
entry = katze_property_proxy (settings, "download-manager", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
proxy_download_manager_icon_cb (entry, NULL, GTK_IMAGE (button));
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_download_manager_icon_cb), button);
FILLED_ADD (hbox, 1, 2, 1, 2);
INDENTED_ADD (label);
entry = katze_property_proxy (settings, "download-manager", "application-Network");
SPANNED_ADD (entry);
label = katze_property_label (settings, "news-aggregator");
INDENTED_ADD (label, 0, 1, 2, 3);
hbox = gtk_hbox_new (FALSE, 4);
button = gtk_image_new ();
gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
gtk_widget_set_size_request (button, icon_width, icon_height);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 4);
entry = katze_property_proxy (settings, "news-aggregator", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
proxy_download_manager_icon_cb (entry, NULL, GTK_IMAGE (button));
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (proxy_download_manager_icon_cb), button);
FILLED_ADD (hbox, 1, 2, 2, 3);
INDENTED_ADD (label);
entry = katze_property_proxy (settings, "news-aggregator", "application-News");
SPANNED_ADD (entry);
#endif
/* Page "Network" */
PAGE_NEW (GTK_STOCK_NETWORK, _("Network"));
FRAME_NEW (_("Network"));
TABLE_NEW (5, 2);
#if !HAVE_HILDON
label = katze_property_label (settings, "http-proxy");
INDENTED_ADD (label, 0, 1, 0, 1);
INDENTED_ADD (label);
entry = katze_property_proxy (settings, "http-proxy", NULL);
FILLED_ADD (entry, 1, 2, 0, 1);
SPANNED_ADD (entry);
INDENTED_ADD (gtk_event_box_new ());
button = katze_property_proxy (settings, "auto-detect-proxy", NULL);
FILLED_ADD (button, 1, 2, 1, 2);
SPANNED_ADD (button);
g_signal_connect (settings, "notify::auto-detect-proxy",
G_CALLBACK (midori_preferences_notify_auto_detect_proxy_cb), entry);
midori_preferences_notify_auto_detect_proxy_cb (settings, NULL, entry);
#endif
label = katze_property_label (settings, "identify-as");
INDENTED_ADD (label, 0, 1, 2, 3);
button = katze_property_proxy (settings, "identify-as", NULL);
FILLED_ADD (button, 1, 2, 2, 3);
label = katze_property_label (settings, "ident-string");
INDENTED_ADD (label, 0, 1, 3, 4);
entry = katze_property_proxy (settings, "ident-string", NULL);
g_signal_connect (settings, "notify::identify-as",
G_CALLBACK (midori_preferences_notify_identify_as_cb), entry);
midori_preferences_notify_identify_as_cb (settings, NULL, entry);
FILLED_ADD (entry, 1, 2, 3, 4);
label = katze_property_label (settings, "cache-size");
INDENTED_ADD (label, 0, 1, 4, 5);
hbox = gtk_hbox_new (FALSE, 4);
entry = katze_property_proxy (settings, "cache-size", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("MB")),
FALSE, FALSE, 0);
FILLED_ADD (hbox, 1, 2, 4, 5);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "identify-as", "custom-ident-string");
SPANNED_ADD (button);
/* Page "Privacy" */
PAGE_NEW (GTK_STOCK_INDEX, _("Privacy"));
FRAME_NEW (_("Web Cookies"));
TABLE_NEW (3, 2);
label = katze_property_label (settings, "accept-cookies");
INDENTED_ADD (label, 0, 1, 0, 1);
INDENTED_ADD (label);
button = katze_property_proxy (settings, "accept-cookies", NULL);
FILLED_ADD (button, 1, 2, 0, 1);
SPANNED_ADD (button);
button = katze_property_proxy (settings, "original-cookies-only", NULL);
SPANNED_ADD (button, 0, 1, 1, 2);
hbox = gtk_hbox_new (FALSE, 4);
INDENTED_ADD (button);
label = katze_property_label (settings, "maximum-cookie-age");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
INDENTED_ADD (label);
entry = katze_property_proxy (settings, "maximum-cookie-age", NULL);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("days")),
FALSE, FALSE, 0);
FILLED_ADD (hbox, 1, 2, 1, 2);
SPANNED_ADD (entry);
label = gtk_label_new (_("days"));
SPANNED_ADD (label);
FRAME_NEW (_("History"));
TABLE_NEW (3, 2);
button = katze_property_proxy (settings, "remember-last-visited-pages", NULL);
SPANNED_ADD (button, 0, 1, 0, 1);
hbox = gtk_hbox_new (FALSE, 4);
button = katze_property_label (settings, "maximum-history-age");
INDENTED_ADD (button);
button = katze_property_proxy (settings, "maximum-history-age", NULL);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("days")),
FALSE, FALSE, 0);
SPANNED_ADD (hbox, 1, 2, 0, 1);
button = katze_property_proxy (settings, "remember-last-form-inputs", NULL);
SPANNED_ADD (button, 0, 2, 1, 2);
SPANNED_ADD (button);
label = gtk_label_new (_("days"));
SPANNED_ADD (label);
button = katze_property_proxy (settings, "remember-last-downloaded-files", NULL);
SPANNED_ADD (button, 0, 2, 2, 3);
g_object_unref (sizegroup);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (preferences)->vbox),
preferences->notebook, FALSE, FALSE, 4);
#if HAVE_OSX
GtkWidget* icon;
hbox = gtk_hbox_new (FALSE, 0);
button = gtk_button_new ();
icon = gtk_image_new_from_stock (GTK_STOCK_HELP, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (button), icon);
g_signal_connect (button, "clicked",
G_CALLBACK (midori_preferences_help_clicked_cb), preferences);
gtk_box_pack_end (GTK_BOX (hbox),
button, FALSE, FALSE, 4);
gtk_box_pack_end (GTK_BOX (GTK_DIALOG (preferences)->vbox),
hbox, FALSE, FALSE, 0);
#endif
gtk_widget_show_all (GTK_DIALOG (preferences)->vbox);
INDENTED_ADD (button);
}

View File

@ -14,8 +14,6 @@
#include "midori-websettings.h"
#include <gtk/gtk.h>
#include <katze/katze.h>
G_BEGIN_DECLS
@ -38,7 +36,7 @@ typedef struct _MidoriPreferencesClass MidoriPreferencesClass;
struct _MidoriPreferencesClass
{
GtkDialogClass parent_class;
KatzePreferencesClass parent_class;
};
GType

View File

@ -407,9 +407,9 @@ midori_search_action_manage_activate_cb (GtkWidget* menuitem,
/* Private function, used by MidoriView */
/* static */ GdkPixbuf*
midori_search_action_get_icon (KatzeNet* net,
KatzeItem* item,
GtkWidget* widget)
midori_search_action_get_icon (KatzeItem* item,
GtkWidget* widget,
const gchar** icon_name)
{
const gchar* icon;
@ -417,25 +417,21 @@ midori_search_action_get_icon (KatzeNet* net,
{
GdkScreen* screen;
GtkIconTheme* icon_theme;
gint width, height;
GdkPixbuf* pixbuf;
if (G_UNLIKELY (!(screen = gtk_widget_get_screen (widget))))
return gtk_widget_render_icon (widget, GTK_STOCK_FILE,
GTK_ICON_SIZE_MENU, NULL);
screen = gtk_widget_get_screen (widget);
icon_theme = gtk_icon_theme_get_for_screen (screen);
gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (widget),
GTK_ICON_SIZE_MENU, &width, &height);
if ((pixbuf = gtk_icon_theme_load_icon (icon_theme, icon, MAX (width, height),
GTK_ICON_LOOKUP_USE_BUILTIN, NULL)))
return pixbuf;
if (gtk_icon_theme_has_icon (icon_theme, icon))
*icon_name = icon;
else
*icon_name = GTK_STOCK_FILE;
return NULL;
}
if ((icon = katze_item_get_uri (item)) && (g_strstr_len (icon, 8, "://")))
return katze_net_load_icon (net, icon, NULL, widget, NULL);
return katze_load_cached_icon (icon, widget);
return gtk_widget_render_icon (widget, GTK_STOCK_FILE,
GTK_ICON_SIZE_MENU, NULL);
*icon_name = GTK_STOCK_FILE;
return NULL;
}
static void
@ -463,13 +459,20 @@ midori_search_action_icon_released_cb (GtkWidget* entry,
{
do
{
const gchar* icon_name;
menuitem = gtk_image_menu_item_new_with_label (
katze_item_get_name (item));
image = gtk_image_new ();
icon = midori_search_action_get_icon (
MIDORI_SEARCH_ACTION (action)->net, item, entry);
gtk_image_set_from_pixbuf (GTK_IMAGE (image), icon);
g_object_unref (icon);
icon = midori_search_action_get_icon (item, entry, &icon_name);
if (icon)
{
gtk_image_set_from_pixbuf (GTK_IMAGE (image), icon);
g_object_unref (icon);
}
else
gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name,
GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), image);
#if GTK_CHECK_VERSION (2, 16, 0)
gtk_image_menu_item_set_always_show_image (
@ -501,8 +504,7 @@ midori_search_action_icon_released_cb (GtkWidget* entry,
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_search_action_manage_activate_cb), action);
gtk_widget_show (menuitem);
sokoke_widget_popup (entry, GTK_MENU (menu),
NULL, SOKOKE_MENU_POSITION_LEFT);
katze_widget_popup (entry, GTK_MENU (menu), NULL, KATZE_MENU_POSITION_LEFT);
}
static gboolean
@ -525,11 +527,19 @@ midori_search_action_set_entry_icon (MidoriSearchAction* search_action,
if (search_action->current_item)
{
icon = midori_search_action_get_icon (search_action->net,
search_action->current_item, entry);
gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, icon);
g_object_unref (icon);
const gchar* icon_name;
icon = midori_search_action_get_icon (search_action->current_item,
entry, &icon_name);
if (icon)
{
gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, icon);
g_object_unref (icon);
}
else
gtk_icon_entry_set_icon_from_icon_name (GTK_ICON_ENTRY (entry),
GTK_ICON_ENTRY_PRIMARY, icon_name);
sokoke_entry_set_default_text (GTK_ENTRY (entry),
katze_item_get_name (search_action->current_item));
}
@ -819,13 +829,18 @@ midori_search_action_dialog_render_icon_cb (GtkTreeViewColumn* column,
KatzeItem* item;
MidoriSearchAction* search_action;
GdkPixbuf* icon;
const gchar* icon_name;
gtk_tree_model_get (model, iter, 0, &item, -1);
search_action = g_object_get_data (G_OBJECT (treeview), "search-action");
icon = midori_search_action_get_icon (search_action->net, item, treeview);
g_object_set (renderer, "pixbuf", icon, "yalign", 0.25, NULL);
g_object_unref (icon);
if ((icon = midori_search_action_get_icon (item, treeview, &icon_name)))
{
g_object_set (renderer, "pixbuf", icon, "yalign", 0.25, NULL);
g_object_unref (icon);
}
else
g_object_set (renderer, "icon-name", icon_name, "yalign", 0.25, NULL);
g_object_unref (item);
}
@ -1016,6 +1031,10 @@ midori_search_action_get_editor (MidoriSearchAction* search_action,
if (new_engine)
katze_array_add_item (search_action->search_engines, item);
/* If it isn't a new search engine but the old default one,
we need to update the default search engine after editing it. */
else if (item == midori_search_action_get_default_item (search_action))
midori_search_action_set_default_item (search_action, item);
}
gtk_widget_destroy (dialog);
}
@ -1217,7 +1236,9 @@ midori_search_action_get_dialog (MidoriSearchAction* search_action)
toplevel ? GTK_WINDOW (toplevel) : NULL,
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
#if !HAVE_OSX
#if !HAVE_HILDON
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
#endif
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
#endif
NULL);

View File

@ -30,7 +30,7 @@
#define STOCK_STYLE "gnome-settings-theme"
#define STOCK_TRANSFER "package"
#define STOCK_TRANSFERS "package"
#define STOCK_PLUGINS GTK_STOCK_CONVERT
#define STOCK_PLUGINS "gnome-mime-application-x-shockwave-flash"
#define STOCK_BOOKMARK_ADD "stock_add-bookmark"
#define STOCK_HOMEPAGE GTK_STOCK_HOME
@ -43,4 +43,13 @@
#define STOCK_USER_TRASH "gnome-stock-trash"
#define STOCK_WINDOW_NEW "stock_new-window"
#if defined (HAVE_HILDON) && HAVE_HILDON
#undef STOCK_BOOKMARKS
#define STOCK_BOOKMARKS "general_mybookmarks_folder"
#undef STOCK_NEWS_FEED
#define STOCK_NEWS_FEED "general_rss"
#undef STOCK_WEB_BROWSER
#define STOCK_WEB_BROWSER "general_web"
#endif
#endif /* !__MIDORI_STOCK_H__ */

View File

@ -40,18 +40,13 @@ webkit_web_frame_print (WebKitWebFrame* web_frame);
#endif
GdkPixbuf*
midori_search_action_get_icon (KatzeNet* net,
KatzeItem* item,
GtkWidget* widget);
midori_search_action_get_icon (KatzeItem* item,
GtkWidget* widget,
const gchar** icon_name);
static void
midori_view_construct_web_view (MidoriView* view);
GdkPixbuf*
midori_view_get_snapshot (MidoriView* view,
gint width,
gint height);
static void
midori_view_item_meta_data_changed (KatzeItem* item,
const gchar* key,
@ -625,8 +620,8 @@ midori_view_update_icon (MidoriView* view,
if (!icon)
{
GdkScreen* screen;
GtkIconTheme* icon_theme;
gchar** parts;
GtkIconTheme* icon_theme = NULL;
gchar** parts = NULL;
gchar* icon_name;
if ((screen = gtk_widget_get_screen (GTK_WIDGET (view))))
@ -638,8 +633,6 @@ midori_view_update_icon (MidoriView* view,
katze_assign (parts, NULL);
}
}
else
parts = NULL;
if (parts)
icon = midori_view_mime_icon (icon_theme, "%s-%s",
@ -713,12 +706,14 @@ midori_view_web_view_navigation_decision_cb (WebKitWebView* web_view
MidoriView* view)
{
const gchar* uri = webkit_network_request_get_uri (request);
if (g_str_has_prefix (uri, "mailto:"))
if (g_str_has_prefix (uri, "mailto:") || g_str_has_prefix (uri, "tel:"))
{
webkit_web_policy_decision_ignore (decision);
sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (web_view)),
uri, GDK_CURRENT_TIME, NULL);
return TRUE;
if (sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (web_view)),
uri, GDK_CURRENT_TIME, NULL))
{
webkit_web_policy_decision_ignore (decision);
return TRUE;
}
}
/* TODO: Handle more external protocols */
return FALSE;
@ -818,6 +813,71 @@ webkit_web_view_progress_changed_cb (WebKitWebView* web_view,
}
#if WEBKIT_CHECK_VERSION (1, 1, 6)
#if WEBKIT_CHECK_VERSION (1, 1, 14)
static void
midori_view_web_view_resource_request_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
WebKitWebResource* web_resource,
WebKitNetworkRequest* request,
WebKitNetworkResponse* response,
MidoriView* view)
{
const gchar* uri = webkit_network_request_get_uri (request);
/* Only apply custom URIs to special pages for security purposes */
if (!webkit_web_data_source_get_unreachable_uri (
webkit_web_frame_get_data_source (web_frame)))
return;
if (g_str_has_prefix (uri, "res://"))
{
gchar* filename = g_build_filename ("midori/res", &uri[5], NULL);
gchar* filepath = sokoke_find_data_filename (filename);
gchar* file_uri;
g_free (filename);
file_uri = g_filename_to_uri (filepath, NULL, NULL);
g_free (filepath);
webkit_network_request_set_uri (request, file_uri);
g_free (file_uri);
}
else if (g_str_has_prefix (uri, "stock://"))
{
GtkIconTheme* icon_theme = gtk_icon_theme_get_default ();
const gchar* icon_name = &uri[8] ? &uri[8] : "";
gint icon_size = 22;
GtkIconInfo* info;
if (g_ascii_isalpha (icon_name[0]))
icon_size = strstr (icon_name, "dialog") ? 48 : 22;
else if (g_ascii_isdigit (icon_name[0]))
{
guint i = 0;
while (icon_name[i])
if (icon_name[i++] == '/')
{
gchar* size = g_strndup (icon_name, i - 1);
icon_size = atoi (size);
g_free (size);
icon_name = &icon_name[i];
}
}
if ((info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, icon_size, 0)))
{
const gchar* filename = gtk_icon_info_get_filename (info);
if (filename)
{
gchar* file_uri = g_filename_to_uri (filename, NULL, NULL);
webkit_network_request_set_uri (request, file_uri);
g_free (file_uri);
}
gtk_icon_info_free (info);
}
}
}
#endif
static gboolean
webkit_web_view_load_error_cb (WebKitWebView* web_view,
WebKitWebFrame* web_frame,
@ -832,18 +892,25 @@ webkit_web_view_load_error_cb (WebKitWebView* web_view,
g_free (template_file);
if (g_file_get_contents (path, &template, NULL, NULL))
{
#if !WEBKIT_CHECK_VERSION (1, 1, 14)
SoupServer* res_server;
guint port;
#endif
gchar* res_root;
gchar* stock_root;
gchar* title;
gchar* message;
gchar* result;
#if WEBKIT_CHECK_VERSION (1, 1, 14)
res_root = g_strdup ("res:/");
stock_root = g_strdup ("stock:/");
#else
res_server = sokoke_get_res_server ();
port = soup_server_get_port (res_server);
res_root = g_strdup_printf ("http://localhost:%d/res", port);
stock_root = g_strdup_printf ("http://localhost:%d/stock", port);
#endif
title = g_strdup_printf (_("Error - %s"), uri);
message = g_strdup_printf (_("The page '%s' couldn't be loaded."), uri);
@ -952,13 +1019,13 @@ webkit_web_view_load_finished_cb (WebKitWebView* web_view,
URI1|title1,URI2|title2
FIXME: Ensure separators contained in the string can't break it */
gchar* value = sokoke_js_script_eval (js_context,
"function links (l) { var f = new Array (); for (i in l) "
"(function (l) { var f = new Array (); for (i in l) "
"{ var t = l[i].type; var r = l[i].rel; "
"if (t && (t.indexOf ('rss') != -1 || t.indexOf ('atom') != -1)) "
"f.push (l[i].href + '|' + l[i].title);"
"else if (r && r.indexOf ('icon') != -1) f.push (l[i].href); } "
"return f; }"
"links (document.getElementsByTagName ('link'))", NULL);
"return f; })("
"document.getElementsByTagName ('link'));", NULL);
gchar** items = g_strsplit (value, ",", 0);
guint i = 0;
gchar* default_uri = NULL;
@ -1193,14 +1260,22 @@ gtk_widget_button_press_event_cb (WebKitWebView* web_view,
clipboard = gtk_clipboard_get_for_display (
gtk_widget_get_display (GTK_WIDGET (view)),
GDK_SELECTION_PRIMARY);
uri = gtk_clipboard_wait_for_text (clipboard);
if (uri && strchr (uri, '.'))
if ((uri = gtk_clipboard_wait_for_text (clipboard)))
{
KatzeArray* empty_array = katze_array_new (KATZE_TYPE_ITEM);
guint i = 0;
while (uri[i++] != '\0')
if (uri[i] == '\n' || uri[i] == '\r')
uri[i] = ' ';
new_uri = sokoke_magic_uri (g_strstrip (uri), NULL);
new_uri = sokoke_magic_uri (g_strstrip (uri), empty_array);
g_object_unref (empty_array);
if (!new_uri)
{
gchar* search;
g_object_get (view->settings, "location-entry-search",
&search, NULL);
new_uri = sokoke_search_uri (search, uri);
}
if (event->state & GDK_CONTROL_MASK)
{
background = view->open_tabs_in_the_background;
@ -1294,6 +1369,19 @@ gtk_widget_scroll_event_cb (WebKitWebView* web_view,
}
#if WEBKIT_CHECK_VERSION (1, 1, 15)
static void
midori_web_view_set_clipboard (GtkWidget* widget,
const gchar* text)
{
GdkDisplay* display = gtk_widget_get_display (widget);
GtkClipboard* clipboard;
clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
gtk_clipboard_set_text (clipboard, text, -1);
clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_PRIMARY);
gtk_clipboard_set_text (clipboard, text, -1);
}
static void
midori_web_view_menu_open_activate_cb (GtkWidget* widget,
MidoriView* view)
@ -1312,10 +1400,7 @@ static void
midori_web_view_menu_link_copy_activate_cb (GtkWidget* widget,
MidoriView* view)
{
GdkDisplay* display = gtk_widget_get_display (widget);
GtkClipboard* clipboard = gtk_clipboard_get_for_display (display,
GDK_SELECTION_CLIPBOARD);
gtk_clipboard_set_text (clipboard, view->link_uri, -1);
midori_web_view_set_clipboard (widget, view->link_uri);
}
static void
@ -1356,11 +1441,8 @@ static void
midori_web_view_menu_image_copy_activate_cb (GtkWidget* widget,
MidoriView* view)
{
GdkDisplay* display = gtk_widget_get_display (widget);
GtkClipboard* clipboard = gtk_clipboard_get_for_display (display,
GDK_SELECTION_CLIPBOARD);
gchar* uri = katze_object_get_string (view->hit_test, "image-uri");
gtk_clipboard_set_text (clipboard, uri, -1);
midori_web_view_set_clipboard (widget, uri);
g_free (uri);
}
@ -1385,11 +1467,8 @@ static void
midori_web_view_menu_video_copy_activate_cb (GtkWidget* widget,
MidoriView* view)
{
GdkDisplay* display = gtk_widget_get_display (widget);
GtkClipboard* clipboard = gtk_clipboard_get_for_display (display,
GDK_SELECTION_CLIPBOARD);
gchar* uri = katze_object_get_string (view->hit_test, "media-uri");
gtk_clipboard_set_text (clipboard, uri, -1);
midori_web_view_set_clipboard (widget, uri);
g_free (uri);
}
@ -1415,7 +1494,7 @@ midori_web_view_menu_video_download_activate_cb (GtkWidget* widget,
MidoriView* view)
{
gchar* uri = katze_object_get_string (view->hit_test, "media-uri");
sokoke_spawn_program (view->download_manager, uri, TRUE);
sokoke_spawn_program (view->download_manager, uri, FALSE);
g_free (uri);
}
#endif
@ -1447,6 +1526,16 @@ midori_web_view_menu_new_tab_activate_cb (GtkWidget* widget,
}
}
#if WEBKIT_CHECK_VERSION (1, 1, 15)
static void
midori_web_view_menu_background_tab_activate_cb (GtkWidget* widget,
MidoriView* view)
{
g_signal_emit (view, signals[NEW_TAB], 0, view->link_uri,
!view->open_tabs_in_the_background);
}
#endif
static void
midori_web_view_menu_search_web_activate_cb (GtkWidget* widget,
MidoriView* view)
@ -1473,10 +1562,7 @@ static void
midori_web_view_menu_copy_activate_cb (GtkWidget* widget,
MidoriView* view)
{
GdkDisplay* display = gtk_widget_get_display (widget);
GtkClipboard* clipboard = gtk_clipboard_get_for_display (display,
GDK_SELECTION_CLIPBOARD);
gtk_clipboard_set_text (clipboard, view->selected_text, -1);
midori_web_view_set_clipboard (widget, view->selected_text);
}
#endif
@ -1493,7 +1579,7 @@ static void
midori_web_view_menu_download_activate_cb (GtkWidget* widget,
MidoriView* view)
{
sokoke_spawn_program (view->download_manager, view->link_uri, TRUE);
sokoke_spawn_program (view->download_manager, view->link_uri, FALSE);
}
static void
@ -1655,6 +1741,11 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
midori_view_insert_menu_item (menu_shell, -1,
_("Open Link in New _Tab"), STOCK_TAB_NEW,
G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), widget);
midori_view_insert_menu_item (menu_shell, -1,
view->open_tabs_in_the_background
? _("Open Link in _Foreground Tab")
: _("Open Link in _Background Tab"), STOCK_TAB_NEW,
G_CALLBACK (midori_web_view_menu_background_tab_activate_cb), widget);
midori_view_insert_menu_item (menu_shell, -1,
_("Open Link in New _Window"), STOCK_WINDOW_NEW,
G_CALLBACK (midori_web_view_menu_new_window_activate_cb), widget);
@ -1767,11 +1858,18 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
while ((item = katze_array_get_nth_item (search_engines, i++)))
{
GdkPixbuf* pixbuf;
const gchar* icon_name;
menuitem = gtk_image_menu_item_new_with_mnemonic (katze_item_get_name (item));
pixbuf = midori_search_action_get_icon (view->net, item,
GTK_WIDGET (web_view));
icon = gtk_image_new_from_pixbuf (pixbuf);
g_object_unref (pixbuf);
pixbuf = midori_search_action_get_icon (item,
GTK_WIDGET (web_view), &icon_name);
if (pixbuf)
{
icon = gtk_image_new_from_pixbuf (pixbuf);
g_object_unref (pixbuf);
}
else
icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
#if GTK_CHECK_VERSION (2, 16, 0)
gtk_image_menu_item_set_always_show_image (
@ -1807,7 +1905,7 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
g_strstrip (view->selected_text);
if (view->selected_text && !strchr (view->selected_text, ' ')
&& strchr (view->selected_text, '.'))
&& (strchr (view->selected_text, '.') || g_strstr_len (view->selected_text, 9, "://")))
{
if (strchr (view->selected_text, '@'))
{
@ -1894,12 +1992,14 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
gtk_menu_shell_append (menu_shell, menuitem);
}
#if !HAVE_HILDON
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "ZoomIn"));
gtk_menu_shell_append (menu_shell, menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "ZoomOut"));
gtk_menu_shell_append (menu_shell, menuitem);
#endif
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "Encoding"));
@ -1911,6 +2011,7 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
{ "EncodingAutomatic" },
{ "EncodingChinese" },
{ "EncodingJapanese" },
{ "EncodingKorean" },
{ "EncodingRussian" },
{ "EncodingUnicode" },
{ "EncodingWestern" },
@ -1928,7 +2029,18 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
}
}
#if !HAVE_HILDON
#if HAVE_HILDON
gtk_menu_shell_append (menu_shell, gtk_separator_menu_item_new ());
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "CompactAdd"));
gtk_menu_shell_append (menu_shell, menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "Fullscreen"));
gtk_menu_shell_append (menu_shell, menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "PrivateBrowsing"));
gtk_menu_shell_append (menu_shell, menuitem);
#else
gtk_menu_shell_append (menu_shell, gtk_separator_menu_item_new ());
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "BookmarkAdd"));
@ -1943,6 +2055,7 @@ webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "AddDesktopShortcut"));
gtk_menu_shell_append (menu_shell, menuitem);
gtk_widget_set_no_show_all (menuitem, TRUE);
#endif
menuitem = sokoke_action_create_popup_menu_item (
@ -1994,6 +2107,12 @@ webkit_web_view_web_view_ready_cb (GtkWidget* web_view,
{
GtkWidget* new_view = gtk_widget_get_parent (web_view);
MidoriNewView where = MIDORI_NEW_VIEW_TAB;
/* FIXME: Open windows opened by scripts in tabs if they otherwise
would be replacing the page the user opened. */
if (view->open_new_pages_in == MIDORI_NEW_PAGE_CURRENT)
return TRUE;
if (view->open_new_pages_in == MIDORI_NEW_PAGE_TAB)
{
if (view->open_tabs_in_the_background)
@ -2003,13 +2122,7 @@ webkit_web_view_web_view_ready_cb (GtkWidget* web_view,
where = MIDORI_NEW_VIEW_WINDOW;
gtk_widget_show (new_view);
if (view->open_new_pages_in == MIDORI_NEW_PAGE_CURRENT)
{
g_debug ("Opening all pages in current tab not implemented");
g_signal_emit (view, signals[NEW_VIEW], 0, new_view, where);
}
else
g_signal_emit (view, signals[NEW_VIEW], 0, new_view, where);
g_signal_emit (view, signals[NEW_VIEW], 0, new_view, where);
return TRUE;
}
@ -2019,14 +2132,21 @@ webkit_web_view_create_web_view_cb (GtkWidget* web_view,
WebKitWebFrame* web_frame,
MidoriView* view)
{
GtkWidget* new_view = g_object_new (MIDORI_TYPE_VIEW,
"net", view->net,
"settings", view->settings,
NULL);
midori_view_construct_web_view (MIDORI_VIEW (new_view));
g_signal_connect (MIDORI_VIEW (new_view)->web_view, "web-view-ready",
G_CALLBACK (webkit_web_view_web_view_ready_cb), view);
return MIDORI_VIEW (new_view)->web_view;
MidoriView* new_view;
if (view->open_new_pages_in == MIDORI_NEW_PAGE_CURRENT)
new_view = view;
else
{
new_view = g_object_new (MIDORI_TYPE_VIEW,
"net", view->net,
"settings", view->settings,
NULL);
midori_view_construct_web_view (new_view);
g_signal_connect (new_view->web_view, "web-view-ready",
G_CALLBACK (webkit_web_view_web_view_ready_cb), view);
}
return new_view->web_view;
}
static gboolean
@ -2073,6 +2193,12 @@ webkit_web_view_mime_type_decision_cb (GtkWidget* web_view,
#else
content_type = g_strdup (mime_type);
#endif
if (!content_type)
#ifdef G_OS_WIN32
content_type = g_content_type_get_mime_type ("*");
#else
content_type = g_strdup ("application/octet-stream");
#endif
description = g_content_type_get_description (content_type);
#if GTK_CHECK_VERSION (2, 14, 0)
icon = g_content_type_get_icon (content_type);
@ -2673,6 +2799,10 @@ midori_view_construct_web_view (MidoriView* view)
g_object_connect (view->web_view,
"signal::navigation-policy-decision-requested",
midori_view_web_view_navigation_decision_cb, view,
#if WEBKIT_CHECK_VERSION (1, 1, 14)
"signal::resource-request-starting",
midori_view_web_view_resource_request_cb, view,
#endif
"signal::load-started",
webkit_web_view_load_started_cb, view,
"signal::load-committed",
@ -2725,7 +2855,7 @@ midori_view_construct_web_view (MidoriView* view)
midori_view_web_view_print_requested_cb, view,
#endif
#if WEBKIT_CHECK_VERSION (1, 1, 6)
"signal::load-error",
"signal-after::load-error",
webkit_web_view_load_error_cb, view,
#endif
NULL);
@ -2777,8 +2907,10 @@ midori_view_set_uri (MidoriView* view,
if (view->speed_dial_in_new_tabs && !g_strcmp0 (uri, ""))
{
#if !WEBKIT_CHECK_VERSION (1, 1, 14)
SoupServer* res_server;
guint port;
#endif
gchar* res_root;
gchar* speed_dial_head;
gchar* speed_dial_body;
@ -2792,10 +2924,15 @@ midori_view_set_uri (MidoriView* view,
if (G_UNLIKELY (!speed_dial_head))
speed_dial_head = g_strdup ("");
#if WEBKIT_CHECK_VERSION (1, 1, 14)
res_root = g_strdup ("res:/");
stock_root = g_strdup ("stock:/");
#else
res_server = sokoke_get_res_server ();
port = soup_server_get_port (res_server);
res_root = g_strdup_printf ("http://localhost:%d/res", port);
stock_root = g_strdup_printf ("http://localhost:%d/stock", port);
#endif
body_fname = g_build_filename (sokoke_set_config_dir (NULL),
"speeddial.json", NULL);
@ -2894,7 +3031,9 @@ midori_view_set_uri (MidoriView* view,
{
midori_view_execute_script (view, &uri[11], NULL);
}
else if (g_str_has_prefix (uri, "mailto:"))
else if (g_str_has_prefix (uri, "mailto:")
|| g_str_has_prefix (uri, "tel:")
|| g_str_has_prefix (uri, "callto:"))
{
sokoke_show_uri (NULL, uri, GDK_CURRENT_TIME, NULL);
}
@ -3138,7 +3277,7 @@ midori_view_get_proxy_menu_item (MidoriView* view)
if (!view->menu_item)
{
title = midori_view_get_display_title (view);
view->menu_item = sokoke_image_menu_item_new_ellipsized (title);
view->menu_item = katze_image_menu_item_new_ellipsized (title);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (view->menu_item),
gtk_image_new_from_pixbuf (view->icon));
@ -3149,13 +3288,6 @@ midori_view_get_proxy_menu_item (MidoriView* view)
return view->menu_item;
}
static void
midori_view_tab_label_menu_new_tab_cb (GtkWidget* menuitem,
MidoriView* view)
{
g_signal_emit (view, signals[NEW_TAB], 0, "", FALSE);
}
static void
midori_view_tab_label_menu_open_cb (GtkWidget* menuitem,
GtkWidget* view)
@ -3213,16 +3345,23 @@ midori_view_tab_label_menu_close_cb (GtkWidget* menuitem,
GtkWidget*
midori_view_get_tab_menu (MidoriView* view)
{
MidoriBrowser* browser;
GtkActionGroup* actions;
GtkWidget* menu;
GtkWidget* menuitem;
g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
browser = midori_browser_get_for_widget (GTK_WIDGET (view));
actions = midori_browser_get_action_group (browser);
menu = gtk_menu_new ();
menuitem = gtk_menu_item_new_with_mnemonic (_("New _Tab"));
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "TabNew"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "UndoTabClose"));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
g_signal_connect (menuitem, "activate",
G_CALLBACK (midori_view_tab_label_menu_new_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_OPEN, NULL);
@ -3270,7 +3409,7 @@ midori_view_tab_label_button_release_event (GtkWidget* tab_label,
GtkWidget* menu = midori_view_get_tab_menu (MIDORI_VIEW (widget));
katze_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
event, KATZE_MENU_POSITION_CURSOR);
return TRUE;
}
@ -3677,8 +3816,6 @@ can_do (find)
* @from_cache: whether to allow caching
*
* Reloads the view.
*
* Note: The @from_cache value is currently ignored.
**/
void
midori_view_reload (MidoriView* view,
@ -3981,7 +4118,22 @@ midori_view_execute_script (MidoriView* view,
return TRUE;
}
/* For now this is private API */
/**
* midori_view_get_snapshot
* @view: a #MidoriView
* @width: the desired width
* @height: the desired height
*
* Take a snapshot of the view at the given dimensions. The
* view has to be mapped on the screen.
*
* If width and height are negative, the resulting
* image is going to be optimized for speed.
*
* Returns: a newly allocated #GdkPixbuf
*
* Since: 0.2.1
**/
GdkPixbuf*
midori_view_get_snapshot (MidoriView* view,
gint width,

View File

@ -195,6 +195,11 @@ midori_view_execute_script (MidoriView* view,
const gchar* script,
gchar** exception);
GdkPixbuf*
midori_view_get_snapshot (MidoriView* view,
gint width,
gint height);
G_END_DECLS
#endif /* __MIDORI_VIEW_H__ */

View File

@ -50,6 +50,7 @@ struct _MidoriWebSettings
gboolean compact_sidepanel;
gboolean show_panel_controls;
gboolean right_align_sidepanel;
gboolean open_panels_in_windows;
MidoriStartup load_on_startup;
gchar* homepage;
@ -82,14 +83,12 @@ struct _MidoriWebSettings
gboolean remember_last_visited_pages;
gint maximum_history_age;
gboolean remember_last_form_inputs;
gboolean remember_last_downloaded_files;
gchar* http_proxy;
gboolean auto_detect_proxy;
MidoriIdentity identify_as;
gchar* ident_string;
gint cache_size;
gint clear_private_data;
};
@ -127,6 +126,7 @@ enum
PROP_COMPACT_SIDEPANEL,
PROP_SHOW_PANEL_CONTROLS,
PROP_RIGHT_ALIGN_SIDEPANEL,
PROP_OPEN_PANELS_IN_WINDOWS,
PROP_LOAD_ON_STARTUP,
PROP_HOMEPAGE,
@ -150,6 +150,9 @@ enum
PROP_OPEN_TABS_NEXT_TO_CURRENT,
PROP_OPEN_POPUPS_IN_TABS,
PROP_AUTO_LOAD_IMAGES,
PROP_ENABLE_SCRIPTS,
PROP_ENABLE_PLUGINS,
PROP_ZOOM_TEXT_AND_IMAGES,
PROP_FIND_WHILE_TYPING,
PROP_KINETIC_SCROLLING,
@ -159,14 +162,12 @@ enum
PROP_REMEMBER_LAST_VISITED_PAGES,
PROP_MAXIMUM_HISTORY_AGE,
PROP_REMEMBER_LAST_FORM_INPUTS,
PROP_REMEMBER_LAST_DOWNLOADED_FILES,
PROP_HTTP_PROXY,
PROP_AUTO_DETECT_PROXY,
PROP_IDENTIFY_AS,
PROP_IDENT_STRING,
PROP_CACHE_SIZE,
PROP_CLEAR_PRIVATE_DATA
};
@ -215,6 +216,7 @@ midori_preferred_encoding_get_type (void)
static const GEnumValue values[] = {
{ MIDORI_ENCODING_CHINESE, "MIDORI_ENCODING_CHINESE", N_("Chinese (BIG5)") },
{ MIDORI_ENCODING_JAPANESE, "MIDORI_ENCODING_JAPANESE", N_("Japanese (SHIFT_JIS)") },
{ MIDORI_ENCODING_KOREAN, "MIDORI_ENCODING_KOREAN", N_("Korean (EUC-KR)") },
{ MIDORI_ENCODING_RUSSIAN, "MIDORI_ENCODING_RUSSIAN", N_("Russian (KOI8-R)") },
{ MIDORI_ENCODING_UNICODE, "MIDORI_ENCODING_UNICODE", N_("Unicode (UTF-8)") },
{ MIDORI_ENCODING_WESTERN, "MIDORI_ENCODING_WESTERN", N_("Western (ISO-8859-1)") },
@ -252,6 +254,7 @@ midori_toolbar_style_get_type (void)
static const GEnumValue values[] = {
{ MIDORI_TOOLBAR_DEFAULT, "MIDORI_TOOLBAR_DEFAULT", N_("Default") },
{ MIDORI_TOOLBAR_ICONS, "MIDORI_TOOLBAR_ICONS", N_("Icons") },
{ MIDORI_TOOLBAR_SMALL_ICONS, "MIDORI_TOOLBAR_SMALL_ICONS", N_("Small icons") },
{ MIDORI_TOOLBAR_TEXT, "MIDORI_TOOLBAR_TEXT", N_("Text") },
{ MIDORI_TOOLBAR_BOTH, "MIDORI_TOOLBAR_BOTH", N_("Icons and text") },
{ MIDORI_TOOLBAR_BOTH_HORIZ, "MIDORI_TOOLBAR_BOTH_HORIZ", N_("Text beside icons") },
@ -320,7 +323,7 @@ midori_get_download_dir (void)
const gchar* dir = g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD);
if (dir)
{
g_mkdir_with_parents (dir, 0700);
katze_mkdir_with_parents (dir, 0700);
return dir;
}
return g_get_home_dir ();
@ -566,6 +569,22 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
FALSE,
flags));
/**
* MidoriWebSettings:open-panels-in-window:
*
* Whether to open panels in separate windows.
*
* Since: 0.2.2
*/
g_object_class_install_property (gobject_class,
PROP_OPEN_PANELS_IN_WINDOWS,
g_param_spec_boolean (
"open-panels-in-windows",
_("Open panels in separate windows"),
_("Whether to always open panels in separate windows"),
FALSE,
flags));
g_object_class_install_property (gobject_class,
PROP_LOAD_ON_STARTUP,
@ -803,6 +822,32 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/* Override properties to localize them for preference proxies */
g_object_class_install_property (gobject_class,
PROP_AUTO_LOAD_IMAGES,
g_param_spec_boolean (
"auto-load-images",
_("Load images automatically"),
_("Load and display images automatically"),
TRUE,
flags));
g_object_class_install_property (gobject_class,
PROP_ENABLE_SCRIPTS,
g_param_spec_boolean (
"enable-scripts",
_("Enable scripts"),
_("Enable embedded scripting languages"),
TRUE,
flags));
g_object_class_install_property (gobject_class,
PROP_ENABLE_PLUGINS,
g_param_spec_boolean (
"enable-plugins",
_("Enable Netscape plugins"),
_("Enable embedded Netscape plugin objects"),
TRUE,
flags));
/**
* MidoriWebSettings:zoom-text-and-images:
*
@ -881,6 +926,13 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
/**
* MidoriWebSettings:remember-last-visited-pages:
*
* Whether the last visited pages are saved.
*
* Deprecated: 0.2.2
*/
g_object_class_install_property (gobject_class,
PROP_REMEMBER_LAST_VISITED_PAGES,
g_param_spec_boolean (
@ -899,15 +951,6 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
0, G_MAXINT, 30,
flags));
g_object_class_install_property (gobject_class,
PROP_REMEMBER_LAST_FORM_INPUTS,
g_param_spec_boolean (
"remember-last-form-inputs",
_("Remember last form inputs"),
_("Whether the last form inputs are saved"),
TRUE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_REMEMBER_LAST_DOWNLOADED_FILES,
g_param_spec_boolean (
@ -978,15 +1021,6 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_CACHE_SIZE,
g_param_spec_int (
"cache-size",
_("Cache size"),
_("The allowed size of the cache"),
0, G_MAXINT, 100,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
* MidoriWebSettings:clear-private-data:
*
@ -1021,6 +1055,8 @@ notify_default_encoding_cb (GObject* object,
web_settings->preferred_encoding = MIDORI_ENCODING_CHINESE;
else if (!strcmp (encoding, "SHIFT_JIS"))
web_settings->preferred_encoding = MIDORI_ENCODING_JAPANESE;
else if (!strcmp (encoding, "EUC-KR"))
web_settings->preferred_encoding = MIDORI_ENCODING_KOREAN;
else if (!strcmp (encoding, "KOI8-R"))
web_settings->preferred_encoding = MIDORI_ENCODING_RUSSIAN;
else if (!strcmp (encoding, "UTF-8"))
@ -1041,7 +1077,6 @@ midori_web_settings_init (MidoriWebSettings* web_settings)
web_settings->http_proxy = NULL;
web_settings->show_panel_controls = TRUE;
web_settings->open_popups_in_tabs = TRUE;
web_settings->remember_last_form_inputs = TRUE;
web_settings->remember_last_downloaded_files = TRUE;
web_settings->kinetic_scrolling = TRUE;
web_settings->auto_detect_proxy = TRUE;
@ -1070,7 +1105,7 @@ midori_web_settings_finalize (GObject* object)
G_OBJECT_CLASS (midori_web_settings_parent_class)->finalize (object);
}
#if defined (G_OS_UNIX)
#if defined (G_OS_UNIX) && !HAVE_OSX
static gchar*
get_sys_name (void)
{
@ -1233,6 +1268,9 @@ midori_web_settings_set_property (GObject* object,
case PROP_RIGHT_ALIGN_SIDEPANEL:
web_settings->right_align_sidepanel = g_value_get_boolean (value);
break;
case PROP_OPEN_PANELS_IN_WINDOWS:
web_settings->open_panels_in_windows = g_value_get_boolean (value);
break;
case PROP_LOAD_ON_STARTUP:
web_settings->load_on_startup = g_value_get_enum (value);
@ -1277,6 +1315,9 @@ midori_web_settings_set_property (GObject* object,
case MIDORI_ENCODING_JAPANESE:
g_object_set (object, "default-encoding", "SHIFT_JIS", NULL);
break;
case MIDORI_ENCODING_KOREAN:
g_object_set (object, "default-encoding", "EUC-KR", NULL);
break;
case MIDORI_ENCODING_RUSSIAN:
g_object_set (object, "default-encoding", "KOI8-R", NULL);
break;
@ -1316,6 +1357,18 @@ midori_web_settings_set_property (GObject* object,
web_settings->open_popups_in_tabs = g_value_get_boolean (value);
break;
case PROP_AUTO_LOAD_IMAGES:
g_object_set (web_settings, "WebKitWebSettings::auto-load-images",
g_value_get_boolean (value), NULL);
break;
case PROP_ENABLE_SCRIPTS:
g_object_set (web_settings, "WebKitWebSettings::enable-scripts",
g_value_get_boolean (value), NULL);
break;
case PROP_ENABLE_PLUGINS:
g_object_set (web_settings, "WebKitWebSettings::enable-plugins",
g_value_get_boolean (value), NULL);
break;
case PROP_ZOOM_TEXT_AND_IMAGES:
web_settings->zoom_text_and_images = g_value_get_boolean (value);
break;
@ -1341,9 +1394,6 @@ midori_web_settings_set_property (GObject* object,
case PROP_MAXIMUM_HISTORY_AGE:
web_settings->maximum_history_age = g_value_get_int (value);
break;
case PROP_REMEMBER_LAST_FORM_INPUTS:
web_settings->remember_last_form_inputs = g_value_get_boolean (value);
break;
case PROP_REMEMBER_LAST_DOWNLOADED_FILES:
web_settings->remember_last_downloaded_files = g_value_get_boolean (value);
break;
@ -1375,9 +1425,6 @@ midori_web_settings_set_property (GObject* object,
#endif
}
break;
case PROP_CACHE_SIZE:
web_settings->cache_size = g_value_get_int (value);
break;
case PROP_CLEAR_PRIVATE_DATA:
web_settings->clear_private_data = g_value_get_int (value);
break;
@ -1459,6 +1506,9 @@ midori_web_settings_get_property (GObject* object,
case PROP_RIGHT_ALIGN_SIDEPANEL:
g_value_set_boolean (value, web_settings->right_align_sidepanel);
break;
case PROP_OPEN_PANELS_IN_WINDOWS:
g_value_set_boolean (value, web_settings->open_panels_in_windows);
break;
case PROP_LOAD_ON_STARTUP:
g_value_set_enum (value, web_settings->load_on_startup);
@ -1522,6 +1572,18 @@ midori_web_settings_get_property (GObject* object,
g_value_set_boolean (value, web_settings->open_popups_in_tabs);
break;
case PROP_AUTO_LOAD_IMAGES:
g_value_set_boolean (value, katze_object_get_boolean (web_settings,
"WebKitWebSettings::auto-load-images"));
break;
case PROP_ENABLE_SCRIPTS:
g_value_set_boolean (value, katze_object_get_boolean (web_settings,
"WebKitWebSettings::enable-scripts"));
break;
case PROP_ENABLE_PLUGINS:
g_value_set_boolean (value, katze_object_get_boolean (web_settings,
"WebKitWebSettings::enable-plugins"));
break;
case PROP_ZOOM_TEXT_AND_IMAGES:
g_value_set_boolean (value, web_settings->zoom_text_and_images);
break;
@ -1547,9 +1609,6 @@ midori_web_settings_get_property (GObject* object,
case PROP_MAXIMUM_HISTORY_AGE:
g_value_set_int (value, web_settings->maximum_history_age);
break;
case PROP_REMEMBER_LAST_FORM_INPUTS:
g_value_set_boolean (value, web_settings->remember_last_form_inputs);
break;
case PROP_REMEMBER_LAST_DOWNLOADED_FILES:
g_value_set_boolean (value, web_settings->remember_last_downloaded_files);
break;
@ -1571,9 +1630,6 @@ midori_web_settings_get_property (GObject* object,
}
g_value_set_string (value, web_settings->ident_string);
break;
case PROP_CACHE_SIZE:
g_value_set_int (value, web_settings->cache_size);
break;
case PROP_CLEAR_PRIVATE_DATA:
g_value_set_int (value, web_settings->clear_private_data);
break;

View File

@ -43,6 +43,7 @@ enum
MIDORI_CLEAR_WEBSITE_ICONS = 8,
MIDORI_CLEAR_TRASH = 16,
MIDORI_CLEAR_ON_QUIT = 32,
MIDORI_CLEAR_WEB_CACHE = 64,
};
typedef enum
@ -76,6 +77,7 @@ typedef enum
{
MIDORI_ENCODING_CHINESE,
MIDORI_ENCODING_JAPANESE,
MIDORI_ENCODING_KOREAN,
MIDORI_ENCODING_RUSSIAN,
MIDORI_ENCODING_UNICODE,
MIDORI_ENCODING_WESTERN,
@ -105,6 +107,7 @@ typedef enum
{
MIDORI_TOOLBAR_DEFAULT,
MIDORI_TOOLBAR_ICONS,
MIDORI_TOOLBAR_SMALL_ICONS,
MIDORI_TOOLBAR_TEXT,
MIDORI_TOOLBAR_BOTH,
MIDORI_TOOLBAR_BOTH_HORIZ

View File

@ -11,14 +11,14 @@
*/
#include "sokoke.h"
#include "midori-stock.h"
#include "compat.h"
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "compat.h"
#include "midori-stock.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
@ -40,6 +40,17 @@
#include <idna.h>
#endif
#ifdef HAVE_HILDON_FM
#include <hildon/hildon-file-chooser-dialog.h>
#endif
#if HAVE_HILDON
#include <libosso.h>
#include <hildon/hildon.h>
#include <hildon-mime.h>
#include <hildon-uri.h>
#endif
static gchar*
sokoke_js_string_utf8 (JSStringRef js_string)
{
@ -73,7 +84,8 @@ sokoke_js_script_eval (JSContextRef js_context,
{
JSStringRef js_message = JSValueToStringCopy (js_context,
js_exception, NULL);
*exception = sokoke_js_string_utf8 (js_message);
if (exception)
*exception = sokoke_js_string_utf8 (js_message);
JSStringRelease (js_message);
js_value = JSValueMakeNull (js_context);
}
@ -85,17 +97,106 @@ sokoke_js_script_eval (JSContextRef js_context,
return value;
}
static void
error_dialog (const gchar* short_message,
const gchar* detailed_message)
void
sokoke_message_dialog (GtkMessageType message_type,
const gchar* short_message,
const gchar* detailed_message)
{
GtkWidget* dialog = gtk_message_dialog_new (
NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", short_message);
NULL, 0, message_type,
#if HAVE_HILDON
GTK_BUTTONS_NONE,
#else
GTK_BUTTONS_OK,
#endif
"%s", short_message);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", detailed_message);
gtk_widget_show (dialog);
g_signal_connect_swapped (dialog, "response",
G_CALLBACK (gtk_widget_destroy), dialog);
gtk_widget_show (dialog);
}
/**
* sokoke_show_uri_with_mime_type:
* @screen: a #GdkScreen, or %NULL
* @uri: the URI to show
* @mime_type: a MIME type
* @timestamp: the timestamp of the event
* @error: the location of a #GError, or %NULL
*
* Shows the specified URI with an appropriate application,
* as though it had the specified MIME type.
*
* On Maemo, hildon_mime_open_file_with_mime_type() is used.
*
* See also: sokoke_show_uri().
*
* Return value: %TRUE on success, %FALSE if an error occurred
**/
gboolean
sokoke_show_uri_with_mime_type (GdkScreen* screen,
const gchar* uri,
const gchar* mime_type,
guint32 timestamp,
GError** error)
{
gboolean success;
#if HAVE_HILDON
osso_context_t* osso;
DBusConnection* dbus;
osso = osso_initialize (PACKAGE_NAME, PACKAGE_VERSION, FALSE, NULL);
if (!osso)
{
g_print ("Failed to initialize libosso\n");
return FALSE;
}
dbus = (DBusConnection *) osso_get_dbus_connection (osso);
if (!dbus)
{
osso_deinitialize (osso);
g_print ("Failed to get dbus connection from osso context\n");
return FALSE;
}
success = (hildon_mime_open_file_with_mime_type (dbus,
uri, mime_type) == 1);
osso_deinitialize (osso);
#else
GFile* file = g_file_new_for_uri (uri);
gchar* content_type;
GAppInfo* app_info;
GList* files;
gpointer context;
#if GLIB_CHECK_VERSION (2, 18, 0)
content_type = g_content_type_from_mime_type (mime_type);
#else
content_type = g_strdup (mime_type);
#endif
app_info = g_app_info_get_default_for_type (content_type,
!g_str_has_prefix (uri, "file://"));
g_free (content_type);
files = g_list_prepend (NULL, file);
#if GTK_CHECK_VERSION (2, 14, 0)
context = gdk_app_launch_context_new ();
gdk_app_launch_context_set_screen (context, screen);
gdk_app_launch_context_set_timestamp (context, timestamp);
#else
context = g_app_launch_context_new ();
#endif
success = g_app_info_launch (app_info, files, context, error);
g_object_unref (app_info);
g_list_free (files);
g_object_unref (file);
#endif
return success;
}
/**
@ -109,6 +210,8 @@ error_dialog (const gchar* short_message,
* supports xdg-open, exo-open and gnome-open as fallbacks if
* GIO doesn't do the trick.
*
* On Maemo, hildon_uri_open() is used.
*
* Return value: %TRUE on success, %FALSE if an error occurred
**/
gboolean
@ -117,6 +220,11 @@ sokoke_show_uri (GdkScreen* screen,
guint32 timestamp,
GError** error)
{
#if HAVE_HILDON
HildonURIAction* action = hildon_uri_get_default_action_by_uri (uri, NULL);
return hildon_uri_open (uri, action, error);
#else
const gchar* fallbacks [] = { "xdg-open", "exo-open", "gnome-open" };
gsize i;
@ -139,49 +247,113 @@ sokoke_show_uri (GdkScreen* screen,
}
return FALSE;
#endif
}
gboolean
sokoke_spawn_program (const gchar* command,
const gchar* argument,
gboolean quote)
gboolean filename)
{
gchar* argument_escaped;
gchar* command_ready;
gchar** argv;
GError* error;
g_return_val_if_fail (command != NULL, FALSE);
g_return_val_if_fail (argument != NULL, FALSE);
argument_escaped = quote ? g_shell_quote (argument) : g_strdup (argument);
if (strstr (command, "%s"))
command_ready = g_strdup_printf (command, argument_escaped);
if (filename)
{
gboolean success;
#if HAVE_HILDON
osso_context_t* osso;
DBusConnection* dbus;
osso = osso_initialize (PACKAGE_NAME, PACKAGE_VERSION, FALSE, NULL);
if (!osso)
{
sokoke_message_dialog (GTK_MESSAGE_ERROR,
_("Could not run external program."),
"Failed to initialize libosso");
return FALSE;
}
dbus = (DBusConnection *) osso_get_dbus_connection (osso);
if (!dbus)
{
osso_deinitialize (osso);
sokoke_message_dialog (GTK_MESSAGE_ERROR,
_("Could not run external program."),
"Failed to get dbus connection from osso context");
return FALSE;
}
error = NULL;
/* FIXME: This is not correct, find a proper way to do this */
success = (osso_application_top (osso, command, argument) == OSSO_OK);
osso_deinitialize (osso);
#else
GAppInfo* info;
GFile* file;
GList* files;
info = g_app_info_create_from_commandline (command,
NULL, G_APP_INFO_CREATE_NONE, NULL);
file = g_file_new_for_commandline_arg (argument);
files = g_list_append (NULL, file);
error = NULL;
success = g_app_info_launch (info, files, NULL, &error);
g_object_unref (file);
g_list_free (files);
#endif
if (!success)
{
sokoke_message_dialog (GTK_MESSAGE_ERROR,
_("Could not run external program."),
error ? error->message : "");
if (error)
g_error_free (error);
return FALSE;
}
}
else
command_ready = g_strconcat (command, " ", argument_escaped, NULL);
error = NULL;
if (!g_shell_parse_argv (command_ready, NULL, &argv, &error))
{
error_dialog (_("Could not run external program."), error->message);
g_error_free (error);
/* FIXME: Implement Hildon specific version */
gchar* command_ready;
gchar** argv;
if (strstr (command, "%s"))
command_ready = g_strdup_printf (command, argument);
else
command_ready = g_strconcat (command, " ", argument, NULL);
error = NULL;
if (!g_shell_parse_argv (command_ready, NULL, &argv, &error))
{
sokoke_message_dialog (GTK_MESSAGE_ERROR,
_("Could not run external program."),
error->message);
g_error_free (error);
g_free (command_ready);
return FALSE;
}
g_free (command_ready);
g_free (argument_escaped);
return FALSE;
error = NULL;
if (!g_spawn_async (NULL, argv, NULL,
(GSpawnFlags)G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
NULL, NULL, NULL, &error))
{
sokoke_message_dialog (GTK_MESSAGE_ERROR,
_("Could not run external program."),
error->message);
g_error_free (error);
}
g_strfreev (argv);
}
error = NULL;
if (!g_spawn_async (NULL, argv, NULL,
(GSpawnFlags)G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
NULL, NULL, NULL, &error))
{
error_dialog (_("Could not run external program."), error->message);
g_error_free (error);
}
g_strfreev (argv);
g_free (command_ready);
g_free (argument_escaped);
return TRUE;
}
@ -365,6 +537,8 @@ sokoke_magic_uri (const gchar* uri,
/* Just return if it's a javascript: or mailto: uri */
if (g_str_has_prefix (uri, "javascript:")
|| g_str_has_prefix (uri, "mailto:")
|| g_str_has_prefix (uri, "tel:")
|| g_str_has_prefix (uri, "callto:")
|| g_str_has_prefix (uri, "data:"))
return g_strdup (uri);
/* Add file:// if we have a local path */
@ -428,11 +602,22 @@ sokoke_format_uri_for_display (const gchar* uri)
{
if (uri && g_str_has_prefix (uri, "http://"))
{
gchar* unescaped = g_uri_unescape_string (uri, NULL);
gchar* unescaped = g_uri_unescape_string (uri, " +");
#ifdef HAVE_LIBSOUP_2_27_90
gchar* path;
gchar* hostname = sokoke_hostname_from_uri (unescaped, &path);
gchar* decoded = g_hostname_to_unicode (hostname);
gchar* hostname;
gchar* decoded;
if (!unescaped)
return g_strdup (uri);
else if (!g_utf8_validate (unescaped, -1, NULL))
{
g_free (unescaped);
return g_strdup (uri);
}
hostname = sokoke_hostname_from_uri (unescaped, &path);
decoded = g_hostname_to_unicode (hostname);
if (decoded)
{
@ -446,6 +631,15 @@ sokoke_format_uri_for_display (const gchar* uri)
return unescaped;
#elif HAVE_LIBIDN
gchar* decoded;
if (!unescaped)
return g_strdup (uri);
else if (!g_utf8_validate (unescaped, -1, NULL))
{
g_free (unescaped);
return g_strdup (uri);
}
if (!idna_to_unicode_8z8z (unescaped, &decoded, 0) == IDNA_SUCCESS)
return unescaped;
g_free (unescaped);
@ -490,15 +684,6 @@ sokoke_container_show_children (GtkContainer* container)
gtk_container_foreach (container, (GtkCallback)(gtk_widget_show_all), NULL);
}
void
sokoke_widget_popup (GtkWidget* widget,
GtkMenu* menu,
GdkEventButton* event,
SokokeMenuPos pos)
{
katze_widget_popup (widget, menu, event, (KatzeMenuPos)pos);
}
typedef enum
{
SOKOKE_DESKTOP_UNTESTED,
@ -608,24 +793,6 @@ sokoke_xfce_header_new (const gchar* icon,
return NULL;
}
GtkWidget*
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;
}
void
sokoke_widget_set_pango_font_style (GtkWidget* widget,
PangoStyle style)
@ -888,20 +1055,6 @@ sokoke_action_create_popup_menu_item (GtkAction* action)
return menuitem;
}
/**
* sokoke_image_menu_item_new_ellipsized:
* @label: the text of the menu item
*
* Creates a new #GtkImageMenuItem containing an ellipsized label.
*
* Return value: a new #GtkImageMenuItem
**/
GtkWidget*
sokoke_image_menu_item_new_ellipsized (const gchar* label)
{
return katze_image_menu_item_new_ellipsized (label);
}
/**
* sokoke_time_t_to_julian:
* @timestamp: a time_t timestamp value
@ -934,6 +1087,11 @@ sokoke_time_t_to_julian (const time_t* timestamp)
void
sokoke_register_stock_items (void)
{
GtkIconSource* icon_source;
GtkIconSet* icon_set;
GtkIconFactory* factory;
gsize i;
typedef struct
{
const gchar* stock_id;
@ -942,11 +1100,6 @@ sokoke_register_stock_items (void)
guint keyval;
const gchar* fallback;
} FatStockItem;
GtkIconSource* icon_source;
GtkIconSet* icon_set;
GtkIconFactory* factory = gtk_icon_factory_new ();
gsize i;
static FatStockItem items[] =
{
{ STOCK_EXTENSION, NULL, 0, 0, GTK_STOCK_CONVERT },
@ -958,7 +1111,7 @@ sokoke_register_stock_items (void)
{ STOCK_TRANSFER, NULL, 0, 0, GTK_STOCK_SAVE },
{ STOCK_BOOKMARK, N_("_Bookmark"), 0, 0, GTK_STOCK_FILE },
{ STOCK_BOOKMARKS, N_("_Bookmarks"), 0, 0, GTK_STOCK_DIRECTORY },
{ STOCK_BOOKMARKS, N_("_Bookmarks"), GDK_CONTROL_MASK, GDK_B, GTK_STOCK_DIRECTORY },
{ 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 },
@ -972,6 +1125,7 @@ sokoke_register_stock_items (void)
{ STOCK_WINDOW_NEW, N_("New _Window"), 0, 0, GTK_STOCK_ADD },
};
factory = gtk_icon_factory_new ();
for (i = 0; i < G_N_ELEMENTS (items); i++)
{
icon_set = gtk_icon_set_new ();
@ -991,6 +1145,55 @@ sokoke_register_stock_items (void)
gtk_stock_add ((GtkStockItem*)items, G_N_ELEMENTS (items));
gtk_icon_factory_add_default (factory);
g_object_unref (factory);
#if HAVE_HILDON
/* Maemo doesn't theme stock icons. So we map platform icons
to stock icons. These are all monochrome toolbar icons. */
typedef struct
{
const gchar* stock_id;
const gchar* icon_name;
} CompatItem;
static CompatItem compat_items[] =
{
{ GTK_STOCK_ADD, "general_add" },
{ GTK_STOCK_BOLD, "general_bold" },
{ GTK_STOCK_CLOSE, "general_close_b" },
{ GTK_STOCK_DELETE, "general_delete" },
{ GTK_STOCK_DIRECTORY, "general_toolbar_folder" },
{ GTK_STOCK_FIND, "general_search" },
{ GTK_STOCK_FULLSCREEN, "general_fullsize_b" },
{ GTK_STOCK_GO_BACK, "general_back" },
{ GTK_STOCK_GO_FORWARD, "general_forward" },
{ GTK_STOCK_GO_UP, "filemanager_folder_up" },
{ GTK_STOCK_GOTO_FIRST, "pdf_viewer_first_page" },
{ GTK_STOCK_GOTO_LAST, "pdf_viewer_last_page" },
{ GTK_STOCK_INFO, "general_information" },
{ GTK_STOCK_ITALIC, "general_italic" },
{ GTK_STOCK_JUMP_TO, "general_move_to_folder" },
{ GTK_STOCK_PREFERENCES,"general_settings" },
{ GTK_STOCK_REFRESH, "general_refresh" },
{ GTK_STOCK_SAVE, "notes_save" },
{ GTK_STOCK_STOP, "general_stop" },
{ GTK_STOCK_UNDERLINE, "notes_underline" },
{ GTK_STOCK_ZOOM_IN, "pdf_zoomin" },
{ GTK_STOCK_ZOOM_OUT, "pdf_zoomout" },
};
factory = gtk_icon_factory_new ();
for (i = 0; i < G_N_ELEMENTS (compat_items); i++)
{
icon_set = gtk_icon_set_new ();
icon_source = gtk_icon_source_new ();
gtk_icon_source_set_icon_name (icon_source, compat_items[i].icon_name);
gtk_icon_set_add_source (icon_set, icon_source);
gtk_icon_source_free (icon_source);
gtk_icon_factory_add (factory, compat_items[i].stock_id, icon_set);
gtk_icon_set_unref (icon_set);
}
gtk_icon_factory_add_default (factory);
g_object_unref (factory);
#endif
}
/**
@ -1117,6 +1320,7 @@ sokoke_find_data_filename (const gchar* filename)
return g_build_filename (MDATADIR, filename, NULL);
}
#if !WEBKIT_CHECK_VERSION (1, 1, 14)
static void
res_server_handler_cb (SoupServer* res_server,
SoupMessage* msg,
@ -1209,6 +1413,7 @@ sokoke_get_res_server (void)
return res_server;
}
#endif
gchar*
sokoke_replace_variables (const gchar* template,
@ -1234,3 +1439,75 @@ sokoke_replace_variables (const gchar* template,
return result;
}
/**
* sokoke_window_activate_key:
* @window: a #GtkWindow
* @event: a #GdkEventKey
*
* Attempts to activate they key from the event, much
* like gtk_window_activate_key(), including keys
* that gtk_accelerator_valid() considers invalid.
*
* Return value: %TRUE on success
**/
gboolean
sokoke_window_activate_key (GtkWindow* window,
GdkEventKey* event)
{
gchar *accel_name;
GQuark accel_quark;
GObject* object;
GSList *slist;
if (gtk_window_activate_key (window, event))
return TRUE;
/* We don't use gtk_accel_groups_activate because it refuses to
activate anything that gtk_accelerator_valid doesn't like. */
accel_name = gtk_accelerator_name (event->keyval, (event->state & gtk_accelerator_get_default_mod_mask ()));
accel_quark = g_quark_from_string (accel_name);
g_free (accel_name);
object = G_OBJECT (window);
for (slist = gtk_accel_groups_from_object (object); slist; slist = slist->next)
if (gtk_accel_group_activate (slist->data, accel_quark,
object, event->keyval, event->state))
return TRUE;
return FALSE;
}
/**
* sokoke_file_chooser_dialog_new:
* @title: a window title, or %NULL
* @window: a parent #GtkWindow, or %NULL
* @action: a #GtkFileChooserAction
*
* Creates a new file chooser dialog, as appropriate for
* the platform, with buttons according to the @action.
*
* The positive response is %GTK_RESPONSE_OK.
*
* Return value: a new #GtkFileChooser
**/
GtkWidget*
sokoke_file_chooser_dialog_new (const gchar* title,
GtkWindow* window,
GtkFileChooserAction action)
{
const gchar* stock_id = GTK_STOCK_OPEN;
GtkWidget* dialog;
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
stock_id = GTK_STOCK_SAVE;
#ifdef HAVE_HILDON_FM
dialog = hildon_file_chooser_dialog_new (window, action);
#else
dialog = gtk_file_chooser_dialog_new (title, window, action,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
stock_id, GTK_RESPONSE_OK, NULL);
gtk_window_set_icon_name (GTK_WINDOW (dialog), stock_id);
#endif
return dialog;
}

View File

@ -15,8 +15,7 @@
#include <katze/katze.h>
#include <gtk/gtk.h>
#include <libsoup/soup.h>
#include <webkit/webkit.h>
#include <JavaScriptCore/JavaScript.h>
gchar*
@ -27,6 +26,18 @@ sokoke_js_script_eval (JSContextRef js_context,
/* Many themes need this hack for small toolbars to work */
#define GTK_ICON_SIZE_SMALL_TOOLBAR GTK_ICON_SIZE_BUTTON
void
sokoke_message_dialog (GtkMessageType message_type,
const gchar* short_message,
const gchar* detailed_message);
gboolean
sokoke_show_uri_with_mime_type (GdkScreen* screen,
const gchar* uri,
const gchar* mime_type,
guint32 timestamp,
GError** error);
gboolean
sokoke_show_uri (GdkScreen* screen,
const gchar* uri,
@ -55,12 +66,6 @@ sokoke_magic_uri (const gchar* uri,
gchar*
sokoke_format_uri_for_display (const gchar* uri);
typedef enum {
SOKOKE_MENU_POSITION_CURSOR = 0,
SOKOKE_MENU_POSITION_LEFT,
SOKOKE_MENU_POSITION_RIGHT
} SokokeMenuPos;
void
sokoke_combo_box_add_strings (GtkComboBox* combobox,
const gchar* label_first,
@ -73,19 +78,10 @@ sokoke_widget_set_visible (GtkWidget* widget,
void
sokoke_container_show_children (GtkContainer* container);
void
sokoke_widget_popup (GtkWidget* widget,
GtkMenu* menu,
GdkEventButton* event,
SokokeMenuPos pos);
GtkWidget*
sokoke_xfce_header_new (const gchar* icon,
const gchar* title);
GtkWidget*
sokoke_hig_frame_new (const gchar* title);
void
sokoke_widget_set_pango_font_style (GtkWidget* widget,
PangoStyle style);
@ -145,9 +141,6 @@ sokoke_widget_get_text_size (GtkWidget* widget,
GtkWidget*
sokoke_action_create_popup_menu_item (GtkAction* action);
GtkWidget*
sokoke_image_menu_item_new_ellipsized (const gchar* label);
gint64
sokoke_time_t_to_julian (const time_t* timestamp);
@ -168,11 +161,22 @@ sokoke_find_config_filename (const gchar* folder,
gchar*
sokoke_find_data_filename (const gchar* filename);
#if !WEBKIT_CHECK_VERSION (1, 1, 14)
SoupServer*
sokoke_get_res_server (void);
#endif
gchar*
sokoke_replace_variables (const gchar* template,
const gchar* variable_first, ...);
gboolean
sokoke_window_activate_key (GtkWindow* window,
GdkEventKey* event);
GtkWidget*
sokoke_file_chooser_dialog_new (const gchar* title,
GtkWindow* window,
GtkFileChooserAction action);
#endif /* !__SOKOKE_H__ */

View File

@ -10,7 +10,9 @@ 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 WS2_32 OPENSSL HILDON'
obj.uselib = 'UNIQUE LIBSOUP LIBIDN GIO GTK SQLITE LIBNOTIFY WEBKIT LIBXML ' \
'WS2_32 OPENSSL ' \
'HILDON HILDON_FM'
obj.uselib_local = 'katze'
obj.install_path = None
@ -19,7 +21,7 @@ obj.name = 'panels'
obj.target = 'panels'
obj.includes = '. ..'
obj.find_sources_in_dirs ('../panels')
obj.uselib = 'UNIQUE LIBSOUP GMODULE GTHREAD GIO GTK SQLITE WEBKIT LIBXML'
obj.uselib = 'UNIQUE LIBSOUP GMODULE GTHREAD GIO GTK SQLITE WEBKIT LIBXML X11'
obj.uselib_local = 'midori-core'
obj.install_path = None

View File

@ -280,14 +280,21 @@ static void
midori_addons_button_add_clicked_cb (GtkToolItem* toolitem,
MidoriAddons* addons)
{
GtkWidget* dialog = gtk_message_dialog_new (
gchar* path_scripts, *path_styles;
GtkWidget* dialog;
path_scripts = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
PACKAGE_NAME, "scripts", NULL);
path_styles = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
PACKAGE_NAME, "styles", NULL);
dialog = gtk_message_dialog_new (
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (addons))),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
_("Copy userscripts to the folder %s and "
"copy userstyles to the folder %s."),
"~/.local/share/midori/scripts",
"~/.local/share/midori/styles");
"copy userstyles to the folder %s."), path_scripts, path_styles);
g_free (path_scripts);
g_free (path_styles);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}

View File

@ -32,6 +32,10 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
gboolean new_bookmark,
gboolean is_folder);
void
midori_browser_open_bookmark (MidoriBrowser* browser,
KatzeItem* item);
struct _MidoriBookmarks
{
GtkVBox parent_instance;
@ -182,6 +186,14 @@ midori_bookmarks_folder_clicked_cb (GtkWidget* toolitem)
NULL, TRUE, TRUE);
}
static void
midori_bookmarks_import_clicked_cb (GtkWidget* toolitem)
{
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (toolitem));
/* FIXME: Take selected folder into account */
midori_browser_activate_action (browser, "BookmarksImport");
}
static void
midori_bookmarks_cursor_or_row_changed_cb (GtkTreeView* treeview,
MidoriBookmarks* bookmarks)
@ -255,6 +267,13 @@ midori_bookmarks_get_toolbar (MidoriViewable* viewable)
gtk_tool_item_set_expand (toolitem, TRUE);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CONVERT);
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
_("Import bookmarks..."));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_bookmarks_import_clicked_cb), bookmarks);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
gtk_widget_show (GTK_WIDGET (toolitem));
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DIRECTORY);
gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
_("Add a new folder"));
@ -563,9 +582,7 @@ midori_bookmarks_treeview_render_icon_cb (GtkTreeViewColumn* column,
pixbuf = gtk_widget_render_icon (treeview, GTK_STOCK_DIRECTORY,
GTK_ICON_SIZE_MENU, NULL);
else if (katze_item_get_uri (item))
pixbuf = katze_net_load_icon (
MIDORI_BOOKMARKS (gtk_widget_get_parent (treeview))->net,
katze_item_get_uri (item), NULL, treeview, NULL);
pixbuf = katze_load_cached_icon (katze_item_get_uri (item), treeview);
g_object_set (renderer, "pixbuf", pixbuf, NULL);
if (pixbuf)
@ -603,19 +620,17 @@ midori_bookmarks_row_activated_cb (GtkTreeView* treeview,
GtkTreeModel* model;
GtkTreeIter iter;
KatzeItem* item;
const gchar* uri;
model = gtk_tree_view_get_model (treeview);
if (gtk_tree_model_get_iter (model, &iter, path))
{
MidoriBrowser* browser;
gtk_tree_model_get (model, &iter, 0, &item, -1);
uri = katze_item_get_uri (item);
if (uri && *uri)
{
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (bookmarks));
midori_browser_set_current_uri (browser, uri);
}
browser = midori_browser_get_for_widget (GTK_WIDGET (bookmarks));
midori_browser_open_bookmark (browser, item);
g_object_unref (item);
}
@ -797,8 +812,7 @@ midori_bookmarks_popup (GtkWidget* widget,
midori_bookmarks_popup_item (menu, GTK_STOCK_DELETE, NULL,
item, midori_bookmarks_delete_activate_cb, bookmarks);
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR);
}
static gboolean

View File

@ -73,7 +73,7 @@ midori_extensions_class_init (MidoriExtensionsClass* class)
gobject_class->get_property = midori_extensions_get_property;
gobject_class->finalize = midori_extensions_finalize;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
flags = G_PARAM_READWRITE;
g_object_class_install_property (gobject_class,
PROP_APP,
@ -183,6 +183,10 @@ midori_extensions_set_property (GObject* object,
i = 0;
while ((extension = katze_array_get_nth_item (array, i++)))
midori_extensions_add_item_cb (array, extension, extensions);
/* Hide if there are no extensions at all */
if (!katze_array_get_nth_item (array, 0))
gtk_widget_hide (GTK_WIDGET (object));
}
break;
default:
@ -378,8 +382,7 @@ midori_extensions_popup (GtkWidget* widget,
midori_extensions_about_activate_cb, FALSE,
extensions);
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR);
g_free (website);
}

View File

@ -328,7 +328,7 @@ midori_history_add_item_cb (KatzeArray* array,
if (array == history->array)
{
gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
&iter, NULL, G_MAXINT, 0, added_item, -1);
&iter, NULL, 0, 0, added_item, -1);
return;
}
@ -344,7 +344,7 @@ midori_history_add_item_cb (KatzeArray* array,
GtkTreeIter child_iter;
gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
&child_iter, &iter, G_MAXINT, 0, added_item, -1);
&child_iter, &iter, 0, 0, added_item, -1);
break;
}
g_object_unref (item);
@ -560,9 +560,7 @@ midori_history_treeview_render_icon_cb (GtkTreeViewColumn* column,
pixbuf = gtk_widget_render_icon (treeview, GTK_STOCK_DIRECTORY,
GTK_ICON_SIZE_MENU, NULL);
else
pixbuf = katze_net_load_icon (
MIDORI_HISTORY (gtk_widget_get_parent (treeview))->net,
katze_item_get_uri (item), NULL, treeview, NULL);
pixbuf = katze_load_cached_icon (katze_item_get_uri (item), treeview);
g_object_set (renderer, "pixbuf", pixbuf, NULL);
@ -577,7 +575,7 @@ midori_history_treeview_render_text_cb (GtkTreeViewColumn* column,
GtkCellRenderer* renderer,
GtkTreeModel* model,
GtkTreeIter* iter,
GtkWidget* treeview)
MidoriHistory* history)
{
KatzeItem* item;
gint64 age;
@ -590,9 +588,21 @@ midori_history_treeview_render_text_cb (GtkTreeViewColumn* column,
{
gchar* sdate;
g_assert (age >= 0);
/* A negative age is a date in the future, the clock is probably off */
if (age < -1)
{
static gboolean clock_warning = FALSE;
if (!clock_warning)
{
midori_app_send_notification (history->app,
_("Erroneous clock time"),
_("The clock time lies in the past. "
"Please check the current date and time."));
clock_warning = TRUE;
}
}
if (age > 7)
if (age > 7 || age < 0)
{
g_object_set (renderer, "text", katze_item_get_name (item), NULL);
}
@ -828,8 +838,7 @@ midori_history_popup (GtkWidget* widget,
midori_history_popup_item (menu, GTK_STOCK_DELETE, NULL,
item, midori_history_delete_activate_cb, history);
sokoke_widget_popup (widget, GTK_MENU (menu),
event, SOKOKE_MENU_POSITION_CURSOR);
katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR);
}
static gboolean
@ -941,7 +950,7 @@ midori_history_init (MidoriHistory* history)
gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
gtk_tree_view_column_set_cell_data_func (column, renderer_text,
(GtkTreeCellDataFunc)midori_history_treeview_render_text_cb,
treeview, NULL);
history, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
g_object_unref (model);
g_object_connect (treeview,

View File

@ -255,8 +255,7 @@ midori_plugins_init (MidoriPlugins* plugins)
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; }"
"{ f.push (l[i].name + '|' + l[i].filename); } return f; }"
"plugins (navigator.plugins)", NULL);
gchar** items = g_strsplit (value, ",", 0);
guint i = 0;

View File

@ -483,8 +483,7 @@ midori_transfers_popup (GtkWidget* widget,
_("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);
katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR);
}
#endif

View File

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

View File

@ -26,6 +26,7 @@ katze/katze-utils.c
katze/katze-item.c
katze/katze-array.c
katze/katze-arrayaction.c
katze/katze-preferences.c
extensions/adblock.c
extensions/colorful-tabs.c
extensions/cookie-manager/cookie-manager.c
@ -38,9 +39,11 @@ extensions/feed-panel/feed-parse.c
extensions/feed-panel/feed-rss.c
extensions/feed-panel/main.c
extensions/formhistory.c
extensions/mouse-gestures/main.c
extensions/mouse-gestures.c
extensions/page-holder.c
extensions/shortcuts.c
extensions/statusbar-features.c
extensions/tab-panel.c
extensions/tab-switcher.c
extensions/toolbar-editor.c
extensions/web-cache.c

1965
po/ca.po

File diff suppressed because it is too large Load Diff

1761
po/cs.po

File diff suppressed because it is too large Load Diff

1504
po/da.po

File diff suppressed because it is too large Load Diff

1211
po/de.po

File diff suppressed because it is too large Load Diff

1607
po/fr.po

File diff suppressed because it is too large Load Diff

2628
po/gl.po

File diff suppressed because it is too large Load Diff

2682
po/he.po

File diff suppressed because it is too large Load Diff

1335
po/ja.po

File diff suppressed because it is too large Load Diff

2474
po/ko.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2295
po/no.po Normal file

File diff suppressed because it is too large Load Diff

1855
po/pt.po

File diff suppressed because it is too large Load Diff

1655
po/ru.po

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Midori 0.1.9-3345559\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-07-29 23:58+0200\n"
"PO-Revision-Date: 2009-10-12 16:32+0200\n"
"PO-Revision-Date: 2009-11-21 15:33+0100\n"
"Last-Translator: Robert Hartl <hartl.robert@gmail.com>\n"
"Language-Team: Slovak <sk-i18n@lists.linux.sk>\n"
"MIME-Version: 1.0\n"
@ -2028,11 +2028,11 @@ msgstr "Zoznam, detaily a mazanie cookies"
#: ../extensions/feed-panel/feed-atom.c:242
msgid "Failed to find required Atom \"entry\" elements in XML data."
msgstr ""
msgstr "Nepodarilo sa nájsť požadované prvky Atom \"entry\" v dátach XML."
#: ../extensions/feed-panel/feed-atom.c:348
msgid "Failed to find required Atom \"feed\" elements in XML data."
msgstr ""
msgstr "Nepodarilo sa nájsť požadované prvky Atom \"feed\" v dátach XML."
#. i18n: The local date a feed was last updated
#: ../extensions/feed-panel/feed-panel.c:399
@ -2074,7 +2074,7 @@ msgstr "Zlyhalo načítanie XML kanála: %s"
#: ../extensions/feed-panel/feed-rss.c:46
msgid "Failed to find \"channel\" element in RSS XML data."
msgstr "Nepodarilo sa nájsť element \"channel\" v RSS XML dátach"
msgstr "Nepodarilo sa nájsť prvok \"channel\" v RSS dátach XML."
#: ../extensions/feed-panel/feed-rss.c:51
msgid "Unsupported RSS version found."
@ -2082,11 +2082,11 @@ msgstr "Našla sa nepodporovaná verzia RSS"
#: ../extensions/feed-panel/feed-rss.c:148
msgid "Failed to find required RSS \"item\" elements in XML data."
msgstr ""
msgstr "Nepodarilo sa nájsť požadované prvky RSS \"item\" v dátach XML."
#: ../extensions/feed-panel/feed-rss.c:248
msgid "Failed to find required RSS \"channel\" elements in XML data."
msgstr ""
msgstr "Nepodarilo sa nájsť požadované prvky RSS \"channel\" v dátach XML."
#: ../extensions/feed-panel/main.c:114
#, c-format

File diff suppressed because it is too large Load Diff

View File

@ -78,6 +78,9 @@ properties_object_get_set (GObject* object)
g_param_spec_get_name (pspec),
g_param_spec_get_name (pspecs[j]));
if (!(pspec->flags & G_PARAM_READABLE))
continue;
g_object_get (object, property, &value, NULL);
if (type == G_TYPE_PARAM_BOOLEAN)
{

54
wscript
View File

@ -25,7 +25,7 @@ import misc
major = 0
minor = 2
micro = 0
micro = 2
APPNAME = 'midori'
VERSION = str (major) + '.' + str (minor) + '.' + str (micro)
@ -56,12 +56,12 @@ def is_mingw (env):
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)
rc_file = extension ('.rc')(rc_file)
Task.simple_task_type ('winrc', '${WINRC} -o${TGT} ${SRC}', color='BLUE',
before='cc cxx', shell=False)
@ -190,6 +190,15 @@ def configure (conf):
sqlite = 'no '
conf.define ('HAVE_SQLITE', [0,1][sqlite == 'yes'])
if option_enabled ('libnotify'):
check_pkg ('libnotify', mandatory=False)
libnotify = ['N/A','yes'][conf.env['HAVE_LIBNOTIFY'] == 1]
if libnotify != 'yes':
option_checkfatal ('libnotify', 'notifications')
else:
libnotify = 'no '
conf.define ('HAVE_LIBNOTIFY', [0,1][libnotify == 'yes'])
conf.check (lib='m', mandatory=True)
check_pkg ('gmodule-2.0', '2.8.0', False)
check_pkg ('gthread-2.0', '2.8.0', False)
@ -197,6 +206,8 @@ def configure (conf):
args = ''
if Options.platform == 'win32':
args = '--define-variable=target=win32'
elif sys.platform != 'darwin':
check_pkg ('x11')
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')
@ -220,6 +231,8 @@ def configure (conf):
if option_enabled ('hildon'):
if check_pkg ('hildon-1', mandatory=False, var='HILDON'):
check_pkg ('libosso', var='HILDON')
check_pkg ('hildon-1', '2.2', var='HILDON_2_2')
check_pkg ('hildon-fm-2', var='HILDON_FM')
hildon = ['N/A','yes'][conf.env['HAVE_HILDON'] == 1]
if hildon != 'yes':
option_checkfatal ('hildon', 'Maemo integration')
@ -246,6 +259,8 @@ def configure (conf):
conf.define ('HAVE_OSX', int(sys.platform == 'darwin'))
if Options.platform == 'win32':
conf.env.append_value ('LINKFLAGS', '-mwindows')
else:
conf.check (header_name='signal.h')
conf.define ('PACKAGE_VERSION', VERSION)
conf.define ('PACKAGE_NAME', APPNAME)
@ -290,6 +305,7 @@ def configure (conf):
Localization: %(nls)s (intltool)
Icon optimizations: %(icons)s (rsvg-convert)
Persistent history: %(sqlite)s (sqlite3)
Notifications: %(libnotify)s (libnotify)
IDN support: %(idn)s (libidn or libsoup 2.27.90)
User documentation: %(user_docs)s (docutils)
@ -300,7 +316,7 @@ def configure (conf):
Utils.pprint ('RED', 'Please use an older or newer version.')
def set_options (opt):
def is_maemo (): return os.path.exists ('/etc/osso-af-init/osso-gtk.defs')
def is_maemo (): return os.path.exists ('/etc/osso-af-init/')
def add_enable_option (option, desc, group=None, disable=False):
if group == None:
@ -338,9 +354,14 @@ def set_options (opt):
add_enable_option ('unique', 'single instance support', group)
add_enable_option ('libidn', 'international domain name support', group)
add_enable_option ('sqlite', 'history database support', group)
add_enable_option ('libnotify', 'notification support', group)
add_enable_option ('addons', 'building of extensions', group)
add_enable_option ('hildon', 'Maemo integration', group, disable=not is_maemo ())
# Provided for compatibility
opt.add_option ('--build', help='Ignored')
opt.add_option ('--disable-maintainer-mode', help='Ignored')
def build (bld):
def image_to_win32ico (task):
'Converts an image to a Win32 ico'
@ -378,7 +399,7 @@ def build (bld):
if bld.env['docs']:
bld.install_files ('${DOCDIR}/' + APPNAME + '/', \
'AUTHORS ChangeLog COPYING EXPAT README TRANSLATE')
'AUTHORS COPYING ChangeLog EXPAT README')
# Install default configuration
bld.install_files ('${SYSCONFDIR}/xdg/' + APPNAME + '/', 'data/search')
@ -449,22 +470,25 @@ def build (bld):
bld.install_files ('${MDATADIR}/' + APPNAME + '/res', blddir + '/data/logo-shade.png')
else:
Utils.pprint ('BLUE', "logo-shade could not be rasterized.")
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')
bld.install_files ('${MDATADIR}/' + APPNAME, 'data/autosuggestcontrol.js')
bld.install_files ('${MDATADIR}/' + APPNAME, 'data/autosuggestcontrol.css')
# FIXME: Determine the library naming for other platforms
if Options.platform == 'linux':
extensions = os.listdir ('data/extensions')
for extension in extensions:
folder = 'lib' + extension + '.so'
source = 'data/extensions/' + extension + '/config'
if os.path.exists (source):
bld.install_files ('${SYSCONFDIR}/' + APPNAME + \
'/extensions/' + folder, source)
if bld.env['addons']:
bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/autosuggestcontrol.js')
bld.install_files ('${MDATADIR}/' + APPNAME + '/res', 'data/autosuggestcontrol.css')
# FIXME: Determine the library naming for other platforms
if Options.platform == 'linux':
extensions = os.listdir ('data/extensions')
for extension in extensions:
folder = 'lib' + extension + '.so'
source = 'data/extensions/' + extension + '/config'
if os.path.exists (source):
bld.install_files ('${SYSCONFDIR}/' + APPNAME + \
'/extensions/' + folder, source)
if Options.commands['check']:
bld.add_subdirs ('tests')